- New GET /api/tasks/counts endpoint for sidebar totals (independent of board filters)
- New useTaskCounts() hook + BoardSidebar rewired
- New bulk endpoints: POST /api/tasks/bulk-update, bulk-archive-by-ids, /api/backlog/bulk-demote
- BulkActionsBar uses single API calls instead of N sequential requests
- Array size validation (max 100) on all bulk endpoints
- Parallel execution via Promise.allSettled() (~26x faster)
- Updated squad chat model field documentation (#106)
- Version bump to 2.1.4
Closes#104, #105
10/10/10/10 reviewed by TARS (gh-sonnet)
- Use importOriginal to spread actual module exports
- Provide default export required by vitest
- Mock mkdir, access, existsSync for CI runner compatibility
- Add 'Build shared' step to Lint & Type Check job in CI workflow
- Add explicit type annotations to ~50 parameters across server + CLI
- Fix docker-paths test to properly mock filesystem operations
- Verified: clean install → shared build → lint/typecheck/test/build all passing
- Mock fs.mkdir in docker-paths test (EACCES on Linux runners)
- Mock fs.existsSync with smart logic for pnpm-workspace.yaml detection
- Add explicit type annotations to all CLI commands (27 implicit any types)
- Verified: pnpm lint, typecheck, test (1252 tests), build all passing
- Update agent-registry tests for singleton pattern (29 tests)
- Rewrite notification tests for @mention-based API (22 tests)
- Fix auth middleware test fixtures (3 tests)
- Update schema default expectations (1 test)
- Fix docker-paths test to mock fs.mkdir properly
- All 1252 tests passing
Test categories fixed:
1. AgentRegistryService: Changed from constructor to getAgentRegistryService() singleton
2. NotificationService: Complete API rewrite for @mention system
3. Auth middleware: API key format now includes - and _ characters
4. Schema: Metrics period default changed from 24h to 7d
Part of task_20260208_9pK4PX
Resolves#100. Adds configurable trust proxy setting via TRUST_PROXY
environment variable. Supports numeric hop counts, subnet strings, and
named values (loopback, linklocal, uniquelocal). TRUST_PROXY=true is
intentionally blocked (unsafe for production — logs warning and falls
back to default). Disabled by default (no behavior change).
Includes documentation updates for nginx, Caddy, and Docker deployments.
- Add squad-post.sh for regular agent messages
- Add squad-event.sh for lifecycle events (spawned/completed/failed/status)
- Add model field to squad messages (types, server, UI, scripts)
- System events render as divider lines in squad chat panel
- Model attribution displays next to agent names in UI
- Full protocol documented in SQUAD-CHAT-PROTOCOL.md
- Updated CONTRIBUTING.md, README.md, and all SOPs
- Added VK_HOST/VK_PORT env vars to .env.example
4-check cross-model review: 10/10 (Code/GPT-5.1, Func/Grok, Perf/Grok, Sec/GPT-5.1)
Agents: R2-D2 (feature), TARS/CASE/Ava/K-2SO (reviews)
- Add autoSaveDelayMs to TaskBehaviorSettings (default: 500ms)
- Update useDebouncedSave hook to use config setting instead of hardcoded value
- Add UI control in Tasks settings tab (slider: 200-5000ms, step 100)
- Add validation schema (min: 200ms, max: 5000ms)
The default 500ms delay was too aggressive for comfortable text editing,
causing interruptions mid-sentence. This makes the delay user-configurable
to accommodate different typing speeds and preferences.
Co-authored-by: OpenClaw Agent <agent@openclaw.ai>
Add individual on/off toggles for each dashboard widget in
Settings > Board & Display. When 'Show Dashboard' is enabled,
a nested list of 12 widget toggles appears:
- Token Usage, Run Duration, Agent Comparison, Status Timeline
- Cost per Task, Agent Utilization, Wall Time, Session Metrics
- Activity Clock, Where Time Went, Hourly Activity, Trends Charts
All default to ON. Server-side Zod schema updated to accept
the new dashboardWidgets object. Shared types already had the
DashboardWidgetSettings interface from a prior commit.
Data fixes:
- Backfill agent='veritas' on 987 telemetry events (were 'unknown')
- Backfill run.tokens events for Feb 3-5 (46 events, estimated from durations)
- Reset stuck agent status to idle
Utilization:
- Switch from status-history (1 entry!) to telemetry-based computation
- Timezone-aware date bucketing via tz query param
- Current day uses elapsed time, not full 24h
Dashboard layout:
- Remove Success Rate chart (redundant with Session Metrics)
- Task Activity Per Day now full width
- Fix tooltip info icons (delayDuration=0, asChild, button wrapper)
- Default period changed from 3d to 7d (token data starts Jan 31)
- Add ?tz=<offset> to metrics endpoints (e.g. ?tz=-6 for CST, ?tz=9 for JST)
- Server defaults to system time when tz is omitted
- Client auto-sends browser timezone offset on utilization requests
- Shared helpers: toLocalDateStr(), getTodayStr(), getElapsedTodayMs()
- Date bucketing and 'today' detection respect the requested timezone
- Works for any timezone — not hardcoded to any region
Every API response now includes:
meta.timezone: 'UTC-06:00' (human-readable)
meta.utcOffset: -6 (numeric, for client-side math)
Uses system time — no config needed.
- 'Today' detection uses local time (getHours) not UTC (getUTCHours)
- Event timestamps converted to local dates for daily bucketing
- Fixes Feb 5 CST events being bucketed into Feb 6 UTC
- Server uses system timezone (America/Chicago = CST/CDT)
- Fix daily utilization: use elapsed time for current day (was 100% because
active time ÷ 0 hours elapsed = infinity, capped to 100%)
- Activity Clock + Hourly Activity: switch from broken activity.json (1 record)
to status-history endpoint (has actual agent state transitions)
- Task-cost API: add project + totalDurationMs fields for Where Time Went
- Where Time Went: pull real project data from task-cost telemetry
- Wall Time toggle: rewrite with clear labels + info tooltips
- Normalize Feb 3 telemetry outlier (66min → 19min)
GH #92 created: Dashboard widget toggles with descriptions
- Remove Success/Errors card (Sessions widget covers it)
- Activity Over Time: add Y-axis 'Events' label
- Where Time Went: pull real data from telemetry by project (was blank)
- Wall Time: rewrite as Total Agent Time + Avg Run Duration with tooltips
- Activity Clock: add info tooltip explaining the visualization
- Agent Comparison: lower minRuns to 1 so all agents show
- Task-cost API: add project + totalDurationMs fields for widgets
- Normalize Feb 3 time outlier (66min → 19min, capped at p95)
- TrendsCharts (Task Activity per Day): full width layout
- Replace non-existent getStorageBase with DATA_DIR inline constant
- Fix import ordering (path must be imported before DATA_DIR declaration)
- Fix req.params/req.query type casts for Express strict mode
- Add createNotification() to NotificationService for failure-alert backward compat
- Export NotificationService class for type imports
- Cast telemetry events properly in cost-prediction service
- Server builds clean and starts successfully
Inspired by @nateherk's Klouse branded PDF reports.
- 5 report templates: audit, summary, analysis, standup, custom
- Brand config: company name, logo, colors, font, tagline
- Markdown → HTML conversion with print-optimized CSS
- Template-specific styles (audit findings, metrics cards, status colors)
- HTML served directly or printable to PDF via browser
- Reports stored in docs/reports/ and accessible via docs tab
- REST API: generate, list, get, brand CRUD, templates, HTML serve
Inspired by @nateherk's Klouse scheduled deliverables view.
- Deliverables: daily/weekly/biweekly/monthly/custom schedules
- Run tracking: success/failed/skipped with output files and summaries
- Next run calculation, enable/disable toggle
- REST API: CRUD deliverables, record runs, run history
- Tags, agent assignment, output path configuration
- Persistent storage with 500-run history cap
Inspired by @nateherk's Klouse dashboard approach:
'Spin up agents to analyze what broke, why, and how to prevent it'
- Error Learning Service: submit errors, structured analysis, pattern detection
- Auto-tags, severity estimation, repeat detection
- Links analyses to task lessonsLearned field
- Similarity search for 'have we seen this before?'
- Aggregate stats: by type, severity, repeat rate, top prevention steps
- REST API: POST /submit, PATCH /:id, GET /, GET /stats, GET /search
- Cost Prediction Service: predicts task cost based on type, priority, complexity, history
- Prediction factors: type multiplier, priority multiplier, description complexity, project adjustment
- Historical base cost: calculated from telemetry data for similar tasks
- Confidence levels: low/medium/high based on sample size
- Accuracy tracking: predicted vs actual cost comparison for completed tasks
- Accuracy stats: MAE, mean/median accuracy, within-20%/50% metrics, per-type breakdown
- Task schema: added costPrediction and actualCost fields
- REST API: POST /predict, GET /accuracy, GET /accuracy/stats
- Agent Registry Service: registration, heartbeat, capability discovery, stale detection
- REST API: POST /register, POST /:id/heartbeat, DELETE /:id, GET /stats, GET /capabilities/:cap
- Persistent storage: .veritas-kanban/agent-registry.json
- Auto-offline: agents without heartbeat for 5min marked offline
- AGENTS.md template: docs/AGENTS-TEMPLATE.md with full integration guide
1. KanbanBoard now consumes pendingTaskId from ViewContext
- Clicking status history entry navigates to board AND opens task detail
- Fetches task from API if not in current filtered list
2. Status history now captures taskId/taskTitle from activeAgents
- When status changes via activeAgents (not activeTask), derive task info
- Falls back to first activeAgent's taskId/taskTitle
- Fixes missing titles in ~90% of status history entries
- Add comprehensive ANALYTICS.md documenting all endpoints
- Document data models, metrics, and usage examples
- Add TESTING_ANALYTICS.md with test scenarios
- Update swagger.ts with analytics schemas and endpoints
- Include performance benchmarks and troubleshooting guide
Add pre-transition gates that must pass before status change is allowed:
- require-agent: Task must have agent assigned
- require-plan: Description must contain Plan section
- require-verification-complete: All verification steps checked
- require-time-tracked: Time tracking must have entries
- require-closing-comment: Task must have at least one comment
- require-subtasks-complete: All subtasks completed
- require-blocker-reason: blockedReason must be set
Add post-transition actions that fire after status change:
- auto-start-timer: Start time tracking
- auto-stop-timer: Stop time tracking
- send-webhook: POST to URL
- send-notification: Send to channel
- prompt-lessons-learned: Flag for capture
- log-activity: Log to activity feed
API:
- GET/PUT/PATCH /api/settings/transition-hooks
- POST /api/settings/transition-hooks/validate
- CRUD for individual rules at /api/settings/transition-hooks/rules
Config stored in .veritas-kanban/transition-hooks.json
Also adds 'cancelled' status and 'critical' priority to shared types.
Ref: task_20260201_04iPHh
Extended path traversal protection to two services missed in initial audit:
- trace-service.ts: validate attemptId, taskId, traceId before path.join
- template-service.ts: validate templateId in templatePath()
Both now use validatePathSegment() + ensureWithinBase() from utils/sanitize.ts.
Ref: RF-002a Batch 3a Findings (High+Medium severity)
Bug 1: /api/metrics/all was passing the period filter to task counts,
showing only tasks touched within the time window (e.g., 33 todo in 24h)
instead of current board state (124 todo total).
Fix: computeAllMetrics now passes null to computeTaskMetrics so task
status counts always reflect current state. Period filter still applies
to telemetry metrics (runs, tokens, duration).
Bug 2: /api/backlog/count was double-wrapping response (route wrapped
with success/data, then middleware wrapped again).
Fix: Route now returns { count } and lets responseEnvelopeMiddleware
handle wrapping.
Bug: taskToFilename() generates filename from current title, but the
actual file on disk may have a different slug if the title changed after
creation. This caused INTERNAL_ERROR on archive/delete/restore.
Fix: Added findTaskFile() helper that searches by task ID prefix instead
of computing the expected filename. Applied to archiveTask, deleteTask,
and restoreTask.
Also: archiveSprint now throws ValidationError instead of generic Error
for better API error responses.