diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 35d6191..c3699a6 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,75 +1,39 @@ -# LevelCode v1.4.0 - -Extensions from Open VSX install again, and the editor checks them before installing. Up to v1.3.1, LevelCode could not check any signed extension, so every install from Open VSX stopped at **Install Anyway**, and installed extensions never updated. This release checks what Open VSX serves against the registry's own signing key. The agent can also draw now: when structure is the point, it puts a diagram in the chat, in your theme, with boxes that open the code they name. And Gemini 4 Argon, Google's new reasoning model, gets its real context window and room to think. + +# LevelCode vX.Y.Z + + ## Highlights -### Extensions install verified, without Install Anyway - -The editor checks every extension it downloads before installing it. In every LevelCode build until now, the module that does that check was missing: it is Microsoft's, and no open-source build includes it. So every check failed with *Signature verification was not executed*. The editor asked you to install anyway, and quietly never updated what you had. - -v1.4.0 ships LevelCode's own checker in that place. It confirms that the package is exactly what Open VSX published, using the registry's signing key. - -- **If you turned checking off to get past the old prompt, turn it back on.** Setting `extensions.verifySignature` to `false` stops all checking, and an upgrade leaves the setting as you set it. Remove it, or set it to `true`. -- **The key is built into the app and never downloaded.** If Open VSX ever changes it, extensions signed with the new key are refused until a LevelCode update carries that key. Extensions already installed keep working. A daily check against the registry looks for exactly that, so a change shows up first as a failed check on our side, not only as your failed installs. -- **A package that does not match is refused, with the reason.** A package that was changed after publishing, or signed with another key, is refused as untrusted, and the editor says so. -- **It confirms the package came from Open VSX, not that the code is safe.** It says nothing about what an extension does, any more than an app store's signature does. -- **An extension installed from a `.vsix` file is not checked.** It comes without a signature to check it against, as in VS Code. -- **Every build is tested on a real extension.** The build installs one through the app's own command line and stops if it is refused, the test that would have caught this. - -### The agent can draw - -Ask how something works and the agent can answer with a picture. Flows, architectures, decision trees and state machines come out as a diagram in the chat. They are laid out, labelled and drawn in your editor's theme. - -- **Boxes link to code.** A box that names a function or a file opens it at the right line when clicked. -- **Full size and export.** **Full size** opens a zoomable view; **Esc** closes it. The toolbar copies the source, saves SVG or PNG, opens the diagram as Mermaid, or inserts it into a Markdown file. -- **Diagrams stay in the session.** A resumed session shows them again. After **Compact**, the agent can still fetch an old diagram by its id. -- **Screen readers get a text outline** of every diagram, and linked boxes open with Enter or Space. -- **It costs about 970 tokens a request** while it is on: the tool and its rules travel with every request. Turn it off with `levelcode.ai.diagrams.enabled`. - -### Gemini 4 Argon, and room for reasoning models to think +### A project's settings no longer change what the agent may do -Gemini 4 Argon is in the model picker on Pro plans, at about 100 turns a month at Google's introductory price. That part is on our side, so it does not wait for this release. v1.4.0 makes the editor handle it properly: +Until now, a folder's `.vscode/settings.json` could set any LevelCode AI setting, and its value won over yours. A repository you cloned could switch the agent to **Autopilot**, send the chat and your API key to a server of its choosing, or set a verify command that ran after the agent's next edit without asking. Restricted Mode did not stop any of it. We reproduced each of these in the editor, in a trusted folder and in Restricted Mode. -- **Its real window.** It gets its full 1,048,576 tokens of context, image input and the reasoning label in the picker. Before, a generic Gemini rule gave it 1,000,000. -- **A medium reasoning effort for chat and the agent**, and a low one for Compact, so it does not think at length about a summary. -- **Room to answer.** A reasoning model's thinking comes out of the same budget as its answer, so the agent now gives every reasoning model 32,768 tokens a turn instead of the 8,192 default. That covers Argon, Kimi K3 and the OpenAI o-series. Compact gives them 8,192 tokens instead of 1,500, which their thinking alone could use up, leaving an empty summary. +Now only your own user settings count, except for eleven display and context preferences a project may still set: -## New settings +`levelcode.ai.includeActiveFile`, `levelcode.ai.diagrams.enabled`, and `levelcode.ai.chat.` `autoContext`, `autoContextMaxFiles`, `scopeToActiveProject`, `workspaceMap`, `startLocation`, `fontSize`, `maxImagesPerMessage`, `proseWidth`, `groupActivity`. -- `levelcode.ai.diagrams.enabled` (default **on**): let the agent draw diagrams in the chat. +These are the same eleven the browser edition allows. -## New commands - -- **AI: Diagram Statistics**: how the agent's diagrams have gone on this machine (drawn, repaired, fallen back, exported). Kept in the editor's own storage; nothing is sent anywhere. - -## Also fixed - -- **A finished answer is no longer nudged to continue.** An answer whose last line was a Markdown-formatted **Done:** did not end the run, and the agent was asked to keep going. -- **Three backticks inside a sentence** no longer break the paragraph into one line per streamed fragment. -- **A command that prints a lot tells the agent how it ended.** Output over 8,000 characters used to be cut from the end, which is where the failure and the exit code are. Now the agent sees the start and the end, with the gap stated. -- **Output over 256 KiB** is shown from its real start, and the count of what was left out is true. -- **A server that logs more than 100,000 characters before "listening on…"** is still seen as listening. Its port and its preview no longer go missing once the command's card is full. -- **The Welcome page and the Customize panel use the site's words.** The Welcome page now opens with the site's own line, and the customization extension is now called **LevelCode Customization**. Its settings and commands are unchanged. +- **If you set one of the others in a project on purpose, it no longer applies there.** For example, a per-project `levelcode.ai.verify.command`, `levelcode.ai.provider`, `levelcode.ai.baseURL` or `levelcode.cloud.endpoint`. Move it to your user settings. In the project's `settings.json` the editor shows the ignored value faded, with a note saying why. +- **They are now shared by all your profiles.** VS Code keeps settings like these in the Default profile. A value written in another profile's `settings.json` is ignored, and changing one from another profile writes it to the Default profile for you. +- **Nothing changes if you only ever set them in your user settings**, which is where the Settings editor and the chat's own menus put them. ## Not in this release -**LevelCode in a browser tab is not something you can use yet.** Its source is part of this release (`web/`, with a simulated shell for the agent), but it is not hosted anywhere. The Mac app is unchanged by it apart from the shared code it reorganized. That code was run in the real editor, against a stand-in model, before tagging: file writes, review, Undo, commands and diagrams. - -**Diagrams have not yet been drawn by every model.** They were tested with scripted models, in the chat page and in the real editor. If a model draws badly, `levelcode.ai.diagrams.enabled` turns them off. Tell us which model it was. - -**Gemini 4 Argon's reasoning is not carried from one agent step to the next.** The editor does not send it back, and Argon was checked to work without it, but a long task may be less consistent than it would be with it. Carrying it is real adapter work, planned separately. - -**The Sessions panel still does not search.** It has been the stated gap since v1.0.5, and it still is. - -**There is still no Windows or Linux build.** + ## Test coverage -- **126 test files** run in the gate: the bundled extensions, the signature checker and the browser edition. -- **The bundled extensions' 70 suites hold 1,252 counted cases**, up from 49 suites and 892 cases in v1.3.1. Six suites print `N passing` and are not counted. -- `extensionSignature` (59 cases): the checker against real Open VSX packages and signatures, every way a signature can fail to verify, and a sweep showing a changed byte of the signature is always refused. -- The diagram suites (12): the schema and validator, the repair ladder, the layout, the painter, the text forms, the session replay and the host's export checks. -- `agentReasoningBudget` and `compactReasoningHost`: run the real agent loop and the real Compact, and read what each request asked for. + +- `settingsScope` (4 cases): every LevelCode AI setting is user-only unless it is on the list above; every scope is one the editor knows, because it reads a misspelt one as a setting a folder can set; and the desktop and the browser edition allow the same list. +- `scripts/folder-settings-editor-check.js` opens the real editor on a project that tries all of the above and checks that none of it takes effect. It is not part of the gate. -**Full changelog:** https://github.com/levelcodeai/levelcode/compare/v1.3.1...v1.4.0 +**Full changelog:** https://github.com/levelcodeai/levelcode/compare/v1.4.0...vX.Y.Z diff --git a/docs/WEB.md b/docs/WEB.md index 3711f3d..73778c3 100644 --- a/docs/WEB.md +++ b/docs/WEB.md @@ -391,8 +391,11 @@ page runs anyone else's, put the extension host on another registrable domain. host the session token is sent to (`levelcode.cloud.endpoint`), the provider's base URL, Autopilot, or the budgets. The browser manifest makes every `levelcode.*` setting `application`-scoped except an explicit list of display preferences (`WORKSPACE_SETTINGS_OK` in `web/ai-extension/manifest.js`, double-entered in `manifest.test.js`). - The desktop manifest is untouched. Measured in the real workbench 2026-10-11 (unscoped: all three came back as the - folder's values; `application`-scoped: the defaults). + Measured in the real workbench 2026-10-11 (unscoped: all three came back as the folder's values; + `application`-scoped: the defaults). The desktop manifest has the same scopes since 2026-10-19, where Workspace + Trust is on but did not help: the extension declares `untrustedWorkspaces.supported: true`, and VS Code ignores + `restrictedConfigurations` unless it is `'limited'`. `extensions/levelcode-ai/test/settingsScope.test.js` keeps the + two lists equal; `extensions/levelcode-ai/scripts/folder-settings-editor-check.js` checks it in the real editor. - **The shell has no way out, and no secrets.** The engine worker is given no token, key, setting or `vscode` object, has no network (`connect-src` is the page's own; the engine option `network` is never passed) and cannot write: its only file operations are three reads over the RPC, bounded and path-checked on the host side. What it diff --git a/extensions/levelcode-ai/package.json b/extensions/levelcode-ai/package.json index 8239746..97d7be6 100644 --- a/extensions/levelcode-ai/package.json +++ b/extensions/levelcode-ai/package.json @@ -353,21 +353,25 @@ "Any OpenAI-compatible endpoint (set levelcode.ai.baseURL) — vLLM, LM Studio, LiteLLM…" ], "default": "claude", + "scope": "application", "markdownDescription": "Which AI provider chat, inline completion and edit use. Every provider except Anthropic speaks the OpenAI-compatible `/v1/chat/completions` protocol, so one key + one setting unlocks it. **Agent mode currently runs on Anthropic (Claude) only.** Pick a model with **LevelCode: AI: Select Model…** — it sets the provider and model together." }, "levelcode.ai.model": { "type": "string", "default": "", + "scope": "application", "markdownDescription": "Active model id for the selected provider (used by every provider except Claude and Ollama, which keep their own `levelcode.ai.claude.model` / `levelcode.ai.ollama.model`). Usually set for you by **LevelCode: AI: Select Model…**; you can also type any model id your provider serves (e.g. `gpt-4o`, `anthropic/claude-sonnet-4-6` on OpenRouter)." }, "levelcode.ai.baseURL": { "type": "string", "default": "", + "scope": "application", "markdownDescription": "Base URL for the **OpenAI-compatible (custom)** provider — must end in `/v1` (e.g. `http://localhost:8000/v1` for vLLM, `http://localhost:1234/v1` for LM Studio). Only used when `levelcode.ai.provider` is `custom`. Prefer `https` (or explicit localhost) — your key is sent as a Bearer token to this host." }, "levelcode.ai.cloudModel": { "type": "string", "default": "moonshotai/kimi-k2.7-code", + "scope": "application", "markdownDescription": "Which **LevelCode Cloud** (gateway) model to run on a paid plan — chosen from your plan's roster via **LevelCode: AI: Select Model…** (the picker shows the live models with their credit multiplier + turns-left). Ignored on the free plan (always gpt-oss-120b) and in BYOK mode. The backend re-checks entitlement, so this can't over-reach your plan." }, "levelcode.ai.includeActiveFile": { @@ -438,11 +442,13 @@ "levelcode.cloud.endpoint": { "type": "string", "default": "https://levelcode.ai", + "scope": "application", "markdownDescription": "Base URL of your LevelCode Cloud host (Rails on Elastic Beanstalk) — one host serves sign-in, the account dashboard, AND the metered AI gateway. **Dev:** set to your ngrok URL, e.g. `https://thinly.ngrok.app`. **Prod:** `https://levelcode.ai`. Set to empty to make sign-in inert. In **BYOK** mode your keys never leave your machine." }, "levelcode.cloud.apiUrl": { "type": "string", "default": "", + "scope": "application", "markdownDescription": "Advanced: override the **backend API** base (metered gateway + token exchange) only if you split the API onto a different host from the website. Leave empty to use `levelcode.cloud.endpoint` (the normal one-host setup)." }, "levelcode.ai.providerMode": { @@ -456,32 +462,38 @@ "LevelCode Cloud gateway (default) — when you're signed in, AI runs through your metered LevelCode plan (no provider key needed) and automatically falls back to your own key (BYOK) when you're signed out." ], "default": "gateway", + "scope": "application", "markdownDescription": "How AI requests are routed. **gateway** (default): when you're signed in to LevelCode Cloud, requests run through your metered LevelCode plan via `levelcode.cloud.apiUrl` (the Rails backend) — no provider key required — and **automatically fall back to BYOK when you're signed out**, so simply signing in puts you on your plan with nothing to toggle. **byok**: always go direct to your provider with your own key, even when signed in. (The gateway is only ever used while signed in, so this default is safe when signed out.)" }, "levelcode.ai.commandTimeout": { "type": "number", "default": 120000, + "scope": "application", "description": "Backstop timeout in milliseconds before an approved shell command is force-killed (its whole process group). The Stop button on the terminal card is the primary control; set 0 to disable the backstop so long-running servers run until you stop them." }, "levelcode.ai.contextWindow": { "type": "number", "default": 200000, + "scope": "application", "description": "The model's context window in tokens, used for the in-chat context-usage meter and warning. Claude 4 models are 200000; raise to 1000000 if you've enabled the 1M-token context beta." }, "levelcode.ai.debug": { "type": "boolean", "default": false, + "scope": "application", "description": "Print detailed debug logs (every agent/chat action) inline in the chat, prefixed with 🐛 DEBUG. For diagnosing agent/chat issues. Off by default — when on, logs may include file contents, tool arguments, and full model responses, so avoid enabling it during screen-shares or recorded demos." }, "levelcode.ai.agent.maxSteps": { "type": "number", "default": 25, + "scope": "application", "minimum": 1, "description": "Maximum tool-use steps the AI agent may take for one goal before stopping." }, "levelcode.ai.agent.maxTokens": { "type": "number", "default": 8192, + "scope": "application", "minimum": 1024, "maximum": 32768, "description": "Maximum output tokens per agent turn (agent mode only; chat/completions use levelcode.ai.claude.maxTokens). If a turn hits this cap mid-output the agent automatically continues in the next turn (so long answers/files aren't truncated), but raising it lets more come out in one turn. Capped at 32768 to bound worst-case spend across continuation turns." @@ -489,6 +501,7 @@ "levelcode.ai.agent.autopilot": { "type": "boolean", "default": false, + "scope": "application", "description": "Autopilot: let the agent run commands without asking, and prefer verifying its own work over pausing to ask you. It still stops and asks before anything hard to undo — deleting files, sudo, force-push / history rewrite, piping a remote script into a shell, publishing a package, or writing outside the project. File edits stay reviewable with Keep/Undo either way. Off by default." }, "levelcode.ai.diagrams.enabled": { @@ -499,11 +512,13 @@ "levelcode.ai.skills.enabled": { "type": "boolean", "default": true, + "scope": "application", "description": "Let the agent self-select bundled skills (expert playbooks) for matching tasks like code review, bug fixes, and test writing. Each skill is a SKILL.md the agent loads on demand." }, "levelcode.ai.sessions.enabled": { "type": "boolean", "default": true, + "scope": "application", "description": "Save each chat/agent session to History so you can browse and reopen past work. Sessions are stored as plain-text JSONL files under levelcode.ai.sessions.dir (default ~/.levelcode/sessions), one folder per project, and listed with /sessions or the Sessions panel. Turn off to stop recording new sessions (existing files are left untouched)." }, "levelcode.ai.sessions.dir": { @@ -515,32 +530,38 @@ "levelcode.ai.sessions.memory.enabled": { "type": "boolean", "default": true, + "scope": "application", "description": "Project memory: as each session finishes, record a one-line outcome (what it did, which files, its state) to a per-project journal at memory/journal.jsonl, so future sessions can recall what past ones achieved. Plain text you own — greppable, editable, local. Turn off to stop recording outcomes." }, "levelcode.ai.sessions.memory.summarize": { "type": "boolean", "default": true, + "scope": "application", "description": "When a substantive session finishes, make one small, fast-model call to refine its journal outcome into a concrete sentence (what was built/fixed/decided) instead of just its goal headline. Runs in the background and only summarizes outcomes and actions, never quoted code. Turn off to skip the model call and keep the plain headline (no cost)." }, "levelcode.ai.sessions.memory.recallTool": { "type": "boolean", "default": true, + "scope": "application", "description": "Give the agent a recall_sessions tool so it can search this project's past-session outcomes on demand — e.g. when you ask \"what did we do about refunds?\" it looks up the earlier work instead of guessing. Read-only, searches only the local journal. Turn off to remove the tool." }, "levelcode.ai.sessions.memory.facts": { "type": "boolean", "default": true, + "scope": "application", "description": "Let the session summarizer also note durable project facts it observes — stable truths like \"the changelog is RELEASE-NOTES.md\" or a convention. Facts stay marked (inferred) and low-trust until they recur across sessions or you confirm them in the Memory panel, and are only ever outcomes/decisions, never secrets or code. Turn off to record outcomes only." }, "levelcode.ai.sessions.autoArchiveDays": { "type": "number", "default": 30, + "scope": "application", "minimum": 0, "description": "Automatically archive sessions you haven't touched in this many days, to keep History focused on recent work. Archived sessions are hidden from the list but never deleted (the JSONL stays on disk), and pinned sessions are always kept. Set to 0 to turn auto-archiving off." }, "levelcode.ai.sessions.resumeBudgetPct": { "type": "number", "default": 40, + "scope": "application", "minimum": 5, "maximum": 100, "description": "When you resume a session, the share of the model's context window its restored transcript may fill before it is summarized to fit. Lower = resume with less history (cheaper, faster); higher = carry more of the past conversation verbatim. The full transcript is always kept on disk and shown in the replay regardless." @@ -548,27 +569,32 @@ "levelcode.ai.verify.enabled": { "type": "boolean", "default": true, + "scope": "application", "description": "After the agent finishes editing, automatically verify its work — pull editor diagnostics (type/lint errors) for the files it changed and, if a verify command is set, run it — then feed any failures back so the agent self-corrects until clean (bounded by levelcode.ai.verify.maxRounds)." }, "levelcode.ai.verify.command": { "type": "string", "default": "", + "scope": "application", "markdownDescription": "Optional one-shot command run to verify the agent's edits (e.g. `npm run typecheck`, `npm test`, `npm run lint`). It MUST exit on its own — do **not** use a dev server or watch command (those block; the `commandTimeout` backstop force-kills them). Leave empty to verify with editor diagnostics only." }, "levelcode.ai.verify.maxRounds": { "type": "number", "default": 2, + "scope": "application", "minimum": 0, "description": "How many times the agent may be sent back to fix failing verification before it stops and hands the remaining problems to you. 0 = report-only (verification still runs and is shown, but the agent won't auto-retry)." }, "levelcode.ai.verify.includeWarnings": { "type": "boolean", "default": false, + "scope": "application", "description": "Treat editor warnings (not just errors) as verification failures the agent must fix. Off by default — only errors block." }, "levelcode.ai.preview.autoOpen": { "type": "boolean", "default": true, + "scope": "application", "markdownDescription": "When the agent starts a web server in the background, automatically open the site in LevelCode's built-in browser, beside the chat.\n\nOnly **local** addresses are ever opened — `localhost`, `127.0.0.1`, or the IPv6 loopback `[::1]`. The bind addresses `0.0.0.0` and `[::]` count as local and are shown as `localhost`, since a browser can't resolve them. A remote URL printed by a dev script is ignored, never opened.\n\nEach address opens at most once per session, so closing the tab is respected, and your focus is never taken. Turn this off to open previews yourself with **Simple Browser: Show**." }, "levelcode.ai.mcp.servers": { @@ -586,6 +612,7 @@ "levelcode.ai.completions.enabled": { "type": "boolean", "default": true, + "scope": "application", "description": "Show inline AI code completions (ghost text) as you type. Accept with Tab." }, "levelcode.ai.completions.model": { @@ -601,11 +628,13 @@ "Claude Opus 4.8 (most capable, slower)" ], "default": "claude-haiku-4-5-20251001", + "scope": "application", "description": "Claude model used for inline completions. A fast model is recommended for low latency." }, "levelcode.ai.completions.debounce": { "type": "number", "default": 150, + "scope": "application", "minimum": 0, "description": "Idle time in milliseconds before requesting an inline completion (lower = snappier but more requests)." }, @@ -622,22 +651,26 @@ "Claude Haiku 4.5 (fastest)" ], "default": "claude-sonnet-4-6", + "scope": "application", "description": "Claude model to use." }, "levelcode.ai.claude.maxTokens": { "type": "number", "default": 4096, + "scope": "application", "minimum": 256, "description": "Maximum tokens in a Claude chat/completion response. (Agent turns use the separate levelcode.ai.agent.maxTokens setting.)" }, "levelcode.ai.ollama.url": { "type": "string", "default": "http://localhost:11434", + "scope": "application", "description": "Base URL of your local Ollama server." }, "levelcode.ai.ollama.model": { "type": "string", "default": "llama3.1", + "scope": "application", "description": "Ollama model name (must be pulled locally, e.g. `ollama pull llama3.1`)." } } diff --git a/extensions/levelcode-ai/scripts/folder-settings-editor-check.js b/extensions/levelcode-ai/scripts/folder-settings-editor-check.js new file mode 100644 index 0000000..5cb1971 --- /dev/null +++ b/extensions/levelcode-ai/scripts/folder-settings-editor-check.js @@ -0,0 +1,266 @@ +#!/usr/bin/env node +/*--------------------------------------------------------------------------------------------- + * LevelCode — a folder does not configure the agent, checked in the REAL editor + * + * A setting with no "scope" in package.json is read from the open folder's .vscode/settings.json + * too, and the folder's value wins over the user's. This script opens the dev build as a second, + * throwaway instance on a folder whose .vscode/settings.json tries to: + * • turn Autopilot on (levelcode.ai.agent.autopilot) + * • send the chat to its own server (levelcode.ai.baseURL — the user's key goes with it) + * • run a command after every edit (levelcode.ai.verify.command — no approval card) + * and, as a positive control, sets a display preference a folder may set (chat.fontSize). + * + * Two stand-in providers run on localhost: the USER's (named in the profile's settings) and the + * FOLDER's (named in the folder). Both script the same turn: ask to run a command that writes a + * marker file, write notes.txt, finish. Whatever the folder could change shows up as a marker file, + * a request at the folder's server, or a missing approval card. + * + * Run twice by default: once with Workspace Trust off (what a folder the user trusted gets), once + * with trust on and the folder NOT trusted (Restricted Mode). + * + * RUN: node extensions/levelcode-ai/scripts/folder-settings-editor-check.js [--vscode