summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/app.js117
-rw-r--r--web/index.html27
2 files changed, 105 insertions, 39 deletions
diff --git a/web/app.js b/web/app.js
index 28d438a..e935ff0 100644
--- a/web/app.js
+++ b/web/app.js
@@ -496,7 +496,7 @@ async function updateTask(taskId, body) {
}
function createEditForm(task) {
- const c = task.claude || {};
+ const a = task.agent || {};
const form = document.createElement('div');
form.className = 'task-inline-edit';
@@ -517,10 +517,25 @@ function createEditForm(task) {
form.appendChild(makeField('Name', 'input', { type: 'text', name: 'name', value: task.name || '' }));
form.appendChild(makeField('Description', 'textarea', { name: 'description', rows: '2', value: task.description || '' }));
- form.appendChild(makeField('Instructions', 'textarea', { name: 'instructions', rows: '4', value: c.instructions || '' }));
- form.appendChild(makeField('Model', 'input', { type: 'text', name: 'model', value: c.model || 'sonnet' }));
- form.appendChild(makeField('Working Directory', 'input', { type: 'text', name: 'project_dir', value: c.project_dir || '', placeholder: '/path/to/repo' }));
- form.appendChild(makeField('Max Budget (USD)', 'input', { type: 'number', name: 'max_budget_usd', step: '0.01', value: c.max_budget_usd != null ? String(c.max_budget_usd) : '1.00' }));
+ form.appendChild(makeField('Instructions', 'textarea', { name: 'instructions', rows: '4', value: a.instructions || '' }));
+
+ const typeLabel = document.createElement('label');
+ typeLabel.textContent = 'Agent Type';
+ const typeSel = document.createElement('select');
+ typeSel.name = 'type';
+ for (const val of ['claude', 'gemini']) {
+ const opt = document.createElement('option');
+ opt.value = val;
+ opt.textContent = val.charAt(0).toUpperCase() + val.slice(1);
+ if (val === (a.type || 'claude')) opt.selected = true;
+ typeSel.appendChild(opt);
+ }
+ typeLabel.appendChild(typeSel);
+ form.appendChild(typeLabel);
+
+ form.appendChild(makeField('Model', 'input', { type: 'text', name: 'model', value: a.model || 'sonnet' }));
+ form.appendChild(makeField('Project Directory', 'input', { type: 'text', name: 'project_dir', value: a.project_dir || a.working_dir || '', placeholder: '/path/to/repo' }));
+ form.appendChild(makeField('Max Budget (USD)', 'input', { type: 'number', name: 'max_budget_usd', step: '0.01', value: a.max_budget_usd != null ? String(a.max_budget_usd) : '1.00' }));
form.appendChild(makeField('Timeout', 'input', { type: 'text', name: 'timeout', value: formatDurationForInput(task.timeout) || '15m', placeholder: '15m' }));
const prioLabel = document.createElement('label');
@@ -568,7 +583,8 @@ async function handleEditSave(taskId, form, saveBtn) {
const body = {
name: get('name'),
description: get('description'),
- claude: {
+ agent: {
+ type: get('type'),
model: get('model'),
instructions: get('instructions'),
project_dir: get('project_dir'),
@@ -1052,11 +1068,12 @@ function buildValidatePayload() {
const instructions = f.querySelector('[name="instructions"]').value;
const project_dir = f.querySelector('[name="project_dir"]').value;
const model = f.querySelector('[name="model"]').value;
+ const type = f.querySelector('[name="type"]').value;
const allowedToolsEl = f.querySelector('[name="allowed_tools"]');
const allowed_tools = allowedToolsEl
? allowedToolsEl.value.split(',').map(s => s.trim()).filter(Boolean)
: [];
- return { name, claude: { instructions, project_dir, model, allowed_tools } };
+ return { name, agent: { type, instructions, project_dir, model, allowed_tools } };
}
function renderValidationResult(result) {
@@ -1145,6 +1162,7 @@ function initProjectSelect() {
const select = document.getElementById('project-select');
const newRow = document.getElementById('new-project-row');
const newInput = document.getElementById('new-project-input');
+ if (!select) return;
select.addEventListener('change', () => {
if (select.value === '__new__') {
newRow.hidden = false;
@@ -1176,7 +1194,8 @@ async function createTask(formData) {
const body = {
name: formData.get('name'),
description: '',
- claude: {
+ agent: {
+ type: formData.get('type'),
model: formData.get('model'),
instructions: formData.get('instructions'),
project_dir: workingDir,
@@ -1220,7 +1239,8 @@ async function saveTemplate(formData) {
const body = {
name: formData.get('name'),
description: formData.get('description'),
- claude: {
+ agent: {
+ type: formData.get('type'),
model: formData.get('model'),
instructions: formData.get('instructions'),
project_dir: formData.get('project_dir'),
@@ -1395,31 +1415,32 @@ function renderTaskPanel(task, executions) {
overview.appendChild(overviewGrid);
content.appendChild(overview);
- // ── Claude Config ──
- const c = task.claude || {};
- const claudeSection = makeSection('Claude Config');
- const claudeGrid = document.createElement('div');
- claudeGrid.className = 'meta-grid';
- claudeGrid.append(
- makeMetaItem('Model', c.model),
- makeMetaItem('Max Budget', c.max_budget_usd != null ? `$${c.max_budget_usd.toFixed(2)}` : '—'),
- makeMetaItem('Project Dir', c.project_dir),
- makeMetaItem('Permission Mode', c.permission_mode || 'default'),
+ // ── Agent Config ──
+ const a = task.agent || {};
+ const agentSection = makeSection('Agent Config');
+ const agentGrid = document.createElement('div');
+ agentGrid.className = 'meta-grid';
+ agentGrid.append(
+ makeMetaItem('Type', a.type || 'claude'),
+ makeMetaItem('Model', a.model),
+ makeMetaItem('Max Budget', a.max_budget_usd != null ? `$${a.max_budget_usd.toFixed(2)}` : '—'),
+ makeMetaItem('Project Dir', a.project_dir || a.working_dir),
+ makeMetaItem('Permission Mode', a.permission_mode || 'default'),
);
- if (c.allowed_tools && c.allowed_tools.length > 0) {
- claudeGrid.append(makeMetaItem('Allowed Tools', c.allowed_tools.join(', '), { fullWidth: true }));
+ if (a.allowed_tools && a.allowed_tools.length > 0) {
+ agentGrid.append(makeMetaItem('Allowed Tools', a.allowed_tools.join(', '), { fullWidth: true }));
}
- if (c.disallowed_tools && c.disallowed_tools.length > 0) {
- claudeGrid.append(makeMetaItem('Disallowed Tools', c.disallowed_tools.join(', '), { fullWidth: true }));
+ if (a.disallowed_tools && a.disallowed_tools.length > 0) {
+ agentGrid.append(makeMetaItem('Disallowed Tools', a.disallowed_tools.join(', '), { fullWidth: true }));
}
- if (c.instructions) {
- claudeGrid.append(makeMetaItem('Instructions', c.instructions, { fullWidth: true, code: true }));
+ if (a.instructions) {
+ agentGrid.append(makeMetaItem('Instructions', a.instructions, { fullWidth: true, code: true }));
}
- if (c.system_prompt_append) {
- claudeGrid.append(makeMetaItem('System Prompt Append', c.system_prompt_append, { fullWidth: true, code: true }));
+ if (a.system_prompt_append) {
+ agentGrid.append(makeMetaItem('System Prompt Append', a.system_prompt_append, { fullWidth: true, code: true }));
}
- claudeSection.appendChild(claudeGrid);
- content.appendChild(claudeSection);
+ agentSection.appendChild(agentGrid);
+ content.appendChild(agentSection);
// ── Execution Settings ──
const settingsSection = makeSection('Execution Settings');
@@ -2071,23 +2092,51 @@ if (typeof document !== 'undefined') document.addEventListener('DOMContentLoaded
const f = document.getElementById('task-form');
if (result.name)
f.querySelector('[name="name"]').value = result.name;
+<<<<<<< HEAD
+ if (result.agent && result.agent.instructions)
+ f.querySelector('[name="instructions"]').value = result.agent.instructions;
+ if (result.agent && result.agent.working_dir) {
+ const pSel = document.getElementById('project-select');
+ const exists = [...pSel.options].some(o => o.value === result.agent.working_dir);
+||||||| cad057f
+ if (result.claude && result.claude.instructions)
+ f.querySelector('[name="instructions"]').value = result.claude.instructions;
+ if (result.claude && result.claude.working_dir) {
+ const sel = document.getElementById('project-select');
+ const exists = [...sel.options].some(o => o.value === result.claude.working_dir);
+=======
if (result.claude && result.claude.instructions)
f.querySelector('[name="instructions"]').value = result.claude.instructions;
if (result.claude && result.claude.project_dir) {
const sel = document.getElementById('project-select');
const exists = [...sel.options].some(o => o.value === result.claude.project_dir);
+>>>>>>> master
if (exists) {
+<<<<<<< HEAD
+ pSel.value = result.agent.working_dir;
+||||||| cad057f
+ sel.value = result.claude.working_dir;
+=======
sel.value = result.claude.project_dir;
+>>>>>>> master
} else {
- sel.value = '__new__';
+ pSel.value = '__new__';
document.getElementById('new-project-row').hidden = false;
+<<<<<<< HEAD
+ document.getElementById('new-project-input').value = result.agent.working_dir;
+||||||| cad057f
+ document.getElementById('new-project-input').value = result.claude.working_dir;
+=======
document.getElementById('new-project-input').value = result.claude.project_dir;
+>>>>>>> master
}
}
- if (result.claude && result.claude.model)
- f.querySelector('[name="model"]').value = result.claude.model;
- if (result.claude && result.claude.max_budget_usd != null)
- f.querySelector('[name="max_budget_usd"]').value = result.claude.max_budget_usd;
+ if (result.agent && result.agent.model)
+ f.querySelector('[name="model"]').value = result.agent.model;
+ if (result.agent && result.agent.type)
+ f.querySelector('[name="type"]').value = result.agent.type;
+ if (result.agent && result.agent.max_budget_usd != null)
+ f.querySelector('[name="max_budget_usd"]').value = result.agent.max_budget_usd;
if (result.timeout)
f.querySelector('[name="timeout"]').value = result.timeout;
if (result.priority) {
diff --git a/web/index.html b/web/index.html
index 842c272..a2800b0 100644
--- a/web/index.html
+++ b/web/index.html
@@ -52,23 +52,24 @@
<form id="task-form" method="dialog">
<h2>New Task</h2>
<div class="elaborate-section">
- <label>Describe what you want Claude to do
+ <label>Describe what you want the agent to do
<textarea id="elaborate-prompt" rows="3"
placeholder="e.g. run tests with race detector and check coverage"></textarea>
</label>
<button type="button" id="btn-elaborate" class="btn-secondary">
Draft with AI ✦
</button>
- <p class="elaborate-hint">Claude will fill in the form fields below. You can edit before submitting.</p>
+ <p class="elaborate-hint">AI will fill in the form fields below. You can edit before submitting.</p>
</div>
<hr class="form-divider">
<label>Project
<select name="project_dir" id="project-select">
<option value="/workspace/claudomator" selected>/workspace/claudomator</option>
+ <option value="__new__">Create new project…</option>
</select>
</label>
<div id="new-project-row" hidden>
- <label>New project path <input id="new-project-input" placeholder="/workspace/my-project"></label>
+ <label>New Project Path <input id="new-project-input" placeholder="/workspace/my-new-app"></label>
</div>
<label>Name <input name="name" required></label>
<label>Instructions <textarea name="instructions" rows="6" required></textarea></label>
@@ -78,7 +79,15 @@
</button>
<div id="validate-result" hidden></div>
</div>
- <label>Model <input name="model" value="sonnet"></label>
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
+ <label>Agent Type
+ <select name="type">
+ <option value="claude" selected>Claude</option>
+ <option value="gemini">Gemini</option>
+ </select>
+ </label>
+ <label>Model <input name="model" value="sonnet" placeholder="e.g. sonnet, gemini-2.0-flash"></label>
+ </div>
<label>Max Budget (USD) <input name="max_budget_usd" type="number" step="0.01" value="1.00"></label>
<label>Timeout <input name="timeout" value="15m"></label>
<label>Priority
@@ -100,7 +109,15 @@
<h2>New Template</h2>
<label>Name <input name="name" required></label>
<label>Description <textarea name="description" rows="2"></textarea></label>
- <label>Model <input name="model" value="sonnet"></label>
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
+ <label>Agent Type
+ <select name="type">
+ <option value="claude" selected>Claude</option>
+ <option value="gemini">Gemini</option>
+ </select>
+ </label>
+ <label>Model <input name="model" value="sonnet" placeholder="e.g. sonnet, gemini-2.0-flash"></label>
+ </div>
<label>Instructions <textarea name="instructions" rows="6" required></textarea></label>
<label>Project Directory <input name="project_dir" placeholder="/path/to/repo"></label>
<label>Max Budget (USD) <input name="max_budget_usd" type="number" step="0.01" value="1.00"></label>