diff --git a/commands/gsd/discuss-phase.md b/commands/gsd/discuss-phase.md index b710bf134..d205e4903 100644 --- a/commands/gsd/discuss-phase.md +++ b/commands/gsd/discuss-phase.md @@ -1,7 +1,7 @@ --- name: gsd:discuss-phase -description: Gather phase context through adaptive questioning before planning. Use --auto to skip interactive questions (Claude picks recommended defaults). Use --chain for interactive discuss followed by automatic plan+execute. -argument-hint: " [--auto] [--chain] [--batch] [--analyze] [--text]" +description: Gather phase context through adaptive questioning before planning. Use --auto to skip interactive questions (Claude picks recommended defaults). Use --chain for interactive discuss followed by automatic plan+execute. Use --power for bulk question generation into a file-based UI (answer at your own pace). +argument-hint: " [--auto] [--chain] [--batch] [--analyze] [--text] [--power]" allowed-tools: - Read - Write @@ -31,6 +31,7 @@ Extract implementation decisions that downstream agents need — researcher and @~/.claude/get-shit-done/workflows/discuss-phase.md @~/.claude/get-shit-done/workflows/discuss-phase-assumptions.md +@~/.claude/get-shit-done/workflows/discuss-phase-power.md @~/.claude/get-shit-done/templates/context.md diff --git a/get-shit-done/workflows/discuss-phase-power.md b/get-shit-done/workflows/discuss-phase-power.md new file mode 100644 index 000000000..0877ee6e3 --- /dev/null +++ b/get-shit-done/workflows/discuss-phase-power.md @@ -0,0 +1,291 @@ + +Power user mode for discuss-phase. Generates ALL questions upfront into a JSON state file and an HTML companion UI, then waits for the user to answer at their own pace. When the user signals readiness, processes all answers in one pass and generates CONTEXT.md. + +**When to use:** Large phases with many gray areas, or when users prefer to answer questions offline / asynchronously rather than interactively in the chat session. + + + +This workflow executes when `--power` flag is present in ARGUMENTS to `/gsd:discuss-phase`. + +The caller (discuss-phase.md) has already: +- Validated the phase exists +- Provided init context: `phase_dir`, `padded_phase`, `phase_number`, `phase_name`, `phase_slug` + +Begin at **Step 1** immediately. + + + +Run the same gray area identification as standard discuss-phase mode. + +1. Load prior context (PROJECT.md, REQUIREMENTS.md, STATE.md, prior CONTEXT.md files) +2. Scout codebase for reusable assets and patterns relevant to this phase +3. Read the phase goal from ROADMAP.md +4. Identify ALL gray areas — specific implementation decisions the user should weigh in on +5. For each gray area, generate 2–4 concrete options with tradeoff descriptions + +Group questions by topic into sections (e.g., "Visual Style", "Data Model", "Interactions", "Error Handling"). Each section should have 2–6 questions. + +Do NOT ask the user anything at this stage. Capture everything internally, then proceed to generate. + + + +Write all questions to: + +``` +{phase_dir}/{padded_phase}-QUESTIONS.json +``` + +**JSON structure:** + +```json +{ + "phase": "{padded_phase}-{phase_slug}", + "generated_at": "ISO-8601 timestamp", + "stats": { + "total": 0, + "answered": 0, + "chat_more": 0, + "remaining": 0 + }, + "sections": [ + { + "id": "section-slug", + "title": "Section Title", + "questions": [ + { + "id": "Q-01", + "title": "Short question title", + "context": "Codebase info, prior decisions, or constraints relevant to this question", + "options": [ + { + "id": "a", + "label": "Option label", + "description": "Tradeoff or elaboration for this option" + }, + { + "id": "b", + "label": "Another option", + "description": "Tradeoff or elaboration" + }, + { + "id": "c", + "label": "Custom", + "description": "" + } + ], + "answer": null, + "chat_more": "", + "status": "unanswered" + } + ] + } + ] +} +``` + +**Field rules:** +- `stats.total`: count of all questions across all sections +- `stats.answered`: count where `answer` is not null and not empty string +- `stats.chat_more`: count where `chat_more` has content +- `stats.remaining`: `total - answered` +- `question.id`: sequential across all sections — Q-01, Q-02, Q-03, ... +- `question.context`: concrete codebase or prior-decision annotation (not generic) +- `question.answer`: null until user sets it; once answered, the selected option id or free-text +- `question.status`: "unanswered" | "answered" | "chat-more" (has chat_more but no answer yet) + + + +Write a self-contained HTML companion file to: + +``` +{phase_dir}/{padded_phase}-QUESTIONS.html +``` + +The file must be a single self-contained HTML file with inline CSS and JavaScript. No external dependencies. + +**Layout:** + +``` +┌─────────────────────────────────────────────────────┐ +│ Phase {N}: {phase_name} — Discussion Questions │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ 12 total | 3 answered | 9 remaining │ │ +│ └──────────────────────────────────────────────┘ │ +├─────────────────────────────────────────────────────┤ +│ ▼ Visual Style (3 questions) │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ Q-01 │ │ Q-02 │ │ Q-03 │ │ +│ │ Layout │ │ Density │ │ Colors │ │ +│ │ ... │ │ ... │ │ ... │ │ +│ └──────────┘ └──────────┘ └──────────┘ │ +│ ▼ Data Model (2 questions) │ +│ ... │ +└─────────────────────────────────────────────────────┘ +``` + +**Stats bar:** +- Total questions, answered count, remaining count +- A simple CSS progress bar (green fill = answered / total) + +**Section headers:** +- Collapsible via click — show/hide questions in the section +- Show answered count for the section (e.g., "2/4 answered") + +**Question cards (3-column grid):** +Each card contains: +- Question ID badge (e.g., "Q-01") and title +- Context annotation (gray italic text) +- Option list: radio buttons with bold label + description text +- Chat more textarea (orange border when content present) +- Card highlighted green when answered + +**JavaScript behavior:** +- On radio button select: mark question as answered in page state; update stats bar +- On textarea input: update chat_more content in page state; show orange border if content present +- "Save answers" button at top and bottom: serializes page state back to the JSON file path + +**Save mechanism:** +The Save button writes the updated JSON back using the File System Access API if available, otherwise generates a downloadable JSON file the user can save over the original. Include clear instructions in the UI: + +``` +After answering, click "Save answers" — or download the JSON and replace the original file. +Then return to Claude and say "refresh" to process your answers. +``` + +**Answered question styling:** +- Card border: `2px solid #22c55e` (green) +- Card background: `#f0fdf4` (light green tint) + +**Unanswered question styling:** +- Card border: `1px solid #e2e8f0` (gray) +- Card background: `white` + +**Chat more textarea:** +- Placeholder: "Add context, nuance, or clarification for this question..." +- Normal border: `1px solid #e2e8f0` +- Active (has content) border: `2px solid #f97316` (orange) + + + +After writing both files, print this message to the user: + +``` +Questions ready for Phase {N}: {phase_name} + + HTML (open in browser/IDE): {phase_dir}/{padded_phase}-QUESTIONS.html + JSON (state file): {phase_dir}/{padded_phase}-QUESTIONS.json + + {total} questions across {section_count} topics. + +Open the HTML file, answer the questions at your own pace, then save. + +When ready, tell me: + "refresh" — process your answers and update the file + "finalize" — generate CONTEXT.md from all answered questions + "explain Q-05" — elaborate on a specific question + "exit power mode" — return to standard one-by-one discussion (answers carry over) +``` + + + +Enter wait mode. Claude listens for user commands and handles each: + +--- + +**"refresh"** (or "process answers", "update", "re-read"): + +1. Read `{phase_dir}/{padded_phase}-QUESTIONS.json` +2. Recalculate stats: count answered, chat_more, remaining +3. Write updated stats back to the JSON +4. Re-generate the HTML file with the updated state (answered cards highlighted green, progress bar updated) +5. Report to user: + +``` +Refreshed. Updated state: + Answered: {answered} / {total} + Remaining: {remaining} + Chat-more: {chat_more} + + {phase_dir}/{padded_phase}-QUESTIONS.html updated. + +Answer more questions, then say "refresh" again, or say "finalize" when done. +``` + +--- + +**"finalize"** (or "done", "generate context", "write context"): + +Proceed to the **finalize** step. + +--- + +**"explain Q-{N}"** (or "more info on Q-{N}", "elaborate Q-{N}"): + +1. Find the question by ID in the JSON +2. Provide a detailed explanation: why this decision matters, how it affects the downstream plan, what additional context from the codebase is relevant +3. Return to wait mode + +--- + +**"exit power mode"** (or "switch to interactive"): + +1. Read all currently answered questions from JSON +2. Load answers into the internal accumulator as if they were answered interactively +3. Continue with standard `discuss_areas` step from discuss-phase.md for any unanswered questions +4. Generate CONTEXT.md as normal + +--- + +**Any other message:** +Respond helpfully, then remind the user of available commands: +``` +(Power mode active — say "refresh", "finalize", "explain Q-N", or "exit power mode") +``` + + + +Process all answered questions from the JSON file and generate CONTEXT.md. + +1. Read `{phase_dir}/{padded_phase}-QUESTIONS.json` +2. Filter to questions where `answer` is not null/empty +3. Group decisions by section +4. For each answered question, format as a decision entry: + - Decision: the selected option label (or custom text if free-form answer) + - Rationale: the option description, plus `chat_more` content if present + - Status: "Decided" if fully answered, "Needs clarification" if only chat_more with no option selected + +5. Write CONTEXT.md using the standard context template format: + - `` section with all answered questions grouped by section + - `` section for unanswered questions (carry forward for future discussion) + - `` section for any chat_more content that adds nuance + - `` section with reusable assets found during analysis + - `` section (MANDATORY — paths to relevant specs/docs) + +6. If fewer than 50% of questions were answered, warn the user: +``` +Warning: Only {answered}/{total} questions answered ({pct}%). +CONTEXT.md generated with available decisions. Unanswered questions listed as deferred. +Consider running /gsd:discuss-phase {N} again to refine before planning. +``` + +7. Print completion message: +``` +CONTEXT.md written: {phase_dir}/{padded_phase}-CONTEXT.md + + Decisions captured: {answered} + Deferred: {remaining} + +Next step: /gsd:plan-phase {N} +``` + + + +- Questions generated into well-structured JSON covering all identified gray areas +- HTML companion file is self-contained and usable without a server +- Stats bar accurately reflects answered/remaining counts after each refresh +- Answered questions highlighted green in HTML +- CONTEXT.md generated in the same format as standard discuss-phase output +- Unanswered questions preserved as deferred items (not silently dropped) +- `canonical_refs` section always present in CONTEXT.md (MANDATORY) +- User knows how to refresh, finalize, explain, or exit power mode + diff --git a/get-shit-done/workflows/discuss-phase.md b/get-shit-done/workflows/discuss-phase.md index d77fdf93a..30d7a2102 100644 --- a/get-shit-done/workflows/discuss-phase.md +++ b/get-shit-done/workflows/discuss-phase.md @@ -149,6 +149,11 @@ Exit workflow. **If `phase_found` is true:** Continue to check_existing. +**Power mode** — If `--power` is present in ARGUMENTS: +- Skip interactive questioning entirely +- Read and execute @~/.claude/get-shit-done/workflows/discuss-phase-power.md end-to-end +- Do not continue with the steps below + **Auto mode** — If `--auto` is present in ARGUMENTS: - In `check_existing`: auto-select "Skip" (if context exists) or continue without prompting (if no context/plans) - In `present_gray_areas`: auto-select ALL gray areas without asking the user @@ -1135,6 +1140,21 @@ Route to `confirm_creation` step (existing behavior — show manual next steps). + +When `--power` flag is present in ARGUMENTS, skip interactive questioning and execute the power user workflow. + +The power user mode generates ALL questions upfront into machine-readable and human-friendly files, then waits for the user to answer at their own pace before processing all answers in a single pass. + +**Full step-by-step instructions:** @~/.claude/get-shit-done/workflows/discuss-phase-power.md + +**Summary of flow:** +1. Run the same phase analysis (gray area identification) as standard mode +2. Write all questions to `{phase_dir}/{padded_phase}-QUESTIONS.json` and `{phase_dir}/{padded_phase}-QUESTIONS.html` +3. Notify user with file paths and wait for a "refresh" or "finalize" command +4. On "refresh": read the JSON, process answered questions, update stats and HTML +5. On "finalize": read all answers from JSON, generate CONTEXT.md in the standard format + + - Phase validated against roadmap - Prior context loaded (PROJECT.md, REQUIREMENTS.md, STATE.md, prior CONTEXT.md files) diff --git a/tests/discuss-phase-power.test.cjs b/tests/discuss-phase-power.test.cjs new file mode 100644 index 000000000..6c3ee7b44 --- /dev/null +++ b/tests/discuss-phase-power.test.cjs @@ -0,0 +1,144 @@ +/** + * GSD Tools Tests - discuss-phase power user mode + * + * Validates that the --power flag workflow documentation is present and + * correctly describes the bulk question generation/answering flow. + * + * Closes: #1513 + */ + +const { test, describe } = require('node:test'); +const assert = require('node:assert'); +const fs = require('fs'); +const path = require('path'); + +describe('discuss-phase power user mode (#1513)', () => { + const commandPath = path.join(__dirname, '..', 'commands', 'gsd', 'discuss-phase.md'); + const workflowPath = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'discuss-phase.md'); + const powerWorkflowPath = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'discuss-phase-power.md'); + + describe('command file (discuss-phase.md)', () => { + test('mentions --power flag in argument-hint or description', () => { + const content = fs.readFileSync(commandPath, 'utf8'); + assert.ok( + content.includes('--power'), + 'commands/gsd/discuss-phase.md should document the --power flag' + ); + }); + + test('references the power workflow file', () => { + const content = fs.readFileSync(commandPath, 'utf8'); + assert.ok( + content.includes('discuss-phase-power'), + 'command file should reference discuss-phase-power workflow' + ); + }); + }); + + describe('main workflow file (discuss-phase.md)', () => { + test('has power_user_mode section or references discuss-phase-power.md', () => { + const content = fs.readFileSync(workflowPath, 'utf8'); + const hasPowerSection = content.includes('power_user_mode') || content.includes('power user mode'); + const hasReference = content.includes('discuss-phase-power'); + assert.ok( + hasPowerSection || hasReference, + 'discuss-phase.md should have power_user_mode section or reference discuss-phase-power.md' + ); + }); + + test('describes --power flag routing', () => { + const content = fs.readFileSync(workflowPath, 'utf8'); + assert.ok( + content.includes('--power'), + 'discuss-phase.md should describe --power flag handling' + ); + }); + }); + + describe('power workflow file (discuss-phase-power.md)', () => { + test('file exists', () => { + assert.ok( + fs.existsSync(powerWorkflowPath), + 'get-shit-done/workflows/discuss-phase-power.md should exist' + ); + }); + + test('describes the generate step', () => { + const content = fs.readFileSync(powerWorkflowPath, 'utf8'); + assert.ok( + content.includes('generate') || content.includes('Generate'), + 'power workflow should describe generating questions' + ); + }); + + test('describes the wait/notify step', () => { + const content = fs.readFileSync(powerWorkflowPath, 'utf8'); + const hasWait = content.includes('wait') || content.includes('Wait'); + const hasNotify = content.includes('notify') || content.includes('Notify') || content.includes('notif'); + assert.ok( + hasWait || hasNotify, + 'power workflow should describe the wait/notify step after generating files' + ); + }); + + test('describes the refresh step', () => { + const content = fs.readFileSync(powerWorkflowPath, 'utf8'); + assert.ok( + content.includes('refresh') || content.includes('Refresh'), + 'power workflow should describe the refresh step for processing answers' + ); + }); + + test('describes the finalize step', () => { + const content = fs.readFileSync(powerWorkflowPath, 'utf8'); + assert.ok( + content.includes('finalize') || content.includes('Finalize'), + 'power workflow should describe the finalize step for generating CONTEXT.md' + ); + }); + + test('QUESTIONS.json structure has required fields', () => { + const content = fs.readFileSync(powerWorkflowPath, 'utf8'); + assert.ok(content.includes('QUESTIONS.json'), 'should mention QUESTIONS.json file'); + assert.ok(content.includes('"phase"'), 'JSON structure should include phase field'); + assert.ok(content.includes('"stats"'), 'JSON structure should include stats field'); + assert.ok(content.includes('"sections"'), 'JSON structure should include sections field'); + assert.ok( + content.includes('"id"') && content.includes('"title"'), + 'JSON structure should include question id and title fields' + ); + assert.ok( + content.includes('"options"'), + 'JSON structure should include options array' + ); + assert.ok( + content.includes('"answer"'), + 'JSON structure should include answer field' + ); + assert.ok( + content.includes('"status"'), + 'JSON structure should include status field' + ); + }); + + test('describes HTML generation step', () => { + const content = fs.readFileSync(powerWorkflowPath, 'utf8'); + assert.ok( + content.includes('QUESTIONS.html') || content.includes('.html'), + 'power workflow should describe generating the HTML companion file' + ); + assert.ok( + content.includes('HTML') || content.includes('html'), + 'power workflow should mention HTML output' + ); + }); + + test('QUESTIONS.json file naming uses padded phase number', () => { + const content = fs.readFileSync(powerWorkflowPath, 'utf8'); + assert.ok( + content.includes('padded_phase') || content.includes('{padded_phase}') || content.includes('QUESTIONS.json'), + 'power workflow should describe file naming with padded phase number' + ); + }); + }); +});