From 60e600681cf9430f473daff6a803253baf5f7790 Mon Sep 17 00:00:00 2001 From: t Date: Sun, 7 Jun 2026 16:51:08 +0800 Subject: [PATCH] feat(cli): wire --bare and --no-plugins; doc-fix --permission-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both flags were parsed (and parse-tested) but ignored: - --bare: suppress the REPL startup banner (▎ DeepCode line + "Working in" + "Type /help") for scripting / minimal output. - --no-plugins: skip plugin discovery (empty contributions) + wirePlugins — faster start, or to bypass a broken plugin. Threaded through ReplOpts → startRepl. Also flips stale BEHAVIOR_PARITY rows: --permission-mode → ✅ (already wired in #159), --bare → ✅, --no-plugins → 🟡 (--strict still parsed-only). Parsing is covered by the existing parse-args "boolean flags" test; the wiring is smoke-verified against a throwaway HOME (--bare → 0 banner lines vs 1 without; --bare/--no-plugins both run + exit cleanly). cli 137. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/cli/src/cli.ts | 2 ++ apps/cli/src/repl.ts | 56 +++++++++++++++++++++++++++-------------- docs/BEHAVIOR_PARITY.md | 13 +++++----- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/apps/cli/src/cli.ts b/apps/cli/src/cli.ts index 7b140f8..3afbddf 100644 --- a/apps/cli/src/cli.ts +++ b/apps/cli/src/cli.ts @@ -167,6 +167,8 @@ async function main(): Promise { resumeId: args.resumeId, continueSession: args.continue, forkSession: args.forkSession, + bare: args.bare, + noPlugins: args.noPlugins, }); } diff --git a/apps/cli/src/repl.ts b/apps/cli/src/repl.ts index a00ab51..8d57d99 100644 --- a/apps/cli/src/repl.ts +++ b/apps/cli/src/repl.ts @@ -89,6 +89,10 @@ export interface ReplOpts { continueSession?: boolean; /** `--fork-session` → resume into a NEW session, leaving the source intact. */ forkSession?: boolean; + /** `--bare` → suppress the startup banner (scripting / minimal output). */ + bare?: boolean; + /** `--no-plugins` → skip discovering + wiring installed plugins. */ + noPlugins?: boolean; } const DEFAULT_SYSTEM_PROMPT = `You are DeepCode, an AI coding assistant powered by DeepSeek. Help the user with their codebase using the available tools (Read, Write, Edit, Bash, Grep, Glob). Be concise and accurate. When you modify files, briefly explain what you changed and why.`; @@ -274,10 +278,17 @@ export async function startRepl(opts: ReplOpts): Promise { const commands = new CommandRegistry(); // Trusted+enabled plugins contribute skills / sub-agents / commands (their // dirs) + MCP servers. Hooks are merged separately by wirePlugins. - const pluginContrib = await collectPluginContributions({ - home: opts.home, - disabled: settings.disabledPlugins, - }); + // `--no-plugins` skips discovery entirely (faster start / bypass a bad plugin). + const emptyContrib: Awaited> = { + dirs: [], + mcpServers: {}, + }; + const pluginContrib = opts.noPlugins + ? emptyContrib + : await collectPluginContributions({ + home: opts.home, + disabled: settings.disabledPlugins, + }); // Custom prompt-template commands from plugin + user + project commands dirs. const customCommands = await loadSlashCommands({ cwd, @@ -395,19 +406,22 @@ export async function startRepl(opts: ReplOpts): Promise { allowedHttpHookUrls: settings.allowedHttpHookUrls, }); - // M5.2: wire installed plugins (discover + spawn + merge contributed hooks) + // M5.2: wire installed plugins (discover + spawn + merge contributed hooks). + // `--no-plugins` skips this entirely. let pluginsWire: WireResult | null = null; - try { - pluginsWire = await wirePlugins({ - home: opts.home, - disabled: settings.disabledPlugins, - hooks, - capabilities: buildPluginCapabilities(cwd), - sandbox: settings.sandbox, - log: (s) => output.write(s + '\n'), - }); - } catch (err) { - output.write(` ⊞ Plugins: wire-up failed — ${(err as Error).message}\n`); + if (!opts.noPlugins) { + try { + pluginsWire = await wirePlugins({ + home: opts.home, + disabled: settings.disabledPlugins, + hooks, + capabilities: buildPluginCapabilities(cwd), + sandbox: settings.sandbox, + log: (s) => output.write(s + '\n'), + }); + } catch (err) { + output.write(` ⊞ Plugins: wire-up failed — ${(err as Error).message}\n`); + } } let history: StoredMessage[] = resolved.seededHistory; @@ -439,9 +453,13 @@ export async function startRepl(opts: ReplOpts): Promise { history, }; - output.write(`\n ▎ DeepCode · ${ctx.model} · mode: ${ctx.mode} · effort: ${ctx.effort}\n`); - output.write(` Working in ${cwd}\n`); - output.write(` Type /help for commands, /exit to quit.\n\n`); + if (!opts.bare) { + output.write( + `\n ▎ DeepCode · ${ctx.model} · mode: ${ctx.mode} · effort: ${ctx.effort}\n`, + ); + output.write(` Working in ${cwd}\n`); + output.write(` Type /help for commands, /exit to quit.\n\n`); + } const rl = createInterface({ input: opts.input, output, terminal: true }); diff --git a/docs/BEHAVIOR_PARITY.md b/docs/BEHAVIOR_PARITY.md index ebf4333..75f734b 100644 --- a/docs/BEHAVIOR_PARITY.md +++ b/docs/BEHAVIOR_PARITY.md @@ -12,9 +12,10 @@ Legend: `✅` matches · `🟡` matches with caveats · `🔄` deferred · `⚠ > `/release-notes`, and `/bug` (alias `/feedback`) slash commands (PR #150); > `--resume` / `--continue` / `--fork-session` wired to real session resume > (PR #153); the `/init` 3-phase REPL flow; and the CLI `/effort` table reading -> its numbers from `EFFORT_PARAMS` (PR #147). Caveat: `--permission-mode` is -> parsed but **not yet wired**. The Tools table (de-staled in PR #151) was -> re-verified row-by-row this pass — all markers hold. +> its numbers from `EFFORT_PARAMS` (PR #147); `--permission-mode` wired as a +> true `--mode` alias (PR #159); and `--bare` / `--no-plugins` wired. The Tools +> table (de-staled in PR #151) was re-verified row-by-row this pass — all +> markers hold. --- @@ -173,15 +174,15 @@ Specific deviations: | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `--help` / `--version` | ✅ | | `--mode` | ✅ | -| `--permission-mode` | 🔄 — parsed + validated as a `--mode` alias, but **not wired**: the value is currently ignored (pass `--mode`) | +| `--permission-mode` | ✅ — true `--mode` alias (sets `mode`; last of `--mode`/`--permission-mode` wins), wired in PR #159 | | `--model` / `--effort` | ✅ | | `--max-turns` | ✅ | | `-C` / `--cd ` | ✅ — chdir before running (Codex parity); validated eagerly, bad path exits 2 | | `--system-prompt` / `--append-system-prompt[-file]` | ✅ | | `--allowedTools` / `--disallowedTools` | ✅ | -| `--bare` | 🔄 (parsed, semantics deferred) | +| `--bare` | ✅ — suppresses the REPL startup banner (scripting / minimal output) | | `--settings` / `--agents` / `--mcp-config` / `--plugin-dir` / `--plugin-url` | 🔄 (parsed only) | -| `--no-plugins` / `--strict` | 🔄 (parsed only) | +| `--no-plugins` / `--strict` | 🟡 — `--no-plugins` skips plugin discovery + wiring; `--strict` still parsed-only | | `-p` headless | ✅ text/json/stream-json, 5 exit codes | | `--output-format` / `--json-schema` / `--include-partial-messages` | ✅ output-format + json-schema (lightweight top-level validation) + include-partial-messages all implemented (`headless.ts`) | | `--resume ` / `--continue` / `--fork-session` | ✅ resume by id (picker if no id, `-r`), most-recent-in-cwd (`-c`), fork-into-new |