diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 53e2f25..a442d28 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -21,9 +21,9 @@ "description": "Multi-agent workflow for analyzing, reporting, and optimizing Claude Code configuration across your entire machine" }, { - "name": "voyage", - "source": "./plugins/voyage", - "description": "Voyage — brief, research, plan, execute, review, continue. Contract-driven Claude Code pipeline with specialized agent swarms, external research triangulation, adversarial review, post-hoc independent review with Handover 6 feedback loop, multi-session resumption, session decomposition, and headless execution. /trekbrief, /trekplan, and /trekreview each end by building a self-contained operator-annotation HTML (scripts/annotate.mjs, modelled on claude-code-100x): pencil-toggle annotation mode, select text or click any element, pick intent (Fiks/Endre/Spørsmål), comment, Copy Prompt, paste back, Claude revises the .md." + "name": "ultraplan-local", + "source": "./plugins/ultraplan-local", + "description": "Four-command context-engineering pipeline (brief → research → plan → execute) with specialized agent swarms, external research triangulation, adversarial review, session decomposition, and headless execution" }, { "name": "linkedin-thought-leadership", @@ -49,16 +49,6 @@ "name": "okr", "source": "./plugins/okr", "description": "Expert OKR guidance for Norwegian public sector. Write, review, cascade, track and govern OKR based on Google/Doerr methodology adapted for 4-month tertial cycles." - }, - { - "name": "human-friendly-style", - "source": "./plugins/human-friendly-style", - "description": "Shared Claude Code output style for the ktg-plugin-marketplace. Plain-language tone — explains what and why, hides paths/JSON/stack traces by default, matches the user's language." - }, - { - "name": "claude-design", - "source": "./plugins/claude-design", - "description": "End-to-end facilitator for prompting Claude Design (claude.ai/design) — idea to copy-paste-ready prompt with iteration coaching, citing Anthropic primary sources." } ] } diff --git a/.mailmap b/.mailmap deleted file mode 100644 index b6a2a51..0000000 --- a/.mailmap +++ /dev/null @@ -1,4 +0,0 @@ -# Konsoliderer Git-identiteter for statistikk og shortlog. -# Se: https://git-scm.com/docs/gitmailmap - -Kjell Tore Guttormsen diff --git a/CLAUDE.md b/CLAUDE.md index af11fc2..bccb956 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,13 +10,13 @@ plugins/ config-audit/ v3.1.0 — Configuration intelligence (health, opportunities, auto-fix, whats-active) graceful-handoff/ v2.1.0 — Auto-trigger handoff via Stop hook (skill + JSON pipeline + 4-step model-aware context resolution) linkedin-thought-leadership/ v1.2.0 — LinkedIn content pipeline + analytics - llm-security/ v7.7.2 — Security scanning, auditing, threat modeling. HTML report output for all 18 skill commands (render-report CLI + canonical ESM module mirrored bit-identical into the playground). v7.7.2 translated the remaining Norwegian surface text in the playground UI, the canonical renderer, the agent prompts, and the README/CLAUDE.md state sections to English. v7.7.1 stripped the playground to the catalog as the only routable surface. - ms-ai-architect/ v1.15.0 — Microsoft AI architecture (Cosmo Skyberg persona) + manual KB-refresh slash command + v3 project-view (sidebar med 17 artifacts + main + import-modal overlay, v2-surface fjernet i v1.15.0) + llm-security/ v6.0.0 — Security scanning, auditing, threat modeling + ms-ai-architect/ v1.8.0 — Microsoft AI architecture (Cosmo Skyberg persona) okr/ v1.0.0 — OKR guidance for Norwegian public sector - voyage/ v5.0.3 — Brief, research, plan, execute, review, continue. Contract-driven Claude Code pipeline (six-command universal pipeline + multi-session resumption + --gates autonomy chain). /trekbrief, /trekplan, and /trekreview each end by running scripts/annotate.mjs against the just-written .md and printing the file:// link to a self-contained operator-annotation HTML modelled on claude-code-100x/build-site.js: pencil-toggle annotation mode, select text or click any element, choose intent (Fiks/Endre/Spørsmål), comment, sidebar groups by section with delete + Copy Prompt, localStorage persistence per artifact path. v5.0.0 removed the v4.2/v4.3 bespoke playground + /trekrevise + Handover 8; v5.0.1 pointed at /playground document-critique (wrong direction); v5.0.2 was operator-led but too thin; v5.0.3 matches the reference the operator pointed at from day one. + ultraplan-local/ v3.4.0 — Brief, research, plan, execute, review, continue (six-command universal pipeline + multi-session resumption + --gates autonomy chain) shared/ - playground-design-system/ v0.6.0 — Aksel/Digdir-aligned CSS design system + JSON schemas + self-hosted Inter/JetBrains Mono/Source Serif 4 fonts. Tier 1 base + Tier 2 + Tier 3 wave 1+2 (20 components) + Tier 4 project-view-arketype (v0.6.0 — sidebar + main + import-modal overlay). Consumed by ms-ai-architect, okr, llm-security, voyage, config-audit. + playground-design-system/ v0.1 — Aksel/Digdir-aligned CSS design system + JSON schemas + self-hosted Inter/JetBrains Mono/Source Serif 4 fonts (Tier 1+2+3 wave 1+wave 2 = 20 Tier 3 components total). Consumed by ms-ai-architect, okr, llm-security, ultraplan-local, config-audit playground-examples/ — Reference scenarios (ROS-Lier, OKR-Bærum, security-Direktorat) + showcase landing + 12 isolated Tier 3 wave 2 component demos under components/ ``` @@ -35,7 +35,6 @@ Hvert plugin er selvstendig med egen CLAUDE.md, README, hooks, agents og command 1. Plugin `README.md` — detaljert dokumentasjon av endringen 2. Plugin `CLAUDE.md` — arkitektur/oversikt 3. Rot-`README.md` — marketplace-landingssiden (`git.fromaitochitta.com/open/ktg-plugin-marketplace`) -- **Playground-oppdatering:** Ved endring av plugin playground HTML eller delt design-system, følg prosedyren i `shared/PLAYGROUND-MAINTENANCE.md` (4 spor: HTML-endring, DS-endring, screenshots, release). ## Sesjonsfiler (lokale, gitignored) @@ -53,20 +52,3 @@ Disse trackes IKKE i git. Oppdater ved sesjonsslutt. 3. Les REMEMBER.md og TODO.md for sesjonsstatus 4. Jobb innenfor scope 5. Oppdater REMEMBER.md ved avslutning - -## Communication patterns - -### Linking to local files - -When pointing to local files in responses, always use markdown link syntax with a descriptive name: - -- Use `[Human-friendly name](file:///absolute/path)` — never bare `file:///...` URLs or autolinks ``. -- Always use absolute paths. Never `~/` or relative paths. -- For multiple files, render as a bullet list of named markdown links. - -Why: bare `file://` URLs only render the first as clickable across multiple lines. Named markdown links make each entry independently clickable and look cleaner. - -Example: - -- [Brief](file:///Users/ktg/.../brief.html) -- [Research summary](file:///Users/ktg/.../research/summary.md) diff --git a/README.md b/README.md index 0f4df4e..e490866 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Then open Claude Code and type `/plugin` to browse and install plugins from the ## Plugins -### [LLM Security](plugins/llm-security/) `v7.7.2` +### [LLM Security](plugins/llm-security/) `v7.3.1` Security scanning, auditing, and threat modeling for agentic AI projects. @@ -36,13 +36,6 @@ Built on OWASP LLM Top 10 (2025), OWASP Agentic AI Top 10, and the AI Agent Trap - **Deterministic scanning** — 23 Node.js scanners (10 orchestrated + 13 standalone) for byte-level analysis: Shannon entropy, Unicode codepoints, typosquatting detection, taint flow, DNS resolution, git forensics, AI-BOM, attack simulation, IDE extension prescan (VS Code + JetBrains — URL fetch from Marketplace / OpenVSX / direct VSIX / JetBrains Marketplace, hardened ZIP extractor for zip-slip / symlinks / bombs, plus OS sandbox via `sandbox-exec` / `bwrap` so the kernel enforces FS confinement), MCP cumulative-drift baseline reset (E14 — sticky baseline catches slow-burn rug-pulls). Bash-normalize T1-T6 for obfuscation-resistant denylists - **Advisory analysis** — 20 commands that scan, audit, and model threats with structured reports, letter grades, and actionable remediation - **Enterprise governance** — Compliance mapping (EU AI Act, NIST AI RMF, ISO 42001), SARIF 2.1.0 output, structured audit trail, policy-as-code, standalone CLI -- **v7.7.2 language consistency pass (2026-05-19)** — Norwegian had crept into surface text across v7.5-v7.7. Per the `~/.claude/CLAUDE.md` convention (English for code and documentation, Norwegian for dialog only), this release translates the HTML Report-step in all 18 skill commands, the canonical CLI renderer `scripts/lib/report-renderers.mjs`, the playground UI strings, the skill-scanner and mcp-scanner agent prompts, the marketplace + plugin README/CLAUDE.md state sections, and six table cells in `docs/scanner-reference.md`. Demo-state fixture content for the `dft-komplett-demo` project (intentional Norwegian persona) and regex alternations that match Norwegian-language report markdown (`/^high\|^høy/`, `/resolution\|løsning/`) were preserved. No scanner, hook, or behavior changes — purely surface text -- **v7.7.1 playground UX strip (2026-05-18)** — Operator feedback immediately after v7.7.0: the catalog became the only routable surface in the playground (the onboarding/home/project render functions remain in source but are not routable). Topbar simplified to a `Catalog` button + state/theme actions. Breadcrumb org-name replaced with a neutral `llm-security`. The onboarding concept (per-command context injection) is documented as a v7.8.0 candidate in ROADMAP. No scanner or hook behavior changes -- **v7.7.0 HTML report for all 18 skill commands (2026-05-18)** — Every `/security ` that produces a report now prints a clickable `file://` link to a self-contained HTML version. Delivered across five sessions: (1) playground catalog list-view + builder-pane with a copy button; (2) playground project-surface cleanup (stub-screen + topbar split); (3) the 18 inline parsers + renderers moved to a canonical ESM module `scripts/lib/report-renderers.mjs` (the playground keeps a bit-identical inline copy since ESM `import` does not work from `file://`); (4) new zero-dep CLI `scripts/render-report.mjs` — stdin/file/stdout mode, kebab→camel commandId routing, inlines 6 DS stylesheets, ~140 KB self-contained HTML with system-font fallback, absolute `file://` paths for Ghostty cmd-click; (5) all 18 skills wired (4 in session 4 + 14 in session 5). No scanner or hook behavior changes — purely additive -- **v7.6.1 playground visual patch (2026-05-06)** — Six bugs caught by the maintainer during manual browser verification after the v7.6.0 release. All were mismatches between DS classes and how playground renderers used them (or missing DS implementations the renderers assumed existed): `renderFindingsBlock` used the `.findings` outer class (the DS 2-column list+detail grid) → replaced with `
` + the correct `findings__list` pattern; `.report-table` was missing entirely from the DS but used in 7+ renderers → local CSS implementation; `renderPreDeploy` traffic-lights used the fixed 28×28 px `.sm-card__grade` for "PASS"/"PASS-WITH-NOTES"/"FAIL" → width-adapting status pill; threat-model matrix bubbles were not clickable → `' + '' @@ -1928,11 +1880,12 @@ { id: 'reporting', name: 'AI-assistert rapportering' } ]; - // v1.15.0: currentProjectTab beholdes som zombie for ACTIONS['project-tab']- - // back-compat (test-playground-v3.sh asserter at handleren er definert). - // Selve action-en er unreachable fra v3 DOM. currentProjectScreen er fjernet - // sammen med ACTIONS['project-screen']. let currentProjectTab = 'regulatory'; + // Screen-tabs på project-surface (A4 Tier 3): Oversikt / Rapporter / + // Kontekst / Eksport. Default 'rapporter' = primær arbeidsflate (eksisterende + // category-tabs + panels). Andre skjermer er stub i Sesjon 2 og fylles ut + // i senere sesjoner. + let currentProjectScreen = 'rapporter'; function findProject(id) { const list = store.state.projects || []; @@ -1958,6 +1911,7 @@ store.state.projects.push(project); store.state.activeProjectId = id; currentProjectTab = 'regulatory'; + currentProjectScreen = 'rapporter'; return project; } @@ -2066,15 +2020,254 @@ ); } - // v1.15.0: renderCommandSubCard + renderProjectSurface fjernet. - // v3 project-view (renderProjectView/renderProjectSurfaceV3) er nå eneste - // project-overflate. Paste-import er erstattet av modal-flow (import-open). + // ---- Sub-card rendering ---- + + function renderCommandSubCard(cmd, projectId) { + // Sev-modifier: hvis rapporten er parsed, mappe verdict til DS card--severity-{level}. + // Plugin-domain-verdicts (go/block/approved/...) → severity-band (positive/critical/medium). + const project = findProject(projectId); + const report = project && project.reports && project.reports[cmd.id]; + const verdict = report && report.parsed && report.parsed.verdict + ? String(report.parsed.verdict).toLowerCase() : ''; + const sevMap = { + 'go': 'positive', 'approved': 'positive', 'allow': 'positive', + 'go-with-conditions': 'medium', 'warning': 'medium', + 'block': 'critical', 'failed': 'critical' + }; + const sevModifier = sevMap[verdict] || ''; + const sevClass = sevModifier ? ' card--severity-' + sevModifier : ''; + + const titleHtml = ( + '
' + + '
' + + '

' + escapeHtml(cmd.label) + '

' + + '

' + escapeHtml(cmd.description) + '

' + + '
' + + '/architect:' + escapeHtml(cmd.id) + '' + + '
' + ); + + const formZone = ( + '
' + + '

Skjema

' + + '
' + + renderCommandForm(cmd.id, { context: 'project', projectId: projectId, scope: 'p' }) + + '
' + + '
' + ); + + if (!cmd.produces_report) { + // Verktøy: skjema-zone + .guide-panel--info notis + const toolNotice = ( + '
' + + '
' + + '' + + '
' + + '

Verktøy

' + + '

Dette er et verktøy. Ingen rapport-import — bruk skjemaet til å bygge en pipeline-streng som kjøres i terminalen.

' + + '
' + + '
' + + '
' + ); + return ( + '
' + + titleHtml + + formZone + + toolNotice + + '
' + ); + } + + // Rapport-produserende: skjema-zone + paste-import-zone + report-zone + const pasteZone = ( + '
' + + '

Lim inn rapport-output

' + + '
' + + '' + + '
' + + '' + + 'Routes via PARSERS[' + escapeHtml(cmd.report_archetype || '?') + '] → ' + escapeHtml(cmd.renderer || '?') + ' (Step 11/12).' + + '
' + + '
' + + '
' + ); + + const reportZone = ( + '
' + + '

Visualisering

' + + '
' + + '
' + ); + + return ( + '
' + + titleHtml + + formZone + + pasteZone + + reportZone + + '
' + ); + } + + function renderProjectSurface() { + const root = getSurfaceEl('project'); + if (!root) return; + + const project = findProject(store.state.activeProjectId); + if (!project) { + // Mistet aktivt prosjekt — fall tilbake til hjem. + navigate('home'); + return; + } + + const reportTotal = CATALOG.commands.filter(function (c) { return c.produces_report; }).length; + const reportFilled = projectReportCount(project); + + // Action-bar (Tilbake / Slett) flyttet under page-shell-headeren — + // page__header har dedikert verdict-slot som ikke tar arbitrary HTML. + const actionBar = ( + '
' + + '' + + '' + + '
' + ); + + // Tab-list (DS): Oversikt / Rapporter / Kontekst / Eksport. + // Sesjon 2: Rapporter er primær; andre er stub-skjermer som fylles ut + // i Sesjon 3-6. + const SCREENS = [ + { id: 'oversikt', label: 'Oversikt' }, + { id: 'rapporter', label: 'Rapporter' }, + { id: 'kontekst', label: 'Kontekst' }, + { id: 'eksport', label: 'Eksport' } + ]; + const screenTabsHtml = ''; + + // Tabs per CATALOG.categories — kun synlig under "Rapporter"-skjermen. + const tabsHtml = '
' + CATALOG.categories.map(function (cat) { + const isActive = currentProjectTab === cat.id; + return ( + '' + ); + }).join('') + '
'; + + // Render ALLE kategori-paneler i DOM (med [hidden] på inaktive). Dette + // sikrer at querySelectorAll('[data-paste-import]') matcher alle 17 + // rapport-produserende commands uavhengig av aktiv tab. + const panelsHtml = CATALOG.categories.map(function (cat) { + const isActive = currentProjectTab === cat.id; + const cards = CATALOG.commands + .filter(function (c) { return c.category === cat.id; }) + .map(function (c) { return renderCommandSubCard(c, project.id); }).join(''); + return ( + '
' + + cards + + '
' + ); + }).join(''); + + const scenarioChipsList = (project.scenarios || []).map(function (sid) { + const s = SCENARIOS.find(function (x) { return x.id === sid; }); + return '
  • ' + escapeHtml(s ? s.name : sid) + '
  • '; + }).join(''); + + const oversiktHtml = ( + '
    ' + + '
    ' + + '' + + '
    ' + + '

    Oversikt

    ' + + '

    Opprettet ' + escapeHtml((project.createdAt || '').slice(0, 10)) + '. ' + reportFilled + ' av ' + reportTotal + ' rapporter generert.

    ' + + (scenarioChipsList ? '

    Scenarioer:

      ' + scenarioChipsList + '
    ' : '') + + '

    Sesjon 3+: aggregerte verdict-pillen, recommended-next-actions og top-risks vises her.

    ' + + '
    ' + + '
    ' + + '
    ' + ); + + const rapporterHtml = ( + '
    ' + + tabsHtml + + panelsHtml + + '
    ' + ); + + const kontekstHtml = ( + '
    ' + + '
    ' + + '' + + '
    ' + + '

    Kontekst

    ' + + '

    Fellesfeltene fra onboarding gjenbrukes automatisk i alle command-skjemaer. Bruk for å oppdatere.

    ' + + '

    Sesjon 3+: snapshot av de 20 fellesfeltene og hva som er prefilled per command vises her.

    ' + + '
    ' + + '
    ' + + '
    ' + ); + + const eksportHtml = ( + '
    ' + + '
    ' + + '' + + '
    ' + + '

    Eksport

    ' + + '

    Bruk Eksporter i toppmenyen for hele state. Per-prosjekt eksport (PDF/Markdown) kommer i Sesjon 6.

    ' + + '
    ' + + '
    ' + + '
    ' + ); + + const projectShell = renderPageShell({ + eyebrow: 'PROSJEKT', + title: project.name, + lede: project.description || '', + verdict: inferProjectVerdict(project), + keyStats: [ + { label: 'RAPPORTER', value: reportFilled + '/' + reportTotal }, + { label: 'SIST OPPDATERT', value: inferProjectLastUpdated(project) } + ] + }, + '
    ' + + actionBar + + screenTabsHtml + + oversiktHtml + + rapporterHtml + + kontekstHtml + + eksportHtml + + '
    ' + ); + + root.innerHTML = ( + renderTopbar('Prosjekt: ' + escapeHtml(project.name)) + + '
    ' + + projectShell + + '
    ' + ); + + // v1.10.0+: rehydrer paste-imports etter at DOM er bygget. queueMicrotask + // sikrer at innerHTML har commit-et før vi spørr etter [data-paste-import]. + queueMicrotask(rehydratePasteImports); + } // ============================================================ // CATALOG SURFACE (Step 9) // ============================================================ // - // 25 commands gruppert i 5 .expansion-grupper (CATALOG.categories) med + // 24 commands gruppert i 5 .expansion-grupper (CATALOG.categories) med // søke-input som filtrerer på id+label+description+argument_hint. // Hver kategori-expansion rendrer en .catalog-cards-grid med kort. // "Åpne skjema" på et kort åpner renderCommandForm() i modal. @@ -3060,11 +3253,6 @@ } function renderFindingsBlock(findings, label) { - // v1.14.0 sesjon 3: refaktorert fra .report-meta-band-aid til standalone - // findings-section. DS' .findings er grid 360px+1fr (list+detail-panel) — - // siden vi ikke har detail-panel, bruker vi en standalone container med - // .findings__items--standalone-modifier som styles lokalt. - if (!findings || !findings.length) return ''; const items = findings.map(function (f) { return '
  • ' + '' + @@ -3073,10 +3261,14 @@ 'Lokasjon: ' + escapeHtml(f.location || '—') + ' · Severity: ' + escapeHtml(f.severity || '—') + '' + '
  • '; }).join(''); - return '
    ' + - '

    ' + escapeHtml(label) + '

    ' + - '
      ' + items + '
    ' + - '
    '; + return '
    ' + + '
    ' + + '
    ' + + '
    ' + escapeHtml(label) + '' + findings.length + '
    ' + + '
      ' + items + '
    ' + + '
    ' + + '
    ' + + '
    '; } function renderMatrixHtml(data, cons_max) { @@ -3096,14 +3288,12 @@ for (let prob = 1; prob <= probSize; prob++) { const score = prob * cons; const items = byPC[prob + '_' + cons] || []; - // v1.13.0 fix (B3): bobler er nå '; + return '' + (i + 1) + ''; }).join('') + - (items.length > 3 ? '' : '') + + (items.length > 3 ? '+' + (items.length - 3) + '' : '') + '' : ''; html += '
    ' + @@ -3123,13 +3313,8 @@ function renderRadarSvg(axes) { if (!axes || !axes.length) return ''; - // v1.13.0 fix (B4): bump SVG fra 300×300 til 380×380, R fra 100 til 125, - // label-offset fra R+25 til R+28, og dynamisk text-anchor basert på - // horisontal-posisjon. Forhindrer at bottom-labels overlapper ved 6+ - // akser (typisk for ROS med 7 risiko-dimensjoner). Speilet fra - // llm-security v7.6.1 commit f9b555a. const N = axes.length; - const SIZE = 380, cx = SIZE / 2, cy = SIZE / 2, R = 125; + const cx = 150, cy = 150, R = 100; const points = axes.map(function (a, i) { const angle = (i / N) * 2 * Math.PI - Math.PI / 2; const r = R * (Math.max(0, Math.min(5, a.score)) / 5); @@ -3137,11 +3322,9 @@ }).join(' '); const labels = axes.map(function (a, i) { const angle = (i / N) * 2 * Math.PI - Math.PI / 2; - const x = cx + (R + 28) * Math.cos(angle); - const y = cy + (R + 28) * Math.sin(angle); - const dx = Math.cos(angle); - const anchor = Math.abs(dx) < 0.2 ? 'middle' : (dx > 0 ? 'start' : 'end'); - return '' + escapeHtml(a.name) + ''; + const x = cx + (R + 25) * Math.cos(angle); + const y = cy + (R + 25) * Math.sin(angle); + return '' + escapeHtml(a.name) + ''; }).join(''); const spokes = axes.map(function (a, i) { const angle = (i / N) * 2 * Math.PI - Math.PI / 2; @@ -3150,7 +3333,7 @@ return ''; }).join(''); return '
    ' + - '' + + '' + '' + '' + spokes + labels + @@ -3193,23 +3376,15 @@ ''; }).join('') + '
    '; - // v1.14.0 sesjon 4:
    '; }).join('') : ''; - // v1.14.0 sesjon 4: stack-sm rundt expansion-list (etter B-DS-2 fix gir - // expansion__title-main/sub display: block, så vertikal stacking er ren). - const body = cardsHtml + (expansionsHtml ? '
    ' + expansionsHtml + '
    ' : ''); + const body = cardsHtml + (expansionsHtml ? '
    ' + expansionsHtml + '
    ' : ''); slot.innerHTML = renderPageShell({ eyebrow: 'KRAV', title: data.title || 'AI Act-krav per risiko og rolle', @@ -3387,10 +3560,8 @@ '
    ' + ''; }).join(''); - // v1.14.0 sesjon 4: timeline-section standalone (uten .report-meta-wrapper). timelineHtml = - '
    ' + - '

    Frister

    ' + + '

    Frister

    ' + '
    ' + '
    ' + '
    ' + @@ -3411,12 +3582,7 @@ } function renderDpia(data, slot) { - // v1.14.0 sesjon 3: matrix wrappet i .card med h2 for visuell separasjon - // fra residual-pair og threats-tabell (per Anthropic-ref ros-lier-pattern). - const matrixHtml = '
    ' + - '

    5×5 Risikomatrise

    ' + - renderMatrixHtml(data, 5) + - '
    '; + const matrixHtml = renderMatrixHtml(data, 5); const threatsHtml = renderThreatsTable(data.threats); const rp = data.residualPair; let residualHtml = ''; @@ -3480,51 +3646,34 @@ if (n >= 4) return 'medium'; return 'low'; }; - // v1.14.0 sesjon 3: matrix + radar i .ros-layout (1fr 320px) per Anthropic-ref - // ros-lier-scenario. Matrix står i .card, radar i
    '; } const findingsHtml = renderFindingsBlock(data.findings || [], 'Sikkerhetsfunn'); - const body = layoutHtml + smallMultiplesHtml + topRisksHtml + residualHtml + findingsHtml; + const body = matrixHtml + radarHtml + smallMultiplesHtml + topRisksHtml + residualHtml + findingsHtml; // Utvid matrix-risk-6x5-keyStats med RESTRISIKO når residualPair finnes. const baseStats = inferKeyStats(data, 'matrix-risk-6x5'); const stats = (data.keyStats || (rp && rp.after @@ -3580,34 +3729,21 @@ if (n >= 4) return 'medium'; return 'low'; }; - // v1.14.0 sesjon 3: speil renderSecurity-pattern. Matrix + radar i .ros-layout - // (1fr 320px), top-risks + recommendation i .summary-grid (1.4fr 1fr). - const layoutHtml = '
    ' + - '
    ' + - '

    5×5 Risikomatrise

    ' + - renderMatrixHtml(data, 5) + - '
    ' + - '' + - '
    '; - // C4 top-risks-list (max 5) — som
      inne i .card. + const matrixHtml = renderMatrixHtml(data, 5); + const radarHtml = renderRadarSvg(data.radar_axes || []); + // C4 top-risks-list (max 5). const topRisks = (data.topRisks || []).slice(0, 5); - const topRisksCardHtml = topRisks.length ? '
      ' + - '

      Topp-risikoer

      ' + - '
        ' + - topRisks.map(function (r, i) { - const sev = r.severity || sevForScore(r.score); - const scoreLabel = r.score ? String(r.score) : (r.severity || '—').toUpperCase(); - return '
      1. ' + - '' + (i + 1) + '' + - '' + escapeHtml(r.description || '') + '' + - '' + escapeHtml(scoreLabel) + '' + - '
      2. '; - }).join('') + - '
      ' + - '
      ' : ''; + const topRisksHtml = topRisks.length ? '
      ' + + '

      Top-risikoer

      ' + + topRisks.map(function (r, i) { + const sev = r.severity || sevForScore(r.score); + const scoreLabel = r.score ? String(r.score) : (r.severity || '—').toUpperCase(); + return '
      ' + + '' + (i + 1) + '' + + '' + escapeHtml(r.description || '') + '' + + '' + escapeHtml(scoreLabel) + '' + + '
      '; + }).join('') + '
      ' : ''; // B6 residual-pair (gjenbruker mønster fra Dpia / Security). const rp = data.residualPair; let residualHtml = ''; @@ -3636,18 +3772,12 @@ } // D5 recommendation-card. const rec = data.recommendation || ''; - const recommendationCardHtml = rec ? '
    '; } - // v1.13.1 fix (B14): brukeren etterspurte tabell-visning. Legg til en - // phases-summary-tabell over phase-detail-seksjonene som gir oversikt - // (Fase, Varighet, Milepæler-count, Suksess-count, Status). - const phasesSummaryRows = phases.map(function (p, i) { - const state = stepStateFor(p, i); - const stateLabel = state === 'completed' ? 'Ferdig' : state === 'current' ? 'Pågår' : 'Planlagt'; - return '' + - '' + escapeHtml(p.name) + '' + - '' + escapeHtml(String(p.duration_weeks || '—')) + ' uker' + - '' + ((p.milestones || []).length) + '' + - '' + ((p.success_criteria || []).length) + '' + - '' + escapeHtml(stateLabel) + '' + - ''; - }).join(''); - const phasesSummaryHtml = phasesSummaryRows - ? '' + phasesSummaryRows + '
    FaseVarighetMilepælerSuksesskriterierStatus
    ' - : ''; - // v1.14.0 sesjon 5: phase-detail (lokal CSS-mønster) erstattet med - //
    -list (DS-supplement). Default-collapsed, klikkbar - // header = fase-navn + varighet, body = milepæler + suksesskriterier. - // phase-expand-handler er registrert i ACTIONS som alias for samme - // toggle-mønster som requirement-expand. - const detailsHtml = phases.length ? '
    ' + phases.map(function (p, idx) { + const detailsHtml = phases.map(function (p) { const ms = (p.milestones || []).map(function (m) { return '
  • ' + escapeHtml(m) + '
  • '; }).join(''); const sc = (p.success_criteria || []).map(function (s) { return '
  • ' + escapeHtml(s) + '
  • '; }).join(''); - const innerBody = (ms ? '

    Milepæler

      ' + ms + '
    ' : '') + - (sc ? '

    Suksesskriterier

      ' + sc + '
    ' : ''); - return ''; - }).join('') + '
    ' : ''; + return '
    ' + + '

    ' + escapeHtml(p.name) + ' (' + (p.duration_weeks || '?') + ' uker)

    ' + + (ms ? '

    Milepæler

      ' + ms + '
    ' : '') + + (sc ? '

    Suksesskriterier

      ' + sc + '
    ' : '') + + '
    '; + }).join(''); const risksRows = (data.risks || []).map(function (r) { return '' + escapeHtml(r.risk || '') + '' + escapeHtml(r.probability || '') + '' + escapeHtml(r.consequence || '') + '' + escapeHtml(r.mitigation || '') + ''; }).join(''); const risksHtml = risksRows ? '' + risksRows + '
    RisikoSannsynlighetKonsekvensTiltak
    ' : ''; - const body = ribbonHtml + ladderHtml + phasesSummaryHtml + detailsHtml + risksHtml; + const body = ribbonHtml + ladderHtml + detailsHtml + risksHtml; slot.innerHTML = renderPageShell({ eyebrow: 'MIGRASJON', title: data.title || 'Migrasjonsplan', @@ -4125,28 +4224,9 @@ '
    '; }).join(''); const ladderHtml = '
    ' + stepsHtml + '
    '; - // v1.13.1 fix (B15): phases-summary-tabell over phase-detail-seksjonene - // gir struktur og forhindrer at faseinfo flyter horisontalt mot risiko- - // tabellen i renderPoc. Samme mønster som renderMigrate. - const phasesSummaryRows = phases.map(function (p, i) { - const state = stepStateFor(p, i); - const stateLabel = state === 'completed' ? 'Ferdig' : state === 'current' ? 'Pågår' : 'Planlagt'; - return '' + - '' + escapeHtml(p.name) + '' + - '' + escapeHtml(String(p.duration_weeks || '—')) + ' uker' + - '' + ((p.milestones || []).length) + '' + - '' + ((p.success_criteria || []).length) + '' + - '' + escapeHtml(stateLabel) + '' + - ''; - }).join(''); - const phasesSummaryHtml = phasesSummaryRows - ? '' + phasesSummaryRows + '
    FaseVarighetMilepælerSuksesskriterierStatus
    ' - : ''; - // v1.14.0 sesjon 5: phase-detail erstattet med expansion-list (samme - // mønster som renderMigrate). Traffic-light per success-kriterie beholdes - // inne i expansion-body. R15: uten eksplisitt status, bruk fasens state — - // done=green, active=yellow, future=gray. - const detailsHtml = phases.length ? '
    ' + phases.map(function (p, i) { + // B5 traffic-light per success-kriterie. R15: uten eksplisitt status, + // bruk fasens state — done=go, active=warning, future=neutral. + const detailsHtml = phases.map(function (p, i) { const state = stepStateFor(p, i); const tlStatus = state === 'completed' ? 'green' : state === 'current' ? 'yellow' : 'gray'; const ms = (p.milestones || []).map(function (m) { return '
  • ' + escapeHtml(m) + '
  • '; }).join(''); @@ -4158,28 +4238,19 @@ '' + ''; }).join(''); - const innerBody = (ms ? '

    Milepæler

      ' + ms + '
    ' : '') + - (sc ? '

    Suksesskriterier

      ' + sc + '
    ' : ''); - return ''; - }).join('') + '
    ' : ''; + return '
    ' + + '

    ' + escapeHtml(p.name) + ' (' + (p.duration_weeks || '?') + ' uker)

    ' + + (ms ? '

    Milepæler

      ' + ms + '
    ' : '') + + (sc ? '

    Suksesskriterier

      ' + sc + '
    ' : '') + + '
    '; + }).join(''); const risksRows = (data.risks || []).map(function (r) { return '' + escapeHtml(r.risk || '') + '' + escapeHtml(r.probability || '') + '' + escapeHtml(r.consequence || '') + '' + escapeHtml(r.mitigation || '') + ''; }).join(''); const risksHtml = risksRows ? '' + risksRows + '
    RisikoSannsynlighetKonsekvensTiltak
    ' : ''; - const body = ladderHtml + phasesSummaryHtml + detailsHtml + risksHtml; + const body = ladderHtml + detailsHtml + risksHtml; // B1 verdict-pille: data.pocVerdict styrer (go/go-with-conditions/block). // R15: hvis ikke satt, fall tilbake til risk-baserte heuristikk. let verdict = data.verdict || data.pocVerdict; @@ -4231,14 +4302,8 @@ } return '
    ' + escapeHtml(txt).replace(/\n/g, '
    ') + '
    '; }; - // v1.14.0 sesjon 5b: Avvik fra DS-default — vi bruker + - // alle paneler synlige (anchor-jump-TOC), ikke ekte tab-toggle med - // hidden paneler. Dropper derfor role="tab/tablist" siden de impliserer - // tab-control-semantikk vi ikke leverer. aria-current="true" beholdes - // som visuell aktiv-markør (DS-CSS hekter på den). Ekte tab-toggle med - // ' + - '' + - '' + - '' + - '' - ); - } - - function renderArtifactNavItem(commandId, artifact, config, isSelected) { - const cmd = (CATALOG.commands || []).find(function (c) { return c.id === commandId; }) || { id: commandId, label: commandId }; - const filled = !!(artifact && artifact.parsed); - const status = config.getArtifactStatus(filled ? artifact : null); - const state = isSelected ? 'active' : (filled ? 'filled' : 'empty'); - const sev = status.sevClass || 'empty'; - const meta = filled - ? 'Importert ' + (projectViewTimeAgo(artifact.importedAt) || '–') - : 'Ingen rapport'; - const statusPill = filled && status.verdict - ? '' + escapeHtml(String(status.verdict).toUpperCase()) + '' - : ''; - return ( - '
  • ' + - '' + - '' + - '' + escapeHtml(cmd.label || commandId) + '' + - '' + escapeHtml(meta) + '' + - '' + - (statusPill ? '' + statusPill + '' : '') + - '
  • ' - ); - } - - function renderArtifactNav(project, config, selectedId, searchQuery) { - const q = String(searchQuery || '').trim().toLowerCase(); - const artifacts = project.artifacts || {}; - const cmds = (CATALOG.commands || []).filter(function (c) { return c.produces_report && config.renderers[c.id]; }); - const groups = config.categories.slice().sort(function (a, b) { return a.order - b.order; }).map(function (cat) { - const cmdsInCat = cmds.filter(function (c) { - if (c.category !== cat.id) return false; - if (!q) return true; - const hay = (c.id + ' ' + c.label + ' ' + (c.description || '')).toLowerCase(); - return hay.indexOf(q) !== -1; - }); - if (!cmdsInCat.length) return ''; - const items = cmdsInCat.map(function (c) { - return renderArtifactNavItem(c.id, artifacts[c.id] || null, config, c.id === selectedId); - }).join(''); - const filledCount = cmdsInCat.filter(function (c) { return artifacts[c.id] && artifacts[c.id].parsed; }).length; - return ( - '
    ' + - '
    ' + - '' + - '' + escapeHtml(cat.label) + '' + - '' + filledCount + '/' + cmdsInCat.length + '' + - '
    ' + - '
      ' + items + '
    ' + - '
    ' - ); - }).filter(Boolean).join(''); - const overviewActive = !selectedId ? ' data-state="active"' : ''; - return ( - '' - ); - } - - function renderProjectOverview(project, config) { - const artifacts = project.artifacts || {}; - const cats = config.categories.slice().sort(function (a, b) { return a.order - b.order; }); - const verdictGrid = cats.map(function (cat) { - const cmdsInCat = (CATALOG.commands || []).filter(function (c) { return c.category === cat.id && c.produces_report; }); - const filled = cmdsInCat.filter(function (c) { return artifacts[c.id] && artifacts[c.id].parsed; }).length; - const worst = (function () { - const verdicts = cmdsInCat.map(function (c) { - const a = artifacts[c.id]; - return a && a.verdict ? String(a.verdict).toLowerCase() : ''; - }); - if (verdicts.some(function (v) { return v === 'block' || v === 'failed'; })) return 'block'; - if (verdicts.some(function (v) { return v === 'warning' || v === 'go-with-conditions'; })) return 'go-with-conditions'; - if (verdicts.some(function (v) { return v === 'go' || v === 'approved' || v === 'allow'; })) return 'approved'; - return 'n-a'; - })(); - const sev = projectViewSeverityClass(worst); - return ( - '
    ' + - '' + escapeHtml(cat.icon || '') + ' ' + escapeHtml(cat.label) + '' + - '' + renderVerdictPill(worst) + '' + - '' + filled + ' av ' + cmdsInCat.length + ' artefakter' + - '
    ' - ); - }).join(''); - - const risks = config.topRisks(artifacts, 5); - const risksHtml = risks.length - ? '
      ' + risks.map(function (r) { - const sev = projectViewSeverityClass(r.severity); - return '
    1. ' + - '' + escapeHtml(r.id || '–') + '' + - '' + escapeHtml(r.description || '') + '' + - '' + escapeHtml(r.source) + '' + - '
    2. '; - }).join('') + '
    ' - : '

    Ingen risikoer registrert ennå. Importer ROS- eller sikkerhetsrapport.

    '; - - const actions = config.nextActions(artifacts); - const actionsHtml = actions.length - ? '
      ' + actions.map(function (a) { - return '
    1. '; - }).join('') + '
    ' - : '

    Alle anbefalte neste-trinn er fullført.

    '; - - const missing = config.missingReports(artifacts); - const missingHtml = missing.length - ? '
      ' + missing.map(function (cid) { - const cmd = (CATALOG.commands || []).find(function (c) { return c.id === cid; }) || { id: cid, label: cid }; - return '
    • ' + - '' + - '' + escapeHtml(cmd.label || cid) + '' + - '' + - '
    • '; - }).join('') + '
    ' - : '

    Alle må-ha-rapporter er importert.

    '; - - return ( - '
    ' + - '
    ' + - '

    Prosjektoversikt

    ' + - '

    Aggregat per kategori. Velg en artefakt i sidemenyen for å vise full rapport.

    ' + - '
    ' + - '
    ' + verdictGrid + '
    ' + - '
    ' + - '

    Topp-risikoer

    ' + risksHtml + - '
    ' + - '
    ' + - '

    Anbefalte neste-trinn

    ' + actionsHtml + - '
    ' + - '
    ' + - '

    Manglende rapporter (må ha)

    ' + missingHtml + - '
    ' + - '
    ' - ); - } - - function renderProjectArtifact(artifact, config) { - const cmd = (CATALOG.commands || []).find(function (c) { return c.id === artifact.commandId; }) || { id: artifact.commandId, label: artifact.commandId }; - const renderer = config.renderers[artifact.commandId]; - // Bygg en in-memory slot, kall renderer (slot-mutator), trekk ut HTML. - // Eksisterende renderXxx tar (data, slot) og setter slot.innerHTML. - let bodyHtml = ''; - if (renderer && artifact.parsed) { - try { - const slot = (typeof document !== 'undefined') ? document.createElement('div') : null; - if (slot) { - renderer(artifact.parsed, slot); - bodyHtml = slot.innerHTML; - } else { - bodyHtml = '

    Renderer krever DOM (test-miljø).

    '; - } - } catch (e) { - bodyHtml = '

    Rendringsfeil

    ' + - '

    ' + escapeHtml(String(e.message || e)) + '

    '; - } - } else { - bodyHtml = '

    Ingen parsed data.

    '; - } - const updated = projectViewTimeAgo(artifact.updatedAt) || projectViewTimeAgo(artifact.importedAt) || ''; - return ( - '
    ' + - '
    ' + - '
    ' + - 'ARTEFAKT' + - '

    ' + escapeHtml(cmd.label || artifact.commandId) + '

    ' + - (updated ? '

    Sist oppdatert ' + escapeHtml(updated) + '

    ' : '') + - '
    ' + - '
    ' + - '' + - '' + - '
    ' + - '
    ' + - '
    ' + bodyHtml + '
    ' + - '
    ' - ); - } - - function renderEmptyArtifactPrompt(commandId, config) { - const cmd = (CATALOG.commands || []).find(function (c) { return c.id === commandId; }) || { id: commandId, label: commandId }; - return ( - '
    ' + - '' + - '

    Ingen ' + escapeHtml(cmd.label || commandId) + '-rapport ennå

    ' + - '

    ' + escapeHtml(cmd.description || '') + '

    ' + - '
    ' + - '' + - '' + - '
    ' + - '
    ' - ); - } - - function renderProjectMain(project, config, viewState) { - const selectedId = viewState && viewState.selectedArtifactId; - if (!selectedId) { - return '
    ' + - renderProjectOverview(project, config) + - '
    '; - } - const artifact = project.artifacts && project.artifacts[selectedId]; - if (!artifact || !artifact.parsed) { - return '
    ' + - renderEmptyArtifactPrompt(selectedId, config) + - '
    '; - } - return '
    ' + - renderProjectArtifact(artifact, config) + - '
    '; - } - - function renderImportModal(state, config) { - const modal = state && state.ui && state.ui.importModal; - if (!modal || !modal.open) return ''; - const prefillCmd = modal.prefillCommandId || ''; - const prefillText = modal.prefillMarkdown || ''; - const allCmds = (CATALOG.commands || []).filter(function (c) { - return c.produces_report && config.renderers[c.id]; - }); - const cmdOptions = '' + allCmds.map(function (c) { - const sel = c.id === prefillCmd ? ' selected' : ''; - return ''; - }).join(''); - return ( - '' - ); - } - - function renderProjectView(project, config) { - if (!project) return '

    Ingen prosjekt valgt.

    '; - const cfg = config || PROJECT_VIEW_CONFIG; - const ui = (store && store.state && store.state.ui) || {}; - const pv = ui.projectView || {}; - const selectedId = pv.selectedArtifactId || null; - const searchQuery = pv.searchQuery || ''; - const artifacts = project.artifacts || {}; - const aggregateVerdict = cfg.aggregateVerdict(artifacts); - const keyStats = projectViewKeyStats(project, cfg); - const viewState = { - view: selectedId ? (artifacts[selectedId] && artifacts[selectedId].parsed ? 'artifact' : 'empty') : 'overview', - selectedArtifactId: selectedId - }; - const importModalHtml = renderImportModal(store && store.state, cfg); - return ( - '
    ' + - '
    ' + - renderProjectHeader(project, aggregateVerdict, keyStats) + - '
    ' + - '
    ' + - renderArtifactNav(project, cfg, selectedId, searchQuery) + - renderProjectMain(project, cfg, viewState) + - '
    ' + - '
    ' + - importModalHtml - ); - } - - // Eksponer for tester (Sesjon 4) og integrasjon (Sesjon 5). - window.__projectView = { - renderProjectView: renderProjectView, - renderProjectHeader: renderProjectHeader, - renderArtifactNav: renderArtifactNav, - renderArtifactNavItem: renderArtifactNavItem, - renderProjectMain: renderProjectMain, - renderProjectOverview: renderProjectOverview, - renderProjectArtifact: renderProjectArtifact, - renderEmptyArtifactPrompt: renderEmptyArtifactPrompt, - renderImportModal: renderImportModal, - inferCommandIdFromMarkdown: inferCommandIdFromMarkdown, - fingerprintScore: fingerprintScore, - PROJECT_VIEW_CONFIG: PROJECT_VIEW_CONFIG, - COMMAND_FINGERPRINTS: COMMAND_FINGERPRINTS - }; - // === PROJECT_VIEW_V2_END === + window.__rehydratePasteImports = rehydratePasteImports; // ============================================================ // ONBOARDING SURFACE (Step 5) @@ -5884,58 +5224,6 @@ if (handler) handler(ev, actionEl); }); - // v1.13.0 fix (B3): matrix-bobler klikkbare. Klikk scroller til tilsvarende - // rad i Trusler-tabellen og fremhever den kort. Bruker data-threat-id som - // anker. Speilet fra llm-security v7.6.1 commit f9b555a. - // - // v1.13.1 fix (B11): DPIA-fixturer har full-tekst label i matrix_cells men - // T-001..T-005-id i threats-tabellen. Matchet kun mot første-kolonne ga - // klikk uten effekt. Utvid match-strategi: prøv first-cell exact, så - // any-cell substring-match (fuzzy). Også legg til normalisering for å - // håndtere truncation (escapeHtml + slice). - document.addEventListener('click', function (ev) { - const bubble = ev.target.closest('.matrix__bubble[data-threat-id]'); - if (!bubble) return; - const threatId = bubble.getAttribute('data-threat-id'); - if (!threatId) return; - const norm = function (s) { return String(s || '').trim().toLowerCase(); }; - const target = norm(threatId); - const targetHead = target.slice(0, 40); - const tables = document.querySelectorAll('table.report-table'); - // Pass 1: exact match på første-kolonne (T-001-mønster). - for (let t = 0; t < tables.length; t++) { - const rows = tables[t].querySelectorAll('tbody tr'); - for (let r = 0; r < rows.length; r++) { - const firstCell = rows[r].querySelector('td'); - if (firstCell && norm(firstCell.textContent) === target) { - highlightRow(rows[r]); - return; - } - } - } - // Pass 2: substring-match mot enhver celle i raden (label-baserte data-id). - for (let t = 0; t < tables.length; t++) { - const rows = tables[t].querySelectorAll('tbody tr'); - for (let r = 0; r < rows.length; r++) { - const cells = rows[r].querySelectorAll('td'); - for (let c = 0; c < cells.length; c++) { - const cellText = norm(cells[c].textContent); - if (cellText && (cellText.indexOf(targetHead) !== -1 || target.indexOf(cellText.slice(0, 40)) !== -1)) { - highlightRow(rows[r]); - return; - } - } - } - } - function highlightRow(row) { - row.scrollIntoView({ behavior: 'smooth', block: 'center' }); - const orig = row.style.background; - row.style.background = 'var(--color-primary-100, var(--color-bg-soft))'; - row.style.transition = 'background var(--duration-base) var(--ease-default)'; - setTimeout(function () { row.style.background = orig; }, 1600); - } - }); - ACTIONS['onboarding-toggle-group'] = function (ev, el) { const exp = el.closest('.expansion'); if (!exp) return; @@ -5943,22 +5231,6 @@ exp.setAttribute('aria-expanded', open ? 'false' : 'true'); }; - // v1.13.1 fix (B8a): renderRequirements bruker data-action="requirement-expand" - // på hver expansion__head-knapp, men handleren var aldri registrert. Klikk - // gjorde derfor ingenting på R-01..R-09-radene i AI Act-krav-rapporten. - // Samme toggle-mønster som onboarding/catalog. - ACTIONS['requirement-expand'] = function (ev, el) { - const exp = el.closest('.expansion'); - if (!exp) return; - const open = exp.getAttribute('aria-expanded') === 'true'; - exp.setAttribute('aria-expanded', open ? 'false' : 'true'); - }; - - // v1.14.0 sesjon 5: phase-expand alias — renderMigrate + renderPoc bruker - // samme expansion-toggle-mønster som requirement-expand, men med eget action- - // navn for å gjøre intent eksplisitt og åpne for senere divergens. - ACTIONS['phase-expand'] = ACTIONS['requirement-expand']; - ACTIONS['onboarding-goto-group'] = function (ev, el) { const groupId = el.dataset.group; const root = getSurfaceEl('onboarding'); @@ -6007,20 +5279,9 @@ 'activeSurface', 'preferences'].forEach(function (k) { if (demo[k] !== undefined) store.state[k] = demo[k]; }); - // v1.15.0: kjør migrasjonen så demo-state med dataVersion=2 + reports - // konverteres til v3 artifacts-shape FØR render. parserFor sørger for at - // raw_markdown auto-parses inn i artifacts.parsed/verdict/keyStats. - try { migrateDataVersion(store.state, defaultArchetypeFor, defaultParserFor); } - catch (e) { console.warn('[playground v3] load-demo migrate failed:', e); } + // Reset interne UI-state-variabler så project-render starter i 'rapporter'-tab. currentProjectTab = 'regulatory'; - // Reset v3 project-view UI-state så sidebar starter på overview. - if (store.state.ui && store.state.ui.projectView) { - store.state.ui.projectView.selectedArtifactId = null; - store.state.ui.projectView.searchQuery = ''; - } - if (store.state.ui && store.state.ui.importModal) { - store.state.ui.importModal.open = false; - } + currentProjectScreen = 'rapporter'; navigate(demo.activeSurface || 'project'); }; @@ -6136,8 +5397,24 @@ }); }; - // v1.15.0: ACTIONS['project-screen'] fjernet sammen med screen-tabs i - // renderProjectSurface (v3 project-view bruker artifact-sidebar i stedet). + ACTIONS['project-screen'] = function (ev, el) { + const screen = el.dataset.screen; + if (!screen) return; + currentProjectScreen = screen; + // Toggle aria-current på .tab-list-knappene + [hidden] på .tab-panel-paneler + // uten full re-render (bevarer evt textarea-input i panels). + const root = getSurfaceEl('project'); + if (!root) return; + const tabs = root.querySelectorAll('.tab-list .tab'); + tabs.forEach(function (t) { + t.setAttribute('aria-current', t.dataset.screen === screen ? 'true' : 'false'); + }); + const screens = root.querySelectorAll('.tab-panel[data-screen-id]'); + screens.forEach(function (s) { + if (s.dataset.screenId === screen) s.removeAttribute('hidden'); + else s.setAttribute('hidden', ''); + }); + }; ACTIONS['parse'] = function (ev, el) { const commandId = el.dataset.command; @@ -6151,247 +5428,6 @@ handlePasteImport(commandId, markdown); }; - // ============================================================ - // PROJECT-VIEW V2 ACTIONS (Sesjon 3) - // ============================================================ - // - // Disse handlers betjener renderProjectView (parallell implementasjon). - // Ingen call-site i Sesjon 3 — Sesjon 5 bytter renderProjectSurface → - // renderProjectView i renderActive() og aktiverer hele kjeden. - - function projectViewUiState() { - if (!store || !store.state) return null; - if (!store.state.ui) store.state.ui = {}; - if (!store.state.ui.projectView) { - store.state.ui.projectView = { selectedArtifactId: null, searchQuery: '' }; - } - if (!store.state.ui.importModal) { - store.state.ui.importModal = { open: false, prefillCommandId: '', prefillMarkdown: '' }; - } - return store.state.ui; - } - - ACTIONS['project-select-artifact'] = function (ev, el) { - const id = el.dataset.artifactId; - if (!id) return; - const ui = projectViewUiState(); - if (!ui) return; - ui.projectView.selectedArtifactId = id; - scheduleRender(); - }; - - ACTIONS['project-show-overview'] = function () { - const ui = projectViewUiState(); - if (!ui) return; - ui.projectView.selectedArtifactId = null; - scheduleRender(); - }; - - ACTIONS['import-open'] = function (ev, el) { - const ui = projectViewUiState(); - if (!ui) return; - const prefillCmd = (el && el.dataset && el.dataset.prefillCommand) || ''; - ui.importModal.open = true; - ui.importModal.prefillCommandId = prefillCmd; - // Hvis det allerede finnes artifact for prefillCmd, fyll markdown så - // re-import-flowen får eksisterende tekst tilgjengelig. - const project = findProject(store.state.activeProjectId); - const existing = project && project.artifacts && project.artifacts[prefillCmd]; - ui.importModal.prefillMarkdown = (existing && existing.raw_markdown) || ''; - scheduleRender(); - }; - - ACTIONS['import-close'] = function () { - const ui = projectViewUiState(); - if (!ui) return; - ui.importModal.open = false; - ui.importModal.prefillCommandId = ''; - ui.importModal.prefillMarkdown = ''; - scheduleRender(); - }; - - ACTIONS['artifact-reimport'] = function (ev, el) { - const cid = el && el.dataset && el.dataset.command; - if (!cid) return; - const ui = projectViewUiState(); - if (!ui) return; - const project = findProject(store.state.activeProjectId); - const existing = project && project.artifacts && project.artifacts[cid]; - ui.importModal.open = true; - ui.importModal.prefillCommandId = cid; - ui.importModal.prefillMarkdown = (existing && existing.raw_markdown) || ''; - scheduleRender(); - }; - - ACTIONS['artifact-delete'] = function (ev, el) { - const cid = el && el.dataset && el.dataset.command; - if (!cid) return; - if (typeof confirm === 'function' && !confirm('Slette artefakt for «' + cid + '»? Kan ikke angres.')) return; - const project = findProject(store.state.activeProjectId); - if (!project) return; - if (project.artifacts && project.artifacts[cid]) delete project.artifacts[cid]; - if (project.reports && project.reports[cid]) delete project.reports[cid]; - const ui = projectViewUiState(); - if (ui && ui.projectView.selectedArtifactId === cid) ui.projectView.selectedArtifactId = null; - scheduleRender(); - }; - - // Smart-detect på textarea-input i import-modal. - // Re-rendrer kun .import-modal__detect + .import-modal__preview-banner-områdene - // (ikke full surface-render — beholder cursor i textarea). - const projectViewDetectDebounceMs = 250; - let projectViewDetectTimer = null; - function projectViewRunDetect() { - const modal = document.querySelector('[data-import-modal]'); - if (!modal) return; - const ta = modal.querySelector('[data-import-markdown]'); - const detectEl = modal.querySelector('[data-import-detect]'); - const select = modal.querySelector('[data-import-command]'); - const previewEl = modal.querySelector('[data-import-preview]'); - const saveBtn = modal.querySelector('[data-import-save]'); - if (!ta || !detectEl) return; - const text = ta.value || ''; - const result = inferCommandIdFromMarkdown(text, PARSERS); - if (result && result.confidence >= 0.7) { - const cmd = (CATALOG.commands || []).find(function (c) { return c.id === result.commandId; }); - const label = cmd ? cmd.label : result.commandId; - const pct = Math.round(result.confidence * 100); - detectEl.innerHTML = '' + - '✓ Detektert: ' + escapeHtml(label) + ' (' + pct + '% sikker)' + - ''; - if (select && !select.value) select.value = result.commandId; - } else if (result) { - const pct = Math.round(result.confidence * 100); - detectEl.innerHTML = '' + - 'Mulig: ' + escapeHtml(result.commandId) + ' (' + pct + '%) — bekreft i dropdown' + - ''; - } else { - detectEl.innerHTML = ''; - } - // Preview: parse + render hvis vi har gyldig command + tekst. - const activeCmd = select ? select.value : ''; - if (activeCmd && text.trim() && previewEl) { - const cmd = (CATALOG.commands || []).find(function (c) { return c.id === activeCmd; }); - if (cmd && cmd.report_archetype) { - const parser = PARSERS[cmd.report_archetype]; - const renderer = RENDERERS[cmd.renderer]; - if (parser && renderer) { - try { - const r = parser(text); - if (r && r.ok && r.data) { - previewEl.innerHTML = ''; - renderer(r.data, previewEl); - if (saveBtn) saveBtn.removeAttribute('disabled'); - } else { - previewEl.innerHTML = '

    Klarte ikke å tolke markdown — sjekk at det matcher /' + escapeHtml(activeCmd) + '-formatet.

    '; - if (saveBtn) saveBtn.setAttribute('disabled', ''); - } - } catch (e) { - previewEl.innerHTML = '

    Parser-feil: ' + escapeHtml(String(e.message || e)) + '

    '; - if (saveBtn) saveBtn.setAttribute('disabled', ''); - } - } - } - } else if (previewEl) { - previewEl.innerHTML = ''; - if (saveBtn) saveBtn.setAttribute('disabled', ''); - } - } - - ACTIONS['import-detect'] = function () { - if (projectViewDetectTimer) clearTimeout(projectViewDetectTimer); - projectViewDetectTimer = setTimeout(projectViewRunDetect, projectViewDetectDebounceMs); - }; - - ACTIONS['import-save'] = function () { - const modal = document.querySelector('[data-import-modal]'); - if (!modal) return; - const select = modal.querySelector('[data-import-command]'); - const ta = modal.querySelector('[data-import-markdown]'); - if (!select || !ta) return; - const cid = select.value; - const text = ta.value || ''; - if (!cid || !text.trim()) return; - const cmd = (CATALOG.commands || []).find(function (c) { return c.id === cid; }); - if (!cmd || !cmd.report_archetype) return; - const parser = PARSERS[cmd.report_archetype]; - if (!parser) return; - const r = parser(text); - if (!r || !r.ok || !r.data) return; - const project = findProject(store.state.activeProjectId); - if (!project) return; - if (!project.artifacts) project.artifacts = {}; - const arche = cmd.report_archetype; - const nowIso = new Date().toISOString(); - const existing = project.artifacts[cid]; - const verdict = r.data.verdict || inferVerdict(r.data, arche); - const keyStats = Array.isArray(r.data.keyStats) ? r.data.keyStats : inferKeyStats(r.data, arche); - project.artifacts[cid] = { - commandId: cid, - raw_markdown: text, - parsed: r.data, - verdict: verdict, - keyStats: keyStats, - importedAt: existing ? existing.importedAt : nowIso, - updatedAt: nowIso - }; - // Bakover-kompat: speil til project.reports inntil v1.16.0. - if (!project.reports) project.reports = {}; - if (!project.reports[cid]) project.reports[cid] = { input: {} }; - project.reports[cid].raw_markdown = text; - project.reports[cid].parsed = r.data; - project.reports[cid].updatedAt = nowIso; - const ui = projectViewUiState(); - if (ui) { - ui.importModal.open = false; - ui.importModal.prefillCommandId = ''; - ui.importModal.prefillMarkdown = ''; - ui.projectView.selectedArtifactId = cid; - } - scheduleRender(); - }; - - // Live søk i sidebar — re-render hele project-view-surface ville flyttet - // textarea-caret i import-modal og søkefelt-caret. Setter searchQuery - // og re-rendrer kun nav-containeren in-place. - document.addEventListener('input', function (ev) { - if (!ev.target || !ev.target.matches) return; - if (ev.target.matches('[data-project-search]')) { - const ui = projectViewUiState(); - if (!ui) return; - ui.projectView.searchQuery = ev.target.value || ''; - const project = findProject(store.state.activeProjectId); - const root = document.querySelector('[data-surface="project"] .project-view .project-view__nav'); - if (project && root && root.parentNode) { - const tmp = document.createElement('div'); - tmp.innerHTML = renderArtifactNav(project, PROJECT_VIEW_CONFIG, ui.projectView.selectedArtifactId, ui.projectView.searchQuery); - const newNav = tmp.firstElementChild; - if (newNav) { - root.parentNode.replaceChild(newNav, root); - const searchInput = newNav.querySelector('[data-project-search]'); - if (searchInput) { - searchInput.focus(); - const len = searchInput.value.length; - try { searchInput.setSelectionRange(len, len); } catch (_e) { /* ignore */ } - } - } - } - return; - } - if (ev.target.matches('[data-import-markdown]')) { - const handler = ACTIONS['import-detect']; - if (handler) handler(ev, ev.target); - } - }); - - // change-event på import-modal-dropdown trigger preview-refresh. - document.addEventListener('change', function (ev) { - if (!ev.target || !ev.target.matches) return; - if (ev.target.matches('[data-import-command]')) { - projectViewRunDetect(); - } - }); - // ---- Step 8: copy-command + preview-command ---- ACTIONS['copy-command'] = function (ev, el) { diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/01-onboarding-empty-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/01-onboarding-empty-dark.png deleted file mode 100644 index 3441da8..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/01-onboarding-empty-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/01-onboarding-empty-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/01-onboarding-empty-light.png deleted file mode 100644 index 2166e22..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/01-onboarding-empty-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/02-project-rapporter-regulatory-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/02-project-rapporter-regulatory-dark.png deleted file mode 100644 index 55dd30f..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/02-project-rapporter-regulatory-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/02-project-rapporter-regulatory-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/02-project-rapporter-regulatory-light.png deleted file mode 100644 index 0eeb1f2..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/02-project-rapporter-regulatory-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-documentation-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-documentation-dark.png deleted file mode 100644 index 08f7597..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-documentation-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-documentation-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-documentation-light.png deleted file mode 100644 index 576c060..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-documentation-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-economy-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-economy-dark.png deleted file mode 100644 index 19c2b9c..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-economy-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-economy-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-economy-light.png deleted file mode 100644 index 45c909d..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-economy-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-security-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-security-dark.png deleted file mode 100644 index 8169f4b..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-security-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-security-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-security-light.png deleted file mode 100644 index da5d472..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-security-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-tool-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-tool-dark.png deleted file mode 100644 index 5457c74..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-tool-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-tool-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-tool-light.png deleted file mode 100644 index 97dc768..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/03-project-rapporter-tool-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/04-project-oversikt-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/04-project-oversikt-dark.png deleted file mode 100644 index bacc478..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/04-project-oversikt-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/04-project-oversikt-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/04-project-oversikt-light.png deleted file mode 100644 index 2438838..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/04-project-oversikt-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/05-project-kontekst-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/05-project-kontekst-dark.png deleted file mode 100644 index d0b2410..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/05-project-kontekst-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/05-project-kontekst-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/05-project-kontekst-light.png deleted file mode 100644 index 0f5da0f..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/05-project-kontekst-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/06-project-eksport-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/06-project-eksport-dark.png deleted file mode 100644 index ded331e..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/06-project-eksport-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/06-project-eksport-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/06-project-eksport-light.png deleted file mode 100644 index 09f1ab9..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/06-project-eksport-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/07-home-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/07-home-dark.png deleted file mode 100644 index 01d3caf..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/07-home-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/07-home-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/07-home-light.png deleted file mode 100644 index 5247ca3..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/07-home-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/08-catalog-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/08-catalog-dark.png deleted file mode 100644 index 90b8a87..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/08-catalog-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/08-catalog-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/08-catalog-light.png deleted file mode 100644 index ffebc40..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/08-catalog-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/09-onboarding-prefilled-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/09-onboarding-prefilled-dark.png deleted file mode 100644 index 009ecac..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/09-onboarding-prefilled-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/09-onboarding-prefilled-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.14.0/09-onboarding-prefilled-light.png deleted file mode 100644 index 2166e22..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.14.0/09-onboarding-prefilled-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/01-onboarding-empty-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/01-onboarding-empty-dark.png deleted file mode 100644 index a3ae5fa..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/01-onboarding-empty-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/01-onboarding-empty-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/01-onboarding-empty-light.png deleted file mode 100644 index 2166e22..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/01-onboarding-empty-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/02-project-overview-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/02-project-overview-dark.png deleted file mode 100644 index 0083a02..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/02-project-overview-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/02-project-overview-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/02-project-overview-light.png deleted file mode 100644 index 1279d74..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/02-project-overview-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/03-project-artifact-classify-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/03-project-artifact-classify-dark.png deleted file mode 100644 index 2f13e4f..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/03-project-artifact-classify-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/03-project-artifact-classify-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/03-project-artifact-classify-light.png deleted file mode 100644 index ce014d0..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/03-project-artifact-classify-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/04-project-artifact-security-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/04-project-artifact-security-dark.png deleted file mode 100644 index 69b26d5..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/04-project-artifact-security-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/04-project-artifact-security-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/04-project-artifact-security-light.png deleted file mode 100644 index 63943de..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/04-project-artifact-security-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/05-project-artifact-ros-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/05-project-artifact-ros-dark.png deleted file mode 100644 index 845a291..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/05-project-artifact-ros-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/05-project-artifact-ros-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/05-project-artifact-ros-light.png deleted file mode 100644 index 26eb802..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/05-project-artifact-ros-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/06-project-artifact-cost-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/06-project-artifact-cost-dark.png deleted file mode 100644 index 060ecf0..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/06-project-artifact-cost-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/06-project-artifact-cost-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/06-project-artifact-cost-light.png deleted file mode 100644 index 35d51c7..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/06-project-artifact-cost-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/07-project-artifact-summary-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/07-project-artifact-summary-dark.png deleted file mode 100644 index 3770d47..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/07-project-artifact-summary-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/07-project-artifact-summary-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/07-project-artifact-summary-light.png deleted file mode 100644 index 08673f0..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/07-project-artifact-summary-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/08-project-import-modal-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/08-project-import-modal-dark.png deleted file mode 100644 index 031c1f8..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/08-project-import-modal-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/08-project-import-modal-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/08-project-import-modal-light.png deleted file mode 100644 index 3e110fb..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/08-project-import-modal-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/09-project-search-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/09-project-search-dark.png deleted file mode 100644 index 7fff2c5..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/09-project-search-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/09-project-search-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/09-project-search-light.png deleted file mode 100644 index 1a9e64d..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/09-project-search-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/10-home-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/10-home-dark.png deleted file mode 100644 index 01d3caf..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/10-home-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/10-home-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/10-home-light.png deleted file mode 100644 index 5247ca3..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/10-home-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/11-catalog-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/11-catalog-dark.png deleted file mode 100644 index 90b8a87..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/11-catalog-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/11-catalog-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/11-catalog-light.png deleted file mode 100644 index ffebc40..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/11-catalog-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/12-onboarding-prefilled-dark.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/12-onboarding-prefilled-dark.png deleted file mode 100644 index 009ecac..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/12-onboarding-prefilled-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/12-onboarding-prefilled-light.png b/plugins/ms-ai-architect/playground/screenshots/v1.15.0/12-onboarding-prefilled-light.png deleted file mode 100644 index 2166e22..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v1.15.0/12-onboarding-prefilled-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/artifact-dark.png b/plugins/ms-ai-architect/playground/screenshots/v2-mockup/artifact-dark.png deleted file mode 100644 index 4a6d204..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/artifact-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/artifact-light.png b/plugins/ms-ai-architect/playground/screenshots/v2-mockup/artifact-light.png deleted file mode 100644 index ac29e75..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/artifact-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/empty-dark.png b/plugins/ms-ai-architect/playground/screenshots/v2-mockup/empty-dark.png deleted file mode 100644 index 22ebf60..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/empty-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/empty-light.png b/plugins/ms-ai-architect/playground/screenshots/v2-mockup/empty-light.png deleted file mode 100644 index ecd1e4a..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/empty-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/import-dark.png b/plugins/ms-ai-architect/playground/screenshots/v2-mockup/import-dark.png deleted file mode 100644 index 0e1fcdf..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/import-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/import-light.png b/plugins/ms-ai-architect/playground/screenshots/v2-mockup/import-light.png deleted file mode 100644 index c5a86d6..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/import-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/overview-dark.png b/plugins/ms-ai-architect/playground/screenshots/v2-mockup/overview-dark.png deleted file mode 100644 index 43835c3..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/overview-dark.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/overview-light.png b/plugins/ms-ai-architect/playground/screenshots/v2-mockup/overview-light.png deleted file mode 100644 index 3c85b04..0000000 Binary files a/plugins/ms-ai-architect/playground/screenshots/v2-mockup/overview-light.png and /dev/null differ diff --git a/plugins/ms-ai-architect/playground/vendor/playground-design-system/CHANGELOG.md b/plugins/ms-ai-architect/playground/vendor/playground-design-system/CHANGELOG.md index 3d489a7..8ae80b3 100644 --- a/plugins/ms-ai-architect/playground/vendor/playground-design-system/CHANGELOG.md +++ b/plugins/ms-ai-architect/playground/vendor/playground-design-system/CHANGELOG.md @@ -1,88 +1,5 @@ # playground-design-system — CHANGELOG -## 0.6.0 — 2026-05-15 - -### Added — Project-view archetype (Tier 4) - -Generic "project as artifact-collection" archetype for plugins where a project owns 0-N read-only report artifacts grouped by category. Default view is an aggregated dashboard; clicking a sidebar item swaps the main panel to the per-artifact render. Edit-mode is paste-import only (no inline editor). - -- **New file `components-tier4-project-view.css`** — 11 sections covering: - - `.project-view` + `.project-view__layout` (grid: nav 280px + main 1fr, responsive collapse at 1280 / 960px) - - `.project-view__header` (CSS Grid with eyebrow/title/lede/verdict/key-stats/actions areas) - - `.verdict-pill` (small pill variant — companion to existing `.verdict-pill-lg` in tier2) - - `.project-view__nav` + `.project-view__nav-search` (sticky sidebar with search) - - `.artifact-list` + `__group` / `__group-label` / `__group-count` / `__group-items` / `__item` / `__item-marker` / `__item-body` / `__item-name` / `__item-meta` (grouped, severity-coded sidebar) - - `.artifact-status[data-severity]` (mini-pill: positive | medium | critical) - - `.project-view__main` (main column container) - - `.project-overview` + `__intro` / `__verdict-grid` / `__verdict-tile[data-severity]` / `__section` / `__top-risks` / `__next-actions` / `__missing-reports` (aggregated dashboard) - - `.project-view__artifact` + `__artifact-header` / `__artifact-title` / `__artifact-meta` / `__artifact-actions` / `__artifact-body` (single-rapport viewer wrapper) - - `.empty-artifact-prompt` + `__icon` / `__title` / `__text` / `__actions` (empty-state) - - `.import-modal` + `__backdrop` / `__panel` / `__head` / `__title` / `__close` / `__form` / `__detect` / `__preview` / `__preview-label` / `__footer` (overlay modal for paste-import) - -- **6 new tokens in `tokens.css`:** - - `--project-view-nav-width: 280px` — sidebar width at full layout - - `--project-view-collapse-bp: 960px` — doc-only token referenced by responsive breakpoints - - `--artifact-list-item-pad-y: var(--space-2)` — sidebar row vertical padding - - `--artifact-list-item-pad-x: var(--space-3)` — sidebar row horizontal padding - - `--artifact-marker-size: 14px` — sidebar status marker diameter - - `--artifact-marker-border: 1.5px` — sidebar status marker border thickness - -### Påvirkning - -Endringen er **additiv**: ny komponent-fil + 6 nye tokens, ingen eksisterende selectors eller verdier endres. Plugin-konsumenter (`ms-ai-architect`, `llm-security`, `okr`, `config-audit`, `voyage`) får silent drift mot ny source-commit, men kan re-sync på eget tempo. Bare `ms-ai-architect` og `llm-security` re-syncer i samme commit som denne DS-bumpen (forberedelse til koordinert v1.15.0 / v7.7.0-release etter ~8 sesjoner med JS-implementasjon). - -Førsteadoptere: `ms-ai-architect` v1.15.0 (17 artefakter, 5 kategorier) + `llm-security` v7.7.0 (≥18 artefakter, 6 kategorier). State-driven visibility håndteres i plugin-JS, ikke i denne CSS-en — kun aktiv state rendres per pass. - -### Plugins som må laste den nye filen - -Etter `` til `components-tier3-supplement.css`, legg til: - -```html - -``` - -### For å adoptere v0.6.0 - -```bash -node scripts/sync-design-system.mjs -# --force hvis drift detected -``` - -## 0.5.0 — 2026-05-10 - -### Added -- **voyage scope tokens (B-DS-4):** `--color-scope-voyage` (aqua-blue `#1B5FB8`), `--color-scope-voyage-soft` (`#E5EFFA`), `--color-scope-voyage-strong` (`#143E78`) appended to scope-color group in `tokens.css`. Matches the existing `--color-scope-{architect,okr,security,ultraplan,config}` family so voyage-playground can use the canonical badge convention. -- **`.badge--scope-voyage`** in `base.css`: white-on-aqua-blue badge variant matching the existing scope-badge family. - -### Påvirkning - -Endringen er **additiv**: legger TIL voyage-scope-tokens og en ny badge-modifier. Ingen eksisterende selectors eller token-verdier endres. Plugin-konsumenter (llm-security, ms-ai-architect, okr, config-audit) får stale vendor-state mot ny source-commit, men det er silent drift — re-sync skjer på eget tempo neste playground-touch. Bare `voyage` re-syncer i denne commit-en. - -Førsteadopter: `voyage` v4.3.0 (multi-sesjons-løp 2026-05-10, sesjon 1 = Wave 0+1 Foundation). - -## 0.4.0 — 2026-05-08 - -### Bug fixes -- **`.kanban-card__name`** (components-tier3-supplement.css): bytt `word-break: break-all` til `word-break: break-word` + `overflow-wrap: anywhere`. `break-all` knekker midt i ord ("Tekn isk dokumen tasjon"); ny verdi respekterer ordskjøt og brytter kun lange tokens (B-DS-1). -- **`.expansion__title-main`, `.expansion__title-sub`** (components-tier3-supplement.css): legg til `display: block`. Begge er ``-elementer som flyter inline by default, noe som gir "dokumentertKilde: Art. 9" på samme linje. `display: block` sikrer vertikal stacking (B-DS-2). -- **`.matrix__bubble`** (components.css): legg til `cursor: pointer`, `transition`, `:hover { transform: scale(1.15) }` og `:focus-visible { outline + offset }`. Antar at consumer rendrer bobler som `