From a44a2efae72c11e9a32142a8836a0872619cb165 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Thu, 23 Apr 2026 10:28:46 +0200 Subject: [PATCH] add format engine packages: jovial_svg, markdown, html_core (D-058) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three format engines adopted per the new D-058 rule (format engines clear the dependency bar; UI chrome stays in-house): - jovial_svg 1.1.26 (BSD-3) — SVG renderer via CustomPaint - markdown 7.2.2 (BSD-3) — GFM parser; renderer is ours - flutter_widget_from_html_core 0.17.2 (MIT) — HTML renderer Welcome screen now loads logo.svg via jovial_svg instead of a raster PNG. POLICY.md updated with format engine rule. All three documented in licenses.yaml. Co-Authored-By: Claude Opus 4.6 (1M context) --- POLICY.md | 1 + assets/licenses.yaml | 33 +++++++++++ decisions/tooling.md | 10 ++++ lib/builtin/welcome/src/welcome_view.dart | 10 +++- pubspec.lock | 72 +++++++++++++++++++++++ pubspec.yaml | 6 ++ 6 files changed, 131 insertions(+), 1 deletion(-) diff --git a/POLICY.md b/POLICY.md index 69d90df0..c4b83215 100644 --- a/POLICY.md +++ b/POLICY.md @@ -63,6 +63,7 @@ This is not a preference. It is the project's architectural stance, documented i - **Prefer inlining over depending.** If a package is small and does one thing we need, copy the relevant code (with attribution) rather than taking on the dependency. License permitting, this is usually the right call for utilities under a few hundred lines. - **Prefer vendoring over fetching.** When a dependency is unavoidable and small enough to own, fork it into the repo and maintain it ourselves. The dep graph stops at our fence. - **Reject deep trees.** A direct dependency that itself has fifteen transitive dependencies is fifteen dependencies we are taking on, not one. Evaluate the whole subtree, not just the top. +- **Format engines clear the bar.** Packages that parse or render external file formats (SVG, markdown, HTML, terminal escapes, tree-sitter grammars) are adoptable — they are not shortcuts for lazy coding but maintained renderers for specs we didn't write. The distinction: UI chrome (panels, tabs, canvas, layout) we own; someone else's file format we adopt and sandbox. See D-058. ### Every dependency is audited diff --git a/assets/licenses.yaml b/assets/licenses.yaml index d4fd781c..bc313864 100644 --- a/assets/licenses.yaml +++ b/assets/licenses.yaml @@ -142,6 +142,39 @@ dependencies: wasmtime engine. Source repos are tree-sitter/tree-sitter- on GitHub; sqlite is dhcmrlchtdj/tree-sitter-sqlite (MIT). + - name: jovial_svg + kind: dart-package + version: "1.1.26" + homepage: https://pub.dev/packages/jovial_svg + license: BSD-3-Clause + purpose: >- + SVG renderer. CustomPaint-based — parses SVG at runtime into + a DAG of drawing commands and renders via Canvas. Used for + workspace SVG files and the app icon. Format engine, not UI + chrome. + + - name: markdown + kind: dart-package + version: "7.2.2" + homepage: https://pub.dev/packages/markdown + license: BSD-3-Clause + purpose: >- + Markdown parser (AST only). Parses GFM (tables, task lists, + fenced code blocks) into a node tree. Clide owns the renderer + — walks the AST to produce Flutter widgets with tree-sitter + syntax highlighting in code blocks. + + - name: flutter_widget_from_html_core + kind: dart-package + version: "0.17.2" + homepage: https://pub.dev/packages/flutter_widget_from_html_core + license: MIT + purpose: >- + HTML-to-widget renderer. Parses HTML into Flutter widgets + with no JavaScript execution. Used for rendering HTML content + in the viewer. Sandboxed — tag/attribute whitelist enforced + at usage site. + # Build-time-only dependencies — test runners, mocks, lints. Tracked # here for audit completeness; NOT rendered in the About screen. dev_dependencies: diff --git a/decisions/tooling.md b/decisions/tooling.md index 4e1a5ff0..80f6e9f6 100644 --- a/decisions/tooling.md +++ b/decisions/tooling.md @@ -32,4 +32,14 @@ Toolchain, supply chain, CI, ignore strategy. - **Cost:** Script names have a convention to follow. - **Raised by:** 2026-04-21 planning (caught during commit rehearsal). +### D-058: Format engines are adoptable dependencies +- **Date:** 2026-04-23 +- **Decision:** The "own the rendering stack" guardrail applies to **UI chrome** — panels, tabs, panes, canvas, terminal, layout primitives. **Format engines** — packages that parse or render external file formats (SVG, markdown, HTML, terminal escape sequences, tree-sitter grammars) — are adoptable like any other dependency: vet, exact-pin, CVE-lock, document in `licenses.yaml`. They are not shortcuts for lazy coding; they are well-maintained renderers for formats we didn't invent. The distinction: if it renders *our* UI, we own it; if it renders *someone else's file format*, we adopt a parser/renderer and sandbox it. +- **Adopted under this rule:** `jovial_svg` (SVG renderer), `markdown` (MD parser; renderer is ours), `flutter_widget_from_html_core` (HTML renderer; sandboxed), `xterm` (terminal emulator), tree-sitter (syntax highlighting). Canvas (`CustomPaint` + `InteractiveViewer`) stays in-house — UI chrome, not a format engine. +- **Amendment to D-031 (prefer-zero-deps):** D-031's "prefer-zero-deps" still applies — every new dependency needs justification. This record clarifies that format engines clear the justification bar by default. The supply-chain gate (exact-pin, advisory review, `licenses.yaml`) still applies. +- **Rationale:** Reimplementing SVG, markdown, or VT100 parsing adds months of work for no fidelity gain. tree-sitter already set this precedent. The key is sandboxing: HTML rendering must whitelist tags/attributes; SVG must not execute scripts; markdown rendering goes through our own widget builder so we control the output. +- **Cost:** Each adopted engine adds transitive dependencies and supply-chain surface. Mitigated by exact-pinning and `make security`. +- **Cross-reference:** [D-031](#d-031-prefer-zero-deps-exact-pin), [D-042](#d-042-dependencies-documented-in-licensesyaml). +- **Raised by:** 2026-04-23 format engine evaluation. + --- diff --git a/lib/builtin/welcome/src/welcome_view.dart b/lib/builtin/welcome/src/welcome_view.dart index 49343e15..fe66a902 100644 --- a/lib/builtin/welcome/src/welcome_view.dart +++ b/lib/builtin/welcome/src/welcome_view.dart @@ -2,7 +2,9 @@ import 'dart:async'; import 'package:clide/kernel/kernel.dart'; import 'package:clide/widgets/widgets.dart'; +import 'package:flutter/services.dart' show rootBundle; import 'package:flutter/widgets.dart'; +import 'package:jovial_svg/jovial_svg.dart'; class WelcomeView extends StatelessWidget { const WelcomeView({super.key}); @@ -54,7 +56,13 @@ class _Header extends StatelessWidget { return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Image.asset('assets/logo/logo-192.png', width: 72, height: 72), + SizedBox( + width: 72, + height: 72, + child: ScalableImageWidget.fromSISource( + si: ScalableImageSource.fromSvg(rootBundle, 'assets/logo/logo.svg'), + ), + ), const SizedBox(width: 24), Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/pubspec.lock b/pubspec.lock index 66799e1b..2e4efbe9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -105,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" equatable: dependency: transitive description: @@ -160,6 +168,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_widget_from_html_core: + dependency: "direct main" + description: + name: flutter_widget_from_html_core + sha256: "7ff010b116f6abc16429923e616fbc727f3f65ef4cee12ffdb280aeecbc21e7f" + url: "https://pub.dev" + source: hosted + version: "0.17.2" frontend_server_client: dependency: transitive description: @@ -181,6 +197,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" + http: + dependency: transitive + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" http_multi_server: dependency: transitive description: @@ -210,6 +242,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + jovial_misc: + dependency: transitive + description: + name: jovial_misc + sha256: "4301011027d87b8b919cb862db84071a34448eadbb32cc8d40fe505424dfe69a" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + jovial_svg: + dependency: "direct main" + description: + name: jovial_svg + sha256: a3cab3d46dc8df80cf0792e5e4246cbe13287542d9a357007114b1057da2fe89 + url: "https://pub.dev" + source: hosted + version: "1.1.26" leak_tracker: dependency: transitive description: @@ -250,6 +298,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + markdown: + dependency: "direct main" + description: + name: markdown + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + url: "https://pub.dev" + source: hosted + version: "7.2.2" matcher: dependency: transitive description: @@ -314,6 +370,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" + url: "https://pub.dev" + source: hosted + version: "7.0.2" platform: dependency: transitive description: @@ -551,6 +615,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" xterm: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index dbbc0856..8b22cd92 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,12 @@ dependencies: ffi: 2.1.3 + jovial_svg: 1.1.26 + + markdown: 7.2.2 + + flutter_widget_from_html_core: 0.17.2 + dev_dependencies: flutter_test: sdk: flutter