From 9562b72568a40676824bf3f50ed8321afd46727e Mon Sep 17 00:00:00 2001 From: trick77 Date: Wed, 6 May 2026 15:37:59 +0200 Subject: [PATCH 1/4] 0.2.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e44250..c9748d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "opencode-presets", - "version": "0.2.2", + "version": "0.2.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opencode-presets", - "version": "0.2.2", + "version": "0.2.3", "license": "MIT", "dependencies": { "ajv": "8.20.0", diff --git a/package.json b/package.json index 9dbe35c..86147a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencode-presets", - "version": "0.2.2", + "version": "0.2.3", "description": "Interactive CLI that patches opencode.json with curated config presets — LSP, MCP, permissions.", "type": "module", "bin": { From 5052c62738793e0ec534c88c2432d949769e8fbb Mon Sep 17 00:00:00 2001 From: trick77 Date: Fri, 8 May 2026 07:27:16 +0200 Subject: [PATCH 2/4] feat(mcp-intellij): add JetBrains IDE MCP preset with prompt defaults Adds presets/mcp-intellij.conf for the JetBrains "MCP Server" plugin (loopback HTTP at port 64342 by default). Extends the @prompt directive with an optional 4th field "default" used when the user submits an empty line; rejected on type=secret. Existing 2- and 3-field @prompt forms are unchanged. --- AGENTS.md | 5 ++++- README.md | 1 + presets/mcp-intellij.conf | 16 ++++++++++++++++ src/batch.ts | 15 +++++++++++---- src/parse-conf.ts | 12 ++++++++---- test/parse-conf.test.ts | 22 ++++++++++++++++++++++ 6 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 presets/mcp-intellij.conf diff --git a/AGENTS.md b/AGENTS.md index 8bd40fb..9e09927 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,7 +24,10 @@ matter): - `@name`, `@description`, `@author`, `@version`, `@path` — required. - `@mode` — `replace` (default) | `merge` | `merge-overwrite`. - `@fetch: URL -> dest [sha256=hex]` — repeatable. -- `@prompt: name | type | help` — repeatable; type ∈ `text`/`secret`. +- `@prompt: name | type | help | default` — repeatable; type ∈ + `text`/`secret`. Help and default are optional. Default is + forbidden when type is `secret`. When the user enters an empty + line, the default is used. Body is JSONC. After parsing it must be valid JSON of the shape the leaf at `@path` expects (object/array/scalar all allowed for `replace`; diff --git a/README.md b/README.md index 1b28594..7392a67 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ each write — no auto-pruning, so they pile up. | `jdtls-clean-workspace` | LSP | replace | Stops jdtls from writing `.project`/`.classpath`/etc. into your project root | | `mcp-remote-add` | MCP | replace | Add a remote MCP server with bearer-token auth (prompts for id, URL, token) | | `mcp-remote-add-noauth` | MCP | replace | Add a remote MCP server without auth (prompts for id, URL) | +| `mcp-intellij` | MCP | replace | Add the JetBrains IDE MCP server (loopback HTTP, default port 64342) | | `permissions-git-safe` | Permissions | merge | Read-only git commands (status, diff, log, branch --list, fetch, etc.) | | `permissions-shell-safe` | Permissions | merge | Low-risk shell commands (ls, cat, grep, rg, jq, yq, etc.) | | `permissions-build-tools` | Permissions | merge | Build tools (node, npm, mvn, gradle, make, python, pip, cargo, go) | diff --git a/presets/mcp-intellij.conf b/presets/mcp-intellij.conf new file mode 100644 index 0000000..a025c69 --- /dev/null +++ b/presets/mcp-intellij.conf @@ -0,0 +1,16 @@ +// @name: mcp-intellij +// @description: Adds the JetBrains IDE MCP server (IntelliJ, PyCharm, +// etc.) to opencode as a remote HTTP server at +// http://127.0.0.1:/stream. Requires the "MCP Server" plugin +// to be installed and enabled in the IDE. Press Enter to accept +// the default port 64342. To remove: +// `opencode-presets remove mcp-intellij`. +// @author: Jan +// @version: 0.1.0 +// @path: mcp.intellij +// @prompt: port | text | IDE MCP server port | 64342 +{ + "type": "remote", + "url": "http://127.0.0.1:{{prompt:port}}/stream", + "enabled": true +} diff --git a/src/batch.ts b/src/batch.ts index 839bda9..963ca18 100644 --- a/src/batch.ts +++ b/src/batch.ts @@ -93,11 +93,18 @@ export async function runBatch({ resets, confPaths, target, cacheDir, backupDir m.promptValues = {}; for (const p of m.meta.prompts) { const label = ' ' + c.bold(p.name) + - (p.help ? c.meta(' (' + p.help + ')') : '') + ': '; - const val = p.type === 'secret' ? await promptSecret(label) : await promptText(label); + (p.help ? c.meta(' (' + p.help + ')') : '') + + (p.default !== undefined ? c.meta(' [default: ' + p.default + ']') : '') + + ': '; + const raw = p.type === 'secret' ? await promptSecret(label) : await promptText(label); + let val = raw; if (!val) { - console.error(c.err(`error: prompt "${p.name}" cannot be empty`)); - process.exit(1); + if (p.default !== undefined) { + val = p.default; + } else { + console.error(c.err(`error: prompt "${p.name}" cannot be empty`)); + process.exit(1); + } } if (p.name === 'name' && !ID_RE.test(val)) { console.error(c.err(`error: invalid identifier "${val}" — must match ${ID_RE.source}`)); diff --git a/src/parse-conf.ts b/src/parse-conf.ts index 94d6206..66be486 100644 --- a/src/parse-conf.ts +++ b/src/parse-conf.ts @@ -13,6 +13,7 @@ export interface PromptDirective { name: string; type: PromptType; help: string; + default?: string; } export interface ConfMeta { @@ -124,17 +125,20 @@ export function parseConfString(raw: string, filePath = ''): ParsedConf function parsePrompt(value: string, filePath: string): PromptDirective { const parts = value.split('|').map(s => s.trim()); - if (parts.length < 2 || parts.length > 3) { - throw parseError(filePath, 0, `@prompt must be "name | type | help" (help optional), got "${value}"`); + if (parts.length < 2 || parts.length > 4) { + throw parseError(filePath, 0, `@prompt must be "name | type | help | default" (help and default optional), got "${value}"`); } - const [name, type, help = ''] = parts; + const [name, type, help = '', def] = parts; if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(name)) { throw parseError(filePath, 0, `@prompt name must be alphanumeric/underscore/hyphen, got "${name}"`); } if (type !== 'text' && type !== 'secret') { throw parseError(filePath, 0, `@prompt type must be "text" or "secret", got "${type}"`); } - return { name, type, help }; + if (def !== undefined && type === 'secret') { + throw parseError(filePath, 0, `@prompt default value is not allowed for type "secret" (got "${value}")`); + } + return def !== undefined ? { name, type, help, default: def } : { name, type, help }; } function parseFetch(value: string, filePath: string): FetchDirective { diff --git a/test/parse-conf.test.ts b/test/parse-conf.test.ts index 9662fbe..28dcff4 100644 --- a/test/parse-conf.test.ts +++ b/test/parse-conf.test.ts @@ -126,6 +126,28 @@ describe('parseConfString — @prompt', () => { const src = minimalHeader + '// @prompt: x | bogus\n\n{}'; assert.throws(() => parseConfString(src), /type must be/); }); + + test('parses name | type | help | default', () => { + const src = minimalHeader + '// @prompt: port | text | server port | 64342\n\n{}'; + const { meta } = parseConfString(src); + assert.deepEqual(meta.prompts[0], { name: 'port', type: 'text', help: 'server port', default: '64342' }); + }); + + test('parses default with empty help', () => { + const src = minimalHeader + '// @prompt: port | text | | 64342\n\n{}'; + const { meta } = parseConfString(src); + assert.deepEqual(meta.prompts[0], { name: 'port', type: 'text', help: '', default: '64342' }); + }); + + test('rejects default on secret', () => { + const src = minimalHeader + '// @prompt: token | secret | bearer | hunter2\n\n{}'; + assert.throws(() => parseConfString(src), /not allowed for type "secret"/); + }); + + test('rejects more than 4 fields', () => { + const src = minimalHeader + '// @prompt: a | text | b | c | d\n\n{}'; + assert.throws(() => parseConfString(src), /@prompt must be/); + }); }); describe('parseConfString — body and unknowns', () => { From 8e09d2e50ba5a721490ae29bd4bb16a3353687bc Mon Sep 17 00:00:00 2001 From: trick77 Date: Fri, 8 May 2026 07:28:12 +0200 Subject: [PATCH 3/4] docs(mcp-intellij): emphasize plugin must be switched on --- presets/mcp-intellij.conf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/presets/mcp-intellij.conf b/presets/mcp-intellij.conf index a025c69..1aad2df 100644 --- a/presets/mcp-intellij.conf +++ b/presets/mcp-intellij.conf @@ -1,9 +1,10 @@ // @name: mcp-intellij // @description: Adds the JetBrains IDE MCP server (IntelliJ, PyCharm, // etc.) to opencode as a remote HTTP server at -// http://127.0.0.1:/stream. Requires the "MCP Server" plugin -// to be installed and enabled in the IDE. Press Enter to accept -// the default port 64342. To remove: +// http://127.0.0.1:/stream. IMPORTANT: the "MCP Server" +// plugin MUST be installed AND switched on in the IDE — opencode +// cannot reach the endpoint otherwise. Press Enter to accept the +// default port 64342. To remove: // `opencode-presets remove mcp-intellij`. // @author: Jan // @version: 0.1.0 From 353d5c2db7593be19efe0d97727fde1a7769ea37 Mon Sep 17 00:00:00 2001 From: trick77 Date: Fri, 8 May 2026 07:29:47 +0200 Subject: [PATCH 4/4] docs(mcp-intellij): explain what the JetBrains MCP plugin actually does --- presets/mcp-intellij.conf | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/presets/mcp-intellij.conf b/presets/mcp-intellij.conf index 1aad2df..d2bbb1b 100644 --- a/presets/mcp-intellij.conf +++ b/presets/mcp-intellij.conf @@ -1,6 +1,14 @@ // @name: mcp-intellij -// @description: Adds the JetBrains IDE MCP server (IntelliJ, PyCharm, -// etc.) to opencode as a remote HTTP server at +// @description: Connects opencode to a running JetBrains IDE +// (IntelliJ IDEA, PyCharm, WebStorm, GoLand, RustRover, etc.) via +// the official "MCP Server" plugin. Once enabled, opencode can see +// what you're doing in the IDE in real time — the currently open +// file, caret position, selected text, list of open editors, recent +// files, project structure, and diagnostics — and can drive the IDE +// back: open files, jump to symbols, run/debug configurations, and +// apply edits through the IDE's own refactoring engine. This makes +// "fix the thing I'm looking at" prompts work without copy-paste. +// Wired up as a remote HTTP MCP server at // http://127.0.0.1:/stream. IMPORTANT: the "MCP Server" // plugin MUST be installed AND switched on in the IDE — opencode // cannot reach the endpoint otherwise. Press Enter to accept the