Commit graph

548 commits

Author SHA1 Message Date
1d8ebf259b Skjermklipp-input: paste screenshot i chat → CAS → media-node (oppgave 29.1)
Frontend:
- ChatInput: paste-handler detekterer bilder fra clipboard (ClipboardEvent),
  laster opp til CAS via uploadMedia med metadata_extra { source: "screenshot" }
- Chat-side: viser bildenoder inline med AI-beskrivelse når tilgjengelig
- api.ts: uploadMedia støtter nå metadata_extra for ekstra node-metadata

Backend (maskinrommet):
- upload_media: nytt metadata_extra multipart-felt som merges inn i
  media-nodens metadata (f.eks. source, description)
- describe_image: ny jobbtype — enqueuues automatisk for screenshot-uploads,
  kaller synops-ai med --image for AI-beskrivelse av bildet
- Beskrivelsen lagres tilbake i media-nodens metadata.description

synops-ai:
- Nytt --image flag for multimodal LLM-kall (vision) via LiteLLM
- Sender bilde som base64 data-URL i OpenAI-kompatibelt format
- Brukes av describe_image-jobben for bildbeskrivelse
2026-03-18 21:07:00 +00:00
09ed49d7d7 Starter oppgave 29.1 2026-03-18 20:55:34 +00:00
d3ecb5b279 synops-health: sjekk status for alle tjenester i stacken (oppgave 28.7)
CLI-verktøy som sjekker PG, Caddy, Maskinrommet, LiteLLM, Whisper,
LiveKit og Authentik parallelt. Output: JSON med status per tjeneste
+ samlet helsetilstand (healthy/degraded). Exit-kode 0 = alt oppe.

Gjenbruker samme mønster som maskinrommet/src/health.rs men som
frittstående verktøy — kan brukes av admin-dashboard, overvåking,
og direkte fra CLI.
2026-03-18 20:54:27 +00:00
8f12b08c25 Starter oppgave 28.7 2026-03-18 20:50:26 +00:00
f1e6355037 synops-backup: PG-dump + CAS-filiste + metadata-snapshot (oppgave 28.6)
Nytt Rust CLI-verktøy som erstatter scripts/backup-pg.sh:
- pg_dump -Fc via docker exec (konsistent snapshot)
- CAS-manifest: liste over alle filer med hash og størrelse
- Metadata-snapshot (JSON) med tidsstempel, modus, statistikk
- --full / --incremental / --payload-json for jobbkø
- Rotasjon av gamle dumper (30 dager, kun ved --full)

Output: strukturert JSON med backup-sti og detaljer.
2026-03-18 20:45:02 +00:00
0f7fdb75e0 Starter oppgave 28.6 2026-03-18 20:40:25 +00:00
053990d222 synops-validate: sjekk at en node matcher forventet skjema for sin node_kind (oppgave 28.5)
Nytt CLI-verktøy som henter en node fra PG og validerer:
- Basisfelter: visibility, created_by, metadata-type, kjent node_kind
- node_kind-spesifikk metadata: collection (traits), ai_preset,
  orchestration, media, communication
- Relasjonelle sjekker: person→auth_identities, agent→agent_identities

Samler alle avvik (feiler ikke på første treff). Output i markdown
eller JSON (--format). Exit-koder: 0=OK, 1=avvik, 2=feil.

Valideringsreglene speiler maskinrommet/src/intentions.rs slik at
skrivestien og valideringsverktøyet håndhever samme skjema.
2026-03-18 20:37:23 +00:00
fa7b8f500d Starter oppgave 28.5 2026-03-18 20:30:25 +00:00
bdb4a697f5 synops-notify: send varsel via epost, WebSocket-push, eller begge (oppgave 28.4)
Nytt CLI-verktøy som sender varsler til brukere via to kanaler:
- Email: Slår opp epost fra auth_identities, kaller synops-mail
- WebSocket: Oppretter notification-node i PG med node_access for mottaker,
  PG NOTIFY-trigger leverer via portvokteren til brukerens WS-tilkobling

Støtter --channel email|ws|both (default: ws) og --payload-json for jobbkø-dispatch.
Validerer at mottaker er person/agent. JSON-output til stdout.
2026-03-18 20:27:04 +00:00
e0afec848b Starter oppgave 28.4 2026-03-18 20:20:27 +00:00
2fa5d7ef2f AI-kostnadstak per bruker/samling: budsjettsjekk før AI-kall (oppgave 28.3)
Samlings- og brukernoder kan nå ha ai_budget i metadata:
  { "ai_budget": { "monthly_limit_usd": 50.0 } }

Før hvert AI-kall aggregeres inneværende måneds forbruk fra
ai_usage_log og sammenlignes med grensen. Ved overskridelse:
- AI-kallet blokkeres med feilmelding
- En work_item-node opprettes med tag "budget_exceeded"
- Work_item knyttes til samlingen via belongs_to-edge

Endringer:
- migrations/029: requested_by-kolonne i ai_usage_log + indekser
- synops-ai: --collection-id/--user-id flagg, budsjettsjekk i prompt
- maskinrommet/ai_budget.rs: delt budsjettsjekk-modul
- maskinrommet/ai_process.rs: budsjettsjekk før AI gateway-kall
- docs/infra/ai_gateway.md: oppdatert § 6.3 fra "fase 2" til implementert
2026-03-18 20:19:52 +00:00
c0f05ab5e9 Starter oppgave 28.3 2026-03-18 20:10:30 +00:00
a06b79478a AI-rutingskontroll i admin: 13 kontekster konfigurerbare uten redeploy (oppgave 28.2)
Utvider /admin/ai med full kontroll over hvilken modellalias som brukes
per AI-kontekst. Admin kan bytte modell for orkestrering, bot-chat,
oppsummering, edge-forslag, klassifisering osv. uten å restarte
maskinrommet.

Endringer:
- Migration 028: seeder 7 nye kontekster i ai_job_routing
  (orchestration_script/dream, bot_chat/triage, summarize, suggest_edges, classify)
- Backend: resolve_routing_or_default() i ai_admin.rs — felles oppslag
  mot ai_job_routing med fallback til sidelinja/rutine
- Dispatchers (ai_edges, summarize) bruker nå routing-tabellen i stedet
  for hardkodede env-variabler — endringer trer i kraft umiddelbart
- Frontend: Ruting-tab omskrevet med kategoriserte kontekster
  (Orkestrering, Bot & chat, Analyse, Prosessering), beskrivelser per
  kontekst, og støtte for egendefinerte regler
- Docs: ai_gateway.md §3.4 oppdatert med alle 13 kontekster
2026-03-18 20:06:50 +00:00
1c59604b07 Starter oppgave 28.2 2026-03-18 19:55:35 +00:00
8436f75d87 synops-ai prompt: direkte LLM-kall via LiteLLM (oppgave 28.1)
Legger til `synops-ai prompt`-subkommando for enkel prompt-inn/tekst-ut
bruk av LLM via LiteLLM gateway. Eksisterende script-generering
flyttes til `synops-ai script`-subkommando.

Prompt-modus:
- --prompt (påkrevd): bruker-prompt
- --model (valgfri): modellalias, slås opp fra ai_job_routing hvis utelatt
- --system (valgfri): systemprompt
- --job-type: for modelloppslag og logging (default: simple_prompt)
- --temperature: LLM-temperatur (default: 0.7)
- Logger tokenbruk i ai_usage_log

Seed: simple_prompt → sidelinja/rutine i ai_job_routing.
2026-03-18 19:51:44 +00:00
b89f307fa2 Starter oppgave 28.1 2026-03-18 19:45:28 +00:00
8f7d2d7fe8 MindMap-trait for samlingsnoder (oppgave 27.3)
Gjør mindmap til et offisielt trait som kan velges ved opprettelse
av samlingsnoder. Frontend-komponenten (27.1) og BlockShell-panelet
(27.2) var allerede på plass — dette kobler traiten inn i backend-
validering og pakke-definisjoner.

Endringer:
- Lagt til "mindmap" i VALID_TRAITS (intentions.rs)
- Validering av konfig: default_depth 1-3, layout radial/tree
- Inkludert mindmap i Podcaststudio- og Wiki-pakker (traits.ts)
- Oppdatert trait-katalog i docs/primitiver/traits.md
2026-03-18 19:44:30 +00:00
49d8599056 Starter oppgave 27.3 2026-03-18 19:40:27 +00:00
6c5cdf817d MindMap BlockShell-panel i arbeidsflaten (oppgave 27.2)
Legger til MindMap-støtte i workspace-siden slik at tankekartet
kan brukes som et fritt plassert BlockShell-panel med fullskjerm,
resize og drag-handle — på linje med alle andre trait-paneler.

Samlingssiden hadde allerede full MindMap-integrasjon fra 27.1.
Workspace-siden manglet import, knownTraits-oppføring og
rendering i både mobil- og desktop-modus.
2026-03-18 19:38:49 +00:00
1144933ac0 Starter oppgave 27.2 2026-03-18 19:35:27 +00:00
e6b55543b5 MindMap Svelte-komponent med radial/tree-layout (oppgave 27.1)
Ny MindMapTrait-komponent som viser noder og edges fra WebSocket-stores
i radial eller hierarkisk tree-layout via d3-hierarchy.

- Bygger trestruktur fra rotnode med konfigurerbar dybde (1-3 hopp)
- Radial layout (trigonometrisk) og tree layout (hierarkisk) med toggle
- Pan/zoom via d3-zoom, auto-fit ved oppstart
- Klikk node = ny rot (med tilbake-historikk), dobbeltklikk = åpne
- Edge-type-filtrering og visuell stil (farge, stiplet linje)
- Privacy-markering på private noder
- Responsivt: forenklet toolbar på mobil
- Registrert som 'mindmap' trait i katalog og workspace-typer
- Koblet inn i collection-side (desktop BlockShell + mobil tabs)
2026-03-18 19:32:17 +00:00
461c3bfb79 Starter oppgave 27.1 2026-03-18 19:26:14 +00:00
752548d01b Gjør fase 27-30 uavhengige av epost-fasen (26)
26.2 er blokkert av SMTP-credentials. Fase 27 (tankekart),
28 (CLI+AI-ruting), 29 (universell input) og 30 (podcast)
avhenger nå av fase 25, ikke 26. Task-runneren kan fortsette.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 19:25:56 +00:00
b096434ff6 synops-mail CLI + msmtp-oppsett (oppgave 26.2, venter SMTP-credentials)
Implementerer synops-mail --send --to <epost> --subject <emne> CLI-verktøy
for utgående epost via msmtp. Alt er ferdig og testet strukturelt:

- tools/synops-mail: Rust CLI som bygger RFC 5322-melding og sender via msmtp
- /srv/synops/config/msmtp/msmtprc: msmtp-konfig mot Hetzner-relay (587/STARTTLS)
- Installert til /usr/local/bin/synops-mail

Blokkert av: mangler SMTP-relay brukernavn/passord. Hetzner-relay
(mail.your-server.de) krever autentisering, port 25 er blokkert utgående.
Trenger credentials i msmtprc for å fullføre.
2026-03-18 19:12:14 +00:00
abf8b526c3 Starter oppgave 26.2 2026-03-18 19:05:24 +00:00
25fc1a1b59 Username i auth_identities: Authentik-synk ved login (oppgave 26.1)
Legger til username-kolonne i auth_identities med UNIQUE constraint.
Ved innlogging sender SvelteKit preferred_username fra Authentik til
maskinrommet POST /auth/sync, som oppdaterer kolonnen. Grunnlaget
for epost-ruting i fase 26: vegard@synops.no → username-oppslag.
2026-03-18 19:04:57 +00:00
6b81569581 Starter oppgave 26.1 2026-03-18 19:00:29 +00:00
8af4265b6e synops-clip orkestrering-støtte: cli_tool-registrering + clip_url jobb/API (oppgave 25.4)
Gjør synops-clip tilgjengelig i orkestreringer ved å:

1. Registrere synops-clip som cli_tool-node (migration 026) med norske
   aliases (clip, klipp, hent artikkel) og args_hints for script-kompilatoren.
   Orkestreringer kan nå skrive "1. clip fra event (lagre node, bruker)"
   som kompileres til "synops-clip --url {event.url} --write --created-by ...".

2. Legge til clip_url som jobbtype i jobbkøen (clip.rs) — spawner
   synops-clip med riktige env-variabler (DATABASE_URL, AI_GATEWAY_URL, etc).

3. Legge til POST /intentions/clip_url API-endepunkt slik at frontend
   og andre klienter kan trigge URL-klipping direkte.

4. Utvide trigger-konteksten med event.url og event.created_by slik at
   orkestreringer som reagerer på URL-deling kan videresende URL til
   synops-clip via variabel-substitusjon.
2026-03-18 18:55:11 +00:00
8f02dbabc4 Starter oppgave 25.4 2026-03-18 18:45:27 +00:00
f22465d72b @bot URL-klipping i chat: synops-clip-integrasjon (oppgave 25.3)
Når en bruker limer inn en URL i chatten, gjenkjenner synops-respond
URL-en automatisk, kaller synops-clip --write for å hente, parse og
oppsummere artikkelen, og inkluderer resultatet i prompten slik at
Claude kan presentere oppsummeringen naturlig.

Ved betalingsmur: Claude informerer brukeren og ber om innlimt innhold.
Maks 3 URL-er per melding, 60s timeout per klipp.

Endringer:
- synops-respond: URL-deteksjon (regex), synops-clip-kall, prompt-kontekst
- maskinrommet/agent.rs: videresend env-variabler for synops-clip
- maskinrommet-env.sh: SYNOPS_CLIP_SCRIPTS env-variabel
- docs/infra/claude_agent.md: dokumentert URL-klipping-flyten
2026-03-18 18:41:33 +00:00
16ee209283 Starter oppgave 25.3 2026-03-18 18:35:25 +00:00
c0fecf2f4e synops-clip --write: node-opprettelse med AI-oppsummering (oppgave 25.2)
Legger til --write-modus som oppretter:
- content-node med artikkelinnhold og metadata.source_url
- tagged-edge "clipped" (self-tag)
- AI-oppsummering via LiteLLM (integrert i node-innhold)
- mentions-edges til gjenkjente entiteter i kunnskapsgrafen

AI-analysen er robust: feiler den, opprettes noden uten oppsummering.
Gjenbruker eksisterende topic-noder der navnene matcher (case-insensitive).
Nye entiteter opprettes som topic-noder med entity_type i metadata.
Ressursforbruk logges til resource_usage_log.

Nye CLI-flagg: --write, --created-by <uuid>
Payload-JSON utvides med write + created_by for jobbkø-integrasjon.
2026-03-18 18:33:07 +00:00
0ebe3b0421 Starter oppgave 25.2 2026-03-18 18:25:35 +00:00
5dead5dac9 synops-clip: CLI for web article extraction (oppgave 25.1)
Nytt verktøy som henter og parser webartikler til ren tekst + metadata.
Bruker Mozilla Readability (via Node.js) for artikkelekstraksjon, med
Playwright som fallback for JS-rendrede sider.

Arkitektur:
- Rust CLI (clap, reqwest) håndterer HTTP-henting, paywall-deteksjon, JSON-output
- Node.js-hjelpeskript (readability.mjs) bruker @mozilla/readability + jsdom
- Playwright-script (playwright.mjs) for headless browser-fallback
- Støtter --payload-json for maskinrommet/jobbkø-integrasjon

Paywall-deteksjon basert på:
- Kort innhold (<200 tegn)
- Norske/engelske paywall-fraser i innholdet
- CSS-klasser/HTML-attributter (piano, schibsted, amedia, etc.)
- Schema.org isAccessibleForFree meta-tagg

Output: JSON med title, author, date, content, url, paywall, excerpt, source
2026-03-18 18:24:22 +00:00
b447c8272f Starter oppgave 25.1 2026-03-18 18:15:26 +00:00
1f21f90f76 Seed-orkestreringer og flerords-verbstøtte (oppgave 24.9)
Fem standard-orkestreringer opprettet som seed-data:
- Podcast-pipeline (transkriber → oppsummer → RSS)
- Publiseringsflyt (render → indeks → RSS)
- AI-beriking (foreslå koblinger ved nytt innhold)
- Planlagt publisering (render ved tidspunkt)
- Podcast TTS (kaskade fra pipeline → les opp oppsummering)

Podcast-pipeline → TTS demonstrerer kaskade via triggers-edge.

Script-kompilatoren utvidet med flerords-verbstøtte: aliaser som
"generer feed", "les opp", "foreslå koblinger" matcher nå korrekt
selv om parseren splitter ved første mellomrom. Prøver verb + N
første ord av objekt opptil 3 ord.
2026-03-18 18:11:02 +00:00
98654c4a84 Podcast: re-publisering flytter has_media-edge, gammel fil prunes etter grace period
Ved ny versjon av lydfil: flytt has_media-edge til ny fil,
derived_from-edge bevarer historikk, gammel fil mister aktive
edges og prunes etter 30 dager (konfigurerbart for RSS-cache).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 18:06:11 +00:00
88945b0d64 Starter oppgave 24.9 2026-03-18 18:00:33 +00:00
b94576cded Legg til fase 30: komplett podcast-hosting uten ekstern avhengighet
8 oppgaver: iTunes/Podcasting 2.0 RSS-tags, nedlastingsstatistikk
(IAB-kompatibel), embed-spiller, import fra eksisterende podcast
med prøveimport-flyt (importer → test → re-importer nye → 301),
og feed-redirect for å flytte bort.

Feature-spec: docs/features/podcast_hosting.md
Ingen castopod — podcasten er noder med riktige edges og en feed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 17:59:59 +00:00
44327df370 Kaskade: triggers-edge mellom orkestreringer (oppgave 24.8)
Etter vellykket pipeline-utførelse sjekker handle_orchestrate() om
orkestreringen har utgående triggers-edges til andre orchestration-noder.
Hvert gyldig mål enqueues som ny orchestrate-jobb med kaskade-kontekst.

Syklusdeteksjon via cascade_chain i jobb-payload:
- Sporer alle orchestration-IDer allerede utført i kjeden
- Blokkerer target som allerede finnes i kjeden (direkte + indirekte syklus)
- Dybdegrense på 10 ledd (MAX_CASCADE_DEPTH)
- Blokkerte kaskader logges i orchestration_log med status=skipped

Nedstrøms orkestreringer mottar:
- trigger_event: "cascade"
- upstream_orchestration_id i trigger_context
- {event.upstream_orchestration_id} tilgjengelig i script

Kaskade-feil er ikke-fatale — selve orkestreringen rapporteres som suksess.

8 nye enhetstester for syklusdeteksjon og dybdegrense.
2026-03-18 17:57:26 +00:00
d435f6ab33 Starter oppgave 24.8 2026-03-18 17:50:27 +00:00
a7e2bd6b60 Legg til fase 29: universell input — alle modaliteter blir noder
12 oppgaver: skjermklipp, RSS/feed-abonnement, webhook (universell
ekstern input med templates), video-opptak, geolokasjon, håndskrift/
tegning, kalender-import (ICS + CalDAV).

Feature-spec: docs/features/universell_input.md
Prinsipp: modaliteten er transport, noden er det som lever videre.
Alt fra screenshot til GitHub-webhook ender som noder i grafen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 17:48:40 +00:00
45916a6f1d Fullfør oppgave 24.7: oppdater tasks.md og tools/README.md
Markerer 24.7 som ferdig. Legger synops-ai i verktøy-tabellen.
2026-03-18 17:48:11 +00:00
d18dfc260f AI-assistert oppretting: synops-ai genererer orkestreringsscript fra fritekst (oppgave 24.7)
Nytt CLI-verktøy `synops-ai` som leser cli_tool-noder fra PG, bygger
en systemprompt med tilgjengelige verktøy og script-grammatikk, og
bruker LLM til å foreslå orkestreringsscript fra fritekst-beskrivelse.

Tre moduser:
- Synkron: --description "..." → LLM genererer script → JSON output
- System prompt: --generate-system-prompt → skriver auto-generert prompt
- Eventually: --eventually → lagrer som work_item for Claude Code

Maskinrommet: nytt endepunkt POST /intentions/ai_suggest_script som
kaller synops-ai, validerer resultatet med script_compiler, og returnerer
script + kompileringsresultat til frontend.

Frontend: AI-assistent-knapp i OrchestrationTrait med fritekst-input,
generer-knapp, og feilvisning. Generert script settes direkte i editoren.

Migration: synops-ai seeded som cli_tool-node med norske verb-alias.
2026-03-18 17:47:32 +00:00
91a73329a4 Starter oppgave 24.7 2026-03-18 17:35:28 +00:00
376bf7ee62 Orchestration UI: editor med tre visninger, sanntids kompilering, testkjøring (oppgave 24.6)
Backend:
- POST /intentions/compile_script — kompilerer script, returnerer diagnostikk + kompilert resultat
- POST /intentions/test_orchestration — trigger manuell testkjøring via jobbkø
- GET /query/orchestration_log — henter kjørehistorikk for en orkestrering
- "orchestration" lagt til som gyldig trait for samlingsnoder

Frontend:
- OrchestrationTrait.svelte — BlockShell-panel med:
  - Tre tabber: Enkel (editor), Teknisk (kompilert CLI), Kompilert (JSON)
  - Sanntids kompilering med 500ms debounce og diagnostikk-visning
  - Trigger-velger (6 event-typer) og executor-velger (script/bot/dream)
  - "Test kjøring"-knapp (lagrer + oppretter testjobb i køen)
  - Kjørehistorikk-panel med steg-status, varighet, feilmeldinger
  - Responsiv: container queries + mobile viewport fallback
- Registrert i collection-page (mobil + desktop), workspace/types.ts
- API-funksjoner: compileScript, testOrchestration, fetchOrchestrationLog
2026-03-18 17:30:52 +00:00
984f5e2f75 Starter oppgave 24.6 2026-03-18 17:20:26 +00:00
059c776bf4 Script-executor: vaktmesteren eksekverer kompilerte pipelines (oppgave 24.5)
Ny modul script_executor.rs som tar en kompilert pipeline fra
script_compiler og kjører stegene sekvensielt:

- Substituerer {event.*}-variabler fra trigger-kontekst
- Spawner hvert CLI-verktøy som subprosess via generisk dispatch
- VED_FEIL-håndtering: steg-fallback → global fallback → stopp
- Spesialhåndtering av work_item (oppretter oppgave-node i grafen)
- Logger hvert steg i ny orchestration_log-tabell

handle_orchestrate i jobs.rs utvides: kompilerer + utfører i
samme jobb (var tidligere kun kompilering).

Migration 023: orchestration_log-tabell med indekser for
effektiv spørring per orkestrering og per jobb.
2026-03-18 17:18:10 +00:00
e5ef7145ac Starter oppgave 24.5 2026-03-18 17:10:28 +00:00
47299435ab cli_tool alias-metadata: seed 14 verktøy med aliases og args_hints (oppgave 24.4)
Alle eksisterende CLI-verktøy har nå cli_tool-noder i PG med:
- aliases: norske verb for script-kompilatoren ("transkriber", "oppsummer", etc.)
- args_hints: mapping fra menneskelige argumenter til CLI-flagg
  ("stor modell" → "--model large", "lydfilen" → "--cas-hash {event.cas_hash}")

Muliggjør at script-kompilatoren (24.3) kan slå opp verktøy fra PG
og kompilere menneskelig scriptspråk til faktiske CLI-kall.
2026-03-18 17:09:53 +00:00