atom-agent 1.4.0 → 1.5.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/CHANGELOG.md +70 -0
- package/README.md +221 -224
- package/dist/App.js +922 -341
- package/dist/adapters.js +502 -21
- package/dist/agent/goal-evaluator.js +3 -0
- package/dist/agent/loop.js +250 -434
- package/dist/agent/tool-pipeline.js +398 -0
- package/dist/agent/turn-events.js +12 -0
- package/dist/cli.js +57 -8
- package/dist/compact.js +72 -8
- package/dist/config.js +19 -0
- package/dist/context-manager.js +6 -2
- package/dist/extensions.js +6 -0
- package/dist/file-diffs.js +108 -0
- package/dist/kilo.js +1 -1
- package/dist/local-discovery.js +2 -2
- package/dist/media.js +276 -0
- package/dist/overflow.js +140 -0
- package/dist/policy.js +8 -0
- package/dist/providers.js +11 -3
- package/dist/scheduler.js +38 -9
- package/dist/session-revert.js +125 -0
- package/dist/sessions.js +101 -0
- package/dist/snapshots.js +69 -0
- package/dist/system.js +2 -89
- package/dist/telemetry.js +79 -5
- package/dist/todos.js +241 -0
- package/dist/tools/filesystem.js +102 -22
- package/dist/tools/registry.js +184 -45
- package/dist/tools/ripgrep.js +7 -6
- package/dist/tools/search.js +172 -17
- package/dist/tools/shared.js +6 -0
- package/dist/tools.js +7 -39
- package/dist/ui/diff-panel.js +1 -1
- package/dist/ui/diff-view.js +13 -5
- package/dist/ui/diff.js +67 -0
- package/dist/ui/errors.js +20 -6
- package/dist/ui/input.js +24 -20
- package/dist/ui/live-tail.js +36 -1
- package/dist/ui/markdown.js +9 -4
- package/dist/ui/modals.js +7 -5
- package/dist/ui/paint-scheduler.js +120 -0
- package/dist/ui/palette.js +4 -2
- package/dist/ui/pickers.js +4 -1
- package/dist/ui/side-by-side.js +81 -22
- package/dist/ui/status-bar.js +63 -8
- package/dist/ui/stream-store.js +7 -0
- package/dist/ui/theme.js +23 -1
- package/dist/ui/todo-panel.js +5 -2
- package/dist/ui/tool-inspector.js +33 -4
- package/dist/ui/transcript.js +8 -5
- package/dist/web/events.js +93 -0
- package/dist/web/runtime.js +790 -0
- package/dist/web/server.js +570 -0
- package/dist/web/ui/app.js +1925 -0
- package/dist/web/ui/index.html +135 -0
- package/dist/web/ui/styles.css +515 -0
- package/dist/zen.js +532 -34
- package/documentation/cli.md +5 -5
- package/documentation/configuration.md +11 -6
- package/documentation/development.md +4 -3
- package/documentation/goals.md +1 -1
- package/documentation/index.md +4 -4
- package/documentation/providers.md +2 -3
- package/documentation/skills.md +3 -3
- package/documentation/tools.md +8 -3
- package/documentation/troubleshooting.md +1 -1
- package/package.json +3 -2
package/documentation/cli.md
CHANGED
|
@@ -10,9 +10,11 @@ atom # run the installed binary (runs dist/cli.js)
|
|
|
10
10
|
atom --help # usage, env vars, commands, providers (exits, no TUI)
|
|
11
11
|
atom --dashboard # write ~/.atom/telemetry/dashboard.html and exit (no TUI)
|
|
12
12
|
atom --serve [--port <n>] # serve the live observability webUI on loopback (no TUI, Ctrl+C stops)
|
|
13
|
+
atom --web [--port <n>] # serve the local agentic Web UI on loopback (no TUI, Ctrl+C stops)
|
|
14
|
+
atom --no-extensions # boot with zero third-party extensions (alias: --lockdown)
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
`--help` (or `-h`) prints usage and exits. `--dashboard` and `--serve` handle local observability without starting the TUI (see [Observability](observability.md)). Any other invocation starts the TUI, even without a key.
|
|
17
|
+
`--help` (or `-h`) prints usage and exits. `--dashboard` and `--serve` handle local observability without starting the TUI (see [Observability](observability.md)). `--web` starts the agentic Web UI over the same runtime as the TUI (loopback-only; JSON API at `/api/health`, `/api/providers`, `/api/sessions`). Extension flags (`--no-extensions` / `--lockdown`, repeatable `--enable-extension <glob>` / `--disable-extension <glob>`) control third-party extension loading and win over `atom.json` (see [Extensions](extensions.md) and [Configuration](configuration.md)). Any other invocation starts the TUI, even without a key.
|
|
16
18
|
|
|
17
19
|
## Slash commands
|
|
18
20
|
|
|
@@ -20,16 +22,14 @@ Type `/` to autocomplete as you type. Full registry (`src/App.tsx`):
|
|
|
20
22
|
|
|
21
23
|
| Command | What it does |
|
|
22
24
|
|---|---|
|
|
23
|
-
| `/model` | Unified model picker: active provider first, then other keyed providers plus the always-visible keyless Kilo list (free models badged `(free)`, `free` filters them). Cross-provider pick switches provider |
|
|
24
|
-
| `/models [refresh]` | Local discovery status; `refresh` re-probes local servers (or the Kilo gateway catalog while Kilo is active) |
|
|
25
|
+
| `/model [filter\|refresh]` | Unified model picker: active provider first, then other keyed providers plus the always-visible keyless Kilo list (free models badged `(free)`, `free` filters them). Cross-provider pick switches provider. `refresh` re-probes local servers (or the Kilo gateway catalog while Kilo is active); plain text pre-filters the picker |
|
|
25
26
|
| `/provider` | Provider plus key picker; validates and stores in `~/.atom/auth.json` (Kilo key optional — empty Enter continues anonymously) |
|
|
26
27
|
| `/new` | Start a brand-new session (conversation plus counters reset, previous kept for `/resume`) |
|
|
27
28
|
| `/rename <name>` | Rename the current session (id and history untouched; quotes optional) |
|
|
28
29
|
| `/plan`, `/yolo` | Retired as typed commands — `Tab` is the only mode switcher (normal → yolo → plan → normal); typing them explains this instead of switching |
|
|
29
30
|
| `/effort` | Reasoning-effort picker (`Auto`/`Low`/`Medium`/`High`/`Max`; sent for every model on every provider — `reasoning_effort` on OpenAI-chat, thinking budget on Anthropic, thinking level on Gemini; `Auto` omits it) |
|
|
30
31
|
| `/tools` | List tools with one-line descriptions |
|
|
31
|
-
| `/
|
|
32
|
-
| `/skill` | Invoke a skill by name (`/skill:name`; skills also complete in the `/` menu) |
|
|
32
|
+
| `/skill [name]` | Skill picker (list, filter, invoke); `/skill:name` invokes directly (skills also complete in the `/` menu) |
|
|
33
33
|
| `/context` | Show context usage by source (system, tools, history, skills, config, prefix-cache) |
|
|
34
34
|
| `/queue` | List queued follow-ups (`/queue clear` wipes; cap 10, in-memory only) |
|
|
35
35
|
| `/steer` | Steer the running turn, or send when idle (`/steer <text>`) |
|
|
@@ -24,9 +24,12 @@ Template lives in `.env.example`. Never commit a real key.
|
|
|
24
24
|
| `ATOM_TELEMETRY` | Local observability recording (`0`/`false`/`no`/`off` disables; `1`/`true`/`yes`/`on` forces on) | on (wins over `atom.json`) |
|
|
25
25
|
| `ATOM_TELEMETRY_PORT` | Pinned port for the observability webUI (`atom --serve`; `--port` wins over this) | ephemeral (OS-assigned, printed on start) |
|
|
26
26
|
| `ATOM_EXTENSIONS` | Extra extension directory for discovery (project, global, then this; see [Extensions](extensions.md)) | none |
|
|
27
|
-
| `ATOM_OLLAMA_URL` | Ollama base URL override for local discovery | `http://
|
|
28
|
-
| `ATOM_LMSTUDIO_URL` | LM Studio base URL override for local discovery | `http://
|
|
29
|
-
| `ATOM_LLAMACPP_URL` | llama.cpp base URL override for local discovery | `http://
|
|
27
|
+
| `ATOM_OLLAMA_URL` | Ollama base URL override for local discovery | `http://127.0.0.1:11434` |
|
|
28
|
+
| `ATOM_LMSTUDIO_URL` | LM Studio base URL override for local discovery | `http://127.0.0.1:1234` |
|
|
29
|
+
| `ATOM_LLAMACPP_URL` | llama.cpp base URL override for local discovery | `http://127.0.0.1:8080` |
|
|
30
|
+
| `ATOM_STALL_TIMEOUT_MS` | Silent-stream stall guard for streaming readers | `60000` (60s; fails fast instead of hanging a silent 200-OK stream) |
|
|
31
|
+
| `ATOM_FAST_LIST` | File-listing fast path (`0` forces the legacy walker) | fast path on |
|
|
32
|
+
| `ATOM_INCREMENTAL` | Incremental Ink rendering (`0` restores full-frame rendering) | incremental on |
|
|
30
33
|
|
|
31
34
|
`openai-compatible` uses stored key plus baseURL only. No env vars.
|
|
32
35
|
|
|
@@ -44,8 +47,10 @@ Precedence overall: env vars > saved session picks (`/model`, `/provider`, `/eff
|
|
|
44
47
|
| `provider` | First-run default provider (needs its key, except keyless Kilo/local) | known provider id |
|
|
45
48
|
| `model` | Default model id | non-empty string |
|
|
46
49
|
| `reasoningEffort` | Default reasoning effort | `auto`/`low`/`medium`/`high`/`max` (`default` still accepted as an alias for `auto`) |
|
|
47
|
-
| `maxToolSteps` |
|
|
50
|
+
| `maxToolSteps` | Optional cap on tool rounds per turn (`ATOM_MAX_TOOL_STEPS` wins over this) | 5-100 (default uncapped; the shipped `atom.example.json` sets `30` as a starting point) |
|
|
48
51
|
| `compactPct` | Auto-compact percent of verified window | 50-95 (default 83) |
|
|
52
|
+
| `compactAuto` | Master switch for automatic compaction (manual `/compact` always works) | boolean (default on) |
|
|
53
|
+
| `compactReserve` | Reserved output buffer in tokens for the usable-limit calculation | 4096-100000 (tokens) |
|
|
49
54
|
| `network` | Webfetch SSRF policy: which network zones the model may retrieve | object with boolean `allowPublic` (default true), `allowLocalhost` (default true), `allowPrivate` (default false), `allowLinkLocal` (default false) |
|
|
50
55
|
| `telemetry` | Local observability recording (see [Observability](observability.md)) | `{enabled?: boolean}` (default on; `ATOM_TELEMETRY=0` wins) |
|
|
51
56
|
| `extensions` | Extension enable/disable patterns by name (see [Extensions](extensions.md); CLI `--enable-extension`/`--disable-extension` win over this) | `{enabled?: string[], disabled?: string[]}` (default load all; `disabled` wins over `enabled`) |
|
|
@@ -90,7 +95,7 @@ The allowance is informational only: history is never truncated — there are no
|
|
|
90
95
|
|
|
91
96
|
## Session file
|
|
92
97
|
|
|
93
|
-
`~/.atom/session.json`, version 1, atomic temp-plus-rename saves, `0600` POSIX. See [Sessions](sessions.md).
|
|
98
|
+
Single-turn save: `~/.atom/session.json`, version 1, atomic temp-plus-rename saves, `0600` POSIX. Durable multi-session records live under `~/.atom/sessions/<id>.json` plus a plaintext `active` pointer. See [Sessions](sessions.md).
|
|
94
99
|
|
|
95
100
|
## AGENTS.md and system prompt
|
|
96
101
|
|
|
@@ -104,7 +109,7 @@ Final system prompt is two layers (`src/system.ts`, `src/zen.ts`):
|
|
|
104
109
|
- Repo overlay: `AGENTS.md` in cwd, or `OPENCODE_AGENTS_PATH` override. Capped at 12KB
|
|
105
110
|
- To change bot identity, edit the one-liner. To add project instructions, edit `AGENTS.md`
|
|
106
111
|
|
|
107
|
-
ATOM loads the project `AGENTS.md` at startup so it
|
|
112
|
+
ATOM loads the project `AGENTS.md` at startup when present, so it picks up repo tools, rules, and permission model. This checkout ships no `AGENTS.md` (per-project overlay only).
|
|
108
113
|
|
|
109
114
|
## Context windows
|
|
110
115
|
|
|
@@ -17,7 +17,8 @@ Build output goes to `dist/` (`atom` runs `dist/cli.js`). `dist/` is gitignored
|
|
|
17
17
|
npm start # tsx src/cli.tsx
|
|
18
18
|
npm test # vitest run (fully mocked, never hits live APIs)
|
|
19
19
|
npm run typecheck # tsc --noEmit
|
|
20
|
-
npm run build # tsc -p tsconfig.build.json (src -> dist)
|
|
20
|
+
npm run build # tsc -p tsconfig.build.json (src -> dist) plus copy-web-ui (web UI assets into dist/)
|
|
21
|
+
npm run bench # node scripts/bench-render.mjs (render-throughput benchmark)
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
Tests use `"test-key"` placeholders. Never paste a real key into fixtures, logs, or commits.
|
|
@@ -27,7 +28,7 @@ Tests use `"test-key"` placeholders. Never paste a real key into fixtures, logs,
|
|
|
27
28
|
```text
|
|
28
29
|
.
|
|
29
30
|
├── src/
|
|
30
|
-
│ ├── cli.tsx # entry: --help/--dashboard/--serve, always starts TUI (missing key guides to /provider)
|
|
31
|
+
│ ├── cli.tsx # entry: --help/--dashboard/--serve/--web, extension flags; always starts TUI otherwise (missing key guides to /provider)
|
|
31
32
|
│ ├── App.tsx # Ink TUI: transcript, pickers (/model /provider /effort), modes, status line
|
|
32
33
|
│ ├── context-windows.ts # curated per-model context windows + `token: (P%) NK` format
|
|
33
34
|
│ ├── compact.ts # context compaction: load/trigger math, split, summary POST (tools off, 4096 cap)
|
|
@@ -59,4 +60,4 @@ Add or update tests for behavior changes. A fix without a test that would have c
|
|
|
59
60
|
|
|
60
61
|
## Agent workflow in this repo
|
|
61
62
|
|
|
62
|
-
The repo `AGENTS.md` defines the loop the agent follows: read before edit,
|
|
63
|
+
The repo `AGENTS.md` defines the loop the agent follows: read before edit, uncapped tool rounds per turn by default (optional cap via `ATOM_MAX_TOOL_STEPS` / `maxToolSteps`, clamped 5-100), todowrite list for 3 or more steps with exactly one `in_progress`, verify every change with the suite. Issues live as local markdown under `.scratch/` (see [Issue tracker](../docs/agents/issue-tracker.md)).
|
package/documentation/goals.md
CHANGED
|
@@ -30,7 +30,7 @@ One pinned session goal that keeps the agent working turn-to-turn until it is do
|
|
|
30
30
|
|
|
31
31
|
## Known limits
|
|
32
32
|
|
|
33
|
-
- The `update_goal` schema
|
|
33
|
+
- The `update_goal` schema rides the chat-payload `tools` list only while a goal turn is live (hidden on non-goal turns so it cannot be misused); the model discovers it through the continuation message prose plus the live tool definition.
|
|
34
34
|
- Multi-turn goal behavior against live models is unproven; the loop, judge, and gate paths are covered by mocked suites.
|
|
35
35
|
|
|
36
36
|
## Code
|
package/documentation/index.md
CHANGED
|
@@ -35,7 +35,7 @@ This index is the entry point. The README stays focused on evaluate, install, an
|
|
|
35
35
|
|
|
36
36
|
Project conventions the agent itself loads at runtime:
|
|
37
37
|
|
|
38
|
-
-
|
|
39
|
-
- [Issue tracker](agents/issue-tracker.md) - local markdown issues under `.scratch/`
|
|
40
|
-
- [Triage labels](agents/triage-labels.md) - canonical triage roles
|
|
41
|
-
- [Domain docs](agents/domain.md) - CONTEXT.md plus ADR conventions
|
|
38
|
+
- `AGENTS.md` (per-project, when present) - agent instructions loaded into the system prompt
|
|
39
|
+
- [Issue tracker](../docs/agents/issue-tracker.md) - local markdown issues under `.scratch/`
|
|
40
|
+
- [Triage labels](../docs/agents/triage-labels.md) - canonical triage roles
|
|
41
|
+
- [Domain docs](../docs/agents/domain.md) - CONTEXT.md plus ADR conventions
|
|
@@ -20,7 +20,7 @@ Keys are never printed full (masked as last4), never logged, never in fixtures (
|
|
|
20
20
|
## Kilo Gateway (default)
|
|
21
21
|
|
|
22
22
|
- Kilo is ATOM's default provider: fresh installs start on Kilo with no key required
|
|
23
|
-
- The model catalog is discovered live via `GET https://api.kilo.ai/api/gateway/models` (cached for 5 minutes; `/
|
|
23
|
+
- The model catalog is discovered live via `GET https://api.kilo.ai/api/gateway/models` (cached for 5 minutes; `/model refresh` re-fetches while Kilo is active). Nothing is hardcoded — the catalog is authoritative, and free-model availability can change as Kilo updates it
|
|
24
24
|
- Anonymous access covers eligible free models (ids ending in `:free`, including the `kilo-auto/free` dynamic routing model, which Kilo resolves server-side). Without a key ATOM prefers `kilo-auto/free` when exposed, else the first free model, else the first live id
|
|
25
25
|
- Configure a key with `/provider` (validated, stored in `~/.atom/auth.json`) or `KILO_API_KEY` to unlock the full catalog; authenticated requests send `Authorization: Bearer <key>`, anonymous requests send no auth header at all
|
|
26
26
|
- Free models show a `(free)` badge in `/model` and match the `free` filter
|
|
@@ -59,8 +59,7 @@ File lives at `~/.atom/auth.json` (`ATOM_HOME` overrides the home dir). `0600` o
|
|
|
59
59
|
## Switching
|
|
60
60
|
|
|
61
61
|
- `/provider`: pick provider, paste key once (validated, stored), chat. Kilo's key is optional — without one the prompt offers anonymous free-model use. Switching provider keeps session history text. System prompt stays
|
|
62
|
-
- `/model`: unified picker — active provider's live models first (fallback on any failure), then every other keyed provider's models plus the always-visible keyless Kilo and local lists (cached live list when warm, else fallback). `openai-compatible` joins only with both a key and a stored baseURL. Type to filter (`free` matches free Kilo models), list windows to 10 rows, picking another provider's model switches provider too
|
|
63
|
-
- `/models refresh`: re-probes local servers; while Kilo is active it refreshes the Kilo gateway catalog instead
|
|
62
|
+
- `/model`: unified picker — active provider's live models first (fallback on any failure), then every other keyed provider's models plus the always-visible keyless Kilo and local lists (cached live list when warm, else fallback). `openai-compatible` joins only with both a key and a stored baseURL. Type to filter (`free` matches free Kilo models), list windows to 10 rows, picking another provider's model switches provider too. `/model <text>` opens pre-filtered; `/model refresh` re-probes local servers (Kilo gateway catalog while Kilo is active)
|
|
64
63
|
- `/effort`: reasoning-effort picker (`Auto`/`Low`/`Medium`/`High`/`Max`). Sent for every model on every provider: `reasoning_effort` on OpenAI-chat kinds (zen, OpenAI, DeepSeek, Mistral, Kilo, openai-compatible, locals), a `thinking` budget on Anthropic, a `thinkingConfig.thinkingLevel` on Gemini. `Auto` omits the knob. A model that truly lacks the knob fails the POST with a 400 naming it — the turn warns and retries once without it, so `(unsupported)` only ever reflects an actual server rejection
|
|
65
64
|
|
|
66
65
|
Custom server: pick `openai-compatible`, paste the baseURL (validated as http/https, trailing slashes trimmed) and key. Endpoint helper appends `/chat/completions` when missing.
|
package/documentation/skills.md
CHANGED
|
@@ -34,7 +34,7 @@ Support files: `references/<...>` and `scripts/<...>` mentions inside the body a
|
|
|
34
34
|
|
|
35
35
|
## Listing and precedence
|
|
36
36
|
|
|
37
|
-
`/
|
|
37
|
+
`/skill` opens the searchable picker (names only, type to filter, arrows to browse, `Enter` stages for confirm). `skillsListText` (headless use) prints `Skills (N):` with one runnable `/skill:name` plus source per line — no descriptions in either surface. Model-only skills show `[auto-only]` instead of hiding. Notes and warnings ride along visibly. Empty with no warnings prints the install hint (`add SKILL.md skills under .claude/skills/, .agents/skills/, or the ~/. counterparts`).
|
|
38
38
|
|
|
39
39
|
Name clashes: global (personal) wins over project on exact-name matches, with a visible note. Same-level duplicates keep the first with a note. Pure function `resolveSkills`, covered by `tests/skills.test.ts`.
|
|
40
40
|
|
|
@@ -42,7 +42,7 @@ Name clashes: global (personal) wins over project on exact-name matches, with a
|
|
|
42
42
|
|
|
43
43
|
Three tiers: (1) name plus description of every skill is known to the matcher at all times; (2) the `SKILL.md` body loads only on activation; (3) `references/` and `scripts/` files load on demand (inlined for explicit manual loads; the model reads them via `read` for auto loads). The transcript always shows one plain line per load (`deploy loaded`), never the body.
|
|
44
44
|
|
|
45
|
-
- Manual: `/skill:name` (canonical; legacy `/skill-name` still works) loads the full body plus inlined references into context for that turn. Discovery without dispatch: the `/
|
|
45
|
+
- Manual: `/skill:name` or `/skill <name>` (canonical; legacy `/skill-name` still works) loads the full body plus inlined references into context for that turn. Discovery without dispatch: the `/skill` picker (type to filter, arrows to browse, `Enter` stages `/skill:name` into the input — nothing is sent) and the `/` slash menu (skill rows complete on first `Enter`, run on the second) both confirm before loading; a fully typed `/skill:name`, `/skill <name>`, or `/skill-name` runs on first `Enter`. `allowed-tools` in frontmatter become turn-scoped auto-approvals. User-invocable `false` entries reject manual invocation
|
|
46
46
|
- Auto: deterministic whole-word description match with a high bar — distinct `name` plus `description` words (length 3 or more, stopwords dropped) appearing as whole message words, at least 3 hits, best score first, at most 1 skill per turn. Auto loads Tier 2 only (body without inlined references, truncated at 12KB with a read pointer). `disable-model-invocation` skills never match. See `matchSkills` in `src/skills.ts`
|
|
47
47
|
- Deny rules still win over skill grants. See [Permissions](permissions.md)
|
|
48
48
|
|
|
@@ -54,4 +54,4 @@ Grant trust (`skillGrantsFor` in `src/policy.ts`, covered by `tests/policy.test.
|
|
|
54
54
|
2. Keep the body self-contained; reference large helpers via `references/...` so they inline only when needed
|
|
55
55
|
3. Declare least-privilege `allowed-tools`
|
|
56
56
|
4. Set `user-invocable: false` for auto-only helpers, `disable-model-invocation: true` for manual-only helpers
|
|
57
|
-
5. Verify with `/
|
|
57
|
+
5. Verify with `/skill` listing plus `tests/skills*.test.ts` patterns
|
package/documentation/tools.md
CHANGED
|
@@ -12,11 +12,11 @@ Extensions can register brand-new model-callable tools via `api.registerTool({ n
|
|
|
12
12
|
|
|
13
13
|
| Tool | What it does | Permission in normal mode |
|
|
14
14
|
|---|---|---|
|
|
15
|
-
| `read` | Read files, list directories. Args: `path`, optional 1-based `offset`/`limit` | auto |
|
|
15
|
+
| `read` | Read files (UTF-8 text, or PNG/JPEG/GIF/WebP as vision input), list directories. Args: `path`, optional 1-based `offset`/`limit` (text only) | auto |
|
|
16
16
|
| `write` | Create or overwrite files (creates parent dirs). Silent pre-mutation snapshot for rewind | asks |
|
|
17
17
|
| `edit` | Exact-match patch. Fails on no match, on multiple matches without `replaceAll`, on stale read | asks |
|
|
18
|
-
| `grep` | Line-regex search under `dir
|
|
19
|
-
| `glob` | List paths matching pattern under `dir
|
|
18
|
+
| `grep` | Line-regex search under `dir` (a directory, or a single file to search just it). Case-sensitive; `(?i)` prefix = case-insensitive. `include` glob with `{a,b}` (e.g. `*.{ts,tsx}`), `outputMode`: `content`, `files_with_matches`, `count` | auto |
|
|
19
|
+
| `glob` | List paths matching pattern (`*`, `?`, `**`, `{a,b}`) under `dir` (a directory, or a single file to test just it), newest-first | auto |
|
|
20
20
|
| `bash` | Shell command. JSON result with `exitCode`, `stdout`, `stderr`. Optional `runInBackground` | asks |
|
|
21
21
|
| `bash_output` | Poll a background shell task by `taskId` | auto |
|
|
22
22
|
| `webfetch` | Fetch a page as `markdown`, `text`, or `html`. http upgrades to https. Gated by the network SSRF policy (see below) | auto |
|
|
@@ -33,6 +33,7 @@ Read-only set: `read`, `grep`, `glob`, `webfetch`, `websearch`, `bash_output`, `
|
|
|
33
33
|
| Path | Cap | Behavior |
|
|
34
34
|
|---|---|---|
|
|
35
35
|
| `read` output | ~64KB | Head plus truncation note. Full text spills to `<tmpdir>/atom-overflow/` with a `read` pointer |
|
|
36
|
+
| `read` image | 8 MiB per image | PNG/JPEG/GIF/WebP attach as vision input (see below); larger images refused with downscale guidance |
|
|
36
37
|
| `bash` stdout/stderr | ~8KB each | Each stream capped independently, JSON flags `stdoutTruncated`/`stderrTruncated`, overflow pointer on spill |
|
|
37
38
|
| `bash_output` streams | ~8KB each | Same spill behavior for background stdout/stderr |
|
|
38
39
|
| `webfetch` download | ~1MB | Noted as `[truncated: download exceeded ~1MB]` |
|
|
@@ -53,6 +54,10 @@ Count-cap notes (`grep`/`glob` over-cap) and prompt-assembly caps (skills, compa
|
|
|
53
54
|
|
|
54
55
|
No path sandbox. Relative paths resolve against cwd. Absolute paths and `..` escapes are allowed anywhere on the machine, including sensitive locations like `~/.ssh/`. Treat those contents as untrusted. Never exfiltrate or commit secrets. The permission mode is the control plane. See [Permissions](permissions.md).
|
|
55
56
|
|
|
57
|
+
## Image input (vision)
|
|
58
|
+
|
|
59
|
+
`read` on a PNG, JPEG, GIF, or WebP file (detected by magic bytes, up to 8 MiB) attaches it as vision input: the result reads `Image read successfully: <path> (<mime>, <bytes> bytes, attached as vision input)` plus a `[media:<id> ...]` token. History, transcript, and `session.json` carry only that short token (images live under `~/.atom/media/`, pruned after 7 days); at POST time the token expands to provider-native image blocks (OpenAI `image_url`, Anthropic base64 `image` blocks, Gemini `inline_data`). Context accounting charges the deterministic base64 wire cost per token, so the load stays honest. Compaction summaries and the goal judge always strip images to `[image omitted: ...]` markers (text-only, cheap). A model that rejects image input (400 naming images) retries once automatically with images stripped. Anything else binary — PDF, AVIF, BMP, audio, video — is refused with convert-first guidance (e.g. `pdftoppm`/`pdftotext`); oversize images are refused with downscale guidance. Covered by `tests/media.test.ts`.
|
|
60
|
+
|
|
56
61
|
## Network policy (`webfetch` SSRF gate)
|
|
57
62
|
|
|
58
63
|
Every URL — the initial one and every redirect hop — classifies into a zone (`public`, `localhost`, `private` RFC1918/CGNAT/TEST-NET, `link-local` incl. cloud metadata `169.254.169.254`, `blocked` for unparseable/unresolvable) and is checked against the `network` policy from `atom.json` (defaults: public + localhost allowed). Redirects are followed manually (cap 5, loop-detected, credentialed/scheme-changing targets refused) so a public URL can never bounce to metadata or the LAN unseen; each hop re-resolves DNS and the worst zone wins for multi-address hosts. IP-literal tricks (octal/hex forms, IPv4-mapped IPv6) classify by their real address. Known limitation: DNS rebind between check and fetch (TOCTOU) would need connection-level IP pinning, which global fetch does not offer. See [Configuration](configuration.md). Covered by `tests/policy.test.ts`.
|
|
@@ -15,7 +15,7 @@ Never print full keys, never commit them, never put them in fixtures.
|
|
|
15
15
|
|
|
16
16
|
## Model list fails
|
|
17
17
|
|
|
18
|
-
`/model` falls back to the offline list when the live `/models` call fails (Kilo falls back to the `kilo-auto/free` routing placeholder). That is expected offline. Check endpoint override (`OPENCODE_ZEN_ENDPOINT`), network, and key validity before assuming a bug. While Kilo is active, `/
|
|
18
|
+
`/model` falls back to the offline list when the live `/models` call fails (Kilo falls back to the `kilo-auto/free` routing placeholder). That is expected offline. Check endpoint override (`OPENCODE_ZEN_ENDPOINT`), network, and key validity before assuming a bug. While Kilo is active, `/model refresh` re-fetches the gateway catalog.
|
|
19
19
|
|
|
20
20
|
Effort (`/effort`: `Auto`/`Low`/`Medium`/`High`/`Max`) is sent for every model on every provider. If a turn warns that an effort level "is not supported by" a model, the server rejected the knob with a 400 and the turn continued without it — the setting is kept, so switching back to a supporting model re-applies it.
|
|
21
21
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atom-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Agentic terminal coding assistant: multi-provider LLM loop with local file/shell/web tools in an Ink (React) TUI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,8 +38,9 @@
|
|
|
38
38
|
"scripts": {
|
|
39
39
|
"start": "tsx src/cli.tsx",
|
|
40
40
|
"test": "vitest run",
|
|
41
|
+
"bench": "node scripts/bench-render.mjs",
|
|
41
42
|
"typecheck": "tsc --noEmit",
|
|
42
|
-
"build": "tsc -p tsconfig.build.json",
|
|
43
|
+
"build": "tsc -p tsconfig.build.json && node scripts/copy-web-ui.mjs",
|
|
43
44
|
"prepublishOnly": "npm run build"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|