Commit Graph

303 Commits

Author SHA1 Message Date
root
bf79ab13bd feat(card): jobs / capture queue 2026-06-02 22:45:10 +10:00
root
e368ea41d8 feat(sacred-valley): drag-to-reorder with server-persisted layout
Adds HTML5 drag-to-reorder for .sv-card elements in Sacred Valley. The
pure moveId helper is unit-tested. Drop calls PUT /api/dashboard/layout
to persist the new card_order; DOM reflects the new order immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:39:57 +10:00
root
01177a2cbd feat(card): host-perf 2026-06-02 22:34:44 +10:00
root
3492b24dac feat(host): /api/host CPU/mem/disk/net from /proc
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:34:04 +10:00
root
03803f39f0 feat(card): weather 2026-06-02 22:32:22 +10:00
root
42a4b5ef33 feat(weather): /api/weather Open-Meteo proxy with 15-min cache
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:31:48 +10:00
root
eda61a19b2 feat(card): clock (Melbourne) 2026-06-02 22:30:24 +10:00
root
0a683c097d test: de-brittle /health version assertion (was pinned to stale alpha-6)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:29:57 +10:00
root
c3a3ac4feb feat(sacred-valley): card factory, registry ordering, view skeleton
Adds the Plan 6 card framework: svCard() chrome factory, pure orderCards()
ordering helper with unit tests, three stub card modules (clock/weather/host-perf),
and rewrites sacred_valley.js with the two-band layout that mounts ordered cards.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:26:09 +10:00
root
4b5faefa80 feat(sacred-valley): refined-B card chrome + theme tokens 2026-06-02 22:20:43 +10:00
root
5c6d2077c3 feat(dashboard): owner-only GET/PUT /api/dashboard/layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:19:37 +10:00
root
c67ac27545 feat(dashboard): dashboard_layout table + repo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:17:27 +10:00
root
629b42f502 docs: Plan 6 implementation plan (Sacred Valley widgets)
23 TDD tasks across 4 phases: grid framework + data cards, reuse cards,
speedtest, Little Blue health band. Verified against repo patterns (validate,
api.put, requireOwner, pg-boss, migrations).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:11:56 +10:00
root
34f5995810 docs: Plan 6 — cache service icons locally (no CDN slug leak)
Server-side icon cache (lib/health/icons.js + GET /api/icons/:slug.png) fetches
each icon once from dashboard-icons into a persistent dir and serves it from the
LAN. Browser never contacts the CDN; slug sanitized; first-letter fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:04:04 +10:00
root
f2f1ee4b10 docs: Plan 6 (Sacred Valley widgets) design spec
Two-band dashboard: draggable data cards (clock/weather/host-perf/speedtest/
jobs/inbox/search) + Little Blue read-only Health band (config registry +
pg-boss health engine + grouped service tiles w/ auto-icons). Refined-B chrome,
server-side layout persistence, polling refresh. Fix-it agent deferred.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:03:11 +10:00
root
28e66c6946 chore: version 2.0.0-alpha.7 — security hardening + Yerin security agent
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 00:24:34 +10:00
root
806e21cb13 docs: mark resolved items (auth hardening, crash-proofing, context allow-list, Yerin tools)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 00:17:53 +10:00
root
a3eb5a58f0 feat(security): seed Yerin agent + registry-selectable MCP server
- migration 011_yerin.sql: seed read-only 'yerin' agent ({read:true}, kind claude,
  model NULL = server default; switch to local Ollama via agents.model anytime)
- companion-stdio.js: select the toolset from VOID_TOOL_REGISTRY ('security' →
  Yerin's securityRegistry; default → Dross's companionRegistry)
- tests/mcp/registry_select.test.js

Remaining for Yerin (left for review): an entry point (route or cron) + persona
prompt — see docs/yerin-security-agent.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 00:17:53 +10:00
root
c45246b918 feat(security): grow Yerin's toolset (pending_review, resource_exposure, token_audit)
Three more read-only tools on securityRegistry:
- pending_review: agent-proposed changes awaiting approval (injection surface)
- resource_exposure: host/url/status attack-surface inventory (resources.listExposure,
  scalar cols only — no monitoring/metadata/credentials)
- token_audit: token label/last_used/revoked, never the hash

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 00:17:45 +10:00
root
aa9cf0917e fix(auth): O(1) selector+verifier token verification
verifyToken loaded every non-revoked token and bcrypt-compared each (O(n) per
request — auth-latency DoS + linear scaling). New token format
vk_<selector>.<verifier>: the non-secret selector is indexed and locates exactly
one row; only the verifier is bcrypt-hashed. Legacy NULL-selector tokens still
verify via a fallback scan. Dropped the useless idx_agent_tokens_hash.

- migration 010_token_selector.sql (adds selector col + unique partial index)
- createToken/verifyToken reworked; also adds listTokenMeta (read for Yerin's
  token_audit tool)
- tests/repos/token_selector.test.js

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 00:17:45 +10:00
root
10a8b813a5 fix: crash-proofing + small robustness fixes
- pool.js: add pool.on('error') handler — an idle-client error (DB restart /
  .215 failover) previously crashed the process (no 'error' listener → throw)
- context tool: project a SAFE_COLUMNS allow-list for resources (never the
  monitoring/metadata JSON blobs); also add 'resource' to TABLE (was unhandled)
- applyPendingChange: guard the 'upsert' arm so a non-upsertable entity_type
  fails with a clear ValidationError instead of a bare TypeError

Tests: pool_error, context (resource case), pending_extended_actions (guard).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 00:17:15 +10:00
root
afbf075d26 docs: security sweep, code review, Yerin design, Plan 6 brainstorm brief
- security-sweep-2026-06-01.md: fresh sweep of alpha.6 (1 fixed, findings + carry-overs)
- code-review-2026-06-01.md: optimisation/cleanliness notes (pool error handler,
  O(n) bcrypt token scan, FTS index alignment, dup auth parsing)
- yerin-security-agent.md: security-agent design + tool roadmap + Orthos role proposal
- plan-6-brainstorm-brief.md: Sacred Valley widget inventory + open design questions
- security-followups.md: marked the pending_changes CHECK finding RESOLVED

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 23:26:46 +10:00
root
6c393d8069 feat(security): Yerin security-agent toolset (read-only)
New securityRegistry (separate from companionRegistry) with two read-only,
secret-free tools for the Yerin security agent:
- audit_log: query the redacted audit trail by actor_kind/actor_id
- agent_inventory: list agents + capabilities/scopes (explicit projection,
  never SELECT *, no token material)

Follows the existing createRegistry() pattern. Design + wiring roadmap in
docs/yerin-security-agent.md. Not yet seeded/exposed over MCP (left for review).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 23:26:46 +10:00
root
459a7749c9 fix(auth): constant-time owner-token comparison
Owner bearer token was compared with === / !==, which short-circuits on the
first differing byte and leaks token length+prefix via response timing
(security-sweep-2026-06-01.md). New timingSafeStrEqual (crypto.timingSafeEqual
with a length pre-check so it never throws on length mismatch); wired into both
owner.js and agent_auth.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 23:26:46 +10:00
root
c591b2aed1 fix(pending): allow suggest-tier 'upsert' drafts; make dependency wiring owner-only
The pending_changes.action CHECK only permitted create/update/delete, so a
suggest-tier agent hitting POST /api/refs/upsert (or the resource dependency
routes) 500'd on the INSERT (docs/security-followups.md HIGH finding).

- migration 009: widen CHECK to include 'upsert'
- applyPendingChange: dispatch 'upsert' -> refsRepo.upsertByExternal on approve
- resources.js: add_dependency/remove_dependency are now owner-only (requireOwner),
  infra wiring is never diverted to pending_changes
- tests/api/pending_extended_actions.test.js: regression coverage

Full suite green (278 pass / 1 skip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 23:19:44 +10:00
root
8ce97bbacc feat(companion): Dross persona (Cradle) + migration 008 rename; remove dead API-key path
- system prompt = Dross (Ozriel's construct fragment, per Void 1.0), with tool guidance
- migration 008 renames the seeded agent 'companion' → display name 'Dross'
- removed lib/ai/anthropic.js + lib/ai/agent/runtime.js + tests + @anthropic-ai/sdk dep (companion now runs via the claude CLI; kept lib/ai/secret.js for the Vaultwarden roadmap)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:58:43 +10:00
root
d35e43a8ad polish(ui): friendly tool-chip labels (strip mcp__void__ prefix)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:50:27 +10:00
root
f8beff8702 fix(companion): accept view:null in turn schema (rail sends null when no active entity)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:49:08 +10:00
root
02efff83ce test: isolate tests on void_test DB (stop resetDb wiping prod void)
resetDb() DROPs schema; dev DATABASE_URL pointed at the shared prod void DB on
.215. setup.js now forces a dedicated void_test DB (TEST_DATABASE_URL or derived)
and throws if it would target prod. Created void_test + pg_hba rule on CT 310.
Verified: full suite green, prod void space count unchanged (2→2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:45:17 +10:00
root
3988425e67 chore: gitignore python build artifacts (untrack pycache/egg-info)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:23:06 +10:00
root
16497bd9db chore: version 2.0.0-alpha.6 — companion on Claude CLI subprocess (Max subscription)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:22:53 +10:00
root
1b8dc91800 fix(companion): emit draft from user-turn tool_result + stamp space_id on created entities
- driver: tool_results arrive as type:'user' content blocks (not bare); parse them
- route: tool_result content is a JSON string; parse it for pending_change_id → draft event
- propose_change: inject ctx.space_id into create payloads (model can't know the uuid; tables require it)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:21:15 +10:00
root
1e8bbca2a5 fix(claude-cli): --resume for continuing turns (reusing --session-id errored on turn 2)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:18:13 +10:00
root
c73be6681f fix(claude-cli): feed prompt via stdin (variadic --tools/--allowedTools ate the positional)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:15:14 +10:00
root
23616d24d6 fix(companion): absolute node path for MCP spawn + restrict to mcp tools
claude resolves the MCP server command against the child env (no PATH), so a
bare 'node' failed to spawn (status:failed). Use process.execPath. Also pass
--tools to drop claude's built-ins (Bash/Read/Write/…) — companion gets only
the four mcp__void__* tools.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:11:09 +10:00
root
c4b014c15e fix(companion): pass DATABASE_URL/OLLAMA_URL to MCP stdio child explicitly
Don't rely on env inheritance/cwd-dotenv for the claude-spawned MCP server.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:01:26 +10:00
root
51bc5912ff feat(api): companion route drives claude CLI + MCP tools (subscription auth)
Replaces the runTurn/callModel/Anthropic-API-key path in POST /turn with
runClaudeTurn (claude CLI) backed by a per-turn MCP config that spawns
companion-stdio.js. Extracts pending_change_id from tool_result events
defensively (structuredContent → text-JSON fallback). Rewrites companion
test to inject fake-claude-draft.js via app.locals.claudeExe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 21:57:05 +10:00
root
bc1b820cc8 feat(ai): claude CLI subprocess driver (subscription auth, stream-json)
Implements runClaudeTurn() — spawns the claude CLI for a single companion
turn using subscription/OAuth auth (strips ANTHROPIC_API_KEY +
ANTHROPIC_AUTH_TOKEN from child env), streaming normalised events (delta,
tool, tool_result, result, error) via onEvent callback.

Includes hermetic test + fake-claude.js fixture that mimics real 2.1.159
stream-json output; zero network/CLI calls in the test suite.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 21:51:55 +10:00
root
1c03d6c277 feat(mcp): stdio MCP server exposing the four companion tools
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 21:45:42 +10:00
root
c7a94f26d1 chore: version 2.0.0-alpha.5 + plan-5 completion doc
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 19:41:46 +10:00
root
15d45a8fd6 fix(ui): companion rail loads current space on initial page load
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 19:39:18 +10:00
root
f49282b00c feat(ui): right-rail companion chat — streaming, tool chips, inline drafts
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 19:34:27 +10:00
root
19a20ba083 feat(ui): authenticated POST->SSE reader
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 19:28:25 +10:00
root
df03286415 feat(api): companion SSE turn endpoint + per-Space history
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 19:14:44 +10:00
root
d593234904 feat(ai): agent runtime tool-use loop with event streaming
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:30:46 +10:00
root
09a27e8495 feat(ai): Anthropic client + streaming callModel adapter
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:24:59 +10:00
root
02e2a633f0 feat(ai): wire the four v1 companion tools into a shared registry
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:18:44 +10:00
root
7282729654 feat(ai): propose_change tool — drafts to pending_changes, never applies
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:16:53 +10:00
root
2e121ce6d4 feat(ai): context tool — resolve the active view entity
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:14:42 +10:00
root
d80c550d2e feat(ai): search + read grounding tools
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:12:03 +10:00