airlok 0.4.0 → 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 CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  All notable changes to airlok. The format follows Keep a Changelog; versions follow SemVer.
4
4
 
5
+ ## [0.5.0] - 2026-09-12
6
+
7
+ ### Added
8
+
9
+ - A status line during each turn: a spinner, what airlok is doing (`thinking`, `reading src/main.rs`, `running cargo test`), the seconds so far, and the tokens used this turn, redrawn in place below the output and cleared before anything else prints. It is off when stdout is not a terminal, with `NO_COLOR`, and with `-v`.
10
+ - Esc cancels a running turn as Ctrl-C does: the partial reply is kept and marked interrupted. The terminal is in cbreak mode only while a turn runs, and is restored when the turn ends, before each confirmation, on a panic, and on SIGTERM. Keys typed during a turn start the next prompt.
11
+ - Plan mode, with `/plan` or `--plan`. The model gets only `read_file`, `glob`, `grep`, and `list_dir`, the system prompt says the rest are unavailable, and it ends its reply with a plan. `/go` runs the plan as the task in normal mode; `/plan` again leaves without running it. Per-model settings are sent unchanged in both modes.
12
+ - `!command` runs a command in the working directory and adds the command and its output to the conversation. `#note` appends a list item to `./AIRLOK.md`, creating it, and rebuilds the context block.
13
+ - `@` completes paths from the working directory, fuzzy and gitignore-aware; Tab inserts the path as plain text. Typing `/` shows the matching commands with their descriptions. A prefix runs the first match, and an unknown command suggests the closest.
14
+ - Alt+Enter inserts a newline, and so does Shift+Enter in terminals that send Esc then Enter for it.
15
+ - Write confirmations show line numbers, syntax highlighting, and +/- gutters, and page at 40 lines; `v` shows the rest.
16
+ - A dim footer after each turn: model, context %, session id.
17
+ - `[models."<id>"]` config sections with `reasoning_effort`, sent by the openai provider only for that model id. Azure's `gpt-6-astra` needs `reasoning_effort = "none"` to use tools on Chat Completions; when a provider rejects its reasoning effort, airlok names the setting to add. `/model` shows the configured effort.
18
+
19
+ ### Changed
20
+
21
+ - The REPL starts with one line: version, model, directory, notes such as a resumed session or confirmations being off, and `/help for commands`.
22
+ - Ctrl-C at an empty prompt does nothing; it used to print a hint.
23
+ - Runs of read-only tool calls show on the status line and end with one `read N files` line, in place of the updating `reading N files...` line.
24
+ - Slash commands are listed harmless and frequent first, since a prefix now runs the first match.
25
+
26
+ ## [0.4.1] - 2026-09-11
27
+
28
+ ### Added
29
+
30
+ - `/model [<id>]` shows the model or switches it for the rest of the session, without validating the id. `/provider [anthropic|openai]` switches provider when a key is available for it and otherwise names the missing key. Both are recorded in the session file, and `--resume` continues on the session's last model when it used the configured provider and no `--model` is given.
31
+
32
+ ### Fixed
33
+
34
+ - Markdown lines slightly wider than the terminal no longer leave a bullet, a bold label, or a styled first word such as `airlok` alone on a line. termimad's wrap cut between style runs; airlok now wraps word by word. Paragraphs and list items are rendered per block (when a blank line or the next block marker arrives, or the reply ends), so a paragraph split across source lines reflows as one. A paragraph now appears when it completes, not line by line.
35
+ - The REPL prompt always starts on its own line: rustyline checks the cursor column before each prompt.
36
+
5
37
  ## [0.4.0] - 2026-09-11
6
38
 
7
39
  ### Added
package/README.md CHANGED
@@ -5,18 +5,23 @@ airlok is a terminal coding agent with one differentiator: it is a privacy airlo
5
5
  ## Install
6
6
 
7
7
  ```sh
8
- cargo install airlok
9
- # or
10
- npm install -g airlok
8
+ curl -fsSL https://airlok.dev/install.sh | sh
11
9
  # or
12
10
  brew install airlok-dev/tap/airlok
11
+ # or
12
+ npm install -g airlok
13
+ # or, built from source
14
+ cargo install --git https://github.com/airlok-dev/airlok airlok --locked
13
15
  ```
14
16
 
17
+ `install.sh` installs the latest release for macOS or Linux. It checks the release's installer against the sha256 digest GitHub publishes for it, then runs it; set `AIRLOK_NO_MODIFY_PATH=1` to leave your shell profile alone.
18
+
15
19
  ## Usage
16
20
 
17
21
  ```sh
18
22
  airlok # interactive session in the current directory
19
23
  airlok "create hello.txt containing hello" # run one task in the current directory
24
+ airlok --plan # start in plan mode: the model researches, then proposes a plan
20
25
  airlok --resume # continue the latest saved session here (REPL, or with a task)
21
26
  airlok --resume=<id> "summarise what we did" # continue a particular one
22
27
  airlok sessions # list saved sessions for this directory
@@ -32,23 +37,59 @@ airlok context # print the context block sent wi
32
37
  airlok redactions # list what the redactor detects and how each kind is treated
33
38
  ```
34
39
 
35
- Every `write_file` and `edit_file` call shows a unified diff and asks `Apply? [y]es / [n]o / [a]ll / [q]uit`. Every `bash` call that is not on the allow list shows the command and asks the same way. `y` applies this one, `n` sends a rejection back to the model so it can adapt, `a` approves the rest of that kind for the run, and `q` aborts the run with a non-zero exit. Prompts are read from the terminal, not stdin, so piped input still works; without a terminal, pass `--yes` or turn the confirmations off in the config.
40
+ Every `write_file` and `edit_file` call shows a diff with line numbers, three lines of context, +/- gutters, and syntax highlighting, and asks `Apply? [y]es / [n]o / [a]ll / [q]uit`. A diff longer than 40 lines stops at `... N more lines, [v] to view all`; `v` prints the rest and asks again. Every `bash` call that is not on the allow list shows the command and asks the same way. `y` applies this one, `n` sends a rejection back to the model so it can adapt, `a` approves the rest of that kind for the run, and `q` aborts the run with a non-zero exit. Prompts are read from the terminal, not stdin, so piped input still works; without a terminal, pass `--yes` or turn the confirmations off in the config.
36
41
 
37
- Model output is rendered as markdown (headings, emphasis, lists, tables, highlighted code) when stdout is a terminal; set `NO_COLOR` or redirect stdout for plain text. Runs of read-only tool calls collapse to one `reading N files...` line; `-v` shows every call.
42
+ Model output is rendered as markdown (headings, emphasis, lists, tables, highlighted code) when stdout is a terminal; set `NO_COLOR` or redirect stdout for plain text. Runs of read-only tool calls show on the status line and end with one `read N files` line; `-v` shows every call.
38
43
 
39
- ### Sessions
44
+ ### Interactive sessions
40
45
 
41
- `airlok` with no task opens a session. The prompt shows the model and the directory (`gpt-5.5 airlok> `), each line you type is one turn, and the conversation carries across turns. Ctrl-C during a turn cancels it: the text streamed so far stays in the history marked as interrupted, tool calls that had not run are dropped, and you get the prompt back. Ctrl-D or `/exit` saves and quits.
46
+ `airlok` with no task opens a session. It starts with one line (version, model, directory, `/help for commands`), the prompt shows the model and the directory (`gpt-5.5 airlok> `), each line you send is one turn, and the conversation carries across turns. After each turn a dim footer shows the model, how full the context is, and the session id.
47
+
48
+ While a turn runs, a status line below the output shows a spinner, what airlok is doing (`thinking`, `reading src/main.rs`, `running cargo test`), the seconds so far, and the tokens used this turn. It is cleared before anything else prints. It is off when stdout is not a terminal, when `NO_COLOR` is set, and with `-v`, whose logs share the terminal.
49
+
50
+ | Key | What it does |
51
+ |---|---|
52
+ | Enter | send the line |
53
+ | Alt+Enter | start a new line in the same message. Shift+Enter does the same in terminals that send Esc then Enter for it; most send a plain Enter |
54
+ | Tab | take the first `/` command or `@` path on offer; Tab again cycles through the rest |
55
+ | Right arrow | take the rest of the `/` command shown after the cursor |
56
+ | Esc or Ctrl-C | during a turn, cancel it |
57
+ | Ctrl-C | at the prompt, clear the line; on an empty line it does nothing |
58
+ | Ctrl-D | save and quit |
59
+ | Ctrl-R | search this run's history; Up and Down step through it |
60
+
61
+ A cancelled turn keeps the text streamed so far in the history, marked as interrupted; tool calls that had not run are dropped, and you get the prompt back. Keys typed while a turn runs are kept and start the next prompt.
62
+
63
+ | Input | What it does |
64
+ |---|---|
65
+ | `/` at the start | a slash command. A menu of the matching commands and what they do shows as you type. A prefix runs the first match in the menu (`/co` is `/cost`); an unknown name gets the closest command suggested |
66
+ | `@` anywhere | `@` and part of a path offers matching files and directories from the working directory, fuzzy and gitignore-aware. Tab inserts the path as plain text, without the `@` |
67
+ | `!` at the start | runs the rest with `sh -c` in the working directory and prints the output. The command and its output go into the conversation for the model's next turn. `bash_timeout_secs` applies, and the command cannot read input |
68
+ | `#` at the start | appends the rest to `./AIRLOK.md` as a list item, creating the file, and rebuilds the context block so it applies from the next turn. A new `AIRLOK.md` takes precedence over a `CLAUDE.md` or `AGENTS.md` beside it, and the confirmation says so. Instructions are read from the repository root, so from a subdirectory the note lands in a file the context block does not read |
42
69
 
43
70
  | Command | What it does |
44
71
  |---|---|
45
72
  | `/help` | list the commands |
46
- | `/clear` | start a new session; the current one stays saved |
47
- | `/compact` | summarise older turns to free context |
73
+ | `/model [<id>]` | show the model, or use `<id>` for the rest of the session; not validated, the provider rejects a bad id on the next turn |
74
+ | `/plan` | turn plan mode on or off |
75
+ | `/go` | carry out the plan from plan mode, back in normal mode |
76
+ | `/provider [<name>]` | show the provider, or switch to `anthropic` or `openai` if a key is available for it; says which key is missing otherwise |
48
77
  | `/cost` | tokens used so far, and whether they are estimates |
49
- | `/redactions` | what was redacted before leaving this machine (kind and length only) |
78
+ | `/compact` | summarise older turns to free context |
50
79
  | `/config` | the effective configuration |
51
- | `/exit` | save and quit |
80
+ | `/redactions` | what was redacted before leaving this machine (kind and length only) |
81
+ | `/clear` | start a new session; the current one stays saved |
82
+ | `/exit` | save and quit; `/quit` works too |
83
+
84
+ #### Plan mode
85
+
86
+ `/plan`, or `--plan` at startup, switches to plan mode, and the prompt shows `[plan]`. The model gets only the read-only tools (`read_file`, `glob`, `grep`, `list_dir`): `write_file`, `edit_file`, and `bash` are left out of the request, the system prompt says they are unavailable, and a call to one of them anyway is refused. The model researches the task and ends its reply with a plan. `/go` leaves plan mode and sends that plan back as the task, with every tool available again. `/plan` a second time leaves without running anything. Per-model settings such as `reasoning_effort` are sent the same way in both modes. Plan mode is not saved with the session, so `--resume` starts in normal mode unless `--plan` is given.
87
+
88
+ #### Providers in a session
89
+
90
+ `[provider]` settings (`api_key_cmd`, `api_key_env`, `base_url`) belong to the configured provider. After `/provider` switches to the other one, it runs on that provider's default model and its default key variables (`ANTHROPIC_API_KEY`; `AZURE_OPENAI_API_KEY` or `OPENAI_API_KEY`); switching back restores the configured one. Both changes are written to the session file, and `--resume` continues on the session's last model when it used the configured provider and `--model` is not given.
91
+
92
+ ### Sessions
52
93
 
53
94
  Every turn, one-shot or interactive, is saved under `$XDG_DATA_HOME/airlok/sessions/<hash of the directory>/` (`~/.local/share/airlok` by default). `airlok --resume` picks up the latest session for the directory; it rebuilds the context block, so the model sees the current tree and git state, and adds a note with the resume time. `airlok sessions` lists what is there.
54
95
 
@@ -119,6 +160,9 @@ max_bytes = 32768 # cap on the context block; tree is cut first, then ins
119
160
 
120
161
  [redact]
121
162
  show_secrets_in_output = false # show secrets from files in full in the terminal instead of masked
163
+
164
+ [models."gpt-6-astra"] # settings for one model id (the deployment name on Azure); none by default
165
+ reasoning_effort = "none" # openai only, sent as reasoning_effort; not validated
122
166
  ```
123
167
 
124
168
  For openai, `base_url` falls back to the `OPENAI_BASE_URL` environment variable when the config does not set it.
@@ -141,6 +185,8 @@ base_url = "https://<resource>.openai.azure.com/openai/v1"
141
185
  api_key_cmd = "az cognitiveservices account keys list -n <resource> -g <resource-group> --query key1 -o tsv"
142
186
  ```
143
187
 
188
+ Azure's `gpt-6-astra` accepts tools on Chat Completions only with reasoning off, so it needs `[models."gpt-6-astra"]` with `reasoning_effort = "none"`. Without it, airlok shows the provider's error and names that setting. The entry applies however the model is chosen, `/model gpt-6-astra` included.
189
+
144
190
  With this in the user config, plain `airlok "..."` works. The key is sent in Azure's `api-key` header, chosen from the host. No shell wrapper or exported variable is needed.
145
191
 
146
192
  ## Licence
@@ -19,7 +19,7 @@
19
19
  "hasInstallScript": true,
20
20
  "license": "MIT OR Apache-2.0",
21
21
  "name": "airlok",
22
- "version": "0.4.0"
22
+ "version": "0.5.0"
23
23
  },
24
24
  "node_modules/detect-libc": {
25
25
  "engines": {
@@ -48,5 +48,5 @@
48
48
  }
49
49
  },
50
50
  "requires": true,
51
- "version": "0.4.0"
51
+ "version": "0.5.0"
52
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "artifactDownloadUrls": [
3
- "https://github.com/airlok-dev/airlok/releases/download/v0.4.0"
3
+ "https://github.com/airlok-dev/airlok/releases/download/v0.5.0"
4
4
  ],
5
5
  "bin": {
6
6
  "airlok": "run-airlok.js"
@@ -60,7 +60,7 @@
60
60
  "zipExt": ".tar.xz"
61
61
  }
62
62
  },
63
- "version": "0.4.0",
63
+ "version": "0.5.0",
64
64
  "volta": {
65
65
  "node": "18.14.1",
66
66
  "npm": "9.5.0"