Skip to content

feat(cli): interactive init P2 — clack, vendor CLIs, pinned MCP, update - #161

Open
PatrickSys wants to merge 3 commits into
cursor/mcp-init-six-clients-2776from
cursor/interactive-init-p2-f180
Open

PatrickSys wants to merge 3 commits into
cursor/mcp-init-six-clients-2776from
cursor/interactive-init-p2-f180

Conversation

@PatrickSys

@PatrickSys PatrickSys commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

What / Why

Minimal interactive init for the candidate release: detect installed MCP clients, let the user choose tools (@clack/prompts or --clients), merge MCP config files under the project root. --dry-run prints previews and writes nothing.

Removed from earlier iterations: update, npm update notice/cache, config backups, post-init indexing, MCP smoke checks, and vendor CLI registration (sources of most review findings).

Release notes

Candidate-only until shipped; README/client-setup say wizard is not in published 2.2.0.

Smoke

  • node dist/index.js init --yes --clients cursor --dry-run --root .
  • npm pack → install tarball → same dry-run (see tests/cli-init-built-exec.test.ts)
Open in Web Open in Cursor 

Phase P2 builds on the six-client init work: unified diff previews, tiny-config
backups, Claude Desktop detection, npx -y codebase-context@latest launches,
daily npm update notice, post-setup indexing with progress, and expanded tests.
…heck

Adopt @clack/prompts with --yes --clients and --scope project for CI.
Configure Claude, Codex, and VS Code through their CLIs; merge JSON for
Cursor and OpenCode only. Pin codebase-context@version by default with
update command and opt-in --track-latest. Finish init with MCP initialize
smoke test. Add server.json for registry metadata and README install buttons.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T22:55:33.276137Z 7bffa1e PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7bffa1eaf1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli-init-smoke.ts Outdated
Comment on lines +7 to +9
function frameMessage(body: string): string {
const bytes = Buffer.byteLength(body, 'utf8');
return `Content-Length: ${bytes}\r\n\r\n${body}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use newline-delimited JSON for the MCP startup check

Every init run that reaches the default server check will time out even when the server is healthy. The server uses StdioServerTransport in src/index.ts, and the SDK's stdio implementation reads and writes newline-delimited JSON, not Content-Length frames. These headers therefore cause parsing errors, while the response parser below also cannot consume valid SDK responses. Use the SDK client transport or newline-delimited messages in both directions so normal setup can complete without --skip-server-check.

Useful? React with 👍 / 👎.

Comment thread src/cli-init-register.ts Outdated
Comment on lines +107 to +108
args: ['mcp', 'add', 'codebase-context', '--', ...launch.shellCommand],
cwd: options.scope === 'project' ? rootPath : undefined

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor project scope when registering Codex

With the default --scope project, this still modifies the user's global Codex configuration: changing cwd does not change where codex mcp add writes. The upstream command implementation explicitly describes add as “add a server launcher entry to ~/.codex/config.toml” and writes through config.codex_home. Consequently, initializing another repository replaces the global server's fixed project argument, affecting other Codex projects; meanwhile, update searches the project-local .codex/config.toml and misses the registration. Implement genuine project-scoped registration or explicitly reject that scope instead of silently writing globally.

Useful? React with 👍 / 👎.

Comment thread src/cli-update.ts Outdated
Comment on lines +49 to +52
const merged = await _buildMergedMcpContent(generated.path, generated.content, client);
const existing = await fs.readFile(generated.path, 'utf8').catch(() => null);
if (existing === null) return 'missing';
if (merged.content === existing) return 'unchanged';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check that the server entry exists before applying an update

Running update with its default client list registers Codebase Context in existing client config files that never contained it. _buildMergedMcpContent deliberately inserts the generated server when the entry is absent, so checking only whether the config file exists allows this branch to write a new registration; the Codex branch has the same behavior through _buildMergedCodexContent. For example, updating an existing Cursor installation also adds the server to an unrelated opencode.json containing only other settings. Inspect the parsed config for an existing Codebase Context entry before merging, and report missing rather than installing it.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 0/5

[Medium impact] The changes reach developer setup workflows across several MCP clients.

Do not merge until setup and upgrades work through the real executable, backups preserve privacy, and existing index settings remain intact.

Findings

  1. P1 Upgrade command starts a server ▶
  2. P1 Healthy servers fail setup ▶
  3. P1 Project setup changes user settings ▶
  4. P1 Windows VS Code setup fails ▶
  5. P1 Security Backups expose private config ▶
  6. P1 Setup disables existing semantic search ▶
  7. P1 Registered clients keep old pins ▶
  8. P1 Upgrade registers unselected clients ▶
  9. P1 Notice cache blocks setup ▶
  10. P2 Update check delays local setup ▶
  11. P2 Preview commands write files ▶
  12. P2 Install guide describes unreleased behavior ▶
  13. P2 CI example rejects its clients ▶

Summary

This PR adds interactive client selection, vendor CLI registration, pinned launches, config previews and backups, indexing, a startup check, and an update command.

  • The init wizard lets developers choose and register MCP clients.
  • Pinned MCP setups can be refreshed with the update command.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Run init] --> B[Check npm version and write notice cache]
  B --> C[Choose clients and preview changes]
  C --> D{Client kind}
  D -->|Cursor or OpenCode| E[Back up and merge JSON]
  D -->|Claude, Codex, or VS Code| F[Run vendor command]
  E --> G[Build index unless skipped]
  F --> G
  G --> H[Check MCP startup unless skipped]
  I[Run update] --> J[Executable command list]
  J --> K[Starts MCP server: update is missing]
Loading

Reviews (1) · Last reviewed commit: "feat(cli): clack init via vendor CLIs, p..." · Reviewed by Greptile

Comment thread src/cli.ts Outdated
Comment on lines +281 to +282
if (command === 'update') {
return handleUpdateCli(argv.slice(1));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Upgrade command starts a server

update is added to handleCliCommand, but not to CLI_SUBCOMMANDS in src/index.ts. Running codebase-context update therefore starts the MCP server instead of updating configs. Add the command to the executable's routing list and cover the real entrypoint.

Knowledge Base Used: Command-line workflows

Comment thread src/cli-init-smoke.ts Outdated
Comment on lines +7 to +9
function frameMessage(body: string): string {
const bytes = Buffer.byteLength(body, 'utf8');
return `Content-Length: ${bytes}\r\n\r\n${body}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Healthy servers fail setup

verifyMcpServerStarts sends and expects Content-Length frames, but the MCP SDK's stdio transport uses newline-separated JSON. A healthy server cannot complete this check, so normal init waits for the timeout and reports failure after writing configs. Use the SDK client transport for the handshake and require a successful result.

Knowledge Base Used: MCP service interface

Comment thread src/cli-init-register.ts Outdated
Comment on lines +107 to +108
args: ['mcp', 'add', 'codebase-context', '--', ...launch.shellCommand],
cwd: options.scope === 'project' ? rootPath : undefined

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Project setup changes user settings

For Codex, --scope project only changes the working folder. codex mcp add still writes user config, as the setup guide explains. The default project-scoped setup therefore changes a user-wide registration and pins it to this project's folder. Write project config for this scope, or reject the unsupported scope before changing anything.

Comment thread src/cli-init-runner.ts Outdated
Comment on lines +21 to +25
const result = spawnSync(file, args, {
cwd: options.cwd,
env: options.env ?? process.env,
encoding: 'utf8',
shell: false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Windows VS Code setup fails

Windows VS Code registration selects code.cmd, then passes it to spawnSync with shell: false. Windows cannot execute a .cmd file this way, so init --clients vscode --scope user fails before registering the server. Use a Windows-aware launcher that preserves argument quoting.

Comment thread src/cli-init.ts Outdated
} catch (error) {
if (!isFileNotFound(error)) throw error;
}
await fs.writeFile(backupPath, existingText, 'utf8');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Backups expose private config

backupTinyConfig copies the whole existing config without preserving its permissions. If the process uses a 022 umask, updating a 0600 Cursor or OpenCode config creates a readable 0644 backup. If that config contains another server's credentials and its parent folders are accessible, other local users can read them. Create the backup with permissions no broader than the original.

How this was verified: The JSON update path copies the existing file into a new sibling using fs.writeFile without a mode, while the normal config writer explicitly preserves the original mode.

Suggested change
await fs.writeFile(backupPath, existingText, 'utf8');
const { mode } = await fs.stat(configPath);
await fs.writeFile(backupPath, existingText, { encoding: 'utf8', flag: 'wx', mode });

Comment thread src/cli-init-version-notice.ts Outdated
}
if (!latestVersion) return;

await writeCache(cachePath, { checkedAtMs: nowMs, latestVersion });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Notice cache blocks setup

If the home cache is unwritable, writeCache rejects outside the guarded network request. handleInitCli awaits it before doing any setup work, so even project-local setup fails. Treat cache-write failures as optional and continue.

Suggested change
await writeCache(cachePath, { checkedAtMs: nowMs, latestVersion });
await writeCache(cachePath, { checkedAtMs: nowMs, latestVersion }).catch(() => undefined);

Comment thread src/cli-init-version-notice.ts Outdated
Comment on lines +49 to +51
const response = await fetchImpl(`https://registry.npmjs.org/${packageName}/latest`, {
headers: { accept: 'application/json' }
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Update check delays local setup

The daily version request has no timeout, yet setup waits for it before showing the wizard. If the registry or proxy stalls, setup waits until the network stack gives up. Give this optional request a short deadline and continue when it expires.

Suggested change
const response = await fetchImpl(`https://registry.npmjs.org/${packageName}/latest`, {
headers: { accept: 'application/json' }
});
const response = await fetchImpl(`https://registry.npmjs.org/${packageName}/latest`, {
headers: { accept: 'application/json' },
signal: AbortSignal.timeout(3_000)
});

Comment thread src/cli-init.ts Outdated
}
if (!(await fs.stat(options.rootPath)).isDirectory())
throw new Error(`Project root is not a directory: ${options.rootPath}`);
await maybePrintInitUpdateNotice(PKG_VERSION, { disabled: options.noUpdateNotice });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Preview commands write files

--dry-run and --preview still run the notice before their read-only paths. On a successful uncached check, this creates or changes the home cache despite the no-write promise. Disable cache writes for these modes; the current dry-run tests hide this path by disabling the notice entirely.

Suggested change
await maybePrintInitUpdateNotice(PKG_VERSION, { disabled: options.noUpdateNotice });
await maybePrintInitUpdateNotice(PKG_VERSION, {
disabled: options.noUpdateNotice || options.dryRun || options.preview
});

Comment thread README.md Outdated
Comment on lines +9 to +12
Use Node.js 22 or newer. From your project root:

```bash
npx -y codebase-context init

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Install guide describes unreleased behavior

The new install section recommends unpinned npx ... init as the supported wizard, but the setup guide explicitly says this wizard is absent from the published package. This violates the repository requirement that public docs not claim capabilities that are not shipped and tested. Keep the candidate entrypoint instructions until the matching release is available. This requirement must be satisfied before merging.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread README.md Outdated
Non-interactive CI:

```bash
npx -y codebase-context init --yes --clients cursor,opencode --scope project --dry-run

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 CI example rejects its clients

The CI example passes cursor,opencode as one client, but the parser accepts only one exact client ID per flag. Copying this command fails with an unsupported-client error. Use --clients cursor --clients opencode, or add comma-separated parsing.

Suggested change
npx -y codebase-context init --yes --clients cursor,opencode --scope project --dry-run
npx -y codebase-context init --yes --clients cursor --clients opencode --scope project --dry-run

Remove update command, npm notice cache, backups, indexing, smoke checks,
and vendor CLI registration. Init only merges MCP config files for selected
clients. Docs label wizard as unreleased candidate. Add dist/npm-pack exec tests.
@cursor

cursor Bot commented Oct 30, 2026

Copy link
Copy Markdown

Simplified per Patrick (a5702be): ~980 lines removed, ~181 added. init = detect → pick clients → merge project MCP configs; --dry-run writes nothing. Removed update, npm notice/cache, backups, first index, MCP smoke test, and vendor CLI paths. Docs mark wizard as unreleased candidate. Tested via node dist/index.js and npm pack install (tests/cli-init-built-exec.test.ts).

Greptile/Codex findings: removed (not patched) — upgrade command, smoke check, vendor CLI scope, Windows code.cmd, backups, index embedding override, pin refresh/update registration, notice cache, blocking npm check, dry-run cache writes, CI comma clients; fixed — unreleased docs honesty, dry-run writes nothing, real executable tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants