Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eight-seas-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@nanocollective/nanocoder': patch
---

Defer ink and @/app loading in the CLI entry point until the interactive TUI branch, so --acp, --plain and auth paths no longer pay the Ink/App module-graph cost at startup.
5 changes: 5 additions & 0 deletions .changeset/feat-vscode-settings-dashboard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nanocollective/nanocoder": minor
---

Added Settings Tab to the VS Code extension webview for configuring providers and behavior directly from the UI.
5 changes: 5 additions & 0 deletions .changeset/fix-cancel-stops-execution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nanocollective/nanocoder": patch
---

Fixed the VS Code extension's stop button leaving a request running. Two holes: `AcpSession.cancel()` aborted the current controller and immediately replaced it with a fresh one, so a cancel that landed before the turn read the signal — the window while the agent is still resolving the prompt's file references — handed the turn an unaborted controller and the stop was lost. The controller is now rotated when a turn begins instead. Separately, the extension never answered the agent's pending permission request when you hit stop: the tool card kept its spinner and Allow/Deny buttons, and because the request stayed on the pending list every later message was refused with "Please approve or deny the pending tool before sending a new message" until the window was reloaded. Stopping (or reconnecting after the agent process restarts) now resolves those requests as cancelled. Thanks to @akramcodez. Closes #864.
11 changes: 11 additions & 0 deletions .changeset/fix-vscode-tool-aggregator-reset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@nanocollective/nanocoder": patch
---

Fixed new tool calls landing back in an earlier card instead of a fresh one when a thought, reply, edit card, or plan update came in between. Closes #856.

Fixed a manually collapsed tool card re-expanding on its next update.

Reused one footer per agent turn instead of creating one per text segment.

Fixed a turn's copy button sometimes copying a newer turn's text instead of its own.
5 changes: 5 additions & 0 deletions .changeset/loud-plums-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nanocollective/nanocoder": patch
---

Setup wizard's config location picker now shows the resolved path next to each option instead of a bare label.
5 changes: 5 additions & 0 deletions .changeset/sunset-setup-commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nanocollective/nanocoder": minor
---

Sunset `/setup-providers` and `/setup-mcp` in favour of `/settings`. Both retired names still work for now — they open the matching `/settings` tab with a notice instead of erroring. `/settings` now takes a tab argument (`/settings providers`, `/settings mcp`), MCP has its own settings tab, and provider edits made from settings apply to the running session instead of waiting for the next launch. Selecting a provider or MCP server in settings now opens that entry's edit/delete choice directly, with a separate row for adding a new one.
5 changes: 5 additions & 0 deletions .changeset/vscode-code-lens-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nanocollective/nanocoder": minor
---

Added editor code lenses to the VS Code extension: every function, method, constructor and class now carries `Explain Code` and `Generate Tests` links, and clicking one reveals the chat view and sends that symbol - instruction, `file:startLine-endLine` and the source, fenced with the document language - as a prompt. Symbols come from the language server, so no per-language parsing is involved, and the lenses can be turned off with `nanocoder.codeLens`. Long symbols are capped before being inlined, so a lens click on a large class cannot spend a whole context window on one turn. Also fixes a pre-existing hang where sending a message while a tool approval was still pending left the composer spinning forever. Closes #750.
5 changes: 5 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ jobs:
- name: Run TypeScript type checking
run: pnpm test:types

# The root tsconfig only includes source/**, so the extension's own
# sources and specs are checked by their own project or not at all.
- name: Run TypeScript type checking (VS Code extension)
run: pnpm test:types:vscode

test-format:
name: Format Checks
runs-on: ubuntu-latest
Expand Down
Binary file modified assets/nanocoder-vscode.vsix
Binary file not shown.
2 changes: 1 addition & 1 deletion badges/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion badges/forks.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion badges/npm-downloads-monthly.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion badges/repo-size.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 34 additions & 16 deletions benchmarks/measure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,34 +122,30 @@ function measureModuleCount(args: string[]): number {
}

/**
* Boots the CLI in interactive mode under the counting loader, waits until
* the module-resolution count has been stable for `stableMs`, then kills the
* process and returns the final count.
* Boots the CLI under the counting loader, waits until the module-resolution
* count has been stable for `stableMs`, then kills the process and returns
* the final count plus approximate wall-clock boot time.
*
* This measures the full app graph (Ink, hooks, tool manager, command
* registry, MCP loader, etc.) rather than just the `--help` fast path.
* This measures the full resolved graph for the given args (interactive TUI,
* ACP server, etc.) rather than just a oneshot `--help` fast path.
* Polling-until-stable keeps the result deterministic regardless of machine
* speed: we wait for steady state, not a fixed wall-clock window.
*/
/**
* Same polling-until-stable pattern as `measureInteractiveModuleCount`, but
* returns both the module count AND the wall-clock time (in ms) from process
* spawn to the moment the module count reached its final value.
*
* The wall-clock number is labelled **approximate** because it's
* machine-dependent and subject to I/O / scheduler noise. It's not a
* deterministic metric like module count — it's a sanity check that
* optimizations translate into real boot-time savings on the local machine.
*/
async function measureInteractiveStartup(
async function measureStartupUntilStable(
args: string[] = [],
label = 'interactive',
): Promise<{moduleCount: number; bootMs: number}> {
const loaderPath = path.join(__dirname, 'count-loader.mjs');
const loaderUrl = new URL(`file://${loaderPath}`).href;
const countFile = path.join(
repoRoot,
'benchmarks',
`.module-count-interactive-${process.pid}-${Date.now()}`,
`.module-count-${label}-${process.pid}-${Date.now()}`,
);

const child = spawn(
Expand Down Expand Up @@ -356,7 +352,7 @@ async function runWithUrlCapture(
CI: '1',
// Keep the user's global MCP config out of the graph
// so the explain breakdown only reflects nanocoder's own
// boot cost. Matches `measureInteractiveStartup`.
// boot cost. Matches `measureStartupUntilStable`.
NODE_ENV: 'test',
},
},
Expand Down Expand Up @@ -709,13 +705,23 @@ export async function measure(): Promise<Measurements> {
// clock boot number; the module count is deterministic so we only keep
// the first one.
const interactiveRuns = [
await measureInteractiveStartup(),
await measureInteractiveStartup(),
await measureInteractiveStartup(),
await measureStartupUntilStable([], 'interactive'),
await measureStartupUntilStable([], 'interactive'),
await measureStartupUntilStable([], 'interactive'),
];
const interactiveModuleCount = interactiveRuns[0].moduleCount;
const bootSamples = interactiveRuns.map(r => r.bootMs).sort((a, b) => a - b);
const interactiveBootMsMedian = bootSamples[1];
// ACP server is long-lived (JSON-RPC over stdin/stdout). Poll until the
// module graph is stable, then terminate — same pattern as interactive.
const acpRuns = [
await measureStartupUntilStable(['--acp'], 'acp'),
await measureStartupUntilStable(['--acp'], 'acp'),
await measureStartupUntilStable(['--acp'], 'acp'),
];
const acpModuleCount = acpRuns[0].moduleCount;
const acpBootSamples = acpRuns.map(r => r.bootMs).sort((a, b) => a - b);
const acpBootMsMedian = acpBootSamples[1];
// Time from spawn to first stdout byte — what the user actually perceives.
const firstRenderMs = await measureTimeToFirstRender();
const distStats = measureDir(path.join(repoRoot, 'dist'));
Expand Down Expand Up @@ -810,6 +816,18 @@ export async function measure(): Promise<Measurements> {
value: interactiveBootMsMedian,
warnOnDecrease: false,
},
// ACP server steady-state module graph (no Ink / App). Deterministic
// proxy for editor-integration startup cost.
acp_module_count: {
kind: 'numeric',
value: acpModuleCount,
warnOnDecrease: false,
},
acp_boot_ms_approx: {
kind: 'numeric',
value: acpBootMsMedian,
warnOnDecrease: false,
},
// Time from spawn to first stdout byte — what the user sees.
// Measured without the ESM loader so there's no instrumentation
// overhead. Median of 3 runs.
Expand Down
4 changes: 2 additions & 2 deletions docs/configuration/mcp-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Create a `.mcp.json` file in your project root:
}
```

Use `/mcp` to view connected servers and their tools. Use `/setup-mcp` for interactive setup.
Use `/mcp` to view connected servers and their tools. Use `/settings mcp` for interactive setup.

## Optional: Local-First Cross-Session Memory

Expand Down Expand Up @@ -241,7 +241,7 @@ Supported syntax: `$VAR`, `${VAR}`, `${VAR:-default}`

## Setup Wizard

Run `/setup-mcp` for interactive configuration with:
Run `/settings mcp` for interactive configuration with:

- Pre-configured templates for popular servers (Filesystem, GitHub, Brave Search, Context7, DeepWiki, Playwright, etc.)
- Custom server setup for stdio, HTTP, and WebSocket
Expand Down
Loading