mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-04 06:29:42 +02:00
chore: bump version to 0.1434
This commit is contained in:
+164
-2
@@ -3482,6 +3482,10 @@ class ClaudemanApp {
|
||||
// Stop any existing generation first
|
||||
this.stopPlanGeneration();
|
||||
|
||||
// Close old plan subagent windows and clear their state
|
||||
// This ensures clicking on prompts shows fresh data, not cached from previous runs
|
||||
this.closePlanSubagentWindows();
|
||||
|
||||
// Reset stopped flag to allow new SSE events
|
||||
this.planGenerationStopped = false;
|
||||
|
||||
@@ -4795,23 +4799,181 @@ class ClaudemanApp {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get agent info from planSubagents Map
|
||||
const agentInfo = this.planSubagents.get(agentId);
|
||||
const isRunning = agentInfo?.status === 'running';
|
||||
const taskDescription = this.ralphWizardConfig?.taskDescription || 'No task description available';
|
||||
|
||||
try {
|
||||
const filePath = `${agentType}/prompt.md`;
|
||||
const res = await fetch(`/api/cases/${encodeURIComponent(caseName)}/ralph-wizard/file/${encodeURIComponent(filePath)}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success) {
|
||||
this.showPlanFileWindow(agentType, 'prompt.md', `Error: ${data.error}`, false);
|
||||
// File not found - show contextual message based on agent status
|
||||
if (isRunning) {
|
||||
const content = this.buildAgentRunningContent(agentType, agentInfo, taskDescription);
|
||||
this.showPlanFileWindow(agentType, 'prompt.md', content, false);
|
||||
} else {
|
||||
// Agent completed but no prompt file - might have failed
|
||||
const content = this.buildAgentNoPromptContent(agentType, taskDescription);
|
||||
this.showPlanFileWindow(agentType, 'prompt.md', content, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.showPlanFileWindow(agentType, 'prompt.md', data.data.content, false);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch prompt:', err);
|
||||
this.showPlanFileWindow(agentType, 'prompt.md', `Error fetching prompt: ${err.message}`, false);
|
||||
if (isRunning) {
|
||||
const content = this.buildAgentRunningContent(agentType, agentInfo, taskDescription);
|
||||
this.showPlanFileWindow(agentType, 'prompt.md', content, false);
|
||||
} else {
|
||||
this.showPlanFileWindow(agentType, 'prompt.md', `Error fetching prompt: ${err.message}`, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildAgentRunningContent(agentType, agentInfo, taskDescription) {
|
||||
const typeDescriptions = {
|
||||
research: {
|
||||
title: 'Research Agent',
|
||||
role: 'Gathering external resources, exploring the codebase, and identifying patterns',
|
||||
activities: [
|
||||
'Reading CLAUDE.md and project documentation',
|
||||
'Exploring the codebase structure with Glob and Grep',
|
||||
'Searching the web for relevant documentation and examples',
|
||||
'Identifying existing patterns and conventions',
|
||||
'Finding similar implementations to reference',
|
||||
],
|
||||
},
|
||||
requirements: {
|
||||
title: 'Requirements Analyst',
|
||||
role: 'Breaking down the task into concrete, actionable requirements',
|
||||
activities: [
|
||||
'Analyzing the task description for functional requirements',
|
||||
'Identifying non-functional requirements (performance, security)',
|
||||
'Detecting edge cases and error scenarios',
|
||||
'Defining acceptance criteria for each requirement',
|
||||
],
|
||||
},
|
||||
architecture: {
|
||||
title: 'Architecture Planner',
|
||||
role: 'Designing the technical approach and file structure',
|
||||
activities: [
|
||||
'Identifying files to create or modify',
|
||||
'Planning the module/component structure',
|
||||
'Defining interfaces and data flow',
|
||||
'Ensuring consistency with existing architecture',
|
||||
],
|
||||
},
|
||||
testing: {
|
||||
title: 'TDD Specialist',
|
||||
role: 'Planning the test-first development strategy',
|
||||
activities: [
|
||||
'Identifying test cases for each requirement',
|
||||
'Planning unit, integration, and E2E tests',
|
||||
'Defining test fixtures and mocks needed',
|
||||
'Ensuring edge cases have test coverage',
|
||||
],
|
||||
},
|
||||
risks: {
|
||||
title: 'Risk Analyst',
|
||||
role: 'Identifying potential issues and mitigation strategies',
|
||||
activities: [
|
||||
'Analyzing potential failure points',
|
||||
'Identifying security concerns',
|
||||
'Flagging performance bottlenecks',
|
||||
'Suggesting rollback strategies',
|
||||
],
|
||||
},
|
||||
verification: {
|
||||
title: 'Verification Expert',
|
||||
role: 'Validating plan completeness and quality',
|
||||
activities: [
|
||||
'Checking all requirements have implementation steps',
|
||||
'Verifying test coverage is adequate',
|
||||
'Ensuring dependencies are correctly ordered',
|
||||
'Scoring plan quality and completeness',
|
||||
],
|
||||
},
|
||||
'execution-optimizer': {
|
||||
title: 'Execution Optimizer',
|
||||
role: 'Optimizing the plan for Claude Code execution',
|
||||
activities: [
|
||||
'Identifying tasks that can run in parallel',
|
||||
'Grouping related tasks for efficiency',
|
||||
'Marking fresh context requirements',
|
||||
'Estimating token usage per task',
|
||||
],
|
||||
},
|
||||
'final-review': {
|
||||
title: 'Final Reviewer',
|
||||
role: 'Performing holistic validation of the complete plan',
|
||||
activities: [
|
||||
'Checking for gaps or missing steps',
|
||||
'Validating task ordering and dependencies',
|
||||
'Ensuring the plan is implementable',
|
||||
'Final quality assessment',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const info = typeDescriptions[agentType] || {
|
||||
title: agentType,
|
||||
role: 'Processing the task',
|
||||
activities: ['Working on the task...'],
|
||||
};
|
||||
|
||||
const elapsed = agentInfo?.startTime
|
||||
? Math.floor((Date.now() - agentInfo.startTime) / 1000)
|
||||
: 0;
|
||||
const model = agentInfo?.model || 'unknown';
|
||||
|
||||
let content = `# ${info.title} - Still Running\n\n`;
|
||||
content += `⏳ **Status:** Generating... (${elapsed}s elapsed)\n`;
|
||||
content += `🤖 **Model:** ${model}\n\n`;
|
||||
content += `---\n\n`;
|
||||
content += `## Role\n${info.role}\n\n`;
|
||||
content += `## Currently Working On\n`;
|
||||
info.activities.forEach(activity => {
|
||||
content += `- ${activity}\n`;
|
||||
});
|
||||
content += `\n---\n\n`;
|
||||
content += `## Task Being Analyzed\n\n`;
|
||||
content += `\`\`\`\n${taskDescription}\n\`\`\`\n\n`;
|
||||
content += `---\n\n`;
|
||||
content += `*The full prompt will be available once the agent completes.*\n`;
|
||||
content += `*Click again after completion to see the actual prompt that was used.*`;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
buildAgentNoPromptContent(agentType, taskDescription) {
|
||||
const typeLabels = {
|
||||
research: 'Research Agent',
|
||||
requirements: 'Requirements Analyst',
|
||||
architecture: 'Architecture Planner',
|
||||
testing: 'TDD Specialist',
|
||||
risks: 'Risk Analyst',
|
||||
verification: 'Verification Expert',
|
||||
'execution-optimizer': 'Execution Optimizer',
|
||||
'final-review': 'Final Reviewer',
|
||||
};
|
||||
|
||||
let content = `# ${typeLabels[agentType] || agentType} - No Prompt Available\n\n`;
|
||||
content += `The prompt file for this agent was not saved.\n\n`;
|
||||
content += `This can happen if:\n`;
|
||||
content += `- The agent failed before completing\n`;
|
||||
content += `- The plan generation was cancelled\n`;
|
||||
content += `- There was an error saving the output\n\n`;
|
||||
content += `---\n\n`;
|
||||
content += `## Task Description\n\n`;
|
||||
content += `\`\`\`\n${taskDescription}\n\`\`\``;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
async showPlanAgentFiles(agentId, agentType) {
|
||||
const caseName = this.ralphWizardConfig?.caseName;
|
||||
if (!caseName) {
|
||||
|
||||
+69
-84
@@ -426,15 +426,19 @@
|
||||
<div class="modal-tab-content" id="respawn-tab">
|
||||
<!-- Respawn Settings Section -->
|
||||
<div class="session-respawn-section" id="sessionRespawnSection">
|
||||
<div class="section-divider">
|
||||
<div class="respawn-header">
|
||||
<div class="session-respawn-status" id="sessionRespawnStatus">
|
||||
<span class="respawn-status-indicator"></span>
|
||||
<span class="respawn-status-text">Not active</span>
|
||||
</div>
|
||||
<div class="respawn-actions">
|
||||
<button class="btn-toolbar btn-success btn-sm" onclick="app.enableRespawnFromModal()" id="modalEnableRespawnBtn">Enable</button>
|
||||
<button class="btn-toolbar btn-danger btn-sm" onclick="app.stopRespawnFromModal()" id="modalStopRespawnBtn" style="display: none;">Stop</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Run Duration</label>
|
||||
<label>Duration</label>
|
||||
<div class="duration-presets">
|
||||
<button type="button" class="duration-preset-btn" data-minutes="30" onclick="app.selectDurationPreset('30')">30m</button>
|
||||
<button type="button" class="duration-preset-btn" data-minutes="60" onclick="app.selectDurationPreset('60')">1h</button>
|
||||
@@ -450,92 +454,81 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="form-hint">How long to run the respawn loop</span>
|
||||
</div>
|
||||
|
||||
<div class="form-section-header">Prompts</div>
|
||||
<div class="form-row">
|
||||
<label>Update Prompt</label>
|
||||
<input type="text" id="modalRespawnPrompt" value="update all the docs and CLAUDE.md" placeholder="Prompt to send when idle" onchange="app.autoSaveRespawnConfig()">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>After Update Prompt</label>
|
||||
<div class="checkbox-group-inline">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalRespawnSendClear" checked onchange="app.autoSaveRespawnConfig()">
|
||||
<span>Send /clear</span>
|
||||
</label>
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalRespawnSendInit" checked onchange="app.autoSaveRespawnConfig()">
|
||||
<span>Send /init</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Kickstart Prompt</label>
|
||||
<input type="text" id="modalRespawnKickstart" value="" placeholder="Optional: prompt if /init doesn't trigger work" onchange="app.autoSaveRespawnConfig()">
|
||||
<span class="form-hint">Sent only when /init completes but Claude stays idle</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Auto-Accept Plan Mode</label>
|
||||
<div class="checkbox-group-inline">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalRespawnAutoAccept" checked onchange="app.autoSaveRespawnConfig()">
|
||||
<span>Accept plan mode approvals</span>
|
||||
</label>
|
||||
</div>
|
||||
<span class="form-hint">Presses Enter to accept plan approvals and default question options when Claude is waiting</span>
|
||||
</div>
|
||||
|
||||
<div class="respawn-actions">
|
||||
<button class="btn-toolbar btn-success" onclick="app.enableRespawnFromModal()" id="modalEnableRespawnBtn">Enable Respawn</button>
|
||||
<button class="btn-toolbar btn-danger" onclick="app.stopRespawnFromModal()" id="modalStopRespawnBtn" style="display: none;">Stop Respawn</button>
|
||||
<div class="form-section-header">Behavior</div>
|
||||
<div class="respawn-options-row">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalRespawnSendClear" checked onchange="app.autoSaveRespawnConfig()">
|
||||
<span>Send /clear</span>
|
||||
</label>
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalRespawnSendInit" checked onchange="app.autoSaveRespawnConfig()">
|
||||
<span>Send /init</span>
|
||||
</label>
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalRespawnAutoAccept" checked onchange="app.autoSaveRespawnConfig()">
|
||||
<span>Auto-accept prompts</span>
|
||||
</label>
|
||||
</div>
|
||||
<span class="form-hint">Auto-accept presses Enter for plan approvals and default question options</span>
|
||||
</div>
|
||||
</div><!-- End respawn-tab -->
|
||||
|
||||
<!-- Context Management Tab Content -->
|
||||
<div class="modal-tab-content hidden" id="context-tab">
|
||||
<div class="form-row">
|
||||
<label>Auto-Compact Context</label>
|
||||
<div class="auto-clear-row">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalAutoCompactEnabled" onchange="app.autoSaveAutoCompact()">
|
||||
<span>Enable at</span>
|
||||
</label>
|
||||
<div class="input-suffix input-suffix-sm">
|
||||
<input type="number" id="modalAutoCompactThreshold" value="110000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoCompact()">
|
||||
<span>tokens</span>
|
||||
<div class="form-section-header">Token Management</div>
|
||||
<div class="context-settings-grid">
|
||||
<div class="context-setting">
|
||||
<div class="context-setting-header">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalAutoCompactEnabled" onchange="app.autoSaveAutoCompact()">
|
||||
<span>Auto-Compact</span>
|
||||
</label>
|
||||
<div class="input-suffix input-suffix-sm">
|
||||
<input type="number" id="modalAutoCompactThreshold" value="110000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoCompact()">
|
||||
<span>tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" id="modalAutoCompactPrompt" value="" placeholder="Focus prompt (optional)" onchange="app.autoSaveAutoCompact()">
|
||||
<span class="form-hint">Summarizes context while preserving key information</span>
|
||||
</div>
|
||||
<input type="text" id="modalAutoCompactPrompt" value="" placeholder="Optional: focus prompt for compact" class="mt-sm" onchange="app.autoSaveAutoCompact()">
|
||||
<span class="form-hint">Summarizes context while preserving key information</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Auto-Clear Context</label>
|
||||
<div class="auto-clear-row">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalAutoClearEnabled" onchange="app.autoSaveAutoClear()">
|
||||
<span>Enable at</span>
|
||||
</label>
|
||||
<div class="input-suffix input-suffix-sm">
|
||||
<input type="number" id="modalAutoClearThreshold" value="140000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoClear()">
|
||||
<span>tokens</span>
|
||||
<div class="context-setting">
|
||||
<div class="context-setting-header">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalAutoClearEnabled" onchange="app.autoSaveAutoClear()">
|
||||
<span>Auto-Clear</span>
|
||||
</label>
|
||||
<div class="input-suffix input-suffix-sm">
|
||||
<input type="number" id="modalAutoClearThreshold" value="140000" min="10000" max="500000" step="10000" onchange="app.autoSaveAutoClear()">
|
||||
<span>tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="form-hint">Full context reset at threshold (use higher than compact)</span>
|
||||
</div>
|
||||
<span class="form-hint">Completely resets context (use higher threshold than compact)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-section-header">File Watching</div>
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Image Watcher</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="modalImageWatcherEnabled" checked onchange="app.toggleSessionImageWatcher()">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Auto-popup new images (screenshots, etc.) in this session's directory</span>
|
||||
<span class="form-hint">Auto-popup new images (screenshots, generated files) in this session's directory</span>
|
||||
</div>
|
||||
</div><!-- End context-tab -->
|
||||
|
||||
@@ -547,34 +540,34 @@
|
||||
<input type="checkbox" id="modalRalphEnabled">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Enable Ralph / Todo tracker for this session (auto-detects loops and todos)</span>
|
||||
<span class="form-hint">Auto-detects loops and todos in Claude output</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Completion Phrase</label>
|
||||
<input type="text" id="modalRalphPhrase" placeholder="e.g., COMPLETE, DONE, FINISHED">
|
||||
<span class="form-hint">The phrase Claude outputs when the loop is complete (without <promise> tags)</span>
|
||||
<span class="form-hint">Phrase Claude outputs when loop is complete (without <promise> tags)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Max Iterations</label>
|
||||
<input type="number" id="modalRalphMaxIterations" value="0" min="0" max="1000">
|
||||
<span class="form-hint">Maximum respawn cycles (0 = unlimited)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Max Todos</label>
|
||||
<input type="number" id="modalRalphMaxTodos" value="50" min="1" max="500">
|
||||
<span class="form-hint">Maximum todos to track per session</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Todo Expiration</label>
|
||||
<div class="input-suffix input-suffix-sm">
|
||||
<input type="number" id="modalRalphTodoExpiration" value="60" min="1" max="1440">
|
||||
<span>min</span>
|
||||
<div class="form-section-header">Limits</div>
|
||||
<div class="ralph-limits-grid">
|
||||
<div class="form-col">
|
||||
<label>Max Iterations</label>
|
||||
<input type="number" id="modalRalphMaxIterations" value="0" min="0" max="1000">
|
||||
<span class="form-hint">0 = unlimited</span>
|
||||
</div>
|
||||
<div class="form-col">
|
||||
<label>Max Todos</label>
|
||||
<input type="number" id="modalRalphMaxTodos" value="50" min="1" max="500">
|
||||
<span class="form-hint">Per session</span>
|
||||
</div>
|
||||
<div class="form-col">
|
||||
<label>Todo Expiration</label>
|
||||
<div class="input-suffix input-suffix-sm">
|
||||
<input type="number" id="modalRalphTodoExpiration" value="60" min="1" max="1440">
|
||||
<span>min</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="form-hint">Minutes before todos auto-expire</span>
|
||||
</div>
|
||||
|
||||
<div class="ralph-config-actions">
|
||||
@@ -1153,14 +1146,6 @@
|
||||
<details class="advanced-options">
|
||||
<summary>Advanced Options</summary>
|
||||
<div class="advanced-options-content">
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Auto-Start After Plan</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="ralphAutoStart">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Automatically start the loop when plan generation completes</span>
|
||||
</div>
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Enable Respawn</label>
|
||||
<label class="switch">
|
||||
|
||||
+125
-4
@@ -1754,6 +1754,8 @@ body {
|
||||
|
||||
.btn-toolbar.btn-claude svg {
|
||||
flex-shrink: 0;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
/* Shell Button - Special styling */
|
||||
@@ -2492,6 +2494,21 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Fix CSS specificity: ID selector overrides class selector, so we need this explicit rule */
|
||||
#summary-tab.hidden,
|
||||
#respawn-tab.hidden,
|
||||
#context-tab.hidden,
|
||||
#ralph-tab.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Also hide child elements when parent tab is hidden (belt and suspenders) */
|
||||
#summary-tab.hidden .run-summary-filters,
|
||||
#summary-tab.hidden .run-summary-timeline,
|
||||
#summary-tab.hidden .run-summary-footer {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#summary-tab .run-summary-filters {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -2958,13 +2975,35 @@ body {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
/* Respawn header with status and actions */
|
||||
.respawn-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.respawn-header .respawn-actions {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Respawn options row - inline checkboxes */
|
||||
.respawn-options-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
/* Respawn actions in modal */
|
||||
.respawn-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.session-respawn-actions {
|
||||
@@ -3003,7 +3042,89 @@ body {
|
||||
}
|
||||
|
||||
.modal-tab-content.hidden {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Context Tab Settings Grid */
|
||||
.context-settings-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.context-setting {
|
||||
padding: 0.875rem;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.context-setting-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.625rem;
|
||||
}
|
||||
|
||||
.context-setting-header .checkbox-inline span {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.context-setting-header .input-suffix-sm {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.context-setting-header .input-suffix-sm input {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.context-setting input[type="text"] {
|
||||
width: 100%;
|
||||
padding: 0.375rem 0.5rem;
|
||||
background: var(--bg-input);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
color: var(--text);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.context-setting input[type="text"]:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.context-setting .form-hint {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
/* Ralph Limits Grid */
|
||||
.ralph-limits-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.ralph-limits-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.ralph-limits-grid .form-col input[type="number"] {
|
||||
width: 100%;
|
||||
padding: 0.375rem 0.5rem;
|
||||
background: var(--bg-input);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
color: var(--text);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.ralph-limits-grid .form-col .form-hint {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
/* Ralph Config Actions */
|
||||
|
||||
+19
-2
@@ -14,7 +14,7 @@ import Fastify, { FastifyInstance, FastifyReply } from 'fastify';
|
||||
import fastifyStatic from '@fastify/static';
|
||||
import path, { join, dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync } from 'node:fs';
|
||||
import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
||||
import fs from 'node:fs/promises';
|
||||
import { execSync } from 'node:child_process';
|
||||
import { homedir, totalmem, freemem, loadavg, cpus } from 'node:os';
|
||||
@@ -2518,6 +2518,17 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
|
||||
const resolvedBase = resolve(casesDir);
|
||||
if (resolvedCase.startsWith(resolvedBase) && existsSync(casePath)) {
|
||||
outputDir = join(casePath, 'ralph-wizard');
|
||||
|
||||
// Clear old ralph-wizard directory to ensure fresh prompts for each generation
|
||||
// This prevents stale prompts from previous runs being shown when clicking on agents
|
||||
if (existsSync(outputDir)) {
|
||||
try {
|
||||
rmSync(outputDir, { recursive: true, force: true });
|
||||
console.log(`[API] Cleared old ralph-wizard directory: ${outputDir}`);
|
||||
} catch (err) {
|
||||
console.warn(`[API] Failed to clear ralph-wizard directory:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2665,11 +2676,17 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
|
||||
});
|
||||
|
||||
// Read a specific ralph-wizard file
|
||||
this.app.get('/api/cases/:caseName/ralph-wizard/file/:filePath', async (req) => {
|
||||
// Cache disabled to ensure fresh prompts when starting new plan generations
|
||||
this.app.get('/api/cases/:caseName/ralph-wizard/file/:filePath', async (req, reply) => {
|
||||
const { caseName, filePath } = req.params as { caseName: string; filePath: string };
|
||||
const casesDir = join(homedir(), 'claudeman-cases');
|
||||
const casePath = join(casesDir, caseName);
|
||||
|
||||
// Prevent browser caching - prompts change between plan generations
|
||||
reply.header('Cache-Control', 'no-store, no-cache, must-revalidate');
|
||||
reply.header('Pragma', 'no-cache');
|
||||
reply.header('Expires', '0');
|
||||
|
||||
// Security: Path traversal protection for case name
|
||||
const resolvedCase = resolve(casePath);
|
||||
const resolvedBase = resolve(casesDir);
|
||||
|
||||
Reference in New Issue
Block a user