@giovannijecha/jecode 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,8 +9,8 @@
9
9
  <p align="center"><strong>Your code. Your loop.</strong></p>
10
10
 
11
11
  <p align="center">
12
- A focused coding agent that lives in your terminal, keeps tool use visible,
13
- and stays under your control.
12
+ A focused terminal coding agent with visible tool use, durable sessions, and
13
+ one controller that stays under your control.
14
14
  </p>
15
15
 
16
16
  <p align="center">
@@ -21,356 +21,342 @@
21
21
  </p>
22
22
 
23
23
  <p align="center">
24
- <a href="https://github.com/giovannijecha/jecode/blob/main/CHANGELOG.md">Changelog</a> ·
24
+ <a href="https://github.com/giovannijecha/jecode/blob/main/CHANGELOG.md">Changelog</a> &middot;
25
25
  <a href="https://github.com/giovannijecha/jecode/releases">Releases</a>
26
26
  </p>
27
27
 
28
- > Jecode is an early 0.6.x release. The core loop is usable today; commands and
28
+ > Jecode is currently pre-1.0. The core loop is usable today, but commands and
29
29
  > terminal interactions may still evolve before 1.0.
30
30
 
31
31
  ## Why Jecode
32
32
 
33
- - **One controller.** One visible loop talks to the model, runs tools, and returns
34
- control to you. Independent reads can overlap inside one step; writes and
35
- commands remain ordered. There are no hidden workers or delegated agents.
36
- - **Terminal-native.** The transcript, composer, searchable menus, tool output,
37
- diffs, approvals, reasoning, and status all share one full-screen TUI.
38
- - **Permission-aware.** Reads stay transparent; dangerous actions ask first.
39
- Session approvals can be reviewed and revoked.
40
- - **Durable by default.** Interactive conversations survive terminal exits and
41
- can be resumed without replaying tools. Batch runs remain stateless.
42
- - **Context-bounded.** Older model context is summarized automatically while
43
- the complete conversation and transcript remain available in the session.
44
- - **Provider-neutral.** Use Anthropic or OpenAI API keys, a ChatGPT account, or
45
- a local/remote Ollama server without changing the workflow.
46
- - **Lean by construction.** Jecode installs as plain JavaScript, runs on
47
- Node.js 22.18+ (22.x) or Node.js 24+, executes no installation scripts, and
48
- has zero third-party runtime dependencies.
49
-
50
- ## Install
51
-
52
- Jecode requires **Node.js 22.18+ on the 22.x line, or Node.js 24+**, and npm:
53
-
54
- ~~~console
33
+ - **One visible loop.** One controller talks to the model, runs tools, and
34
+ returns control to you. Independent reads may overlap inside a step; writes
35
+ and commands stay ordered. There are no delegated agents or hidden model
36
+ workers.
37
+ - **Terminal-native today.** The transcript, composer, searchable menus, tool
38
+ output, diffs, approvals, reasoning, and status share one full-screen TUI.
39
+ - **Permission-aware.** Tool use is visible. Dangerous actions ask first, and
40
+ remembered session approvals can be reviewed or revoked.
41
+ - **Durable and context-bounded.** Interactive conversations survive terminal
42
+ exits. Older model context can be compacted while the complete conversation
43
+ and transcript remain available in the saved session.
44
+ - **Multi-provider.** Use Anthropic or OpenAI API keys, an eligible ChatGPT
45
+ account, or a local, cloud, or remote Ollama server without changing the
46
+ workflow.
47
+ - **Lean by construction.** Jecode ships as owned JavaScript built on Node.js
48
+ primitives, executes no installation scripts, and has zero third-party
49
+ runtime dependencies. This is a permanent product constraint, not a temporary
50
+ optimization.
51
+
52
+ ## Quick start
53
+
54
+ Jecode requires **Node.js 22.18+ on the 22.x line, or Node.js 24+**, and npm.
55
+
56
+ ```console
55
57
  npm install --global @giovannijecha/jecode
56
58
  jecode --version
57
- ~~~
59
+ cd path/to/your/project
60
+ jecode
61
+ ```
58
62
 
59
- To try prereleases instead, install the opt-in **next** channel with
60
- `npm install --global @giovannijecha/jecode@next`.
63
+ Jecode opens directly on an empty composer. Use `/providers` to connect a
64
+ service, `/models` to choose a model, then describe the work you want done.
61
65
 
62
- Published npm packages are the supported installation artifacts. Git URL
63
- installs are intentionally unsupported: the source tree contains no generated
64
- runtime and defines no install-time build hook.
66
+ ```text
67
+ Review this project, explain its architecture, and propose the smallest safe
68
+ change to improve startup performance.
69
+ ```
65
70
 
66
- Then open the project you want to work on and run Jecode:
71
+ Use `jecode --root path/to/project` to select another workspace, or
72
+ `jecode --ephemeral` when the conversation must stay memory-only.
67
73
 
68
- ~~~console
69
- cd path/to/your/project
70
- jecode
71
- ~~~
74
+ Resume a saved conversation for the current workspace with a searchable picker:
72
75
 
73
- Resume a saved conversation for the current project with a searchable picker,
74
- or open the most recent one directly:
75
-
76
- ~~~console
76
+ ```console
77
77
  jecode resume
78
78
  jecode resume --latest
79
- ~~~
79
+ ```
80
80
 
81
- Use `jecode --ephemeral` when a conversation must stay memory-only.
81
+ Run `jecode --help` for every startup option. Windows, Ubuntu, and macOS are
82
+ covered by the project test matrix.
82
83
 
83
- You can point at another workspace explicitly:
84
+ ### Prereleases
84
85
 
85
- ~~~console
86
- jecode --root path/to/your/project
87
- ~~~
86
+ The stable npm package is the supported installation artifact. To try an
87
+ opt-in prerelease:
88
88
 
89
- Run **jecode --help** for all startup options. Tested platforms are Windows,
90
- Ubuntu, and macOS.
89
+ ```console
90
+ npm install --global @giovannijecha/jecode@next
91
+ ```
91
92
 
92
- ### Update
93
+ Git URL installs are intentionally unsupported: the source tree contains no
94
+ generated runtime and defines no install-time build hook.
93
95
 
94
- Install the current stable release over the existing global command:
96
+ ### Update and uninstall
95
97
 
96
- ~~~console
98
+ ```console
97
99
  npm install --global @giovannijecha/jecode
98
100
  jecode --version
99
- ~~~
101
+ npm uninstall --global @giovannijecha/jecode
102
+ ```
103
+
104
+ Uninstalling the command preserves `~/.jecode`. Remove that directory only when
105
+ you intentionally want to erase saved settings, credentials, accounts, and
106
+ sessions.
100
107
 
101
- If you installed Jecode from GitHub before the scoped npm package existed,
102
- remove the old unscoped package once before updating:
108
+ If an older GitHub installation still owns the `jecode` executable, remove the
109
+ legacy unscoped package before installing the scoped package:
103
110
 
104
- ~~~console
111
+ ```console
105
112
  npm uninstall --global jecode
106
113
  npm install --global @giovannijecha/jecode
107
- ~~~
114
+ ```
108
115
 
109
- An `EEXIST` error for a `bin/jecode` path usually means that this legacy
110
- executable still owns the command. Remove it instead of installing with
111
- `--force`.
112
-
113
- ### Uninstall
114
-
115
- ~~~console
116
- npm uninstall --global @giovannijecha/jecode
117
- ~~~
118
-
119
- Uninstalling the command preserves **~/.jecode** so saved settings and
120
- credentials remain available after a reinstall. Remove that directory only
121
- when you intentionally want to erase Jecode's local data.
116
+ Do not work around the resulting `EEXIST` error with `--force`.
122
117
 
123
118
  ### Linux and WSL
124
119
 
125
- WSL has its own Node.js installation and `PATH`; the Node.js version installed
120
+ WSL uses its own Node.js installation and `PATH`; the Node.js version installed
126
121
  on Windows does not apply inside it. Keep user-installed npm commands in the
127
- Linux user path and put that path before inherited Windows entries:
122
+ Linux user path:
128
123
 
129
- ~~~console
124
+ ```console
130
125
  npm config set prefix "$HOME/.local"
131
126
  export PATH="$HOME/.local/bin:$PATH"
132
127
  npm install --global @giovannijecha/jecode
133
128
  hash -r
134
129
  command -v jecode
135
130
  jecode --version
136
- ~~~
131
+ ```
137
132
 
138
133
  Persist the `PATH` export in `~/.profile` or your shell's startup file. Inside
139
- WSL, **command -v jecode** should resolve below `/home/...`, not below
140
- `/mnt/c/.../Volta`. Do not ignore an `EBADENGINE` warning: **node --version**
141
- must report 22.18+ on the 22.x line, or 24+.
134
+ WSL, `command -v jecode` should resolve below `/home/...`, not through an
135
+ inherited Windows path below `/mnt/c`. Do not ignore `EBADENGINE`: `node
136
+ --version` must report 22.18+ on the 22.x line, or 24+.
142
137
 
143
- ### Build from source
144
-
145
- ~~~console
146
- git clone https://github.com/giovannijecha/jecode.git
147
- cd jecode
148
- npm ci --ignore-scripts
149
- npm run build:release
150
- npm link
151
- jecode
152
- ~~~
153
-
154
- Development runs TypeScript directly with **npm run start**. **dist/** is an
155
- ignored, generated tree used only by linked commands and release tarballs.
156
- **npm run pack:release** rebuilds it from a clean target before packing; the
157
- trusted publish workflow performs the same explicit build. Installing the
158
- published package runs no compilation or installation scripts.
159
-
160
- ## First session
161
-
162
- Jecode opens on an empty composer instead of forcing a setup wizard. Type
163
- **/providers** to connect the services you use, then **/models** to choose from
164
- their combined live catalogues. **/settings** keeps the selected model and the
165
- remaining non-secret defaults together. An API key can remain in memory for
166
- the current session or be saved explicitly under **~/.jecode**; it is never
167
- stored in the workspace.
138
+ ## Providers
168
139
 
169
140
  | Provider ID | Authentication | Notes |
170
- |---|---|---|
171
- | anthropic | ANTHROPIC_API_KEY | Anthropic API |
172
- | openai | OPENAI_API_KEY | OpenAI API |
173
- | openai-codex | ChatGPT OAuth | Experimental; uses eligible ChatGPT Codex access |
174
- | ollama | OLLAMA_API_KEY for Cloud/remote | Cloud with a key, local without one |
175
-
176
- Choose **ChatGPT** in **/providers** to sign in on OpenAI's website without
177
- pasting a key.
178
- Jecode offers a local browser callback and a device-code flow; WSL and remote
179
- terminals default to the device code. The connection is saved only after the
180
- flow completes. Availability and usage limits are determined by the ChatGPT
181
- account and plan, not by OpenAI API credits. This integration is experimental
182
- and is not an endorsement of Jecode by OpenAI.
141
+ | --- | --- | --- |
142
+ | `anthropic` | `ANTHROPIC_API_KEY` | Anthropic API |
143
+ | `openai` | `OPENAI_API_KEY` | OpenAI API |
144
+ | `openai-codex` | ChatGPT OAuth | Experimental; uses eligible ChatGPT Codex access |
145
+ | `ollama` | `OLLAMA_API_KEY` for cloud or remote use | Cloud with a key, local without one |
146
+
147
+ Choose **ChatGPT** in `/providers` to sign in on OpenAI's website without
148
+ pasting a key. Jecode supports a local browser callback and a device-code flow;
149
+ WSL and remote terminals default to the device code. Availability and usage
150
+ limits depend on the ChatGPT account and plan, not on OpenAI API credits. This
151
+ integration is experimental and is not an endorsement of Jecode by OpenAI.
183
152
 
184
153
  Anthropic remains API-key only. Jecode does not reuse a Claude consumer
185
154
  subscription or copy credentials from another client.
186
155
 
187
- Choose **Ollama** in **/providers** to manage its API key and select **cloud**,
188
- **local**, or a custom endpoint. Existing users with an Ollama API key
189
- automatically use **https://ollama.com**; without a key, Jecode uses the local
190
- daemon at **http://127.0.0.1:11434**. Remote custom endpoints must use HTTPS.
156
+ For Ollama, `/providers` can select cloud, local, or a custom endpoint. With an
157
+ Ollama API key Jecode defaults to `https://ollama.com`; without one it defaults
158
+ to `http://127.0.0.1:11434`. Remote custom endpoints must use HTTPS.
191
159
 
192
160
  ## Use the TUI
193
161
 
194
- Type **/** to open searchable command completion inside the composer.
162
+ Type `/` to open searchable command completion inside the composer.
195
163
 
196
164
  | Command | What it does |
197
- |---|---|
198
- | /settings | Manage the selected model, limits, context compaction, effort, motion, and provider access |
199
- | /effort | Change and save reasoning effort directly |
200
- | /providers | Manage API keys, ChatGPT sign-in, and Ollama connections |
201
- | /models | Search models across every available provider and select one |
202
- | /permissions | Change session tool access inline and review remembered approvals |
203
- | /new | Close the current conversation, start clean, and reset tool permissions |
204
- | /export | Save a timestamped Markdown transcript in the launch directory |
205
- | /help | Open a temporary keyboard reference in the composer dock |
206
- | /exit | Restore the terminal and exit |
165
+ | --- | --- |
166
+ | `/settings` | Manage the selected model and saved non-secret defaults |
167
+ | `/effort` | Change and save reasoning effort directly |
168
+ | `/providers` | Manage provider connections, API keys, ChatGPT sign-in, and Ollama endpoints |
169
+ | `/models` | Search all currently usable provider catalogues and select a model |
170
+ | `/permissions` | Change session tool access and review remembered approvals |
171
+ | `/timeline` | Browse completed turns and select where the next branch should begin |
172
+ | `/compact` | Compact the current branch context without deleting saved conversation history |
173
+ | `/new` | Start a new conversation and reset session tool permissions |
174
+ | `/export` | Save a timestamped Markdown transcript in the launch directory |
175
+ | `/help` | Open a temporary keyboard reference in the composer dock |
176
+ | `/exit` | Restore the terminal and exit |
207
177
 
208
178
  Useful controls:
209
179
 
210
- - **Up/Down** moves through command suggestions, menus, and input history.
211
- - **Left/Right** moves the composer cursor or changes an inline menu value;
180
+ - **Up/Down** moves through suggestions, menus, and input history.
181
+ - **Left/Right** moves the cursor or changes an inline value;
212
182
  **Ctrl+Left/Right** moves by word.
213
- - **Backspace/Delete** removes one character; **Ctrl+Backspace/Delete** removes
214
- one word. **Home/End** moves to the start or end of the composer.
183
+ - **Backspace/Delete** removes one character;
184
+ **Ctrl+Backspace/Delete** removes one word.
185
+ - **Home/End** moves to the beginning or end of the composer.
215
186
  - **Tab** completes a slash command without running it; **Enter** sends.
216
187
  - **Alt+Enter** inserts a newline.
217
- - **Esc** closes a menu or interrupts the foreground operation.
188
+ - **Esc** closes the active menu or interrupts foreground work.
218
189
  - **Ctrl+C** interrupts, or exits while idle. **Ctrl+D** requests a clean exit.
219
- - **PageUp/PageDown** and the mouse wheel scroll the transcript without losing
220
- the place you are reading.
190
+ - **PageUp/PageDown** and the mouse wheel scroll the transcript.
221
191
  - **Ctrl+O** expands or compacts the latest reasoning or tool-detail block.
222
192
 
223
- The one-line footer keeps model, effort, and workspace on the left. While work
224
- is active, the right edge shows its current state, elapsed time, and interrupt
225
- hint; readiness guidance and temporary feedback use the same replaceable space
226
- without polluting the transcript. Slash commands never append content to the
227
- conversation or its Markdown export; **/help** closes with **Esc**, and token
228
- accounting remains internal to the active session.
193
+ The footer keeps the active model, effort, and workspace visible. During work,
194
+ it adds the current state, elapsed time, and interrupt hint. Operational
195
+ feedback uses the same replaceable status area instead of adding noise to the
196
+ conversation or its Markdown export.
197
+
198
+ ## Sessions and context
199
+
200
+ Interactive conversations are stored under `~/.jecode/sessions` and scoped to
201
+ the canonical workspace path. A fresh or `/new` conversation is not added to
202
+ the resume picker until it has a settled turn. Resuming and continuing a
203
+ conversation keeps its durable session identity and updates one picker entry
204
+ instead of creating duplicates.
205
+
206
+ `/timeline` shows completed turns in the conversation tree. Selecting an older
207
+ turn changes only the in-memory path: it creates and saves a branch only after
208
+ the next real user message. Cancelling the picker or exiting before that message
209
+ leaves the durable head unchanged. Historical tools are displayed but never
210
+ executed. If a crash interrupted a tool loop, Jecode resumes from the latest
211
+ completed ancestor and lets the next user turn create a branch. `/export`
212
+ writes only the currently selected path.
213
+
214
+ When model-facing context approaches the selected model's usable capacity,
215
+ Jecode asks the provider for a bounded summary of the older prefix and keeps
216
+ recent turns exact. The default trigger is 85% and can be changed from 50% to
217
+ 95%. Live provider metadata or Ollama's allocated context determines the budget
218
+ when available; provider safety limits always win.
219
+
220
+ Compaction changes only the projection sent to the model. Complete messages,
221
+ tool evidence, transcript, export, and conversation tree remain intact. The
222
+ branch-local summary anchor is saved with the session so resume does not repeat
223
+ the same compaction. `/compact` requests this process immediately, even below
224
+ the automatic threshold; it leaves very small contexts unchanged. After
225
+ selecting a historical turn, send the first new message before compacting so
226
+ shared history is never rewritten.
227
+
228
+ ## Batch mode
229
+
230
+ When stdin or stdout is not a terminal, Jecode switches to a plain
231
+ line-oriented mode:
232
+
233
+ ```console
234
+ printf "explain this project\n" | jecode --root .
235
+ ```
236
+
237
+ Batch conversations are stateless. Dangerous tools remain denied unless
238
+ `--auto-approve` is supplied explicitly. Terminal failures are written to
239
+ stderr and exit non-zero so scripts and CI pipelines can stop reliably.
229
240
 
230
241
  ## Configuration
231
242
 
232
243
  Startup precedence is: command-line flags, environment variables, saved
233
- settings, built-in defaults.
244
+ settings, then built-in defaults.
234
245
 
235
246
  | Flag | Environment | Default |
236
- |---|---|---|
237
- | --provider | JECODE_PROVIDER | anthropic |
238
- | --model | JECODE_MODEL | Provider default or interactive selection |
239
- | --ollama-host | OLLAMA_HOST | Cloud with an Ollama key, local without one |
240
- | --root | | Current directory |
241
- | --effort | JECODE_EFFORT | high |
242
- | --max-tokens | JECODE_MAX_TOKENS | 64000; not sent by openai-codex |
243
- | --max-steps | JECODE_MAX_STEPS | 40 |
244
- | --compaction-percent | JECODE_COMPACTION_PERCENT | 85; accepts 50 through 95 |
245
- | --reduced-motion | JECODE_REDUCED_MOTION=1 | Off |
246
- | --auto-approve | JECODE_AUTO_APPROVE=1 | Off |
247
- | --ephemeral | JECODE_EPHEMERAL=1 | Off |
248
-
249
- Persistent preferences live in **~/.jecode/settings.json**. Explicitly saved
250
- API keys live in **~/.jecode/credentials.json**; the ChatGPT OAuth account lives
251
- separately in **~/.jecode/accounts.json**. Both secret stores use owner-only
252
- permissions where the operating system supports them. Environment API keys
253
- always win. Model selection saves the provider and model as one change; the
254
- separate startup flags remain available for automation and override that saved
255
- choice.
256
-
257
- Interactive conversations are stored under **~/.jecode/sessions**, scoped to
258
- the canonical workspace path. A checkpoint contains normalized messages and
259
- the settled transcript needed to redraw the conversation. It excludes stored
260
- provider credentials, OAuth tokens, provider-only opaque response data,
261
- permission choices, draft composer text, transient footer notices, and pending
262
- tool state. Session
263
- files use owner-only modes on POSIX; Windows relies on the user-profile ACL.
264
- `jecode resume` keeps the same durable session identity and advances that
265
- session's conversation tree, so reopening and continuing a conversation does
266
- not create duplicate picker entries. `/new` or a fresh launch starts another
267
- logical session. Resume never executes an old tool call. If a crash left the
268
- newest turn inside a tool loop, the same session resumes from its latest
269
- completed ancestor and the next turn becomes a branch inside its tree because
270
- provider-only continuation data is intentionally not stored.
271
-
272
- When the model-facing context approaches the selected model's usable capacity,
273
- Jecode asks the provider for one bounded summary of its older prefix and keeps
274
- the recent turn exact. The trigger defaults to 85% and can be changed from 50%
275
- through 95% in **/settings**. Live provider metadata or Ollama's allocated
276
- runtime context determines the budget when available; a metadata failure falls
277
- back safely without blocking the turn. Only the provider projection is
278
- replaced: complete messages, tool evidence, transcript, and conversation tree
279
- remain unchanged. The branch-local summary anchor is checkpointed with the
280
- session, so resume reuses it instead of summarizing the same prefix again. A
281
- failed or cancelled optional summary leaves the original context intact; a
282
- definite provider context-limit rejection may trigger one compacted retry.
283
- Internal summary requests count toward provider usage but never appear in the
284
- transcript or Markdown export.
285
-
286
- Jecode has one interface theme: dark Steel. **NO_COLOR** is supported for
247
+ | --- | --- | --- |
248
+ | `--provider` | `JECODE_PROVIDER` | `anthropic` |
249
+ | `--model` | `JECODE_MODEL` | Provider default or interactive selection |
250
+ | `--ollama-host` | `OLLAMA_HOST` | Cloud with an Ollama key, local without one |
251
+ | `--root` | - | Current directory |
252
+ | `--effort` | `JECODE_EFFORT` | `high` |
253
+ | `--max-tokens` | `JECODE_MAX_TOKENS` | `64000`; not sent by `openai-codex` |
254
+ | `--max-steps` | `JECODE_MAX_STEPS` | `40` |
255
+ | `--compaction-percent` | `JECODE_COMPACTION_PERCENT` | `85`; accepts `50` through `95` |
256
+ | `--reduced-motion` | `JECODE_REDUCED_MOTION=1` | Off |
257
+ | `--auto-approve` | `JECODE_AUTO_APPROVE=1` | Off |
258
+ | `--ephemeral` | `JECODE_EPHEMERAL=1` | Off |
259
+
260
+ Non-secret preferences live in `~/.jecode/settings.json`. Explicitly saved API
261
+ keys live in `~/.jecode/credentials.json`, while ChatGPT OAuth accounts live in
262
+ `~/.jecode/accounts.json`. Environment credentials always take precedence.
263
+ Secret stores use owner-only permissions where the operating system supports
264
+ them.
265
+
266
+ Jecode has one current interface theme, Dark Steel. `NO_COLOR` is supported for
287
267
  terminals and pipelines that disable colour.
288
268
 
289
- ## Automation
290
-
291
- When stdin or stdout is piped, Jecode switches to a plain line-oriented mode:
292
-
293
- ~~~console
294
- printf "explain this project\n" | jecode --root .
295
- ~~~
296
-
297
- Batch conversations are never written to the session store.
298
-
299
- Dangerous tools stay denied in batch mode unless **--auto-approve** is supplied
300
- explicitly. A terminal batch failure is written to stderr and exits non-zero,
301
- so shell pipelines can stop reliably.
302
-
303
269
  ## Safety model
304
270
 
305
271
  Jecode treats model output, workspace content, tool output, and terminal text as
306
272
  untrusted data.
307
273
 
308
- - Tool paths are confined to the selected workspace. Writes reject symlink and
309
- junction components, then revalidate the boundary during atomic replacement.
310
- - Dangerous tools ask by default unless explicitly allowed for the session in
311
- **/permissions** or the process started with **--auto-approve**.
312
- - Credential fields are masked and excluded from transcripts. Approved shell
313
- commands receive no secret-bearing environment variables; `SSH_AUTH_SOCK`
314
- is preserved so Git and SSH can use the user's agent, which means an approved
315
- command can request that agent to authenticate. Recognized credential values
316
- are redacted before tool output reaches the model, screen, history, or export.
274
+ - Current filesystem tools are confined to the selected workspace. Writes
275
+ reject symlink and junction components, revalidate boundaries, and use atomic
276
+ replacement.
277
+ - Dangerous tools ask by default unless explicitly allowed for the session or
278
+ the process starts with `--auto-approve`.
279
+ - Credential fields are masked and excluded from transcripts. Recognized
280
+ credential values are redacted before output reaches the model, screen,
281
+ history, or export.
282
+ - Approved shell commands receive no secret-bearing environment variables.
283
+ `SSH_AUTH_SOCK` is preserved so Git and SSH can use the user's agent, which
284
+ means an approved command may ask that agent to authenticate.
317
285
  - ChatGPT OAuth uses PKCE and an exact loopback callback or the OpenAI device
318
- flow. Refresh-token rotation is serialized across Jecode processes; OAuth
319
- tokens are withheld and redacted like API keys.
286
+ flow. Refresh-token rotation is serialized across Jecode processes.
320
287
  - Terminal control characters are neutralized before rendering.
321
- - Remote Ollama endpoints require HTTPS. Provider HTTP redirects are rejected
322
- rather than followed across an implicit trust boundary.
288
+ - Remote Ollama endpoints require HTTPS, and provider redirects are rejected.
323
289
  - Provider handshakes and idle response bodies have finite deadlines. Only
324
290
  idempotent catalogue reads retry; generation requests are never replayed.
325
- - Model and filesystem input are bounded before they reach the screen or
326
- provider.
327
- - Durable session files are versioned, size-bounded, atomically checkpointed,
328
- and treated as untrusted when loaded. A live lease prevents the same saved
329
- session from being resumed by two Jecode processes at once.
291
+ - Model, terminal, and filesystem input are bounded before use.
292
+ - Session files are versioned, size-bounded, atomically checkpointed, and
293
+ treated as untrusted when loaded. A live lease prevents concurrent resume.
330
294
 
331
- `run_command` is not an operating-system sandbox: an approved shell command can
332
- still access files and account resources available to the current user. Review
333
- commands carefully and reserve **--auto-approve** for controlled environments.
295
+ `run_command` is not an operating-system sandbox. An approved command can still
296
+ access files and account resources available to the current user. Review
297
+ commands carefully and reserve `--auto-approve` for controlled environments.
334
298
 
335
- Please read [SECURITY.md](SECURITY.md) before reporting a vulnerability.
299
+ Read [SECURITY.md](SECURITY.md) before reporting a vulnerability.
336
300
 
337
- ## Community
301
+ ## Project direction
338
302
 
339
- Jecode is built around people using the product and telling us where the loop
340
- can improve.
303
+ The terminal is Jecode's current primary interface, not the limit of the
304
+ product. Future interfaces may reuse the same controller, session model, and
305
+ visible control system. Expansion must remain deliberate: no hidden model
306
+ hierarchy, no delegated authority, and no weakening of the zero-dependency
307
+ runtime.
341
308
 
342
- - Ask questions, share workflows, and explore ideas in
343
- [GitHub Discussions](https://github.com/giovannijecha/jecode/discussions).
344
- - Report reproducible bugs and focused feature requests through
345
- [GitHub Issues](https://github.com/giovannijecha/jecode/issues).
346
- - Report security concerns privately through the repository Security tab.
309
+ The single-controller rule limits delegation, not duration or scope. Jecode may
310
+ eventually supervise visible, interruptible processes such as development
311
+ servers, file watchers, and test runners. Those processes remain tools owned by
312
+ the controller; they do not receive independent goals, model loops, or tool
313
+ authority.
347
314
 
348
- Public pull requests are not accepted at this stage; code changes remain a
349
- maintainer/collaborator workflow. See [CONTRIBUTING.md](CONTRIBUTING.md) for the
350
- short routing guide and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for community
351
- expectations.
315
+ The selected workspace is the current default filesystem boundary. Any future
316
+ access to additional directories or resources must use explicit, reviewable,
317
+ revocable grants rather than silently widening that boundary.
352
318
 
353
- ## Development
319
+ ## Build from source
354
320
 
355
- ~~~console
321
+ ```console
322
+ git clone https://github.com/giovannijecha/jecode.git
323
+ cd jecode
356
324
  npm ci --ignore-scripts
357
- npm run check
358
- ~~~
325
+ npm run build:release
326
+ npm link
327
+ jecode --version
328
+ ```
359
329
 
360
- The visual lab exercises the complete production TUI—golden conversation,
361
- live tool trace, output tails, change-centric diffs, approvals, menus, and
362
- fields—without a provider, network access, tool execution, or workspace writes:
330
+ Development runs TypeScript directly with `npm run start`. `dist/` is an
331
+ ignored generated tree used only by linked commands and release tarballs.
332
+ `npm run pack:release` rebuilds it from a clean target. Installing the published
333
+ package runs no compilation or installation scripts.
363
334
 
364
- ~~~console
365
- npm run tui:lab
366
- ~~~
335
+ Run the complete project checks with:
367
336
 
368
- For a manual long-session rendering probe, run **npm run bench:transcript**.
337
+ ```console
338
+ npm run check
339
+ ```
369
340
 
370
- Architecture and security boundaries are documented in
371
- [docs/architecture.md](docs/architecture.md). Brand assets and usage rules live
341
+ Use `npm run tui:lab` to inspect production TUI components with inert local
342
+ fixtures, and `npm run bench:transcript` for a manual long-session rendering
343
+ probe. Architecture and security boundaries are documented in
344
+ [docs/architecture.md](docs/architecture.md); brand assets and usage rules live
372
345
  in [docs/brand.md](docs/brand.md).
373
346
 
347
+ ## Community
348
+
349
+ - Ask questions, share workflows, and explore early ideas in
350
+ [GitHub Discussions](https://github.com/giovannijecha/jecode/discussions).
351
+ - Report reproducible bugs and focused feature requests through
352
+ [GitHub Issues](https://github.com/giovannijecha/jecode/issues).
353
+ - Report security concerns privately through the repository Security tab.
354
+
355
+ Public pull requests are not accepted at this stage. Code changes remain a
356
+ maintainer and invited-collaborator workflow. See
357
+ [CONTRIBUTING.md](CONTRIBUTING.md) and
358
+ [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
359
+
374
360
  ## License
375
361
 
376
362
  Jecode is available under the [MIT License](LICENSE).
package/dist/batch.js CHANGED
@@ -7,6 +7,7 @@ import { stdin, stdout } from "node:process";
7
7
  import { runTurn } from "./controller.js";
8
8
  import { resolveContextPolicy } from "./context/capacity.js";
9
9
  import { compactContext } from "./context/compactor.js";
10
+ import { compactSession } from "./context/manual.js";
10
11
  import { isContextOverflow, shouldResolveContextPolicy } from "./context/policy.js";
11
12
  import { handleCommand } from "./commands.js";
12
13
  import { renderBatch } from "./batch-view.js";
@@ -28,7 +29,10 @@ export async function runBatch(session, environment = {}) {
28
29
  if (line === "")
29
30
  continue;
30
31
  if (line.startsWith("/")) {
31
- if ((await handleCommand(line, session, { emit })) === "exit")
32
+ if ((await handleCommand(line, session, {
33
+ emit,
34
+ compact: () => compactSession(session),
35
+ })) === "exit")
32
36
  break;
33
37
  continue;
34
38
  }