Commit Graph

37 Commits

Author SHA1 Message Date
root
f780043f2d feat(ui): 2.0.0-alpha.13 — finer per-card width scaling (12-col grid + -/+ stepper)
clock/weather etc. default to 1/6 width; sizes store an integer span 1-12
(legacy s/m/l still accepted by /api/dashboard/layout).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 18:23:37 +10:00
root
ce26895d8e feat: 2.0.0-alpha.11 — DB-backed service registry + LAN auto-discovery
- monitored_services table (mig 015) replaces config/services.json (now a boot seed)
- owner CRUD over /api/health/services; GET is DB-backed; cron+worker read the DB
- discover.lan worker: pure-Node TCP sweep + HTTP-title probe -> disabled 'discovered'
  candidates (never clobbers curated entries); POST /api/health/discover + GET .../discovered
- dashboard: Scan button + Discovered(N) section with one-click promote

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 07:55:08 +10:00
root
925cb0d7d6 chore: 2.0.0-alpha.9 — security & correctness hardening (Void 3.0 quick wins)
- Q3: prod void DB role NOSUPERUSER (vector marked trusted; deploy/README documents it)
- Q4: buildChildEnv allow-list for the claude subprocess (no OWNER_TOKEN/DATABASE_URL/secrets leak)
- Q5: pending-change approve claims-before-applying + reopens on failure (no re-approvable dup)
- Q6: /capture/upload validates space_id (UUID+existence); pg pool statement_timeout 30s
- Q9: disabled failing syncoid-donatello timer on Z

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 07:54:57 +10:00
root
b0d54a24cc feat(health): local icon cache /api/icons/:slug.png (no CDN leak)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:58:35 +10:00
root
60273a6204 feat(health): /api/health/services (grouped+counts) + owner /check
Adds GET /api/health/services returning registry services grouped by
category with merged cached status and per-group healthy counts, and
POST /api/health/check (owner-only) that enqueues a health.check
pg-boss job. Registers the health_check worker in the jobs index.
2026-06-02 22:56:50 +10:00
root
e36a87a50e feat(speedtest): worker + hourly cron + history/run routes
Adds speedtest pg-boss worker with injectable runner for testing, hourly
cron enqueue, and /api/speedtest/history (GET) + /run (POST, owner-only) routes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:50:19 +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
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
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
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
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
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
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
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
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
b10b68582d feat(api): capture routes YouTube/Vimeo URLs to ingest.video
POST /api/capture with a youtube.com / youtu.be / vimeo.com URL
enqueues ingest.video (Python worker) instead of ingest.url
(Node worker). Detection by URL hostname; idempotency_key + response
shape unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:08:16 +10:00
root
d7f9bde5e9 feat(api): karakeep webhook (HMAC-verified)
POST /api/ingest/karakeep accepts Karakeep webhook payloads. HMAC
signature on the raw body captured by express.json's verify hook.
Mounted on app before mountApi so it bypasses agentOrOwner — the
shared secret IS the auth.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 03:55:57 +10:00
root
afc20712cb feat(api): capture POST + upload + SSRF-safe URL fetch
safe_fetch.js validates URLs before fetch: rejects non-http(s), literal
or DNS-resolved loopback / RFC1918 / link-local / CGNAT / metadata
addresses; follows redirects manually with the same checks on each hop.
Test fixtures gate the check with VOID_INGEST_ALLOW_PRIVATE for offline
fixtures that hit 127.0.0.1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 03:42:54 +10:00
root
ec8517a82c feat(api): jobs routes (list/get/retry/delete, owner-only)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 03:29:52 +10:00
root
69e26ada98 feat(api): unified FTS search
Single GET /api/search?q=&space_id=&kinds=&limit=&offset= unions FTS
hits across pages / refs / source_docs / messages with a `kind`
discriminator and ts_rank ordering. Each branch's to_tsvector matches
the GIN index expression on its source table so indexes are used.
Messages have no space_id and are excluded when a space filter is set.
Hybrid vector / RRF lands in Plan 3.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 02:04:57 +10:00
root
ec96e4e2e3 feat(api): pending-changes + audit routes
Owner-only routes wired with an applyPendingChange dispatch helper
covering page/project/task/ref/resource/source_doc create/update/delete.
Approve and reject emit their own audit_log entries (actions already in
the CHECK vocab) so the audit trail is self-contained.

Documents a latent bug in security-followups.md: pending_changes.action
CHECK constraint blocks 'upsert' / 'add_dependency' / 'remove_dependency'
divertToPending paths in refs/resources routes when an agent at suggest
tier hits them.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 02:01:10 +10:00
root
5aa6fe772d feat(api): links routes
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 01:50:50 +10:00
root
2eb499c56f feat(api): tags routes
Add lib/api/routes/tags.js: list + upsert at /api/tags, and an
entity-scoped router mounted at /api/:entity_type/:entity_id/tags
for attach (idempotent), list, and detach. entity_type is bounded by
a zod enum covering space/project/task/page/ref/resource/source_doc/
conversation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 01:46:43 +10:00
root
74dac905d3 feat(api): conversations + messages routes
Add conversations CRUD-lite (list, create, get, PATCH status, PATCH
summary which flips status to summarized) and conversation-scoped
messages (append, list ordered by created_at).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 21:07:36 +10:00
root
5437b68316 feat(api): agents routes + token mgmt (owner-only)
Add lib/api/routes/agents.js: list/create/get, PATCH capabilities,
mint token (plaintext returned exactly once, then bcrypt-hashed),
revoke token. All endpoints gated by requireOwner so an agent token
can never bootstrap a new agent or grant itself capabilities.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 21:05:42 +10:00
root
56805053f0 feat(api): capability enforcement on writes
Add lib/api/cap.js: requireWrite(entity_type) maps HTTP method to
action, runs canAct, and tags req.capTier as allow|suggest|deny→403.
Mutating routes (pages, projects, tasks, refs, resources, source_docs)
now check req.capTier and either run the repo (allow) or divert to
pending_changes returning 202 (suggest). Owner and worker actors stay
on the allow path. requireOwner helper added for Task 11.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 21:03:52 +10:00
root
ba782ed690 feat(api): source-docs routes
Add lib/api/routes/source_docs.js: scoped POST under a resource,
get/patch/delete by id, and POST /:id/resync as a Plan 3 stub gated
by ENABLE_RESYNC (503 by default, 202 once workers ship). upstream_url
is required by the DB so the zod schema enforces it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:56:00 +10:00
root
a93e3ca20e feat(api): resources routes + dependencies + change history
Add lib/api/routes/resources.js: CRUD scoped to space; dependency
add/list/remove (cross-space attempts mapped to 409 conflict via the
composite FK); source-docs index per resource; change history via
audit.listForEntity.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:53:10 +10:00
root
78f2e09c74 feat(api): refs routes
Add lib/api/routes/refs.js: list with space_id/kind filters and
paginated, create, get/patch/delete by id, and /upsert that maps to
repo.upsertByExternal for idempotent capture-source ingest.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:50:38 +10:00
root
cf429da534 feat(api): pages routes + revisions + backlinks
Add lib/api/routes/pages.js: list by space, create/get/patch/delete,
get-by-slug, list revisions, and backlinks via entity_links.listTo
enriched with the source entity's title (whitelisted entity_type set
to keep the dynamic-table SELECT bounded).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:48:58 +10:00
root
50649bea5f feat(api): tasks routes
Add lib/api/routes/tasks.js: list by space (status filter), list by
project (position then created_at), create scoped to space with
optional project_id, get/patch/delete by id. status=done flips
completed_at via the repo's existing trigger logic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:46:39 +10:00
root
beb6da21c8 feat(api): projects routes
Add lib/api/routes/projects.js: list by space (with status filter),
create scoped to space, get/patch/delete by id. FK violation from
unknown space_id maps to 400 invalid_space.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 16:39:31 +10:00
root
ebb1e836ca feat(api): spaces routes
Add lib/api/routes/spaces.js: list, create, get-by-id, get-by-slug,
patch, delete. Mounted under /api/spaces. Server smoke restored.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 16:38:23 +10:00