From a3314d902732f0e0ca8126dc23b0831fbfc04461 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 13 May 2026 09:26:04 +0900 Subject: [PATCH] port: plan command graceful degradation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports ECC 17aafc4 ("fix: make plan command work without planner agent") to EGC's commands/egc-plan.toml. The previous prompt asserted that /egc-plan "invokes the planner agent" — when the @planner subagent is unavailable (agents not installed, runtime cannot resolve the name, plugin-only install), the assistant surfaces an "Agent type 'planner' not found" error instead of producing a plan. Changes to the prompt: - Opening paragraph reframes /egc-plan as "creates a plan" and explicitly states inline-by-default + no default subagent delegation. - "How It Works" attributes the steps to "The assistant" instead of "The planner agent". - Example header changes from "Agent (planner):" to "Assistant:" so the example does not imply the agent is mandatory. - "Important Notes" CRITICAL guard is reattributed to "this command" instead of "the planner agent". - "Related Agents" section renamed to "Optional Planner Agent", with explicit fallback instructions: continue inline if @planner is unavailable rather than erroring. tests/commands/plan-command.test.js (new, +3 tests) Asserts the new contract is preserved in the prompt source — catches future regressions where someone reintroduces unconditional planner delegation. Adapted from ECC's test of the same name; the Gemini-adapted version checks for @planner syntax (not Task tool). tests/run-all.js Registers the new test file. ECC commit in scope that did not port: - 2fd8dfc (docs: clarify MCP disable guidance) — entirely Claude Code-specific surface (~/.claude.json runtime persistence, the Claude `/mcp` command, `disabledMcpServers` config key, ECC_DISABLED_MCPS env var, .claude/settings.json paths). EGC's MCP layer is Gemini CLI's mcp-configs/ model; none of the specific facts in the upstream doc map cleanly. EGC's current guidance ("Disable unused servers in project settings") is already harness-correct at the right altitude. Skipping. Lint clean. 279/276 -> 279 total tests pass. --- commands/egc-plan.toml | 16 +++-- tests/commands/plan-command.test.js | 95 +++++++++++++++++++++++++++++ tests/run-all.js | 1 + 3 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 tests/commands/plan-command.test.js diff --git a/commands/egc-plan.toml b/commands/egc-plan.toml index 641f0a5..6ee880e 100644 --- a/commands/egc-plan.toml +++ b/commands/egc-plan.toml @@ -2,7 +2,9 @@ description = "Restate requirements, assess risks, and create step-by-step imple prompt = ''' # Plan Command -This command invokes the **planner** agent to create a comprehensive implementation plan before writing any code. +This command creates a comprehensive implementation plan before writing any code. + +Run inline by default. Do not delegate to the `@planner` subagent (or any other) by default. This keeps `/egc-plan` usable when the runtime ships commands without the matching agent files. ## What This Command Does @@ -22,7 +24,7 @@ Use `/egc-plan` when: ## How It Works -The planner agent will: +The assistant will: 1. **Analyze the request** and restate requirements in clear terms 2. **Break down into phases** with specific, actionable steps @@ -36,7 +38,7 @@ The planner agent will: ``` User: /egc-plan I need to add real-time notifications when markets resolve -Agent (planner): +Assistant: # Implementation Plan: Real-Time Market Resolution Notifications ## Requirements Restatement @@ -91,7 +93,7 @@ Agent (planner): ## Important Notes -**CRITICAL**: The planner agent will **NOT** write any code until you explicitly confirm the plan with "yes" or "proceed" or similar affirmative response. +**CRITICAL**: This command will **NOT** write any code until you explicitly confirm the plan with "yes" or "proceed" or similar affirmative response. If you want changes, respond with: - "modify: [your changes]" @@ -105,7 +107,9 @@ After planning: - Use `/build-and-fix` if build errors occur - Use `/egc-code-review` to review completed implementation -## Related Agents +## Optional Planner Agent + +EGC ships a `planner` agent (`agents/planner.md`) that can produce richer plans for larger features. Use it only when the local runtime already exposes that subagent and the user explicitly asks you to delegate planning — invoke as `@planner`. -This command invokes the `@planner` agent. +If the `@planner` subagent is unavailable (e.g. agents were not installed, or the runtime cannot resolve the name), continue planning inline instead of surfacing an "Agent type 'planner' not found" error. ''' diff --git a/tests/commands/plan-command.test.js b/tests/commands/plan-command.test.js new file mode 100644 index 0000000..902e5e6 --- /dev/null +++ b/tests/commands/plan-command.test.js @@ -0,0 +1,95 @@ +/** + * Tests for commands/egc-plan.toml prompt contract. + * + * Adapted from ECC's tests/commands/plan-command.test.js (commit 17aafc4). + * Verifies that /egc-plan runs inline by default and does not require + * the planner agent to be installed. + */ + +'use strict'; + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +const repoRoot = path.resolve(__dirname, '..', '..'); +const planCommandPath = path.join(repoRoot, 'commands', 'egc-plan.toml'); + +let passed = 0; +let failed = 0; + +function test(name, fn) { + try { + fn(); + console.log(` ✓ ${name}`); + passed += 1; + } catch (err) { + console.log(` ✗ ${name}`); + console.log(` Error: ${err.message}`); + failed += 1; + } +} + +function readPlanCommand() { + return fs.readFileSync(planCommandPath, 'utf8'); +} + +console.log('\n=== Testing /egc-plan command prompt ===\n'); + +test('/egc-plan runs inline by default without requiring planner agent', () => { + const source = readPlanCommand(); + + assert.ok( + source.includes('Do not delegate to the `@planner` subagent'), + 'Expected /egc-plan to avoid default subagent delegation', + ); + assert.ok( + source.includes('If the `@planner` subagent is unavailable'), + 'Expected /egc-plan to define a planner-unavailable fallback', + ); + assert.ok( + !source.includes('This command invokes the **planner** agent'), + 'Expected /egc-plan not to claim unconditional planner invocation', + ); + assert.ok( + !source.includes('The planner agent will:'), + 'Expected /egc-plan to describe inline behavior, not mandatory agent behavior', + ); + assert.ok( + !source.includes('Agent (planner):'), + 'Expected /egc-plan examples not to imply the planner agent is required', + ); +}); + +test('/egc-plan still documents the optional planner agent for manual use', () => { + const source = readPlanCommand(); + + assert.ok( + source.includes('Optional Planner Agent'), + 'Expected /egc-plan to mention the optional planner agent section', + ); + assert.ok( + source.includes('agents/planner.md'), + 'Expected /egc-plan to reference the planner agent source file', + ); +}); + +test('/egc-plan preserves the WAIT-for-CONFIRM contract', () => { + const source = readPlanCommand(); + + assert.ok( + /\*\*CRITICAL\*\*:.*\*\*NOT\*\* write any code until you explicitly confirm/.test(source), + 'Expected /egc-plan to retain the explicit-confirm guard', + ); + assert.ok( + source.includes('WAITING FOR CONFIRMATION'), + 'Expected /egc-plan to retain the WAITING FOR CONFIRMATION marker', + ); +}); + +console.log('\n=== Test Results ==='); +console.log(`Passed: ${passed}`); +console.log(`Failed: ${failed}`); +console.log(`Total: ${passed + failed}\n`); + +process.exit(failed === 0 ? 0 : 1); diff --git a/tests/run-all.js b/tests/run-all.js index c904229..ebb5c84 100644 --- a/tests/run-all.js +++ b/tests/run-all.js @@ -21,6 +21,7 @@ const testFiles = [ 'lib/upstream-drift.test.js', 'hooks/hooks.test.js', 'hooks/block-no-verify.test.js', + 'commands/plan-command.test.js', 'ci/validate-workflow-security.test.js', 'ci/validate-upstream-sync.test.js', 'lint/validators.test.js'