From 0a928144daa78a07abc3ee0167946d573ef29303 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 28 Jan 2026 04:17:14 +0100 Subject: [PATCH] chore: bump version to 0.1411 --- CLAUDE.md | 35 ++++---- package.json | 2 +- src/web/public/app.js | 172 ++++++++++++++++++++++++++++++++++++-- src/web/public/index.html | 7 ++ src/web/public/styles.css | 86 +++++++++++++++++++ 5 files changed, 272 insertions(+), 30 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 39bcd14b..68db2b94 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,7 +16,7 @@ When user says "COM": 1. Increment version in BOTH `package.json` AND `CLAUDE.md` 2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web` -**Version**: 0.1410 (must match `package.json`) +**Version**: 0.1411 (must match `package.json`) ## Project Overview @@ -167,25 +167,20 @@ The app must stay fast with 20 sessions and 50 agent windows: | **Test utilities** | `test/respawn-test-utils.ts` | | **Keyboard shortcuts** | README.md or App Settings in web UI | -## Active Ralph Loop Task +## MCP Server Integration -**Current Task**: Create an improvement plan to make this app(Claudeman) significantly better, but focus on performance, memory leaks, that it runs really fluid and fast and all the functions are working properly also in edge cases. +The `claudeman-mcp` binary provides Model Context Protocol integration for Claude Desktop: -**Case Folder**: `/home/arkon/claudeman-cases/claudeman` +```json +// Add to ~/.claude/claude_desktop_config.json +{ + "mcpServers": { + "claudeman-spawn": { + "command": "node", + "args": ["/path/to/claudeman/dist/mcp-server.js"] + } + } +} +``` -### Key Files -- **Plan Summary**: `/home/arkon/claudeman-cases/claudeman/ralph-wizard/summary.md` - Human-readable plan overview -- **Todo Items**: `/home/arkon/claudeman-cases/claudeman/ralph-wizard/final-result.json` - Contains `items` array with all todo tasks -- **Research**: `/home/arkon/claudeman-cases/claudeman/ralph-wizard/research/result.json` - External resources and codebase patterns - -### How to Work on This Task -1. Read the plan summary to understand the overall approach -2. Check `final-result.json` for the todo items array - each item has `id`, `title`, `description`, `priority` -3. Work through items in priority order (critical → high → medium → low) -4. Use `COMPLETION_PHRASE` when the entire task is complete - -### Research Insights -Check `/home/arkon/claudeman-cases/claudeman/ralph-wizard/research/result.json` for: -- External GitHub repos and documentation links to reference -- Existing codebase patterns to follow -- Technical recommendations from the research phase +This enables Claude Desktop to spawn and manage agents via MCP tools. diff --git a/package.json b/package.json index c7160d5f..0a981208 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claudeman", - "version": "0.1410", + "version": "0.1411", "description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence", "type": "module", "main": "dist/index.js", diff --git a/src/web/public/app.js b/src/web/public/app.js index c606df9a..c60787cb 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -2663,9 +2663,11 @@ class ClaudemanApp { document.getElementById('ralphTaskDescription').value = ''; document.getElementById('ralphCompletionPhrase').value = 'COMPLETE'; this.selectIterationPreset(10); - // Reset auto-start checkbox (off by default) + // Reset auto-start checkboxes (off by default) - there are two, one in step 2 and one in step 3 const autoStartEl = document.getElementById('ralphAutoStart'); + const autoStartStep2El = document.getElementById('ralphAutoStartStep2'); if (autoStartEl) autoStartEl.checked = false; + if (autoStartStep2El) autoStartStep2El.checked = false; // Populate case selector this.populateRalphCaseSelector(); @@ -2767,6 +2769,137 @@ class ClaudemanApp { } } + // Check for existing ralph-wizard research files + async checkExistingWizardFiles() { + const caseName = this.ralphWizardConfig.caseName; + if (!caseName) return; + + try { + const res = await fetch(`/api/cases/${encodeURIComponent(caseName)}/ralph-wizard/files`); + const data = await res.json(); + + if (data.success && data.data?.files?.length > 0) { + this.ralphWizardConfig.existingWizardFiles = data.data.files; + this.updateExistingWizardFilesUI(); + } else { + this.ralphWizardConfig.existingWizardFiles = null; + this.updateExistingWizardFilesUI(); + } + } catch (err) { + console.error('Failed to check for existing wizard files:', err); + this.ralphWizardConfig.existingWizardFiles = null; + } + } + + // Update UI to show existing wizard files option + updateExistingWizardFilesUI() { + const files = this.ralphWizardConfig.existingWizardFiles; + let section = document.getElementById('existingWizardFilesSection'); + + if (!files || files.length === 0) { + section?.remove(); + return; + } + + // Count agents with results + const agentsWithResults = files.filter(f => f.resultFile).length; + + if (!section) { + // Create the section if it doesn't exist - insert before loading state + const loadingState = document.getElementById('planGenerationLoading'); + section = document.createElement('div'); + section.id = 'existingWizardFilesSection'; + section.className = 'existing-wizard-files-section'; + loadingState?.parentNode?.insertBefore(section, loadingState); + } + + section.innerHTML = ` +
+
+ 📁 + Previous Research Found +
+

+ Found ${agentsWithResults} agent result${agentsWithResults !== 1 ? 's' : ''} from a previous plan generation. +

+
+ ${files.filter(f => f.resultFile).map(f => ` + ${this.getAgentTypeLabel(f.agentType)} + `).join('')} +
+
+ + +
+
+ `; + } + + getAgentTypeLabel(agentType) { + const labels = { + research: 'Research', + requirements: 'Requirements', + architecture: 'Architecture', + testing: 'Testing', + risks: 'Risks', + verification: 'Verification', + execution: 'Execution', + 'final-review': 'Review', + }; + return labels[agentType] || agentType; + } + + async reuseExistingWizardFiles() { + // Load the final result if it exists + const caseName = this.ralphWizardConfig.caseName; + try { + const res = await fetch(`/api/cases/${encodeURIComponent(caseName)}/ralph-wizard/file/${encodeURIComponent('final-result.json')}`); + const data = await res.json(); + + if (data.success && data.data?.parsed?.items) { + // Use the existing plan items + this.ralphWizardConfig.generatedPlan = data.data.parsed.items.map((item, idx) => ({ + content: item.content || item.title || `Task ${idx + 1}`, + priority: item.priority || 'P1', + enabled: true, + id: item.id || `reused-${Date.now()}-${idx}`, + source: item.source, + rationale: item.rationale, + tddPhase: item.tddPhase, + })); + this.ralphWizardConfig.planGenerated = true; + this.ralphWizardConfig.reusingExistingFiles = true; + this.ralphWizardConfig.planCost = 0; + + // Hide the existing files section + document.getElementById('existingWizardFilesSection')?.remove(); + + // Show the plan editor + this.renderPlanEditor(); + this.updateDetailLevelButtons(); + } else { + // No final result, just skip to generate with existing research + this.ralphWizardConfig.reusingExistingFiles = true; + this.generatePlan(); + } + } catch (err) { + console.error('Failed to load existing results:', err); + // Fall back to regenerating + this.generatePlan(); + } + } + + regenerateAllWizardFiles() { + // Clear the reuse flag and hide the section + this.ralphWizardConfig.reusingExistingFiles = false; + document.getElementById('existingWizardFilesSection')?.remove(); + this.generatePlan(); + } + // Called when case selector changes onRalphCaseChange() { const caseName = document.getElementById('ralphCaseSelect')?.value; @@ -2774,6 +2907,7 @@ class ClaudemanApp { this.ralphWizardConfig.caseName = caseName; this.ralphWizardConfig.existingPlan = null; this.ralphWizardConfig.useExistingPlan = false; + this.ralphWizardConfig.existingWizardFiles = null; this.checkExistingFixPlan(); } } @@ -2852,6 +2986,19 @@ class ClaudemanApp { this.updateDetailLevelButtons(); } + // Sync auto-start checkboxes between step 2 and step 3 + syncAutoStartCheckbox(sourceEl) { + const step2El = document.getElementById('ralphAutoStartStep2'); + const step3El = document.getElementById('ralphAutoStart'); + const isChecked = sourceEl.checked; + + if (step2El) step2El.checked = isChecked; + if (step3El) step3El.checked = isChecked; + + // Update config + this.ralphWizardConfig.autoStart = isChecked; + } + // Stop any ongoing plan generation (abort fetch, clear timers, hide spinner) stopPlanGeneration() { // Abort ongoing fetch @@ -2903,13 +3050,17 @@ class ClaudemanApp { this.ralphWizardStep = 2; this.updateRalphWizardUI(); - // If there's an existing plan, show the option to use it - // Otherwise auto-start plan generation - if (this.ralphWizardConfig.existingPlan) { - this.updateExistingPlanUI(); - } else { - this.generatePlan(); - } + // Check for existing wizard files first, then existing plan + this.checkExistingWizardFiles().then(() => { + // If there's an existing plan (@fix_plan.md), show the option to use it + if (this.ralphWizardConfig.existingPlan) { + this.updateExistingPlanUI(); + } else if (!this.ralphWizardConfig.existingWizardFiles?.length) { + // No existing files, auto-start plan generation + this.generatePlan(); + } + // If existingWizardFiles exists, the UI will show and wait for user choice + }); } else if (this.ralphWizardStep === 2) { // Must have generated or skipped plan if (!this.ralphWizardConfig.planGenerated && !this.ralphWizardConfig.skipPlanGeneration) { @@ -4732,7 +4883,10 @@ class ClaudemanApp { // Read advanced options (respawn disabled by default for Ralph Loops) config.enableRespawn = document.getElementById('ralphEnableRespawn')?.checked ?? false; - config.autoStart = document.getElementById('ralphAutoStart')?.checked ?? false; + // Check either auto-start checkbox (step 2 or step 3) + config.autoStart = document.getElementById('ralphAutoStart')?.checked || + document.getElementById('ralphAutoStartStep2')?.checked || + this.ralphWizardConfig.autoStart || false; // Close wizard this.closeRalphWizard(); diff --git a/src/web/public/index.html b/src/web/public/index.html index 479b63dc..11ba7faa 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -1030,6 +1030,13 @@ + +
+ +
diff --git a/src/web/public/styles.css b/src/web/public/styles.css index ba24d6db..0f63f818 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -5925,6 +5925,92 @@ kbd { justify-content: center; } +.plan-autostart-toggle { + margin-top: 1.25rem; + padding-top: 1rem; + border-top: 1px solid var(--border); +} + +.plan-autostart-label { + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + justify-content: center; +} + +.plan-autostart-label input[type="checkbox"] { + width: 18px; + height: 18px; + accent-color: var(--accent); + cursor: pointer; +} + +.plan-autostart-text { + font-size: 0.85rem; + color: var(--text); +} + +.plan-autostart-label:hover .plan-autostart-text { + color: var(--accent); +} + +/* Existing wizard files section */ +.existing-wizard-files-section { + padding: 1rem; +} + +.existing-wizard-card { + background: var(--bg-dark); + border: 1px solid var(--accent); + border-radius: 8px; + padding: 1rem; +} + +.existing-wizard-header { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.5rem; +} + +.existing-wizard-icon { + font-size: 1.2rem; +} + +.existing-wizard-title { + font-weight: 600; + color: var(--text); +} + +.existing-wizard-desc { + font-size: 0.85rem; + color: var(--text-dim); + margin: 0 0 0.75rem 0; +} + +.existing-wizard-agents { + display: flex; + flex-wrap: wrap; + gap: 0.35rem; + margin-bottom: 1rem; +} + +.existing-wizard-agent { + background: rgba(96, 165, 250, 0.2); + color: var(--accent); + padding: 0.2rem 0.5rem; + border-radius: 4px; + font-size: 0.75rem; + font-weight: 500; +} + +.existing-wizard-actions { + display: flex; + gap: 0.5rem; + justify-content: center; +} + .plan-cancel-btn { color: var(--red); }