oakode 0.0.0-stage → 0.5.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/CHANGELOG.md +86 -0
- package/LICENSE +9 -0
- package/README.md +243 -2
- package/SECURITY.md +13 -0
- package/dist/account.js +34 -0
- package/dist/agent.js +570 -0
- package/dist/agents/approval.js +116 -0
- package/dist/agents/budget.js +293 -0
- package/dist/agents/child.js +102 -0
- package/dist/agents/host.js +289 -0
- package/dist/agents/orchestrator.js +286 -0
- package/dist/agents/plan.js +143 -0
- package/dist/agents/types.js +20 -0
- package/dist/agents/verify.js +94 -0
- package/dist/app.js +619 -0
- package/dist/auth.js +456 -0
- package/dist/brief.js +97 -0
- package/dist/commands.js +587 -0
- package/dist/compact.js +231 -0
- package/dist/config.js +82 -0
- package/dist/diff.js +98 -0
- package/dist/doctor.js +106 -0
- package/dist/errors.js +15 -0
- package/dist/fileio.js +688 -0
- package/dist/input.js +244 -0
- package/dist/jobs.js +262 -0
- package/dist/main.js +560 -0
- package/dist/mask.js +63 -0
- package/dist/mcp.js +721 -0
- package/dist/models.js +106 -0
- package/dist/modes.js +114 -0
- package/dist/oicki.js +475 -0
- package/dist/output.js +101 -0
- package/dist/permissions.js +389 -0
- package/dist/permissions_ui.js +134 -0
- package/dist/print.js +76 -0
- package/dist/proc.js +63 -0
- package/dist/runners.js +264 -0
- package/dist/serial.js +9 -0
- package/dist/session.js +452 -0
- package/dist/shell.js +40 -0
- package/dist/skills.js +322 -0
- package/dist/syntax.js +80 -0
- package/dist/tools.js +480 -0
- package/dist/tui/editor.js +279 -0
- package/dist/tui/highlight.js +78 -0
- package/dist/tui/markdown.js +254 -0
- package/dist/tui/screen.js +146 -0
- package/dist/tui/tui.js +505 -0
- package/dist/tui/view.js +337 -0
- package/dist/ui.js +105 -0
- package/dist/update.js +64 -0
- package/package.json +57 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
Highlights: protected files and complete approval cards, runner approvals tied to the files that define them, background jobs for servers and slow test suites, a prompt cache that survives mode switches, resumes and compactions, and a transcript you can copy from. No new runtime dependency; Node 22 or newer as before.
|
|
6
|
+
|
|
7
|
+
Behavior changes to know about: `-p` exits non-zero when a turn did not complete or an action was declined, and prints errors to stderr; writes to protected files (`.git/`, `AGENTS.md`, `.mcp.json`, …) always ask, also in Auto Edit; Auto Edit no longer writes under `node_modules/` or a virtualenv without asking; a saved `npm test`-style approval asks once more after `package.json` or a Makefile changes; a typed line starting with `!` runs as a command; commands run with `NO_COLOR=1` and `PAGER=cat`. Session, permission, trust and credential files from 0.4.0 are read as before; 0.4.0 can still read the files 0.5.0 writes (after a downgrade, project skills need `/skills trust` again).
|
|
8
|
+
|
|
9
|
+
### Security
|
|
10
|
+
|
|
11
|
+
- A saved approval of a runner command (`npm test`, `make`, `cargo test`, `pytest`, `./scripts/x.sh` …) asks again when a file that defines what it runs changes: `package.json`, `.npmrc`, the Makefile, `Cargo.toml`, `build.rs`, `pyproject.toml`, lint and build tool configs, the script itself or a script that a `package.json` entry runs, and similar. Wrappers (`bash -lc`, `timeout`, `env`, `cmd /c`) do not hide the runner. Auto Edit no longer writes under `node_modules/` or a virtualenv without asking. With Auto Edit on, the agent could rewrite `package.json` and then run it under the saved `npm test` approval with no prompt. Ordinary source and test edits do not ask again, so the edit-test-fix loop is unchanged; this narrows the gap, it is not a sandbox. Approvals saved earlier take the files as they are when OAKODE starts as their baseline.
|
|
12
|
+
- The subagent plan card and `/agents` show the model's text with escape sequences and invisible characters made visible, as approval cards do. Before, a plan's goal, role or task, a report, or a transcript line could repaint the terminal or hide text from the person approving it.
|
|
13
|
+
- Writes to `.git/`, `.husky/`, `AGENTS.md`/`CLAUDE.md`, `.agents/` and `.mcp.json` always ask. Auto Edit, directory or workspace permissions and Custom "Always Allow" no longer cover them (a hook written to `.git/hooks` ran on your next commit). The decision uses the real path, so a symlink in the repository (`gitlink -> .git`) cannot get around it, and Windows spellings such as `.git.`, `GIT~1` and `file::$DATA` are recognized.
|
|
14
|
+
- Approval cards show the whole command, and MCP arguments in full. Lines are wrapped instead of cut at the terminal width, runs of blanks and invisible characters (bidirectional controls, zero-width and other format characters) are made visible, also in diffs. A command too long for one card must be shown in full before it can be allowed. Before, text past the 14th line or the right edge could be approved, and remembered, unseen. Commands that are very long or contain invisible characters can only be allowed once.
|
|
15
|
+
- Trusting a project's skills now covers their exact contents, checked when they load and again each time one is used. A trusted skill whose files change is disabled until you review it again. Projects trusted before this change keep the skills they had, which are fingerprinted the first time they load; skills added later need `/skills trust`.
|
|
16
|
+
|
|
17
|
+
### Reliability and data integrity
|
|
18
|
+
|
|
19
|
+
- `bash` takes a `timeout` given in milliseconds (`120000`) as such, instead of refusing it and costing a retry (seen in real sessions).
|
|
20
|
+
- Billing: when the credentials on disk become another sign-in (an `oakode login` in another terminal, or an API key saved over it), a running session says so instead of silently billing the new sign-in. A token refresh by another OAKODE window is not a change. Sign-ins made before this version are recognized from their next login.
|
|
21
|
+
- Network: a request that could not connect at all (no network, DNS failure, connection refused) is retried automatically for up to 5 minutes, with a notice for each wait. It was never sent, so it cannot have been billed. Esc stops the retries. When OAKODE gives up, it says the request was not sent and not billed, instead of "may have been billed". Failures after a connection was made are still never resent, including an unreachable-host error on a connection that was already open. Commands that only list models fail at once, as before, instead of waiting.
|
|
22
|
+
- Rate limits: OAKODE waits the full `Retry-After` (up to 60 s, in seconds or as a date) instead of retrying early, with a notice for each wait. A longer wait is reported right away. Connection retries no longer use up the rate-limit retries.
|
|
23
|
+
- Fixed: when a code block taller than the screen streamed in, one of its lines was dropped and a blank line was added near its end.
|
|
24
|
+
- Fixed: when an edit matched only by ignoring whitespace and quote style, lines the model left unchanged were rewritten with its characters. A curly `’` in an untouched string became `'`, and trailing spaces disappeared. Only the lines the model changed are replaced now.
|
|
25
|
+
- Fixed: piped input (`… | oakode -p "…"`) corrupted multibyte characters (Korean, Chinese, emoji) at chunk boundaries. It is now decoded once, including UTF-16 from PowerShell pipes. With an instruction argument, the piped data is wrapped in `<stdin>…</stdin>` so the model can tell the two apart. A pipe that sends nothing for 3 s gets a note on stderr.
|
|
26
|
+
- Fixed: deleting into a `[paste #N …]` marker (Backspace, Delete, Ctrl+W, Ctrl+U) left a broken marker and silently dropped the paste. A marker is now one unit, and the cursor skips over it.
|
|
27
|
+
- Fixed: a response stream that stopped without finishing (a gateway or connection cut) was recorded as a complete answer. It is now reported as an incomplete reply, which may have been billed and is not resent. A single undecodable stream event is skipped with a notice, instead of failing a reply that is being paid for.
|
|
28
|
+
- `-p` exit status: 0 only when the turn completed. An error, an interrupted or incomplete turn (output limit, iteration limit), or an action that was declined because `-p` cannot ask without `--yes` now exits 1 (130 when interrupted), so scripts and CI notice. Errors go to stderr with a resume command that works in `-p` (`oakode -p -r <id> "…"`), instead of the interactive `/retry` hint.
|
|
29
|
+
- Fixed: a command that leaves a process running in the background (`server &`, `sleep 30 & echo ok`) blocked bash until its timeout, then killed the process and reported "timed out" next to "exit code 0". Bash now returns as soon as the shell exits, says background processes are still running, and stops them when OAKODE exits.
|
|
30
|
+
- Fixed: long command output could lose its beginning, often the first error. Capture kept only the last 8 MiB, and the final cut kept only the end. Both now keep the start and the end, and say how much was cut from the middle.
|
|
31
|
+
- Fixed: every OAKODE start created a session file, even when you quit without typing, and `oakode -c` then resumed that empty session. A session file now appears with its first message, and `-c` skips empty files left by older versions.
|
|
32
|
+
|
|
33
|
+
### Cost and speed
|
|
34
|
+
|
|
35
|
+
- Compaction reuses the prompt cache: the summary is requested with the agent's own next request plus one instruction, so almost all of its input is read from the cache, and the model summarizes the full messages instead of a copy with tool results clipped to 3,000 characters. Measured on a 35k-token session (Luna): 0.28 credits instead of 0.56, 99% of the input cached, with a summary of comparable detail. It is used only while the cache is warm (a request in the last 4 minutes); otherwise, after `context_length_exceeded`, or when a model answers it with anything but a summary, the separate summarizer request is used. Compaction's cost is now counted in `/cost` and the turn's cost line (it was left out).
|
|
36
|
+
- `!command` runs a one-line command you type (`!npm test`; never pasted text) right away, without the model or an approval, and its output goes with your next message: "run the tests, then fix them" no longer costs a request and an approval for the command you already chose.
|
|
37
|
+
- The approval menu has "Deny, and say why…": the reason goes to the model with the denial, so it changes course in the same step instead of guessing.
|
|
38
|
+
- A successful edit says where the new text now is (`now at lines 12-18`) and, for small changes, shows those lines, so a next nearby edit needs no re-read. When `old_text` does not match, the error shows the file's actual lines at the closest spot, with the first differing line marked, instead of asking for a re-read.
|
|
39
|
+
- A reply cut off by the output limit or OICKI's 270 s limit runs the tool calls in it that were complete, with the usual approvals; only the last, cut one is not run, and the model is told which. Before, all of them were dropped and the model had to regenerate them in a new paid request.
|
|
40
|
+
- Prompt caching: the system prompt now stays byte-identical for the whole session, until a compaction starts a new context window. Before, switching to or from Plan mode, editing AGENTS.md, a change in the skill list and the date changing each rewrote it, so the next request re-sent the entire conversation uncached. These changes now reach the model as a short notice appended to the conversation, and the cached prefix stays valid. The prompt is kept in the session file, so a resumed session sends the same prompt and is told only what changed while it was closed. Leaving Plan mode says that Plan mode no longer applies.
|
|
41
|
+
- Streaming uses less CPU: the screen is repainted at most once per frame (about 80 times a second), and the answer is re-rendered once per frame instead of once per token. In a benchmark, rendering a long code block took 0.33 s of CPU instead of 1.2 s, and a long prose answer 0.17 s instead of 0.35 s.
|
|
42
|
+
|
|
43
|
+
### New in the terminal
|
|
44
|
+
|
|
45
|
+
- Notifications: an approval or subagent plan waiting while the terminal is in the background sends one desktop notification (OSC 9 in iTerm2, WezTerm and Ghostty; a bell elsewhere). Only after the terminal reports it lost focus, at most one every 5 s; `"notifications": false` in config.json turns them off.
|
|
46
|
+
- Queued messages can be seen and taken back: messages typed while the agent works are listed above the editor until it receives them, then printed in the conversation where it did. Alt+↑ (Option+↑) puts the last one back into the editor to edit and queue again, or to delete. The permanent `⏎ queued` line, which stayed even after a message was withdrawn, is gone.
|
|
47
|
+
- Copy and click: code blocks have no `│` gutter and are not wrapped by OAKODE, URLs are never broken, and finished transcript lines are no longer cut at the terminal width (the terminal soft-wraps them). A copied code block is the code as written, and a long local URL can be clicked.
|
|
48
|
+
- Reads, searches, globs and listings take one line each with a count, such as `(120 lines)` or `(12 matches in 3 files)`, instead of the first lines of their result.
|
|
49
|
+
- After each turn, one dim line shows its time, requests and credits.
|
|
50
|
+
- Background jobs: `bash {background: true}` runs a dev server, watcher or slow test suite as a job (approved like any command), returning once its output matches `until`, it ends, or after `wait` seconds. The new `job` tool polls it for new output only (waiting until it ends or `until` matches, so checking is one request), sends Ctrl+C, or kills it, without an approval since it starts nothing. At most 8 run at once; `/jobs` lists and stops them, the footer counts them, and OAKODE stops them all when it exits.
|
|
51
|
+
- Shortened command output and job logs go to a private per-session folder that `read` and `grep` can open (before, the file was in the system temp folder, unreachable without a bash approval, and never deleted). The folder is removed at exit; folders left by a crash are removed a day later.
|
|
52
|
+
- Commands run with `PAGER=cat`, `GIT_PAGER=cat`, `GH_PAGER=cat`, `GIT_TERMINAL_PROMPT=0` and `NO_COLOR=1`, without `FORCE_COLOR`: `git log` or a credential prompt can no longer hang a command.
|
|
53
|
+
- A command that fails shows it in its header (red, with `exit N`), and a timeout or interrupt in yellow. A command that could not start says so in red. A failed command used to have the same green bullet as a successful one. The `[exit code …]` line is no longer repeated in the output, and a command with no output says so.
|
|
54
|
+
- The live output of a running command shows a progress bar's latest state, instead of a growing row of `�` marks, and a line without a newline no longer grows without limit.
|
|
55
|
+
- Ctrl+C on an unsent draft clears it but keeps it in history: Up brings it back.
|
|
56
|
+
|
|
57
|
+
### Models and subagents
|
|
58
|
+
|
|
59
|
+
- Subagents: the `delegate` tool now says when delegating is not worth it (small projects, one-file changes, known locations), and a one-agent plan gets a warning on the card.
|
|
60
|
+
- Subagents, phase 1 (experimental, off by default): with `"subagents": { "enabled": true }`, the main agent can propose parallel read-only subagents. You approve, edit or deny each plan. They run with dependencies, per-agent and per-turn budgets, timeouts and cancellation; findings come back verified or unverified; `/agents` shows them. Budgets are estimate-based limits, not guarantees. Subagent ratios of credits per USD are learned from real charges and kept in `~/.oakode/credit-rates.json`.
|
|
61
|
+
- OAKODE supports a small set of models: `/model`, `/models`, `oakode models`, completion, `-m` and the saved default offer only those. `"experimentalModels": true` in `~/.oakode/config.json` opts in to the rest of OICKI's catalog, unsupported. Resumed sessions on other models keep them, with a notice; saved defaults are not rewritten. MiMo V2.6 Flash is treated as text-only.
|
|
62
|
+
|
|
63
|
+
## 0.4.0
|
|
64
|
+
|
|
65
|
+
First public beta.
|
|
66
|
+
|
|
67
|
+
- **Sign in with OICKI** (`oakode login`): browser sign-in with PKCE; `--no-browser` and an ssh port-forward hint for remote machines; tokens refresh automatically and safely across several OAKODE windows; an expired or revoked sign-in says so and asks you to sign in again. API keys still work (`oakode login --api-key`, `OICKI_API_KEY`).
|
|
68
|
+
- **Credits and plan** in the status line, `/status`, `/cost` and `oakode status`, with a warning when credits run low or out, and OAKODE's monthly credit limit when you set one under Connected apps.
|
|
69
|
+
- `oakode logout` ends the sign-in on OICKI (token revocation) and deletes the local credentials.
|
|
70
|
+
- `oakode doctor` checks the installation, credentials and connection.
|
|
71
|
+
- Clear messages for `content_filtered` (not billed; rephrase or switch models), `app_limit_exceeded` and too-large requests; only a real context overflow triggers compaction.
|
|
72
|
+
- Images: up to 1.5 MB (larger ones are scaled down on macOS); requests stay under OICKI's 4 MB / 50-image limit by leaving out the oldest images.
|
|
73
|
+
- The reply budget stays inside the context window; waiting out a `Retry-After` no longer looks like a timeout.
|
|
74
|
+
- Fixed: leftover lines in the terminal after a resize; a `/command` typed while busy was sent to the model.
|
|
75
|
+
- Daily, non-blocking update notice (opt out with `OAKODE_NO_UPDATE_CHECK=1`).
|
|
76
|
+
- Syntax check after every write and edit (JavaScript, Python, JSON, YAML, shell).
|
|
77
|
+
- Saved credentials are pinned to the server that issued them.
|
|
78
|
+
- Tested on Linux, macOS and Windows; the published package is installed and run in CI.
|
|
79
|
+
|
|
80
|
+
## 0.3.0
|
|
81
|
+
|
|
82
|
+
Reasoning effort and reasoning continuity, prompt caching (about half the cost on Claude models), cached/reasoning token and credit reporting, images from MCP tools, batched and parallel read-only tool calls, `glob`, gitignore-aware search with context lines, a project brief, a smaller request context, a cached model catalog, and an evaluation harness.
|
|
83
|
+
|
|
84
|
+
## 0.2.x
|
|
85
|
+
|
|
86
|
+
Permission modes, MCP client, skills, compaction, append writes, output budgets, session recovery.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OAKODE contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,244 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OAKODE
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A coding agent for your terminal, powered by [OICKI](https://oicki.vercel.app). It reads your project, edits files, runs commands and tests, and asks before it changes anything. You sign in with your OICKI account; usage is paid from your OICKI credits.
|
|
4
|
+
|
|
5
|
+
- A small set of supported models (affordable coding models with prompt caching, plus two stronger ones), `auto` by default; switch with `/model`. Other models in OICKI's catalog are an opt-in, unsupported experiment (see *Models*).
|
|
6
|
+
- Every write, edit and shell command asks first unless you allow it. Approval is not a sandbox.
|
|
7
|
+
- macOS, Linux and Windows; Node.js 22 or newer.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g oakode
|
|
13
|
+
oakode --version
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Requires [Node.js](https://nodejs.org) 22 or newer. To install a release candidate from its tarball: `npm install -g ./oakode-<version>.tgz`.
|
|
17
|
+
|
|
18
|
+
## Sign in
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
oakode login
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Your browser opens the OICKI sign-in page (OAKODE is registered with OICKI as a public "Sign in with OICKI" client, so there is no secret to configure). Approve OAKODE's access there (the page needs JavaScript):
|
|
25
|
+
|
|
26
|
+
- **Use AI for you** (required): requests are charged to your credits.
|
|
27
|
+
- **See your plan and credits** (recommended): OAKODE shows your balance in its status line.
|
|
28
|
+
- **Expensive models** only if you ask for them: `oakode login --expensive`.
|
|
29
|
+
- **Credit limit for OAKODE:** unlimited by default; you can set a monthly limit there or later under Account → Connected apps.
|
|
30
|
+
|
|
31
|
+
When the browser says "Signed in", go back to the terminal. The sign-in lasts until you have not used OAKODE for 30 days; it renews itself, also with several OAKODE windows open.
|
|
32
|
+
|
|
33
|
+
- **Over SSH or without a browser:** `oakode login --no-browser` prints the link. The page sends your browser back to `localhost:8976` on the machine where the browser runs, so forward that port first: `ssh -L 8976:localhost:8976 <host>` (OAKODE prints the exact command).
|
|
34
|
+
- **With an API key instead** (CI, servers): create one at <https://oicki.vercel.app/dashboard/developer>, then `oakode login --api-key` (hidden input, checked with OICKI), or set `OICKI_API_KEY` (takes precedence, never stored).
|
|
35
|
+
- **Sign out:** `oakode logout` ends this sign-in on OICKI and deletes the credentials stored on this computer (other computers stay signed in). To cut off OAKODE everywhere, remove it under Account → Connected apps in your OICKI account.
|
|
36
|
+
|
|
37
|
+
Credentials are stored in `~/.oakode/auth.json`, readable only by you (on Windows: in your user profile), and are only ever sent to the OICKI server they were issued by.
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
cd your-project
|
|
43
|
+
oakode # interactive session
|
|
44
|
+
oakode "add a --verbose flag to the CLI" # start with a request
|
|
45
|
+
oakode -p "explain src/main.ts" # one answer, non-interactive
|
|
46
|
+
oakode -c # continue the last session here
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Type `/` for commands: `/model` to choose a model, `/status` for your account and session, `/cost` for what this session used, `/diff` for the changes made, `/help` for everything.
|
|
50
|
+
|
|
51
|
+
## Credits and usage
|
|
52
|
+
|
|
53
|
+
- The status line shows the credits this session was charged and, when you granted "see your plan and credits", your remaining balance.
|
|
54
|
+
- `oakode status` and `/status` show your plan, balance, what OAKODE used this billing cycle and, if you set one, OAKODE's monthly credit limit (also in the status line: `app limit 12.5/2,000 credits`, yellow from 80 %, red when used up). OAKODE warns once when your credits run low or out.
|
|
55
|
+
- Prompt caching is used where the model supports it; `/cost` shows how much of the input came from the cache.
|
|
56
|
+
- OAKODE never resends a request that may have been billed; see *Billing and retries* below.
|
|
57
|
+
|
|
58
|
+
## Updating and uninstalling
|
|
59
|
+
|
|
60
|
+
OAKODE checks the npm registry for a newer version at most once a day in the background and mentions it at the next start (`OAKODE_NO_UPDATE_CHECK=1` turns this off; it is off in CI). Update with `npm install -g oakode@latest`. Uninstall with `npm uninstall -g oakode`; your sessions and settings are in `~/.oakode` (delete it to remove them).
|
|
61
|
+
|
|
62
|
+
## Troubleshooting
|
|
63
|
+
|
|
64
|
+
`oakode doctor` checks Node.js, the data directory's permissions, your credentials, the connection to OICKI, the model list and your credits, and says what to do about each problem.
|
|
65
|
+
|
|
66
|
+
| Message | What to do |
|
|
67
|
+
|---|---|
|
|
68
|
+
| Not signed in | `oakode login` |
|
|
69
|
+
| Your OICKI sign-in has expired or was revoked | `oakode login` again; sessions and settings are kept |
|
|
70
|
+
| Not enough credits | add credits or wait for your plan to renew (`oakode status` shows the balance) |
|
|
71
|
+
| Over the monthly credit limit you set for OAKODE (`app_limit_exceeded`) | raise it under Account → Connected apps (it resets on the 1st), or lower `maxOutputTokens` so smaller requests fit |
|
|
72
|
+
| The provider's safety filter refused the request (`content_filtered`) | not billed; rephrase, or switch models with `/model` |
|
|
73
|
+
| The request is larger than OICKI accepts (413) | usually an image; use a smaller one or `/clear` |
|
|
74
|
+
| Ports 8976–8978 are all in use | close what uses them, or `oakode login --api-key` |
|
|
75
|
+
| The saved sign-in is for another server | you set `OAKODE_BASE_URL`; sign in again for that server or unset it |
|
|
76
|
+
|
|
77
|
+
## Privacy
|
|
78
|
+
|
|
79
|
+
OAKODE sends your prompts, the files and command output the agent reads, and tool results to OICKI to get model answers. It has no telemetry. Other network requests: the daily npm update check, and MCP servers you configure. Sessions are stored locally in `~/.oakode/sessions`.
|
|
80
|
+
|
|
81
|
+
## Reference
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
oakode sessions # previous sessions in this directory (id, age, size, first prompt)
|
|
85
|
+
oakode -r <id> # resume a specific one (inside a session: /sessions)
|
|
86
|
+
oakode models [all|text] # supported models (all / matching text with experimental models on): context window, price, access
|
|
87
|
+
oakode -m <model> # use a model for this run (/model inside a session makes it the default)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Subagents (experimental, off by default)
|
|
91
|
+
|
|
92
|
+
With `{ "subagents": { "enabled": true } }` in `~/.oakode/config.json`, the main agent can propose a plan of parallel **read-only** subagents (`read`, `grep`, `glob`, `ls` only) when work splits into independent parts. Nothing runs until you approve the plan in a card that shows each agent's task, model, effort, budget and a rough cost estimate:
|
|
93
|
+
- **Approve** runs the plan.
|
|
94
|
+
- **Details** shows the full tasks.
|
|
95
|
+
- **Edit** lets you change an agent's task, model, effort or budget, remove an agent, or raise the turn's budget.
|
|
96
|
+
- **Deny** runs nothing and spends nothing.
|
|
97
|
+
|
|
98
|
+
How it works:
|
|
99
|
+
- **Running.** Agents run in parallel (`maxParallel`, default 3), wait for their dependencies, and stop at a timeout or request limit.
|
|
100
|
+
- **Permissions.** Each tool call still goes through your permission mode. Approving a plan never approves a tool call.
|
|
101
|
+
- **Reports.** Each agent finishes with a report. A finding is marked ✓ verified only if the agent's own tool results showed the cited lines; anything else is passed to the main agent as an unverified claim.
|
|
102
|
+
- **Budget.**
|
|
103
|
+
- All delegations in one turn share one budget: `budgetCredits`, default 40, which can be raised to `maxBudgetCredits`, at most 200.
|
|
104
|
+
- It is a **client-side limit built on estimates, not a guarantee**: OICKI may charge more than estimated. A charge above its estimate is recorded and stops further spending.
|
|
105
|
+
- For a hard limit, set OAKODE's monthly credit limit under Connected apps in your OICKI account.
|
|
106
|
+
- The main agent's own requests are not part of this budget. Both figures and their total are shown.
|
|
107
|
+
- **`/agents`** shows status, models, effort, tokens, cache use and credits. `/agents <id>` shows details, `/agents log <id>` the transcript, and `/agents cancel <id|all>` cancels. It works while agents run; Esc cancels them all.
|
|
108
|
+
- **Saved and resumed.** Delegations and their results are saved in the session, and a resumed session says which were interrupted. Nothing is re-run automatically.
|
|
109
|
+
- **Not yet.** Non-interactive runs (`-p`) never delegate, and writable agents come in a later phase. The design is in [docs/design/subagents.md](docs/design/subagents.md).
|
|
110
|
+
|
|
111
|
+
### Models
|
|
112
|
+
|
|
113
|
+
OAKODE supports `auto` (the default) and DeepSeek V4.1 Flash, MiMo V2.6 Flash, MiniMax M3.1 Flash, GLM 5.3 Flash, GPT-6 Luna, Ling 3.1 Flash, plus Claude Sonnet 5.5 and GPT-6.1 Sol when you need a stronger model. Their tool calls, multi-step turns and prompt caching were checked through OICKI (`eval/probe.ts`, `eval/cache-probe.ts`). MiMo V2.6 Flash is treated as text-only: images sent to it did not arrive.
|
|
114
|
+
|
|
115
|
+
Only these can be listed and chosen (`/model`, `/models`, `oakode models`, completion, `-m`, the saved default). To try any other model in OICKI's catalog, opt in to **experimental models** in `~/.oakode/config.json`:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{ "experimentalModels": true }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Then `/model` offers "All models (experimental)…", and `/model <text>`, `/models all` and `-m` reach the whole catalog. Experimental models are unsupported: tool use, caching and limits may not work as with the supported ones. This only changes what OAKODE offers; OICKI's access rules (expensive models, credit limits) apply either way. With it off, a session that already uses another model keeps it when resumed (with a notice), and a saved default outside the list is left in the config while new sessions use `auto`.
|
|
122
|
+
|
|
123
|
+
The model list is cached in `~/.oakode/models-cache.json` and refreshed in the background on every start, so startup does not wait for it.
|
|
124
|
+
|
|
125
|
+
In the session (type `/` for a completion list; ↑/↓ + Tab/Enter): `/help /model /models /effort /status /mode /permissions /diff /compact /clear /sessions /resume /history /cost /skills /mcp /retry /exit`. The footer shows the mode, model, context use, credits charged so far (as settled by OICKI) and the prompt-cache hit rate. Answers are rendered as Markdown (highlighted code, tables, lists, links; Unicode-width aware; reflows on resize), with a spinner showing elapsed time and tool status. File changes are shown as a colored unified diff before you approve them; `/diff` shows this session's changes.
|
|
126
|
+
|
|
127
|
+
**Input.** Enter sends. Ctrl+J, Alt+Enter, or Shift+Enter (kitty-protocol terminals) insert a newline; a *typed* trailing `\` then Enter does too. Pasted text uses bracketed paste: it is inserted verbatim (large pastes show as `[paste #1 +120 lines]` and are expanded on send) and **never submits by itself**. If you type while the agent is working, Enter queues your message and the agent receives it after its current tool calls. Queued messages are listed above the editor until then (and printed in the conversation where the model receives them); **Alt+↑** (Option+↑) takes the last one back into the editor, to fix and queue again or to delete. A line starting with a typed `!` (`!npm test`, one line) runs that command right away, without the model or an approval since you typed it (pasted text that begins with `!` is sent as a message, never run); its output goes to the model with your next message, so it costs no request of its own (a leading space sends the text to the model instead). **Ctrl+C** interrupts the running turn (kills the running command, keeps context, and puts any queued text back in the editor); twice at an empty prompt exits. SIGTERM/SIGHUP stop the turn, kill running commands, and restore the terminal.
|
|
128
|
+
|
|
129
|
+
**Resuming.** `oakode -c` / `-r <id>` / `/resume` restore the conversation on screen with the same Markdown and tool displays as live output (the latest ~40 messages; `/history [n|all]` pages back through older ones). Restoring only displays: no tool is run again, and what the model sees is unchanged (a compaction summary still replaces old history for the model, not on screen). `/resume` is a searchable picker (type to filter by text, id, project or date; shows time and message count). Session files from 0.1.0 and 0.2.0 work unchanged.
|
|
130
|
+
|
|
131
|
+
### Tools
|
|
132
|
+
|
|
133
|
+
| Tool | Approval | Notes |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| `read`, `grep`, `glob`, `ls` | none (read-only, workspace-confined) | Never follow symlinks. In a git repository `grep` and `glob` leave out what `.gitignore` excludes (via `git ls-files`, with `core.fsmonitor` forced off so a repository's config cannot run anything); elsewhere they skip `.git` and `node_modules`. Binary and very large files are skipped. `read` takes `paths` to read up to 10 files in one call; `grep` takes `context` lines and `files_only`. Several of these calls in one reply run at the same time. |
|
|
136
|
+
| `edit` | every call | Several `{old_text, new_text}` edits per call, each matched against the original file, non-overlapping. Falls back to whitespace/quote/dash-tolerant matching and says so. Preserves CRLF and BOM, refuses invalid UTF-8/binary, and refuses to write if the file changed while the prompt was open. |
|
|
137
|
+
| `write` | every call | Preserves the CRLF/BOM of the file it replaces. |
|
|
138
|
+
| `bash` | every call | See the safety model below. |
|
|
139
|
+
| `job` | none (starts nothing) | Polls, interrupts (Ctrl+C) or kills a background command. |
|
|
140
|
+
|
|
141
|
+
`write` takes `append: true` to build large files in parts (so one reply never has to carry the whole file). `read` shows png/jpeg/gif/webp images (≤ 1.5 MB; on macOS larger ones are scaled down to a 2048 px JPEG; requests stay under OICKI's 4 MB body limit by leaving out the oldest images) to models that accept image input and says so plainly to models that don't. `write`/`edit` are the supported way to change files: bash edits get no diff preview and are not tracked by `/diff`.
|
|
142
|
+
|
|
143
|
+
After every `write` and `edit`, the file's syntax is checked and any error is reported in the same result (JavaScript with `node --check`, Python with `ast.parse`, JSON, YAML, shell scripts with `bash -n`; nothing is executed, and checkers are never taken from inside the workspace). TypeScript is not checked, to avoid false alarms.
|
|
144
|
+
|
|
145
|
+
**Background jobs.** For a dev server, a watcher or a test suite slower than the timeout, the agent runs `bash` with `background: true` (approved like any command). The call returns once the output matches `until` (for example `listening|ready`), the command ends, or after `wait` seconds. The agent then checks it with `job`: a poll returns only the output since the last one, and waits (default 30 s) until the job ends or `until` matches, so a check costs one request, not a stream of them. At most 8 jobs run at once. `/jobs` lists them, `/jobs kill <id|all>` stops them, the footer counts them, and all are stopped when OAKODE exits (also on Ctrl+C, SIGTERM and SIGHUP; a hard kill of OAKODE itself, such as `kill -9`, leaves them running). Jobs run on plain pipes with stdin closed; nothing interactive. `until` takes simple patterns only (no repeated groups that repeat or branch, no backreferences), so a pattern cannot stall OAKODE.
|
|
146
|
+
|
|
147
|
+
Shortened command output and job logs are saved in a private folder for the session (owner-only, deleted when OAKODE exits). `read` and `grep` can open those files by the path the result gives, without an approval; nothing else outside the workspace is readable. Commands run with `PAGER=cat`, `GIT_PAGER=cat`, `GIT_TERMINAL_PROMPT=0` and `NO_COLOR=1`, so a pager or a credential prompt cannot hang them.
|
|
148
|
+
|
|
149
|
+
`write` and `edit` replace files atomically (temp file in the same directory + rename; mode preserved; in-workspace symlinks stay symlinks).
|
|
150
|
+
|
|
151
|
+
### Safety model
|
|
152
|
+
|
|
153
|
+
**Approval is not a sandbox.**
|
|
154
|
+
|
|
155
|
+
- `read` is the only tool that runs without asking. `read`, `write` and `edit` are confined to the working directory: `..`, absolute paths and symlinks (to files or directories, including ones created while an approval prompt was open) that resolve outside it are refused. Special files (FIFOs, devices) are refused.
|
|
156
|
+
- Every `write`, `edit`, `bash` command and MCP call asks first unless a permission you granted matches. The menu offers *allow once*, *for this session*, *for this project* (stored in `~/.oakode/projects/…/permissions.json`, never in the repository, and only after you choose it), *deny*, or *deny, and say why…* (your one-line reason goes to the model with the denial, so it can change course in the same step); Tab changes the scope (file / directory / workspace for edits; the **exact command** for bash; one tool or a whole server for MCP). A bash permission matches only that exact command string: it never covers other commands, pipelines or substitutions. Nothing classifies a command into being allowed, and there is no global auto-approve (except `--yes`, below); the one classifier only makes runner commands ask again (below). `/permissions` lists and revokes grants. Pasted text and keys typed before the prompt appeared can never approve.
|
|
157
|
+
- An approved command runs unsandboxed with your user's permissions. It can read and change anything you can, including `~/.oakode/auth.json` and your other credentials. Only OICKI/OAKODE variables (`OICKI_*`, `OAKODE_*`, which includes your API key) are removed from its environment; everything else is inherited.
|
|
158
|
+
- **`--yes` removes the only safety control.** Every write, edit and shell command then runs unattended with your user's full permissions. Content the model reads (a README, a web page's text, a dependency's source, a file in a cloned repo) can contain instructions that steer it (prompt injection), and with `--yes` nothing stops those from running commands, reading `~/.oakode/auth.json` or other credentials, or deleting files. Commands also inherit every environment variable except `OICKI_*`/`OAKODE_*` (so `GITHUB_TOKEN`, `AWS_*`, … are exposed). Use it only in a disposable directory or container. Without `--yes`, non-interactive runs (`-p`) deny every write, edit and command.
|
|
159
|
+
- `bash` has a 120s default timeout (max 600s), output capped at 2000 lines / 50KB (start and end kept; full output saved to the session's output folder, which `read` and `grep` can open).
|
|
160
|
+
|
|
161
|
+
### Permission modes
|
|
162
|
+
|
|
163
|
+
Shift+Tab (or `/mode <name>`) cycles **Default → Auto Edit → Plan → Custom**; the active mode is shown first in the footer and a switch applies to the next tool call. OAKODE always starts in Default.
|
|
164
|
+
|
|
165
|
+
| Mode | read / grep / ls | write / edit | bash | MCP tools |
|
|
166
|
+
|---|---|---|---|---|
|
|
167
|
+
| Default | run | follow saved permissions, else ask | same | same |
|
|
168
|
+
| Auto Edit | run | run inside the workspace; anything else asks | follow saved permissions, else ask | same |
|
|
169
|
+
| Plan | run | **blocked** | **blocked** | **blocked** |
|
|
170
|
+
| Custom | per your table | per your table | per your table | per tool / server / all |
|
|
171
|
+
|
|
172
|
+
Plan is enforced when a tool is about to run (and again when it asks for approval), not by the prompt: saved permissions and Custom entries cannot unblock anything in Plan, and `--yes` does not either. `/permissions` is an interactive table for the Custom policy (↑↓ select, ←→ Always Allow / Ask Every Time / Deny, Tab chooses *saved for this project* or *this session only*, Enter for details or to revoke a grant). It supports exact-command bash entries (`bash:<command>`) and per-server and per-tool MCP entries (`mcp:server`, `mcp:server/tool`; most specific wins; `mcp:*` cannot be set to Always Allow). Saved settings live in `~/.oakode/projects/<hash>/permissions.json`, never in the repository. A fresh Custom policy asks exactly like Default. Modes are not sandboxes: a bash command you allow runs with your full permissions and is not confined to the workspace (only the file tools are), and file tools never reach outside the workspace in any mode. Switching modes never enables `--yes`.
|
|
173
|
+
|
|
174
|
+
**Protected files always ask.** Writes to git metadata (anything under `.git/`, whose hooks and config run on your next git command), project instructions (`AGENTS.md`, `CLAUDE.md`), project skills (`.agents/`) and the project's MCP list (`.mcp.json`) are never covered by Auto Edit, a directory or workspace permission, or a Custom "Always Allow". Only a fresh approval or a permission for that exact file allows them; a Custom "Deny" still denies.
|
|
175
|
+
|
|
176
|
+
**Runner commands ask again when their definition changes.** A saved approval (or Custom "Always Allow") of a command such as `npm test`, `make`, `cargo test`, `pytest` or `./scripts/ci.sh` is tied to the files that define what it runs: `package.json` and `.npmrc`, the Makefile, `Cargo.toml` and `build.rs`, `pyproject.toml`, lint and build tool configs, the script itself or a script a `package.json` entry runs, and so on. When one of them changes (by the agent, by you or by a `git pull`), the command asks once more, naming the file; approving it accepts the new contents. Ordinary source and test edits never do, so Auto Edit's edit-test-fix loop keeps running. For the same reason Auto Edit does not cover writes under `node_modules/`, `.venv/` or `venv/`: those hold the programs such commands run. This is a trust tradeoff, not a sandbox: `npm test` still runs whatever the edited tests do. A Custom "Deny" still denies, and a Custom "Always Allow" for all of bash is left as you set it.
|
|
177
|
+
|
|
178
|
+
**Approvals show everything.** A command is shown in full before you approve it: long lines are wrapped, never cut at the terminal width; a run of spaces is shown as a count and invisible characters (zero-width, bidirectional controls) as `⟨U+…⟩`. A very long command shows its start and end, and `v` prints all of it. A command that is very long or contains invisible characters can be allowed once but not remembered.
|
|
179
|
+
|
|
180
|
+
### Skills
|
|
181
|
+
|
|
182
|
+
[Agent Skills](https://agentskills.io) (`SKILL.md` with `name` and `description` frontmatter) are discovered in `~/.agents/skills/`, `~/.oakode/skills/` and `<project>/.agents/skills/`. Only names and descriptions go into the system prompt; the model loads a skill's body (or a file inside its directory) through the `skill` tool, labelled as non-privileged instructions. Skills do not grant permissions (`allowed-tools` is ignored) and file access stays confined to the skill's directory. A repository's skills are **off until you run `/skills trust`** for that project, and trust covers their current contents: if a trusted skill's files change (a `git pull`, a branch switch), it is disabled until you review it with `/skills trust` again. `/skills` lists them, `/skills <name>` shows one.
|
|
183
|
+
|
|
184
|
+
### MCP
|
|
185
|
+
|
|
186
|
+
OAKODE is an MCP client over **stdio** and **Streamable HTTP** (no legacy SSE transport). Tools only: no resources, prompts, sampling or elicitation (server requests for them are declined). Configure servers in `~/.oakode/mcp.json` (yours) or `.mcp.json` in a project:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{"mcpServers": {"files": {"command": "node", "args": ["server.js"], "env": {"K": "v"}, "timeout": 60000},
|
|
190
|
+
"web": {"type": "http", "url": "https://example.com/mcp", "headers": {"Authorization": "Bearer ${TOKEN}"}}}}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
- `${VAR}` / `${VAR:-default}` expand only in *your* file. A server from a repository's `.mcp.json` never starts until you run `/mcp approve <name>`; the approval is bound to that exact configuration, so any change needs a new approval.
|
|
194
|
+
- On Windows, launchers that are `.cmd` files (`npx`, `uvx`) need `cmd`: `"command": "cmd", "args": ["/c", "npx", "-y", "<package>"]`.
|
|
195
|
+
- Servers get a scrubbed environment (no `OICKI_*`/`OAKODE_*`). Tools appear as `mcp__server__tool`, every call asks first whatever the server claims (`readOnlyHint` is ignored), and descriptions and results are treated as untrusted external content.
|
|
196
|
+
- A call interrupted by a lost connection is reported, never silently repeated; the next call reconnects (up to 3 times in a row, then `/mcp reconnect <name>`). `/mcp` also supports `<name>`, `revoke`, `reload`.
|
|
197
|
+
|
|
198
|
+
### Billing and retries
|
|
199
|
+
|
|
200
|
+
OAKODE never resends an AI request automatically unless OICKI documents the failure as safe to repeat: `429 rate_limited` with a `Retry-After` header (waits, up to 3 times), `503 provider_unavailable` (unbilled; up to 2 times), and one token refresh after a `401`. Server errors, dropped connections, timeouts and mid-stream failures are shown and may have been billed; `/retry` sends a new request only when you ask. `max_tokens` is derived from the model's reported output limit (default cap 16384, `OAKODE_MAX_OUTPUT_TOKENS` to change) and kept within what the context window leaves after the prompt; credits are held for it. Only `context_length_exceeded` triggers an automatic compaction; `content_filtered`, `app_limit_exceeded` and a too-large request (413) are explained instead of retried. If a reply is cut off by the output limit or OICKI's 270-second response limit (told apart), its tool calls are not run and the model is told to continue in smaller steps (at most twice per message).
|
|
201
|
+
|
|
202
|
+
**Reasoning.** `/effort <none|minimal|low|medium|high|xhigh|default>` (or `OAKODE_REASONING_EFFORT`) sets `reasoning_effort`; it is sent only to models that take it. A reasoning model's `reasoning_details` are kept with its reply and sent back to that same model on the next request, which some models need to keep reasoning across tool calls.
|
|
203
|
+
|
|
204
|
+
**Images.** Images from `read` and from MCP tools (a browser screenshot, say) are shown to models that accept image input, as a user message after the tool results; only the newest three such messages keep their images in a request.
|
|
205
|
+
|
|
206
|
+
### Keeping context small
|
|
207
|
+
|
|
208
|
+
Command output is cleaned before the model sees it (terminal escapes and progress-bar redraws removed, repeated lines collapsed, long output cut to its start and end; the full text is saved to a temp file whose path is shown). When a request is built, tool results, the big text arguments of old `bash` calls, and images older than the most recent ~30–50 messages are replaced by short placeholders; the big arguments of the model's own `write`/`edit` calls (already on disk) go after ~8–16 messages. The stored session is never changed, the cut-offs only move in steps (20 and 8 messages, so the request prefix stays identical between steps and prompt caches keep hitting), and the result is the same after a resume. For models with explicit prompt caching (Claude, Gemini), cache breakpoints are set on the system prompt and the newest messages; the system prompt, including a short project brief (branch, layout, build/test commands) built at session start, stays identical for the whole session. The default reply budget is 16384 tokens (never above the model's own limit; set `maxOutputTokens` in the config or `OAKODE_MAX_OUTPUT_TOKENS` to change it).
|
|
209
|
+
|
|
210
|
+
### Sessions & context
|
|
211
|
+
|
|
212
|
+
Sessions are append-only JSONL under `~/.oakode/sessions/<project>-<hash of the real path>/`; a session recorded for another directory is never listed or resumed. Every entry is fsynced. If the disk refuses a write, the conversation continues in memory, you are told once, saving is retried with the next message, and anything still unsaved at exit is dumped to a temp file. A crash that leaves a torn last line is tolerated. One OAKODE process may hold a session at a time (lock file; stale locks from dead processes are taken over). On resume, OAKODE tells you if the last run was interrupted; unanswered tool calls are marked as interrupted, and `/retry` continues.
|
|
213
|
+
|
|
214
|
+
When the context nears the window (minus a reserve of up to 16k, scaled down for small-window models), or the request nears OICKI's limits (1,900 messages / 3 MB), older history is summarized by the model and the recent tail is kept verbatim:
|
|
215
|
+
- an existing summary is *updated*, not re-summarized;
|
|
216
|
+
- files read and modified are tracked deterministically from successful tool calls and carried through every compaction;
|
|
217
|
+
- the cut prefers a turn boundary; if one huge turn must be split, the request that started it is kept verbatim;
|
|
218
|
+
- limits follow the model that actually serves `auto` (reported in every response), not just `auto`'s own numbers;
|
|
219
|
+
- an old exchange of large tool results is summarized rather than kept verbatim, and the summarizer has its own output budget (up to 4096 tokens);
|
|
220
|
+
- the summary is requested with the agent's own next request plus one instruction (same system prompt, history and tools), so its input is almost all read from the prompt cache, and the model summarizes full messages rather than a clipped copy. When that request would not fit, after a `context_length_exceeded`, or if it returns anything but a summary, a separate, smaller summarizer request is used instead;
|
|
221
|
+
- if compaction fails, history is left untouched; the turn continues if the request still fits, otherwise it stops with the error. Nothing is dropped: the session file keeps every original message.
|
|
222
|
+
|
|
223
|
+
Every run's end (`complete`, `interrupted`, `error` with the server's code and request id, `iteration_limit`, `output_limit`, `empty_reply`, `terminated`) and every notice are recorded in the session file as `turn` / `notice` entries; `/resume` tells you if the last run did not finish cleanly.
|
|
224
|
+
|
|
225
|
+
Compaction is itself a billable model call; the UI says when it runs, and its cost is counted in `/cost` and the turn's cost line.
|
|
226
|
+
|
|
227
|
+
### Terminal behavior
|
|
228
|
+
|
|
229
|
+
**Notifications.** When an approval (or a subagent plan) waits while the terminal is in the background, OAKODE sends one desktop notification: OSC 9 in iTerm2, WezTerm and Ghostty, a bell elsewhere and inside tmux (most terminals turn a bell in a background window into an alert). It knows the terminal is in the background only from the terminal's focus reports (OAKODE turns them on), so a terminal that does not send them gets no notifications at all; under tmux, `set -g focus-events on` enables them. At most one every 5 seconds. `"notifications": false` in `~/.oakode/config.json` turns them off.
|
|
230
|
+
|
|
231
|
+
The transcript is made to be copied from. Code blocks have no gutter and are not wrapped by OAKODE, URLs are never broken, and finished lines are not cut at the terminal width, so a copied block is the code as written and a long `http://localhost:…` link can still be clicked. Reads, searches, globs and listings are one line each with a count (`● read src/app.ts (120 lines)`); the model sees the contents. After each turn a dim line says what it took: `─ 1m 05s · 7 requests · 3.1 cr ─`.
|
|
232
|
+
|
|
233
|
+
Input typed while OAKODE is starting is captured (raw mode starts before any network call) and processed in order as separate messages. If the terminal stops reading output, OAKODE still exits: shutdown always runs in the same order (kill running commands, save or dump the session, release the lock, then restore the terminal), and a watchdog bound to the process's identity force-exits after 2 s and best-effort restores the terminal when it starts reading again.
|
|
234
|
+
|
|
235
|
+
## Develop
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
npm install && npm run build && npm test # ~300 tests: an in-process fake of the OICKI API (no network, no billing) and real pseudo-terminal sessions (needs python3)
|
|
239
|
+
npm run typecheck
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`AGENTS.md` or `CLAUDE.md` in the project root is added to the system prompt. Configuration lives in `~/.oakode/config.json` (`model`, `maxOutputTokens`, `reasoningEffort`, `experimentalModels`); environment variables are listed in `oakode --help`. Security reports: see [SECURITY.md](SECURITY.md). Changes: [CHANGELOG.md](CHANGELOG.md).
|
|
243
|
+
|
|
244
|
+
**Eval.** `eval/` holds small real coding tasks whose checks the agent never sees. `node eval/run.ts --verify` confirms every check fails before a fix; `node eval/run.ts --base-url <mock>` dry-runs the harness for free; `node eval/run.ts --live --model a,b` sends real, **billed** requests and reports pass rate, time, requests, tool calls per reply, cached tokens, credits and diff size per task.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Please report security problems privately to the maintainers (GitHub: open a private security advisory on this repository) rather than in a public issue. Include steps to reproduce and the OAKODE version (`oakode --version`). We aim to answer within a week.
|
|
6
|
+
|
|
7
|
+
## What OAKODE protects, and what it does not
|
|
8
|
+
|
|
9
|
+
- **Approval is not a sandbox.** Every write, edit and shell command asks first unless a permission you granted matches. An approved command runs with your user's full permissions. `--yes` turns the prompts off entirely: use it only in a disposable directory or container.
|
|
10
|
+
- **Credentials.** Stored in `~/.oakode/auth.json`, created readable only by you (0600 in a 0700 directory; on Windows, inside your user profile). OICKI-related environment variables are removed from commands the agent runs. Saved credentials are only sent to the OICKI server they were issued by. OAuth refresh tokens rotate; refreshes are coordinated across OAKODE processes so a stale token is never reused (OICKI revokes the grant when it sees reuse). `oakode logout` revokes the sign-in on OICKI before deleting the local copy.
|
|
11
|
+
- **Untrusted content.** Files, command output, web content and MCP results the model reads can try to steer it (prompt injection). They are treated as data, and tool calls they cause still need your approval.
|
|
12
|
+
- **Repositories you clone.** Project permissions are stored outside the repository and only after you choose them; a repository's MCP servers and skills stay off until you approve them. OAKODE never runs programs from inside the project on its own (git and the syntax checkers are taken from your PATH outside the project, with repository hooks such as fsmonitor disabled).
|
|
13
|
+
- **File tools** are confined to the working directory and never follow symlinks out of it. Shell commands are not confined.
|
package/dist/account.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { fmtCredits, fmtTokens, green, red, visible, yellow } from "./ui.js";
|
|
2
|
+
export function billingLines(b, kind) {
|
|
3
|
+
if (kind === "apikey")
|
|
4
|
+
return ["credits not visible with an API key (OICKI shows balances only to a signed-in person: `oakode login`)"];
|
|
5
|
+
if (kind !== "oauth")
|
|
6
|
+
return [];
|
|
7
|
+
if (!b)
|
|
8
|
+
return ["credits unknown (the sign-in did not include billing:read; `oakode login` again to grant it)"];
|
|
9
|
+
if (typeof b.credits?.total !== "number")
|
|
10
|
+
return ["credits unknown (unexpected answer from OICKI)"];
|
|
11
|
+
const paint = b.state === "active" ? green : b.state === "low" ? yellow : red;
|
|
12
|
+
const plan = String(b.plan?.label ?? b.plan?.name ?? (b.plan?.status === "none" ? "no plan" : (b.plan?.status ?? "?")));
|
|
13
|
+
const renewsAt = typeof b.plan?.renewsAt === "string" ? new Date(b.plan.renewsAt) : undefined;
|
|
14
|
+
const renews = renewsAt && !Number.isNaN(renewsAt.getTime()) ? `, renews ${renewsAt.toISOString().slice(0, 10)}` : "";
|
|
15
|
+
const lines = [
|
|
16
|
+
`credits ${paint(`${fmtCredits(b.credits.total)} left`)}${b.credits.super ? ` (${fmtCredits(b.credits.standard)} standard + ${fmtCredits(b.credits.super)} super)` : ""} · plan ${visible(plan)}${renews}`,
|
|
17
|
+
`this app ${b.usage ? `${fmtCredits(b.usage.cycleCredits)} credits used this ${b.usage.period === "cycle" ? "billing cycle" : "month"}` : "usage unknown"} · ${appLimit(b) ?? "no monthly limit"}`,
|
|
18
|
+
];
|
|
19
|
+
if (b.state !== "active")
|
|
20
|
+
lines.push(paint(` ${visible(String(b.headline ?? ""))}. ${visible(String(b.message ?? ""))}${b.action ? ` ${visible(b.action.label)}: ${visible(b.action.href)}` : ""}`));
|
|
21
|
+
return lines;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* This app's monthly limit, e.g. "app limit 12.5/2,000 credits" (red when used up), or undefined when there is none.
|
|
25
|
+
* `appLimit` is shown; the deprecated token `allowance` only when an older server sends no `appLimit` at all.
|
|
26
|
+
*/
|
|
27
|
+
export function appLimit(b) {
|
|
28
|
+
const l = b?.appLimit === undefined && b?.allowance ? { unit: "tokens", used: b.allowance.usedTokens, cap: b.allowance.capTokens, exhausted: b.allowance.exhausted } : b?.appLimit;
|
|
29
|
+
if (!l)
|
|
30
|
+
return undefined;
|
|
31
|
+
const f = l.unit === "tokens" ? fmtTokens : (n) => (n >= 1000 ? Math.round(n).toLocaleString("en-US") : String(Math.round(n * 1000) / 1000));
|
|
32
|
+
const text = `app limit ${f(l.used)}/${f(l.cap)} ${l.unit}`;
|
|
33
|
+
return l.exhausted ? red(text + " (used up)") : l.used >= 0.8 * l.cap ? yellow(text) : text;
|
|
34
|
+
}
|