Commit graph

199 commits

Author SHA1 Message Date
Brad Groux
a7877e57b5 v1.2.0: Foundation Hardening (#2, #6, #32)
- Standardize API response envelope and error format (#2)
  - Add UnauthorizedError, ForbiddenError, BadRequestError, InternalError classes
  - Add pagination support with sendPaginated() helper
  - Standardize all 11 route files to use error classes (zero ad-hoc patterns)
  - Standardize auth middleware error responses

- Abstract file storage behind repository interface (#6)
  - Extend storage interfaces: Activity, Template, StatusHistory, ManagedList, Telemetry
  - Implement file-based adapters in FileStorageProvider
  - Add fs-helpers.ts as centralized filesystem access layer
  - Remove direct fs imports from all 10 service/route files

- Complete blocked task status implementation (#32)
  - Fix MCP tools Zod/JSON schema definitions
  - Fix MCP active tasks filter
  - Fix CLI help text and status color formatting

Closes #2, closes #6, closes #32
2026-01-31 23:03:10 -06:00
Scout Murphy
4189af29cb feat: Add webhook notifications for Clawdbot Gateway integration
- Add webhookUrl to NotificationSettingsSchema
- Create clawdbot-webhook-service with fire-and-forget delivery + 1 retry
- Hook into broadcastTaskChange and broadcastChatMessage in broadcast-service
- Support VERITAS_WEBHOOK_URL and VERITAS_WEBHOOK_SECRET env vars
- HMAC-SHA256 payload signing via X-Webhook-Signature header
- Add 16 tests covering config, signing, delivery, retry, and payload formatting
- Update .env.example with new env var documentation
2026-01-31 21:30:02 -07:00
Brad Groux
f3e4ab2375 Merge pull request #26 from BradGroux/fix/timer-stop-cache-race-7
Fixes the timer stop race condition (Issue #7). Debounced field saves no longer overwrite timer state.
2026-01-31 07:28:55 -06:00
Brad Groux
d8dab5a612 chore: bump version to v1.1.0 + changelog 2026-01-31 07:09:18 -06:00
Brad Groux
cb3d3cdc04 fix: chat delete + export + input focus
- Fix delete not clearing UI (React Query kept stale data on 404 refetch)
- Fix post-delete send breaking (server recreates task sessions instead of 404)
- Add chat export as markdown (download icon next to trash)
- Auto-focus input on panel open and after each send
- Defensive delete on server (handle already-deleted sessions)
2026-01-31 07:06:00 -06:00
Brad Groux
89a5fd8b20 feat: wire up chat AI responses via Clawdbot gateway, fix UI bugs
- Chat now generates actual AI responses via Clawdbot gateway WebSocket
- Gateway chat client handles auth, streaming deltas, and final response
- Chat responses broadcast to UI via kanban WebSocket (shared connection)
- Fix double X close button on chat panel (SheetContent built-in + manual)
- Move Chat/Template buttons above tab row to reduce cramping
- Chat/Template buttons now 50/50 full width
- Fix subtask add button height mismatch
- Fix chat send crash (API response type mismatch)
- Remove non-functional agent/model dropdowns from chat panel
- Add model picker (sonnet/opus/haiku) to Agent panel in task detail
- Replace tooltip with inline mode hint text in chat
- Load chat history on panel open (deterministic task session ID)
- Chat stream uses shared WebSocket instead of opening duplicate connection
2026-01-31 06:44:42 -06:00
Brad Groux
e8e153d037 feat: chat interface backend — storage, API, WebSocket (#18) 2026-01-31 05:58:43 -06:00
Brad Groux
782f36c85b feat: agent selection on task creation (#17)
- Add agent field to CreateTaskForm state with 'auto' default
- Agent dropdown in CreateTaskDialog (Auto + all enabled agents)
- Agent field in TaskMetadataSection (task detail panel) — editable inline
- Pass agent through useTemplateForm to task creation API
- Server: accept agent field in create/update task schemas
- TaskService: persist agent field on task creation
- AgentPanel: pre-select task's assigned agent (priority: manual > pre-assigned > routed > default)
- Sprint and Agent dropdowns now share a row for compact layout
2026-01-31 05:53:33 -06:00
Brad Groux
fa7ac0fe1a feat: task-aware agent routing engine (#16)
- Add AgentRoutingConfig types with RoutingRule, RoutingMatchCriteria, RoutingResult
- Add DEFAULT_ROUTING_CONFIG with sensible defaults (code/bug/docs/review rules)
- Create AgentRoutingService with resolveAgent() and getFallback() methods
- First-match-wins rule evaluation with type, priority, project, minSubtasks criteria
- Array support for match criteria (e.g., type: ['code', 'bug'])
- Routing API: POST /agents/route, GET/PUT /agents/routing
- Integrate routing into ClawdbotAgentService.startAgent() for 'auto' agent selection
- Add agent field to Task, CreateTaskInput, UpdateTaskInput, TaskSummary schemas
- Settings UI: routing rules section in Agents tab with add/edit/remove/reorder
- Agent Panel: show routing recommendation when starting agent
- 17 unit tests for routing service (all passing)
- Full typecheck clean across shared, server, and web packages
2026-01-31 05:18:44 -06:00
Brad Groux
b13ecce67a fix: per-task timer exclusivity, not global
Multiple tasks can each have running timers simultaneously — this supports
multi-agent workflows where different agents track different tasks.

Removed:
- getRunningTimerTask() method (global scan)
- Auto-stop of other tasks' timers in startTimer()
- otherRunningTask UI check that hid the Start button

Kept: per-task guard (can't start a timer on a task that already has one running).
2026-01-31 04:49:58 -06:00
Brad Groux
6d63c94c51 refactor: rewrite TimeTrackingSection for reliable state updates
Root cause of all timer UI bugs: the component relied on React Query's
cache propagation chain (mutation → patchTaskInList → useTasks() hook →
re-render) which was unreliable due to structural sharing, concurrent
invalidations from debounced saves, and the multi-layer prop pipeline
(useDebouncedSave → localTask → TaskDetailsTab → TimeTrackingSection).

The fix: TimeTrackingSection now owns its own local state, initialized
from the task prop and updated DIRECTLY from API responses after each
mutation. This guarantees instant UI updates regardless of React Query's
internal state:

- Start timer → API response → setTimeTracking → UI shows Stop immediately
- Stop timer → API response → setTimeTracking → UI shows Start immediately
- Delete entry → API response → setTimeTracking → entry disappears immediately
- Add entry → API response → setTimeTracking → entry appears immediately

The query cache is still patched as a secondary update path (for other
components) and synced from for external changes (WebSocket events,
background refetches), but it's no longer the primary driver.

Also:
- Server timer methods now throw ConflictError (409) / NotFoundError (404)
  instead of generic Error (which mapped to 500)
- Delete buttons disabled while a mutation is in flight
- Removed useCallback (unnecessary for onClick handlers)
- JSON fingerprint for cache sync prevents unnecessary effect fires
2026-01-31 04:48:17 -06:00
Brad Groux
167f1b2acb fix: enforce global timer exclusivity — only one timer at a time
- Server: startTimer() auto-stops any running timer on another task before
  starting the new one. Prevents multiple simultaneous timers.
- Server: updateTask() re-reads from cache inside file lock to prevent
  concurrent writes (debounced saves) from clobbering timer state.
- Server: Added WebSocket broadcasts to all timer routes (start/stop/add/delete)
  so other clients get real-time updates.
- UI: TimeTrackingSection hides Start button when another task has an
  active timer, showing 'Timer active on another task' instead.
- UI: Subscribe directly to query cache for timer state instead of relying
  on the debounced-save prop pipeline.
- UI: Added mutatingRef guard to prevent double-clicks on Start/Stop.

Fixes the issue where 3 tasks could have running timers simultaneously.
2026-01-31 04:41:50 -06:00
Brad Groux
bb453ab6e9 fix: allow explicit IDs when creating managed list items
ManagedListService.create() now accepts an optional 'id' field.
If provided, it uses the explicit ID instead of generating slug-nanoid.
Also adds duplicate ID check to prevent conflicts.

This fixes the corrupted task-type IDs (e.g., 'bug-GdN5rT' instead of 'bug')
that were caused by always appending random suffixes.
2026-01-31 00:34:57 -06:00
Brad Groux
287ac80b3f fix: exempt localhost from auth rate limit (fixes #25) 2026-01-30 23:18:38 -06:00
Brad Groux
33a90bbc63 fix: use TaskService singleton in all routes to fix cache fragmentation
Root cause: Each route file created its own TaskService instance via
'new TaskService()', resulting in 13+ separate in-memory caches.
When task-archive.ts archived a task, it removed it from its own cache,
but tasks.ts (which serves GET /api/tasks) still had the task in its
separate cache — so archived tasks continued appearing in the list.

Fix: All route files now use getTaskService() singleton, ensuring a
single shared cache across all endpoints. Service files retain their
own instances for test isolation.

Fixes #22
2026-01-30 05:29:48 -06:00
Brad Groux
a2aa5053c6 feat: add seed data and first-run auto-seeding for clean public repo
- Remove tracked personal attachment screenshots from git
- Add tasks/attachments/ and tasks/archive-attachments/ to .gitignore
- Create 4 example tasks showcasing features (auth, bug, research, automation)
- Add seedIfEmpty() to TaskService for automatic first-run seeding
- Add pnpm seed script for manual seeding
- Update README quickstart with seed docs
- Fix version badge mismatch (1.1.0 → 1.0.0)
2026-01-29 15:45:38 -06:00
Brad Groux
f60b218c10 fix: add in-process FIFO queue to file-lock for deterministic ordering
File-based locking with wx flag doesn't guarantee ordering within the
same Node.js process — concurrent fs.writeFile calls race at the OS
level. Added a per-file Promise chain that serializes lock requests
in FIFO order within the same process. The file lock still provides
cross-process protection.

Fixes flaky withFileLock serialization test (was ~30% failure rate,
now 20/20 passes).
2026-01-29 07:43:54 -06:00
Brad Groux
8c892d7c22 fix: replace console.* with structured pino logger, fix ESLint errors in k6 load tests 2026-01-29 07:35:48 -06:00
Brad Groux
adc14a49e7 feat: agent CRUD — add, edit, remove agents from Settings UI 2026-01-29 07:19:54 -06:00
Brad Groux
0c0f5b344d security+quality: final codebase review fixes
Security (critical):
- Remove shell:true from preview-service spawn (command injection fix)
- Replace exec() with execFile() in github-service (no shell interpolation)
- Add SIGKILL fallback after SIGTERM timeout in worktree-service

Stability:
- Add process cleanup handlers (SIGTERM/SIGINT) for preview servers
- Add MAX_PREVIEW_SERVERS=5 limit to prevent resource exhaustion
- Memoize WebSocket context value to prevent unnecessary re-renders

Code quality:
- Remove hardcoded 'Brad' author → 'User' (3 files)
- Replace hardcoded localhost:3001 URLs with API_BASE (AttachmentsSection)
- Fix SECURITY-AUDIT.md date (2025 → 2026)
- Add license/repository/author to all 6 package.json files

Data hygiene:
- Untrack all runtime data files (.veritas-kanban/*.json, telemetry, activity)
- Simplify .gitignore: .veritas-kanban/* except .gitkeep
- Removed ~15,700 lines of runtime data from git history
2026-01-29 06:13:10 -06:00
Brad Groux
c95500507e docs: clean up docs folder, update test counts
- Removed 13 sprint files (internal dev history)
- Removed 4 dated audit files + settings-architecture.md (internal working docs)
- Kept: DEPLOYMENT.md, FEATURES.md, security.md
- Updated FEATURES.md: 61 test files, 1,143 tests (was 51 files)
- Updated CHANGELOG.md: corrected test counts for v1.0.0
2026-01-29 06:02:18 -06:00
Brad Groux
7ca26016e3 fix(server): increase agent status idle timeout from 5 to 15 minutes 2026-01-29 05:15:48 -06:00
Brad Groux
9aae5bc579 fix(web): use apiFetch in all hooks to unwrap API response envelope 2026-01-29 05:14:43 -06:00
Brad Groux
aa0c79e9ea test: add k6 load testing suite with 5 scenarios 2026-01-29 05:09:14 -06:00
Brad Groux
a005020bc5 feat(web): improve frontend accessibility to WCAG 2.1 AA 2026-01-29 05:06:26 -06:00
Brad Groux
99be1f6017 feat(server): add Prometheus-compatible metrics export endpoint 2026-01-29 05:05:18 -06:00
Brad Groux
46eff13fa3 feat(server): add circuit breaker pattern for external service calls 2026-01-29 05:01:15 -06:00
Brad Groux
d36ee28a5d feat(server): abstract file storage behind repository interface 2026-01-29 05:00:30 -06:00
Brad Groux
6bdb01f2bd feat(server): standardize API response envelope and error format 2026-01-29 04:57:27 -06:00
Brad Groux
eac0546485 feat(server): add Zod schema validation to all mutating API routes 2026-01-29 04:57:02 -06:00
Brad Groux
858263875d feat(server): add immutable audit log with hash chain for sensitive operations 2026-01-29 04:49:49 -06:00
Brad Groux
61c24462e1 chore: gitignore backup directory 2026-01-29 04:49:11 -06:00
Brad Groux
1ef983bfdf feat(server): add data integrity checks and automatic backup on startup 2026-01-29 04:48:51 -06:00
Brad Groux
f3cc8610a1 feat: add WebSocket heartbeat, reconnection, and connection limits 2026-01-29 04:44:00 -06:00
Brad Groux
6640c4986d feat(server): implement per-route rate limiting with tiered thresholds 2026-01-29 04:43:47 -06:00
Brad Groux
2eef45a5cd feat(web): add React error boundaries with graceful fallback UI 2026-01-29 04:39:30 -06:00
Brad Groux
28a7d9e395 feat(server): add file write locking to prevent race conditions 2026-01-29 04:37:24 -06:00
Brad Groux
16d52c25e5 feat(server): add request timeout middleware to prevent hung connections 2026-01-29 04:33:53 -06:00
Brad Groux
5cfd9d88c2 fix(security): audit dependencies and add automated vulnerability scanning 2026-01-29 04:32:23 -06:00
Brad Groux
a67a7f9393 feat(server): upgrade health endpoint with liveness, readiness, and deep checks 2026-01-29 04:29:33 -06:00
Brad Groux
d8169f6914 fix(ci): remove explicit pnpm version to resolve packageManager conflict 2026-01-29 04:15:06 -06:00
Brad Groux
991385fa18 security: gitignore security.json to prevent re-tracking 2026-01-29 02:46:31 -06:00
Brad Groux
40e6877b9b docs: README platform-agnostic reframe + Moltbot attribution 2026-01-29 02:46:23 -06:00
Brad Groux
3edffec98c chore: bump version to 1.0.0, add CHANGELOG
- Bump all 6 package.json files from 0.1.0 to 1.0.0
- Add CHANGELOG.md with full feature summary
- Git history scrubbed of security.json (JWT secret)
2026-01-29 01:42:04 -06:00
Brad Groux
8a6d870782 docs: deployment guide + README polish 2026-01-29 01:40:32 -06:00
Brad Groux
5f2b77b0c9 security: untrack security.json from git (contains JWT secret) 2026-01-29 01:36:43 -06:00
Brad Groux
1f52ab9dd2 docs: add open source governance files 2026-01-29 01:35:55 -06:00
Brad Groux
de388dc377 feat: complete test coverage sprint - backend 53.5% + E2E 19/19 passing
Backend tests (9 new files):
- summary-service, metrics-helpers, template-service
- status-history-service, trace-service, diff-service
- conflict-service, preview-service, digest-service
- Coverage: 44.27% → 53.52% (897 tests passing)

E2E tests (fixed + hardened):
- Removed debug spec left by sub-agent
- API seed calls now hit backend directly (port 3001)
  to avoid IPv6/Vite proxy issues on macOS
- task-status tests use unique names (prevent strict mode)
- Added waitForResponse for status change assertions
- Enabled webServer auto-start in playwright.config.ts
- All 19 E2E tests passing
2026-01-28 22:42:16 -06:00
Brad Groux
63e961f8d6 refactor: split god files into focused modules
- metrics-service.ts (1727 lines) → 9 files in server/src/services/metrics/
  - types.ts (270), helpers.ts (96), telemetry-reader.ts (99)
  - task-metrics.ts (232), run-metrics.ts (236), token-metrics.ts (225)
  - dashboard-metrics.ts (683), metrics-service.ts facade (108), index.ts (32)
- api.ts (1038 lines) → 9 files in web/src/lib/api/
  - helpers.ts (17), tasks.ts (166), config.ts (100), agent.ts (181)
  - diff.ts (181), entities.ts (245), time.ts (114)
  - managed-list.ts (64), index.ts (77)
- All imports updated, barrel exports maintain backwards compatibility
- TypeScript compiles cleanly for both server and web
- All 740 tests pass (42 test files)
2026-01-28 17:57:45 -06:00
Brad Groux
125430544a docs: add OpenAPI/Swagger API documentation 2026-01-28 17:51:04 -06:00