| Age | Commit message (Collapse) | Author |
|
On tab click, store the tab name under 'activeMainTab' in localStorage.
On DOMContentLoaded, restore the previously active tab instead of
always defaulting to 'queue'.
Exported getActiveMainTab/setActiveMainTab for testability, following
the same pattern as getTaskFilterTab/setTaskFilterTab.
Tests: web/test/tab-persistence.test.mjs (6 tests, all green).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
When the VAPID key changes (e.g. after the key-swap fix), the browser's
cached PushSubscription was created with the old key. Calling
PushManager.subscribe() with a different applicationServerKey then throws
"The provided applicationServerKey is not valid".
Fix by calling getSubscription()/unsubscribe() before subscribe() so any
stale subscription is cleared. Adds web test covering both the stale and
fresh subscription paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
The DB may contain keys generated before the swap fix, with the private
key stored as the public key. Add ValidateVAPIDPublicKey() and use it in
serve.go to detect and regenerate invalid stored keys on startup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
webpush.GenerateVAPIDKeys() returns (privateKey, publicKey) but the
claudomator wrapper declared (publicKey, privateKey), causing the
32-byte private key to be sent to browsers as the applicationServerKey.
Browsers require a 65-byte uncompressed P256 point, so they rejected
it with "The provided applicationServerKey is not valid."
Adds a regression test that asserts public key is 87 chars/65 bytes
with 0x04 prefix and private key is 43 chars/32 bytes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
navigator.serviceWorker.register() returns before the SW is active.
Use navigator.serviceWorker.ready which resolves only once a SW is
controlling the page, so pushManager.subscribe() always has an active SW.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
The app is served at /claudomator/ so the SW and scope must use
BASE_PATH + '/api/push/sw.js' and BASE_PATH + '/' respectively.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Deployment badge now returns null (hidden) when includes_fix is false instead of showing "Not deployed" noise
- Badge also suppressed when fix_commits is empty (no tracked commits to check)
- Notification button label trimmed to just the bell emoji
- Preamble: warn agents not to use absolute paths in git commands (sandbox bypass)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
- POST /api/tasks now reads and stores the project field from request body
- GET /api/tasks/{id} returns project in response (via Task struct json tags)
- list command: adds PROJECT column to tabwriter output
- status command: prints Project line when non-empty
- Tests: TestProject_RoundTrip (API), TestListTasks_ShowsProject, TestStatusCmd_ShowsProject (CLI)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Show task.project as a badge in task card meta row and as a field
in the task detail overview grid. Both display conditionally only
when project is non-empty.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Apache fronts the Go service and only proxies /api/ paths; /sw.js hits
Apache's filesystem and 404s. Serve the service worker from
/api/push/sw.js with Service-Worker-Allowed: / so the browser allows
it to control the full origin scope. Update SW registration URL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
The service runs as www-data which cannot write to the root-owned
config file. VAPID keys are now stored in the settings table in
SQLite (which is writable), loaded on startup, and generated once.
Removes saveVAPIDToConfig and the stale warning on every restart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Web Push:
- WebPushNotifier with VAPID auth; urgency mapped to event type
(BLOCKED=urgent, FAILED=high, COMPLETED=low)
- Auto-generates VAPID keys on first serve, persists to config file
- push_subscriptions table in SQLite (upsert by endpoint)
- GET /api/push/vapid-key, POST/DELETE /api/push/subscribe endpoints
- Service worker (sw.js) handles push events and notification clicks
- Notification bell button in web UI; subscribes on click
File Drop:
- GET /api/drops, GET /api/drops/{filename}, POST /api/drops
- Persistent ~/.claudomator/drops/ directory
- CLAUDOMATOR_DROP_DIR env var passed to agent subprocesses
- Drops tab (📁) in web UI with file listing and download links
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Adds project TEXT column to tasks table via additive migration, updates
CreateTask INSERT, all SELECT queries, and scanTask to persist and
retrieve Task.Project.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Add deployment_status field to task list/get API responses for READY
tasks. The field includes deployed_commit, fix_commits, and includes_fix
so the UI can show whether the deployed server includes each fix.
- internal/api/task_view.go: taskView struct + enrichTask() helper
- handleListTasks/handleGetTask: return enriched taskView responses
- web/app.js: export renderDeploymentBadge(); add badge to READY cards
- web/test/deployment-badge.test.mjs: 8 tests for renderDeploymentBadge
- web/style.css: .deployment-badge--deployed / --pending styles
- server_test.go: 3 new tests (red→green) for enriched task responses
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Move activePerAgent decrement/deletion out of execute() and
executeResume() defers and into the code paths immediately before each
resultCh send (handleRunResult and early-return paths). This guarantees
that when a result consumer reads from the channel the map is already
clean, eliminating a race between defer and result receipt.
Remove the polling loop from TestPool_ActivePerAgent_DeletesZeroEntries
and check the map state immediately after reading the result instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
cp without -r fails on directories. Use find -maxdepth 1 -type f to
copy only files, since hooks/ is for local dev only.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
The deferred activePerAgent cleanup in execute() runs after resultCh is
sent, so a consumer reading Results() could observe the map entry before
it was removed. Poll briefly (100ms max) instead of checking immediately.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Fix four pre-existing bugs exposed after resolving a build failure:
- sandboxCloneSource: accept any URL scheme for origin remote (was filtering out https://)
- setupSandbox callers: fix := shadow variable so sandboxDir is set on BlockedError
- parseGeminiStream: parse result lines to return execution errors and cost
- TestElaborateTask_InvalidJSONFromClaude: stub Gemini fallback so test is hermetic
Add verification infrastructure:
- scripts/verify: runs go build + go test -race, used by hooks and deploy
- scripts/hooks/pre-commit: blocks commits that don't compile
- scripts/hooks/pre-push: blocks pushes where tests fail
- scripts/install-hooks: symlinks version-controlled hooks into .git/hooks/
- scripts/deploy: runs scripts/verify before building the binary
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Adds POST /api/webhooks/github that receives check_run and workflow_run
events and creates a Claudomator task to investigate and fix the failure.
- Config: new webhook_secret and [[projects]] fields in config.toml
- HMAC-SHA256 validation when webhook_secret is configured
- Ignores non-failure events (success, skipped, etc.) with 204
- Matches repo name to configured project dirs (case-insensitive)
- Falls back to single project when no name match found
- 11 new tests covering all acceptance criteria
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Adds GET /api/tasks/{id}/deployment-status which checks whether the
currently-deployed server binary includes the fix commits from the
task's latest execution. Uses git merge-base --is-ancestor to compare
commit hashes against the running version.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- next-task script: exclude rejected tasks from fallback selection; only
pick PENDING tasks with no rejection comment and no prior executions,
or QUEUED tasks (e.g. BUDGET_EXCEEDED retries)
- web/app.js: prompt for optional rejection comment when rejecting a task,
passing it through to the API instead of always sending an empty string
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
elaboration fallback
|
|
- Add ElaborationInput field to Task struct (task.go)
- Add DB migration and update CREATE/SELECT/scan in storage/db.go
- Update handleCreateTask to accept elaboration_input from API
- Update renderSubtaskRollup in app.js to prefer elaboration_input over description
- Capture elaborate prompt in createTask() form submission
- Update subtask-placeholder tests to cover elaboration_input priority
- Fix missing io import in gemini.go
When a task card is waiting for subtasks, it now shows:
1. The raw user prompt from elaboration (if stored)
2. The task description truncated at word boundary (~120 chars)
3. The task name as fallback
4. 'Waiting for subtasks…' only when all fields are empty
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
When a BLOCKED/READY task has no subtasks yet, show the task description
(truncated to ~120 chars at a word boundary) instead of the generic
'Waiting for subtasks…' text. Falls back to task.name if no description,
and finally to the original generic text if neither is present.
- Add truncateToWordBoundary(text, maxLen=120) helper
- Update renderSubtaskRollup(task, footer) to use task object instead of taskId
- Update both READY and BLOCKED call sites
- Add web/test/subtask-placeholder.test.mjs with 11 tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- poll() now calls renderActiveTab(cache) on early-return so switching
tabs always renders immediately instead of leaving the panel blank
- renderRunningView unchanged check now requires running.length > 0,
fixing the empty-state message never appearing when no tasks run
- Extract renderActiveTab() to avoid duplicating the tab switch logic
- Throttle execution history fetch to once per 60s (was every poll)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
When the server restarts after all subtasks complete, the parent task
was left stuck in BLOCKED state because maybeUnblockParent only fires
during a live executor run. RecoverStaleBlocked() scans all BLOCKED
tasks on startup and re-evaluates them using the existing logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
updates
|
|
|
|
READY tasks now call renderSubtaskRollup identical to BLOCKED tasks
(without a question). The rollup appears above Accept/Reject buttons.
New test: web/test/ready-subtasks.test.mjs (10 assertions, all pass).
|
|
|
|
- Fix ephemeral sandbox deletion issue by passing $CLAUDOMATOR_PROJECT_DIR to agents and using it for subtask project_dir.
- Implement sandbox autocommit in teardown to prevent task failures from uncommitted work.
- Track git commits created during executions and persist them in the DB.
- Display git commits and changestats badges in the Web UI execution history.
- Add badge counts to Web UI tabs for Interrupted, Ready, and Running states.
- Improve scripts/next-task to handle QUEUED tasks and configurable DB path.
|
|
- Add computeTabBadgeCounts(tasks) exported pure function
- Add updateTabBadges(tasks) that updates badge spans in tab buttons
- Call updateTabBadges on every poll regardless of active tab
- Add .tab-count-badge spans to interrupted/ready/running tab buttons in HTML
- Add CSS for .tab-count-badge pill styling (hidden when count is zero)
- Add 11 tests in web/test/tab-badges.test.mjs covering all states
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Files changed: CLAUDE.md, internal/api/changestats.go,
internal/executor/executor.go, internal/executor/executor_test.go,
internal/task/changestats.go (new)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Move git diff stat parser to internal/task/changestats.go (shared)
- Add UpdateExecutionChangestats to executor.Store interface
- Extract changestats in Pool.handleRunResult after every execution
- Add three TDD tests: ExtractAndStore, NoChangestats, MalformedChangestats
- Update CLAUDE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Add parseChangestatFromOutput/File helpers in internal/api/changestats.go
to parse git diff --stat summary lines from execution stdout logs
- Wire parser in processResult: after each execution completes, scan the
stdout log for git diff stats and persist via UpdateExecutionChangestats
- Tests: TestGetTask_IncludesChangestats (verifies processResult wiring),
TestListExecutions_IncludesChangestats (verifies storage round-trip)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Add task.Changestats{FilesChanged, LinesAdded, LinesRemoved}
- Add changestats_json column to executions via additive migration
- Add Changestats field to storage.Execution struct
- Add UpdateExecutionChangestats(execID, *task.Changestats) method
- Update all SELECT/INSERT/scan paths for executions
- Test: TestExecution_StoreAndRetrieveChangestats (was red, now green)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
sandboxes
#1 - Diagnostics: tailFile() reads last 20 lines of subprocess stderr and
appends to error message when claude/gemini exits non-zero. Previously all
exit-1 failures were opaque; now the error_msg carries the actual subprocess
output.
#4 - Restart recovery: RecoverStaleRunning() now re-queues tasks after
marking them FAILED, so tasks killed by a server restart automatically
retry on the next boot rather than staying permanently FAILED.
#2 - Stale sandbox: If a resume execution's preserved SandboxDir no longer
exists (e.g. /tmp purge after reboot), clone a fresh sandbox instead of
failing immediately with "no such file or directory".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Sandbox setup runs git commands against project_dir which may be owned
by a different OS user, triggering git's 'dubious ownership' error.
Fix by passing -c safe.directory=* on all git commands that touch
project directories. Also add wildcard to global config for immediate
effect on the running server.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Add UpdateTaskAgent to Store interface and DB implementation
- Call UpdateTaskAgent in Pool.execute to persist assigned agent/model
to database before the runner starts
- Update runTask in app.js to pass selected agent as query param
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
- Added an agent selector (Auto, Claude, Gemini) to the Start Next Task button.
- Updated the backend to pass query parameters as environment variables to scripts.
- Modified the executor pool to skip classification when a specific agent is requested.
- Added --agent flag to claudomator start command.
- Updated tests to cover the new functionality.
|
|
When a task is BLOCKED due to spawned subtasks (no question), the card
footer now fetches and renders a list of subtask names with their state
emoji instead of showing the question/answer input UI. The Cancel button
remains in both cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Two fixes for BLOCKED task issues:
1. Allow BLOCKED → CANCELLED state transition so users can cancel tasks
stuck waiting for input. Adds Cancel button to BLOCKED task cards in
the UI alongside the question/answer controls.
2. Detect when agents write completion reports to $CLAUDOMATOR_QUESTION_FILE
instead of real questions. If the question JSON has no options and no "?"
in the text, treat it as a summary (stored on the execution) and fall
through to normal completion + sandbox teardown rather than blocking.
Also tightened the preamble to make the distinction explicit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
The summary+interactions feature was already fully implemented but
lacked storage-layer tests. Added tests covering round-trip persistence
of task summaries, accumulation of Q&A interactions, and error handling
for nonexistent tasks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
All, Stats, Settings)
- Replace Tasks/Active tabs with Queue (QUEUED+PENDING), Interrupted, Ready top-level tabs
- Add All tab (COMPLETED, TIMED_OUT, BUDGET_EXCEEDED within last 24h) and Settings placeholder
- Export filterQueueTasks, filterReadyTasks, filterAllDoneTasks from app.js
- Refactor poll() to dispatch to active tab's render function instead of always rendering all panels
- Add renderQueuePanel, renderInterruptedPanel, renderReadyPanel, renderAllPanel helpers
- Add tests in web/test/tab-filters.test.mjs covering all new filter functions (16 tests)
- All 165 JS tests and all Go tests pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|