diff --git a/.gitignore b/.gitignore index 4645855..fd9f40d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,7 @@ __pycache__/ # Runtime state .memory/ *.log + +# omo runtime state written into the project .omo dir +thread-tools/ +senpi-task/ diff --git a/README.md b/README.md index b4ca769..4e90245 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,36 @@ # learn +> This fork is adapted for [omo.dev](https://omo.dev). The original pi version lives upstream at [amosblomqvist/learn](https://github.com/amosblomqvist/learn). + [![video](assets/thumbnail.png)](https://www.youtube.com/watch?v=kzcI5F4tGiU) My AI learning system from this video: [How I Use AI to Learn Things](https://www.youtube.com/watch?v=kzcI5F4tGiU). -This is a personal system I built for myself, shared as-is. Built as a pi configuration: the teaching philosophy encoded in a skill, a few small extensions, and agent definitions. +This is a personal system I built for myself, shared as-is. Built as a pi configuration: the teaching philosophy encoded in a skill, a few small extensions, and subagent briefs. ## What's in it -- `skills/teach/` — the philosophy and the process -- `skills/visualize/` — adds a correct, minimal diagram to a lesson when an idea is clearer as a picture +- `skills/teach/` — the philosophy and the process; `researcher.md` is the brief for the researcher subagent +- `skills/visualize/` — adds a correct, minimal diagram to a lesson when an idea is clearer as a picture; `mermaid-maker.md` and `svg-maker.md` are the briefs for the maker subagents - `extensions/ask-user-question/` — the agent asks you questions through a UI popup - `extensions/quiz/` — graded questions with instant feedback (✓/✗, correct answer, explanation) - `extensions/md-log/` — link a markdown file to the session -- `extensions/visual-tools/` — tools for visualization subagents -- `agents/` — `researcher`, `svg-maker`, `mermaid-maker`: the subagents the system delegates to ## Install -This repo **is** a `.pi` directory. From your learning project's root: +This repo **is** a `.omo` directory. From your learning project's root: ```bash -git clone https://github.com/amosblomqvist/learn .pi +git clone .omo ``` -Then open pi in that directory. (Or copy the pieces you want into your existing project config.) +Then open omo in that directory and trust the project when asked (project skills and extensions only load in trusted projects). ## Requirements -- [pi](https://github.com/earendil-works/pi) -- A subagent implementation, so the system can spawn the researcher and the visual makers. Recommended: [pi-interactive-subagents](https://github.com/amosblomqvist/pi-interactive-subagents) (tmux only). With it, everything works out of the box. Any other implementation works too, but expect to adapt the agent definitions, e.g. `agents/researcher.md` lists `safe_bash` in its tools, which is specific to that extension. +- [omo](https://github.com/code-yeongyu/oh-my-openagent). Subagents run through its built-in `task` tool, which spawns a worker that reads the brief file and follows it. +- The visual makers must run on a model that can see images; the skill dispatches them with `category="unspecified-high"`. Point that category at a vision-capable model in `omo.jsonc`. +- Rendering: `npx` (for `@mermaid-js/mermaid-cli`, which uses a puppeteer-managed Chrome) and `rsvg-convert` (or `nix shell nixpkgs#librsvg`, or ImageMagick as a fallback). - `ask-user-question` — use the copy bundled here. If your setup already has an `ask-user-question` extension, use **this** one in its place. Popups from different extensions serialize through a shared UI lock, which only works when it's the same implementation. ## Notes diff --git a/extensions/visual-tools/.gitignore b/extensions/visual-tools/.gitignore deleted file mode 100644 index c2658d7..0000000 --- a/extensions/visual-tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ diff --git a/extensions/visual-tools/index.ts b/extensions/visual-tools/index.ts deleted file mode 100644 index 961e2f2..0000000 --- a/extensions/visual-tools/index.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * visual-tools - * - * A self-contained pi extension that registers custom subagent tools with the - * globally-loaded `interactive-subagents` extension — and does nothing else: - * - * • write_mermaid / edit_mermaid / render_mermaid - * (tools/mermaid_tools.ts) — the mermaid-maker's authoring loop: write a - * Mermaid source, exact-match edit it, render whatever is currently in - * the managed file to a PNG (via the bundled @mermaid-js/mermaid-cli and - * an installed Chrome), return the PNG inline for inspection, and — when - * given `save_as` — publish it into /viz with a unique name. - * • write_svg / edit_svg / render_svg - * (tools/svg_tools.ts) — the svg-maker's authoring loop: same shape, but - * renders hand-written SVG to a PNG via rsvg-convert (fallback: magick). - * - * Each trio maps to ONE file so interactive-subagents loads it once and - * allow-lists all three names. - * - * ── How registration reaches interactive-subagents ────────────────────────── - * The global `interactive-subagents` extension exposes `registerToolExtension` - * on `globalThis.__pi_interactive_subagents`. A child subagent is launched with - * `--no-extensions` plus an explicit `-e ` only for tools whose name → - * path mapping it knows; this extension teaches it about the six names above so - * mermaid-maker / svg-maker (which list them in their `tools:` frontmatter) get - * them loaded into their child process. - * - * pi loads PROJECT-local extensions (this one) BEFORE global ones, so - * `globalThis.__pi_interactive_subagents` does not exist yet when this factory - * runs. We defer registration to `session_start`, which fires once after every - * extension's factory has run. Registration is idempotent (same name+path is a - * no-op), so `/reload` or a "reload"/"new"/"resume" session_start is harmless. - */ - -import type { ExtensionAPI } from "@earendil-works/pi-coding-agent" -import * as fs from "node:fs" -import * as path from "node:path" -import { fileURLToPath } from "node:url" - -const EXT_DIR = path.dirname(fileURLToPath(import.meta.url)) -const MERMAID_TOOLS = path.join(EXT_DIR, "tools", "mermaid_tools.ts") -const SVG_TOOLS = path.join(EXT_DIR, "tools", "svg_tools.ts") - -interface InteractiveSubagentsApi { - registerToolExtension: (name: string, extensionPath: string) => void -} - -function registerToolExtensions(): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const api = (globalThis as any).__pi_interactive_subagents as InteractiveSubagentsApi | undefined - if (!api?.registerToolExtension) return // interactive-subagents not loaded — no-op - - for (const [name, toolPath] of [ - ["write_mermaid", MERMAID_TOOLS], - ["edit_mermaid", MERMAID_TOOLS], - ["render_mermaid", MERMAID_TOOLS], - ["write_svg", SVG_TOOLS], - ["edit_svg", SVG_TOOLS], - ["render_svg", SVG_TOOLS], - ] as const) { - if (!fs.existsSync(toolPath)) continue - try { - api.registerToolExtension(name, toolPath) - } catch { - // Already registered under a different path, or re-registered — ignore. - } - } -} - -export default function (pi: ExtensionAPI) { - pi.on("session_start", async () => { - registerToolExtensions() - }) -} diff --git a/extensions/visual-tools/package-lock.json b/extensions/visual-tools/package-lock.json deleted file mode 100644 index 70592c8..0000000 --- a/extensions/visual-tools/package-lock.json +++ /dev/null @@ -1,2370 +0,0 @@ -{ - "name": "@learn/visual-tools", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@learn/visual-tools", - "version": "0.1.0", - "dependencies": { - "@mermaid-js/mermaid-cli": "^11.4.2" - }, - "devDependencies": { - "@earendil-works/pi-coding-agent": "file:/Users/amos/.nvm/versions/node/v24.14.0/lib/node_modules/@earendil-works/pi-coding-agent", - "@sinclair/typebox": "^0.34.0", - "typescript": "^5.5.0" - }, - "peerDependencies": { - "@earendil-works/pi-coding-agent": "*" - } - }, - "../../../../../../../../../../.nvm/versions/node/v24.14.0/lib/node_modules/@earendil-works/pi-coding-agent": { - "version": "0.80.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@earendil-works/pi-agent-core": "^0.80.3", - "@earendil-works/pi-ai": "^0.80.3", - "@earendil-works/pi-tui": "^0.80.3", - "@silvia-odwyer/photon-node": "0.3.4", - "chalk": "5.6.2", - "cross-spawn": "7.0.6", - "diff": "8.0.4", - "glob": "13.0.6", - "highlight.js": "10.7.3", - "hosted-git-info": "9.0.3", - "ignore": "7.0.5", - "jiti": "2.7.0", - "minimatch": "10.2.5", - "proper-lockfile": "4.1.2", - "semver": "7.8.0", - "typebox": "1.1.38", - "undici": "8.5.0", - "yaml": "2.9.0" - }, - "bin": { - "pi": "dist/cli.js" - }, - "devDependencies": { - "@types/cross-spawn": "6.0.6", - "@types/diff": "7.0.2", - "@types/hosted-git-info": "3.0.5", - "@types/ms": "2.1.0", - "@types/node": "24.12.4", - "@types/proper-lockfile": "4.1.4", - "@types/semver": "7.7.1", - "shx": "0.4.0", - "typescript": "5.9.3", - "vitest": "4.1.9" - }, - "engines": { - "node": ">=22.19.0" - }, - "optionalDependencies": { - "@mariozechner/clipboard": "0.3.9" - } - }, - "node_modules/@antfu/install-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", - "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", - "license": "MIT", - "dependencies": { - "package-manager-detector": "^1.3.0", - "tinyexec": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@braintree/sanitize-url": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", - "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", - "license": "MIT" - }, - "node_modules/@chevrotain/types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", - "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", - "license": "Apache-2.0" - }, - "node_modules/@earendil-works/pi-coding-agent": { - "resolved": "../../../../../../../../../../.nvm/versions/node/v24.14.0/lib/node_modules/@earendil-works/pi-coding-agent", - "link": true - }, - "node_modules/@floating-ui/core": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", - "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.12" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", - "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.8.0", - "@floating-ui/utils": "^0.2.12" - } - }, - "node_modules/@floating-ui/react": { - "version": "0.27.20", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.20.tgz", - "integrity": "sha512-CMqMy7OaXl9W0eq1Uy7L7i2Y/anPvHmFmESd2CEw0t5YvZhcVCeo4MBevAmswRllX7Y2dEidA4ozGPunLSTQpw==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.1.9", - "@floating-ui/utils": "^0.2.12", - "tabbable": "^6.0.0" - }, - "peerDependencies": { - "react": ">=17.0.0", - "react-dom": ">=17.0.0" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", - "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", - "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.8.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", - "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", - "license": "MIT" - }, - "node_modules/@fortawesome/fontawesome-free": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.3.0.tgz", - "integrity": "sha512-Yw4Qa43P6e4Xwh0TwEUkHQNRJInWaqIBo73VJmns3j2AIlZPAvUcR4yGIxCPqPRCgyJ5KIVIalF/I1GxhZ/Kgw==", - "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", - "engines": { - "node": ">=6" - } - }, - "node_modules/@headlessui/react": { - "version": "2.2.10", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.10.tgz", - "integrity": "sha512-5pVLNK9wlpxTUTy9GpgbX/SdcRh+HBnPktjM2wbiLTH4p+2EPHBO1aoSryUCuKUIItdDWO9ITlhUL8UnUN/oIA==", - "license": "MIT", - "dependencies": { - "@floating-ui/react": "^0.26.16", - "@react-aria/focus": "^3.20.2", - "@react-aria/interactions": "^3.25.0", - "@tanstack/react-virtual": "^3.13.9", - "use-sync-external-store": "^1.5.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "react-dom": "^18 || ^19 || ^19.0.0-rc" - } - }, - "node_modules/@headlessui/react/node_modules/@floating-ui/react": { - "version": "0.26.28", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", - "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.1.2", - "@floating-ui/utils": "^0.2.8", - "tabbable": "^6.0.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@headlessui/tailwindcss": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz", - "integrity": "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "tailwindcss": "^3.0 || ^4.0" - } - }, - "node_modules/@iconify/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", - "license": "MIT" - }, - "node_modules/@iconify/utils": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.4.tgz", - "integrity": "sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==", - "license": "MIT", - "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@iconify/types": "^2.0.0", - "import-meta-resolve": "^4.2.0" - } - }, - "node_modules/@internationalized/date": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.2.tgz", - "integrity": "sha512-FY1Y+H64NDs+HAF6omlnWxm3mEpfgaCSWtL5l551ZZfImA+kGjPFgrnJrGjH6lfmLL0g8Z/mBu1R3kufeCp6Jw==", - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" - } - }, - "node_modules/@internationalized/number": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.7.tgz", - "integrity": "sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==", - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" - } - }, - "node_modules/@internationalized/string": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.2.9.tgz", - "integrity": "sha512-kzP/M/mbQxODlmOt4bIQZ2SBVUWUSqMLXooXixnX7noche8WHaQcA+nwFN1K2KCF/cp+LDUhcJsCicwkvhD1pg==", - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" - } - }, - "node_modules/@mermaid-js/layout-elk": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mermaid-js/layout-elk/-/layout-elk-0.2.2.tgz", - "integrity": "sha512-vnH3gtqfhyBiRVKNpT8iDENTw18q/OF0GF/SfYfHN43KZpu+6eZDEOMHTfNYAkpmUWJNgtRQFIS6BTc7vH/DYQ==", - "license": "MIT", - "dependencies": { - "d3": "^7.9.0", - "elkjs": "^0.9.3" - }, - "peerDependencies": { - "mermaid": "^11.0.2" - } - }, - "node_modules/@mermaid-js/layout-tidy-tree": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mermaid-js/layout-tidy-tree/-/layout-tidy-tree-0.2.2.tgz", - "integrity": "sha512-8RmjDXjKJBxqTS1mICStm8zWRM45fSzs0SOrkp28+KsOGS2YEMFMVTwwRU8CsC6M1L+pDYZVjf1m9AC1c9Wndg==", - "license": "MIT", - "optional": true, - "dependencies": { - "d3": "^7.9.0" - }, - "peerDependencies": { - "mermaid": "^11.0.2" - } - }, - "node_modules/@mermaid-js/mermaid-cli": { - "version": "11.16.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-11.16.0.tgz", - "integrity": "sha512-0InK2nbVIMtzVzCugmdvPkAuvS6wRUqU6Utntff1n8c7lgfRZAdhKY6PSKvcIK9nFmuOUzAgB5+x/XWcroZ7Zg==", - "license": "MIT", - "dependencies": { - "@fortawesome/fontawesome-free": "^6.0.0 || ^7.0.1", - "@mermaid-js/layout-elk": "^0.1.5 || ^0.2.0", - "@mermaid-js/mermaid-zenuml": "^0.2.0", - "chalk": "^5.0.1", - "commander": "^13.1.0", - "import-meta-resolve": "^4.1.0", - "katex": "^0.16.25", - "mermaid": "^11.14.0", - "p-limit": "^6.2.0" - }, - "bin": { - "mmdc": "src/cli.js" - }, - "engines": { - "node": "^18.19 || >=20.0" - }, - "optionalDependencies": { - "@mermaid-js/layout-tidy-tree": "^0.2.1" - }, - "peerDependencies": { - "puppeteer": "^23 || ^24 || ^25" - } - }, - "node_modules/@mermaid-js/mermaid-zenuml": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-zenuml/-/mermaid-zenuml-0.2.3.tgz", - "integrity": "sha512-RGBtgL6fc+5Y2Jm9odOH9HRJ80BP4l6atBYnAK5bBzEowF0PU3UtvZRRcbFxImPGPuLIzqZq31ur8lVO0AoF3Q==", - "license": "MIT", - "dependencies": { - "@zenuml/core": "^3.47.0" - }, - "peerDependencies": { - "mermaid": "^10 || ^11" - } - }, - "node_modules/@mermaid-js/parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.2.0.tgz", - "integrity": "sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==", - "license": "MIT", - "dependencies": { - "@chevrotain/types": "~11.1.2" - } - }, - "node_modules/@napi-rs/canvas": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.100.tgz", - "integrity": "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==", - "license": "MIT", - "optional": true, - "workspaces": [ - "e2e/*" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "0.1.100", - "@napi-rs/canvas-darwin-arm64": "0.1.100", - "@napi-rs/canvas-darwin-x64": "0.1.100", - "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", - "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", - "@napi-rs/canvas-linux-arm64-musl": "0.1.100", - "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", - "@napi-rs/canvas-linux-x64-gnu": "0.1.100", - "@napi-rs/canvas-linux-x64-musl": "0.1.100", - "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", - "@napi-rs/canvas-win32-x64-msvc": "0.1.100" - } - }, - "node_modules/@napi-rs/canvas-android-arm64": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz", - "integrity": "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz", - "integrity": "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz", - "integrity": "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz", - "integrity": "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz", - "integrity": "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz", - "integrity": "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz", - "integrity": "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz", - "integrity": "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz", - "integrity": "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-win32-arm64-msvc": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz", - "integrity": "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz", - "integrity": "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@puppeteer/browsers": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.0.6.tgz", - "integrity": "sha512-B/gKoqlFkzhvzsI6jo9K1cZz9o5ypviVv/xu8CwA4grZzyVwN+XfkT+tu8T1zrauuEXv6VhS2oGX+6NL95WcKA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "modern-tar": "^0.7.6", - "yargs": "^18.0.0" - }, - "bin": { - "browsers": "lib/main-cli.js" - }, - "engines": { - "node": ">=22.12.0" - }, - "peerDependencies": { - "proxy-agent": ">=8.0.1", - "yauzl": "^2.10.0 || ^3.4.0" - }, - "peerDependenciesMeta": { - "proxy-agent": { - "optional": true - }, - "yauzl": { - "optional": true - } - } - }, - "node_modules/@react-aria/focus": { - "version": "3.22.1", - "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.22.1.tgz", - "integrity": "sha512-CPxtkyrBi/HYY5P3lE/57sQ6qfa0lN8E55TOm89H0kNGv0lKt+/0zP7lWERzBjRr5IxBVrQX4gFEowBN52LPaA==", - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0", - "react-aria": "^3.48.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-aria/interactions": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.28.1.tgz", - "integrity": "sha512-Bqb+HrD5I5MHS2SKBhISYqo2SW8Y2dfzgF/Y1lIJq7xqLxheo9vzxPGEHhz+XzkgGfoqEJx8A6a3C7uiqS3HWA==", - "license": "Apache-2.0", - "dependencies": { - "@react-types/shared": "^3.34.0", - "@swc/helpers": "^0.5.0", - "react-aria": "^3.48.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-types/shared": { - "version": "3.36.0", - "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.0.tgz", - "integrity": "sha512-DkP/H0C2YjjS7gZWKNqOmU8a16qHPjQNdzMwmTq9SzplM6Iw0kVMTZ0OIoe6FOgGqa+FwMsE2QbPjh/n3g/jXQ==", - "license": "Apache-2.0", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.34.52", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", - "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@swc/helpers": { - "version": "0.5.23", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", - "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@tanstack/react-virtual": { - "version": "3.14.6", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.14.6.tgz", - "integrity": "sha512-4+Uq8m0/gzO4kMCHUEpTtGX1RnONK0C+g88b2ltwPMWUBiaVarBuWKoPJaz7gj1cKCVRAdyu+U8GcKhwCc2beA==", - "license": "MIT", - "dependencies": { - "@tanstack/virtual-core": "3.17.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@tanstack/virtual-core": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.4.tgz", - "integrity": "sha512-nGm5KteqxasUdThLc2izl6dHUqLv0LQj7Nuyo5gYalTPf/U8a9ermvsl7reT+6ioBW1l8WfpP/mcU338nLXpqw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@types/d3": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", - "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", - "license": "MIT", - "dependencies": { - "@types/d3-array": "*", - "@types/d3-axis": "*", - "@types/d3-brush": "*", - "@types/d3-chord": "*", - "@types/d3-color": "*", - "@types/d3-contour": "*", - "@types/d3-delaunay": "*", - "@types/d3-dispatch": "*", - "@types/d3-drag": "*", - "@types/d3-dsv": "*", - "@types/d3-ease": "*", - "@types/d3-fetch": "*", - "@types/d3-force": "*", - "@types/d3-format": "*", - "@types/d3-geo": "*", - "@types/d3-hierarchy": "*", - "@types/d3-interpolate": "*", - "@types/d3-path": "*", - "@types/d3-polygon": "*", - "@types/d3-quadtree": "*", - "@types/d3-random": "*", - "@types/d3-scale": "*", - "@types/d3-scale-chromatic": "*", - "@types/d3-selection": "*", - "@types/d3-shape": "*", - "@types/d3-time": "*", - "@types/d3-time-format": "*", - "@types/d3-timer": "*", - "@types/d3-transition": "*", - "@types/d3-zoom": "*" - } - }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", - "license": "MIT" - }, - "node_modules/@types/d3-axis": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", - "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", - "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-brush": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", - "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", - "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-chord": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", - "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "license": "MIT" - }, - "node_modules/@types/d3-contour": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", - "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", - "license": "MIT", - "dependencies": { - "@types/d3-array": "*", - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", - "license": "MIT" - }, - "node_modules/@types/d3-dispatch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", - "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", - "license": "MIT" - }, - "node_modules/@types/d3-drag": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", - "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", - "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-dsv": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", - "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", - "license": "MIT" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "license": "MIT" - }, - "node_modules/@types/d3-fetch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", - "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", - "license": "MIT", - "dependencies": { - "@types/d3-dsv": "*" - } - }, - "node_modules/@types/d3-force": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", - "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", - "license": "MIT" - }, - "node_modules/@types/d3-format": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", - "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", - "license": "MIT" - }, - "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", - "license": "MIT", - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-hierarchy": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", - "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", - "license": "MIT" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", - "license": "MIT", - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" - }, - "node_modules/@types/d3-polygon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", - "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", - "license": "MIT" - }, - "node_modules/@types/d3-quadtree": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", - "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", - "license": "MIT" - }, - "node_modules/@types/d3-random": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz", - "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==", - "license": "MIT" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", - "license": "MIT", - "dependencies": { - "@types/d3-time": "*" - } - }, - "node_modules/@types/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", - "license": "MIT" - }, - "node_modules/@types/d3-selection": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", - "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", - "license": "MIT" - }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", - "license": "MIT", - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" - }, - "node_modules/@types/d3-time-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", - "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" - }, - "node_modules/@types/d3-transition": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", - "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", - "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-zoom": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", - "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", - "license": "MIT", - "dependencies": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" - } - }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT" - }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT", - "optional": true - }, - "node_modules/@upsetjs/venn.js": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", - "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", - "license": "MIT", - "optionalDependencies": { - "d3-selection": "^3.0.0", - "d3-transition": "^3.0.1" - } - }, - "node_modules/@zenuml/core": { - "version": "3.50.1", - "resolved": "https://registry.npmjs.org/@zenuml/core/-/core-3.50.1.tgz", - "integrity": "sha512-Q18BXvIfhRuGw0JfO4e+pltG04Phhv2E7n35EWTNSZKKH/HEkyE4Sh7KERb9dqaOfjOdRdKvLG0YekjK3fcDXw==", - "license": "MIT", - "dependencies": { - "@floating-ui/react": "^0.27.16", - "@headlessui/react": "^2.2.9", - "@headlessui/tailwindcss": "^0.2.2", - "antlr4": "~4.11.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "color-string": "^2.1.4", - "dompurify": "^3.3.1", - "highlight.js": "^11.10.0", - "html-to-image": "^1.11.13", - "jotai": "^2.16.1", - "marked": "^4.3.0", - "react": "^19.2.3", - "react-dom": "^19.2.3", - "tailwind-merge": "^3.4.0" - }, - "bin": { - "zenuml": "dist/cli/zenuml.mjs" - }, - "engines": { - "node": ">=20" - }, - "optionalDependencies": { - "@napi-rs/canvas": "^0.1.97" - }, - "peerDependencies": { - "playwright-core": "1.57.0" - }, - "peerDependenciesMeta": { - "playwright-core": { - "optional": true - } - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/antlr4": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.11.0.tgz", - "integrity": "sha512-GUGlpE2JUjAN+G8G5vY+nOoeyNhHsXoIJwP1XF1oRw89vifA1K46T6SEkwLwr7drihN7I/lf0DIjKc4OZvBX8w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=14" - } - }, - "node_modules/aria-hidden": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", - "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chromium-bidi": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-16.0.1.tgz", - "integrity": "sha512-J63PGu/9PpeCwLIcKYyzWP6yaVL5pxuBc0shlYCYM8BaAkmlwiQboXO1iNbOgSDbVklEyYFfNEcHD8oOAWacUA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "mitt": "^3.0.1", - "zod": "^3.24.1" - }, - "engines": { - "node": ">=20.19.0 <22.0.0 || >=22.12.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/class-variance-authority": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", - "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", - "license": "Apache-2.0", - "dependencies": { - "clsx": "^2.1.1" - }, - "funding": { - "url": "https://polar.sh/cva" - } - }, - "node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "license": "ISC", - "peer": true, - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/color-name": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", - "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", - "license": "MIT", - "engines": { - "node": ">=12.20" - } - }, - "node_modules/color-string": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", - "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", - "license": "MIT", - "dependencies": { - "color-name": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/cose-base": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", - "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", - "license": "MIT", - "dependencies": { - "layout-base": "^1.0.0" - } - }, - "node_modules/cytoscape": { - "version": "3.34.0", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz", - "integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/cytoscape-cose-bilkent": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", - "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", - "license": "MIT", - "dependencies": { - "cose-base": "^1.0.0" - }, - "peerDependencies": { - "cytoscape": "^3.2.0" - } - }, - "node_modules/cytoscape-fcose": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", - "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", - "license": "MIT", - "dependencies": { - "cose-base": "^2.2.0" - }, - "peerDependencies": { - "cytoscape": "^3.2.0" - } - }, - "node_modules/cytoscape-fcose/node_modules/cose-base": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", - "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", - "license": "MIT", - "dependencies": { - "layout-base": "^2.0.0" - } - }, - "node_modules/cytoscape-fcose/node_modules/layout-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", - "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", - "license": "MIT" - }, - "node_modules/d3": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", - "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", - "license": "ISC", - "dependencies": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "license": "ISC", - "dependencies": { - "d3-path": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-contour": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", - "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", - "license": "ISC", - "dependencies": { - "d3-array": "^3.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", - "license": "ISC", - "dependencies": { - "delaunator": "5" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "license": "ISC", - "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "license": "ISC", - "dependencies": { - "d3-dsv": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", - "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", - "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-sankey": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", - "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "1 - 2", - "d3-shape": "^1.2.0" - } - }, - "node_modules/d3-sankey/node_modules/d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "license": "BSD-3-Clause", - "dependencies": { - "internmap": "^1.0.0" - } - }, - "node_modules/d3-sankey/node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-sankey/node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/d3-sankey/node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", - "license": "ISC" - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dagre-d3-es": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", - "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", - "license": "MIT", - "dependencies": { - "d3": "^7.9.0", - "lodash-es": "^4.17.21" - } - }, - "node_modules/dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", - "license": "MIT" - }, - "node_modules/delaunator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", - "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", - "license": "ISC", - "dependencies": { - "robust-predicates": "^3.0.2" - } - }, - "node_modules/devtools-protocol": { - "version": "0.0.1638949", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1638949.tgz", - "integrity": "sha512-mXwg4Fqnv0WR4iuAT/gYUmctNkjILwXFHyZ+m7Ty1dfr0ezZt2U3gnrrJTfRobJTHoXf+IbuFvFITzLrLFjwJA==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/dompurify": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", - "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" - } - }, - "node_modules/elkjs": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz", - "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==", - "license": "EPL-2.0" - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT", - "peer": true - }, - "node_modules/es-toolkit": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.49.0.tgz", - "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "peer": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", - "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hachure-fill": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", - "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", - "license": "MIT" - }, - "node_modules/highlight.js": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", - "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/html-to-image": { - "version": "1.11.13", - "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz", - "integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==", - "license": "MIT" - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/import-meta-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/jotai": { - "version": "2.20.2", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.20.2.tgz", - "integrity": "sha512-aHB4CNb9qRcyf0mwSB6EO5bCGAjx8cTwFgOFCE2leOnTzqACbnSWG8XoWB3LxCT1Qoj03I1OWAHszDmN4uHb/w==", - "license": "MIT", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0", - "@babel/template": ">=7.0.0", - "@types/react": ">=17.0.0", - "react": ">=17.0.0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@babel/template": { - "optional": true - }, - "@types/react": { - "optional": true - }, - "react": { - "optional": true - } - } - }, - "node_modules/katex": { - "version": "0.16.47", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", - "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" - ], - "license": "MIT", - "dependencies": { - "commander": "^8.3.0" - }, - "bin": { - "katex": "cli.js" - } - }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/khroma": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", - "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" - }, - "node_modules/layout-base": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", - "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", - "license": "MIT" - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lodash-es": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", - "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", - "license": "MIT" - }, - "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/mermaid": { - "version": "11.16.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.16.0.tgz", - "integrity": "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==", - "license": "MIT", - "dependencies": { - "@braintree/sanitize-url": "^7.1.2", - "@iconify/utils": "^3.0.2", - "@mermaid-js/parser": "^1.2.0", - "@types/d3": "^7.4.3", - "@upsetjs/venn.js": "^2.0.0", - "cytoscape": "^3.33.3", - "cytoscape-cose-bilkent": "^4.1.0", - "cytoscape-fcose": "^2.2.0", - "d3": "^7.9.0", - "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.14", - "dayjs": "^1.11.20", - "dompurify": "^3.3.3", - "es-toolkit": "^1.45.1", - "katex": "^0.16.45", - "khroma": "^2.1.0", - "marked": "^16.3.0", - "roughjs": "^4.6.6", - "stylis": "^4.3.6", - "ts-dedent": "^2.2.0", - "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" - } - }, - "node_modules/mermaid/node_modules/marked": { - "version": "16.4.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", - "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "license": "MIT", - "peer": true - }, - "node_modules/modern-tar": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.6.tgz", - "integrity": "sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/p-limit": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", - "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.1.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-manager-detector": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.7.0.tgz", - "integrity": "sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==", - "license": "MIT" - }, - "node_modules/path-data-parser": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", - "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", - "license": "MIT" - }, - "node_modules/points-on-curve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", - "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", - "license": "MIT" - }, - "node_modules/points-on-path": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", - "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", - "license": "MIT", - "dependencies": { - "path-data-parser": "0.1.0", - "points-on-curve": "0.2.0" - } - }, - "node_modules/puppeteer": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-25.3.0.tgz", - "integrity": "sha512-O1tx8S315aw8eI99HZ5ZNcVEzJ9+jKF//eO5UvfZ3cXJ6okZ5sX3Y50u7DJaM+ewEK4LqXP068tBhfRaWikj+g==", - "hasInstallScript": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@puppeteer/browsers": "3.0.6", - "chromium-bidi": "16.0.1", - "devtools-protocol": "0.0.1638949", - "lilconfig": "^3.1.3", - "puppeteer-core": "25.3.0", - "typed-query-selector": "^2.12.2" - }, - "bin": { - "puppeteer": "lib/puppeteer/node/cli.js" - }, - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/puppeteer-core": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.3.0.tgz", - "integrity": "sha512-fm+wpUr2oigH1PXZvwgATrM2tYWHMDG8ASzTEe9uukCye4X5Ldx1K5BTHPFKITrIWvQQAQ256d1NpbEveBcKjA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@puppeteer/browsers": "3.0.6", - "chromium-bidi": "16.0.1", - "devtools-protocol": "0.0.1638949", - "typed-query-selector": "^2.12.2", - "webdriver-bidi-protocol": "0.4.2", - "ws": "^8.21.0" - }, - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-aria": { - "version": "3.50.0", - "resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.50.0.tgz", - "integrity": "sha512-S0Os6QZk33fzUAKu1QLT9afoUaCBt1ZNdoiq0n2YMVgKIdNIQS8zxiZ8O9hYE6QyDkHKjD6q39LQZ+qaSAIgjw==", - "license": "Apache-2.0", - "dependencies": { - "@internationalized/date": "^3.12.2", - "@internationalized/number": "^3.6.7", - "@internationalized/string": "^3.2.9", - "@react-types/shared": "^3.36.0", - "@swc/helpers": "^0.5.0", - "aria-hidden": "^1.2.3", - "clsx": "^2.0.0", - "react-stately": "3.48.0", - "use-sync-external-store": "^1.6.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.7" - } - }, - "node_modules/react-stately": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.48.0.tgz", - "integrity": "sha512-ImicSAG+lTotAe5izcs1fz49Zk48w7pDusqYg04WaPhCoej8BJ24soMu3iLXIrsi273s4P1gZrYGrqReMfgEEA==", - "license": "Apache-2.0", - "dependencies": { - "@internationalized/date": "^3.12.2", - "@internationalized/number": "^3.6.7", - "@internationalized/string": "^3.2.9", - "@react-types/shared": "^3.36.0", - "@swc/helpers": "^0.5.0", - "use-sync-external-store": "^1.6.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/robust-predicates": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", - "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", - "license": "Unlicense" - }, - "node_modules/roughjs": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", - "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", - "license": "MIT", - "dependencies": { - "hachure-fill": "^0.5.2", - "path-data-parser": "^0.1.0", - "points-on-curve": "^0.2.0", - "points-on-path": "^0.2.1" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/stylis": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", - "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", - "license": "MIT" - }, - "node_modules/tabbable": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz", - "integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==", - "license": "MIT" - }, - "node_modules/tailwind-merge": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", - "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwindcss": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", - "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", - "license": "MIT", - "peer": true - }, - "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/ts-dedent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", - "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", - "license": "MIT", - "engines": { - "node": ">=6.10" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/typed-query-selector": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz", - "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==", - "license": "MIT", - "peer": true - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/uuid": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", - "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, - "node_modules/webdriver-bidi-protocol": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.2.tgz", - "integrity": "sha512-VSV+fzfChirL3e7jay2yUC7B4HQCGtEWEg/MSSQbK+qWbqeGlRLlXTzPpYr3XGUvbpDHumWZBJxgesg4N7dbtA==", - "license": "Apache-2.0", - "peer": true - }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/ws": { - "version": "8.21.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", - "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", - "license": "MIT", - "peer": true, - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", - "license": "ISC", - "peer": true, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/extensions/visual-tools/package.json b/extensions/visual-tools/package.json deleted file mode 100644 index 61f34af..0000000 --- a/extensions/visual-tools/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@learn/visual-tools", - "version": "0.1.0", - "description": "visual-tools: custom subagent tools (write/edit/render for Mermaid and SVG) for the interactive-subagents extension.", - "type": "module", - "private": true, - "dependencies": { - "@mermaid-js/mermaid-cli": "^11.4.2" - }, - "devDependencies": { - "@earendil-works/pi-coding-agent": "file:/Users/amos/.nvm/versions/node/v24.14.0/lib/node_modules/@earendil-works/pi-coding-agent", - "@sinclair/typebox": "^0.34.0", - "typescript": "^5.5.0" - }, - "peerDependencies": { - "@earendil-works/pi-coding-agent": "*" - } -} diff --git a/extensions/visual-tools/tools/_common.ts b/extensions/visual-tools/tools/_common.ts deleted file mode 100644 index 2ba3ae5..0000000 --- a/extensions/visual-tools/tools/_common.ts +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Shared helpers for the visual-tools authoring loops (mermaid_tools.ts, - * svg_tools.ts): a subprocess runner, a per-session managed source file, an - * exact-match editor (pi-edit semantics), and publishing a chosen render into - * /viz with a unique filename. - * - * Each tool file keeps its OWN session state (importing the type/helpers here), - * so mermaid and svg never share a source file. - */ - -import { spawn } from "node:child_process" -import { tmpdir } from "node:os" -import { basename, dirname, join } from "node:path" -import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs" - -// rsvg-convert lives under MacPorts (/opt/local/bin); magick/gs under -// /usr/local/bin; Homebrew under /opt/homebrew/bin. Augment PATH so the child -// pi process (which may have inherited a thin PATH) still resolves them. -export const EXTRA_PATH = ["/opt/local/bin", "/usr/local/bin", "/opt/homebrew/bin"] - -// Transient session/preview files live under the OS temp dir (NOT the vault), -// so only the PUBLISHED PNG ever lands inside the Obsidian vault (viz/). -export const STAGING_ROOT = join(tmpdir(), "pi-visual-tools") -export const FILES_DIRNAME = "viz" - -export const CHROME_CANDIDATES = [ - "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", - "/Applications/Chromium.app/Contents/MacOS/Chromium", -] - -export function findChrome(): string | undefined { - for (const c of CHROME_CANDIDATES) if (existsSync(c)) return c - return undefined -} - -export interface RunResult { - code: number | null - stdout: string - stderr: string - timedOut: boolean -} - -export function run( - cmd: string, - args: string[], - opts: { cwd: string; timeoutMs: number; env?: Record }, -): Promise { - return new Promise((resolveRun) => { - const augmentedPath = [...EXTRA_PATH, process.env.PATH ?? ""].join(":") - const child = spawn(cmd, args, { - cwd: opts.cwd, - env: { ...process.env, ...(opts.env ?? {}), PATH: augmentedPath }, - }) - let stdout = "" - let stderr = "" - let timedOut = false - const timer = setTimeout(() => { - timedOut = true - child.kill("SIGKILL") - }, opts.timeoutMs) - child.stdout.on("data", (d) => (stdout += d.toString())) - child.stderr.on("data", (d) => (stderr += d.toString())) - child.on("error", (err) => { - clearTimeout(timer) - resolveRun({ code: null, stdout, stderr: stderr + String(err), timedOut }) - }) - child.on("close", (code) => { - clearTimeout(timer) - resolveRun({ code, stdout, stderr, timedOut }) - }) - }) -} - -/** Per-session managed source file, one per child pi process (pid-keyed). */ -export interface Session { - workDir: string - bodyPath: string -} - -/** Per-session work dir under the OS temp dir, keyed by pid + a group name. */ -export function sessionDir(group: string): string { - return join(STAGING_ROOT, `${group}-${process.pid}`) -} - -/** Write the full source to the managed file, creating the session work dir. */ -export function writeBody(group: string, bodyFileName: string, source: string): Session { - const workDir = sessionDir(group) - mkdirSync(workDir, { recursive: true }) - const bodyPath = join(workDir, bodyFileName) - writeFileSync(bodyPath, source, "utf8") - return { workDir, bodyPath } -} - -/** - * Exact-match single replacement on the current source, matching pi's built-in - * edit: old_text must appear exactly once. Returns the updated content and the - * match offset, or throws a precise error. - */ -export function applyEdit(current: string, oldText: string, newText: string): { updated: string; index: number } { - if (oldText === "") throw new Error("`old_text` must be non-empty.") - if (oldText === newText) throw new Error("`old_text` and `new_text` are identical.") - const first = current.indexOf(oldText) - if (first === -1) { - throw new Error("`old_text` not found in the current source — match it exactly.") - } - const second = current.indexOf(oldText, first + 1) - if (second !== -1) { - let n = 0 - let i = current.indexOf(oldText) - while (i !== -1) { - n++ - i = current.indexOf(oldText, i + oldText.length) - } - throw new Error(`\`old_text\` appears ${n} times — add surrounding context to make it unique.`) - } - const updated = current.slice(0, first) + newText + current.slice(first + oldText.length) - return { updated, index: first } -} - -/** A small numbered window of `content` around char offset `index`. */ -export function snippetAround(content: string, index: number, contextLines = 3): string { - const before = content.slice(0, index) - const hitLine = before.split("\n").length - 1 - const lines = content.split("\n") - const start = Math.max(0, hitLine - contextLines) - const end = Math.min(lines.length - 1, hitLine + contextLines) - const width = String(end + 1).length - const out: string[] = [] - for (let i = start; i <= end; i++) out.push(`${String(i + 1).padStart(width)} ${lines[i]}`) - return out.join("\n") -} - -/** Copy a rendered PNG into /viz with a unique, slugified name. */ -export function publish(pngPath: string, slug: string): { filename: string; path: string } { - const filesDir = join(process.cwd(), FILES_DIRNAME) - mkdirSync(filesDir, { recursive: true }) - const clean = - slug - .toLowerCase() - .replace(/[^a-z0-9]+/g, "-") - .replace(/^-+|-+$/g, "") || "viz" - const filename = `viz-${clean}-${Date.now()}.png` - const dest = join(filesDir, filename) - copyFileSync(pngPath, dest) - return { filename, path: dest } -} - -export { basename, dirname, join, existsSync, mkdirSync, readFileSync, writeFileSync } diff --git a/extensions/visual-tools/tools/mermaid_tools.ts b/extensions/visual-tools/tools/mermaid_tools.ts deleted file mode 100644 index 318aa81..0000000 --- a/extensions/visual-tools/tools/mermaid_tools.ts +++ /dev/null @@ -1,197 +0,0 @@ -/** - * Mermaid authoring loop for the mermaid-maker subagent — three tools that - * share one session-scoped source file: - * - * write_mermaid — write the full Mermaid source to the session's file - * edit_mermaid — exact-match old_text→new_text on that file (pi-edit semantics) - * render_mermaid — render whatever is in the file → PNG, returned inline; - * with `save_as`, also publish it into /viz - * - * Bundled inside the visual-tools extension and exposed to subagents via the - * interactive-subagents `registerToolExtension` hook (see ../index.ts). NOT a - * global pi extension — loaded by the spawned child pi process for any subagent - * whose `tools:` frontmatter includes these names (currently just - * mermaid-maker). All three names map to this one file. - * - * Rendering shells out to the bundled @mermaid-js/mermaid-cli (`mmdc`) with a - * puppeteer config pointing at an installed Chrome, so no Chromium download is - * needed. Module-level session state persists across this child process's tool - * calls and is naturally isolated from any parallel maker (different process). - */ - -import type { ExtensionAPI } from "@earendil-works/pi-coding-agent" -import { Type } from "@sinclair/typebox" -import { fileURLToPath } from "node:url" -import { - applyEdit, - dirname, - existsSync, - findChrome, - join, - mkdirSync, - publish, - readFileSync, - run, - type Session, - snippetAround, - writeBody, - writeFileSync, -} from "./_common.ts" - -const TOOL_DIR = dirname(fileURLToPath(import.meta.url)) -const EXTENSION_DIR = dirname(TOOL_DIR) -const MMDC_BIN = join(EXTENSION_DIR, "node_modules", ".bin", "mmdc") -const GROUP = "mermaid" -const BODY_FILE = "diagram.mmd" -const RENDER_TIMEOUT_MS = 120_000 - -type RenderDetails = { ok: boolean; path: string; filename?: string } - -let session: Session | null = null - -export default function mermaidToolsExtension(pi: ExtensionAPI) { - // ── write_mermaid ────────────────────────────────────────────────────────── - pi.registerTool({ - name: "write_mermaid", - label: "Write Mermaid", - description: - "Write the FULL Mermaid source to this session's managed file (your first " + - "draft or a complete rewrite). You do NOT name the file — edit_mermaid and " + - "render_mermaid act on the same one.\n\n" + - "`source` is a complete Mermaid diagram, e.g. a `graph TD` / `graph LR` " + - "flow, `sequenceDiagram`, `stateDiagram-v2`, `erDiagram`, `classDiagram`, " + - "`mindmap`, or `timeline`. Writing does NOT render — call render_mermaid " + - "when ready. For a small fix, prefer edit_mermaid over rewriting.", - parameters: Type.Object({ - source: Type.String({ - description: "The complete Mermaid diagram source (starts with the diagram type, e.g. `graph TD`).", - }), - }), - async execute(_id, params) { - const source = (params.source ?? "").trim() - if (!source) throw new Error("`write_mermaid` requires a non-empty `source`.") - session = writeBody(GROUP, BODY_FILE, source) - const lines = source.split("\n").length - return { - content: [ - { - type: "text", - text: `Wrote ${lines}-line Mermaid source.\nCall render_mermaid to render it, or edit_mermaid to tweak it.`, - }, - ], - details: { ok: true, path: session.bodyPath, lines }, - } - }, - }) - - // ── edit_mermaid ─────────────────────────────────────────────────────────── - pi.registerTool({ - name: "edit_mermaid", - label: "Edit Mermaid", - description: - "Make a single exact-match replacement in this session's Mermaid source — " + - "the same contract as pi's built-in edit, locked to the one managed file. " + - "`old_text` must appear EXACTLY ONCE (include surrounding context for " + - "uniqueness); on 0 or >1 matches the call fails and nothing changes. Call " + - "write_mermaid first. Editing does NOT render.", - parameters: Type.Object({ - old_text: Type.String({ description: "Exact substring of the current source to replace (must match once)." }), - new_text: Type.String({ description: "Replacement text for `old_text`." }), - }), - async execute(_id, params) { - if (!session || !existsSync(session.bodyPath)) { - throw new Error("edit_mermaid: no source yet — call write_mermaid first.") - } - const current = readFileSync(session.bodyPath, "utf8") - const { updated, index } = applyEdit(current, String(params.old_text ?? ""), String(params.new_text ?? "")) - writeFileSync(session.bodyPath, updated, "utf8") - return { - content: [ - { type: "text", text: "Applied edit. Updated region:\n```\n" + snippetAround(updated, index) + "\n```\nCall render_mermaid to see it." }, - ], - details: { ok: true, path: session.bodyPath }, - } - }, - }) - - // ── render_mermaid ───────────────────────────────────────────────────────── - pi.registerTool({ - name: "render_mermaid", - label: "Render Mermaid", - description: - "Render the CURRENT session Mermaid source to a PNG and return it inline so " + - "you can SEE the diagram and iterate. You do NOT pass the source here — it " + - "comes from the managed file; call write_mermaid first.\n\n" + - "Iterate freely with no `save_as` (preview only). When the diagram is " + - "correct and clean, call once more with `save_as` set to a short kebab-case " + - "topic slug: that publishes the PNG into /viz with a unique " + - "filename and returns the filename to embed. On a render error this returns " + - "the error text instead of an image — fix with edit_mermaid and re-render.", - parameters: Type.Object({ - save_as: Type.Optional( - Type.String({ - description: - "Short kebab-case topic slug (e.g. 'internet-packets'). When set, the " + - "rendered PNG is published to /viz as viz--.png " + - "and the filename is returned. Omit for a preview-only render.", - }), - ), - }), - async execute(_id, params) { - if (!session || !existsSync(session.bodyPath)) { - throw new Error("render_mermaid: no source yet — call write_mermaid first.") - } - const { workDir, bodyPath } = session - mkdirSync(workDir, { recursive: true }) - - const chrome = findChrome() - const cfgPath = join(workDir, "puppeteer.json") - writeFileSync( - cfgPath, - JSON.stringify(chrome ? { executablePath: chrome, args: ["--no-sandbox"] } : { args: ["--no-sandbox"] }), - "utf8", - ) - - const outPath = join(workDir, `render-${Date.now()}.png`) - const res = await run( - MMDC_BIN, - ["-i", bodyPath, "-o", outPath, "-p", cfgPath, "-s", "2", "-b", "white"], - { cwd: workDir, timeoutMs: RENDER_TIMEOUT_MS, env: { PUPPETEER_SKIP_DOWNLOAD: "1" } }, - ) - - if (res.code !== 0 || !existsSync(outPath)) { - const detail = (res.stderr || res.stdout || "unknown error").split("\n").slice(-30).join("\n") - const note = res.timedOut ? "mmdc timed out.\n\n" : "" - return { - content: [ - { - type: "text", - text: `${note}Mermaid render FAILED — no image produced. Fix the source with edit_mermaid and call render_mermaid again.\n\nError:\n${detail}`, - }, - ], - details: { ok: false, path: "" } as RenderDetails, - } - } - - const data = readFileSync(outPath).toString("base64") - const content: Array<{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }> = [] - - if (params.save_as) { - const { filename, path } = publish(outPath, String(params.save_as)) - content.push({ - type: "text", - text: `Published to viz/.\nfilename: ${filename}\npath: ${path}\n\nLOOK at the diagram below to confirm it is correct before returning it.`, - }) - content.push({ type: "image", data, mimeType: "image/png" }) - return { content, details: { ok: true, path, filename } as RenderDetails } - } - - content.push({ - type: "text", - text: "Preview render (not yet saved). LOOK: are arrows/relationships correct, labels right, nothing cramped? Fix with edit_mermaid, or re-render with `save_as` to publish.", - }) - content.push({ type: "image", data, mimeType: "image/png" }) - return { content, details: { ok: true, path: outPath } as RenderDetails } - }, - }) -} diff --git a/extensions/visual-tools/tools/svg_tools.ts b/extensions/visual-tools/tools/svg_tools.ts deleted file mode 100644 index 22fdbcb..0000000 --- a/extensions/visual-tools/tools/svg_tools.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * SVG authoring loop for the svg-maker subagent — three tools that share one - * session-scoped source file: - * - * write_svg — write the full SVG source to the session's file - * edit_svg — exact-match old_text→new_text on that file (pi-edit semantics) - * render_svg — render whatever is in the file → PNG, returned inline; with - * `save_as`, also publish it into /viz - * - * Bundled inside the visual-tools extension and exposed to subagents via the - * interactive-subagents `registerToolExtension` hook (see ../index.ts). Loaded - * by the spawned child pi process for any subagent whose `tools:` frontmatter - * includes these names (currently just svg-maker). All three names map to this - * one file. - * - * Rendering shells out to rsvg-convert (librsvg — good system-font handling), - * falling back to ImageMagick's `magick` if rsvg-convert is absent. Both are - * system binaries; no node render deps. Module-level session state persists - * across this child process's tool calls, isolated from any parallel maker. - */ - -import type { ExtensionAPI } from "@earendil-works/pi-coding-agent" -import { Type } from "@sinclair/typebox" -import { - applyEdit, - existsSync, - join, - mkdirSync, - publish, - readFileSync, - run, - type Session, - snippetAround, - writeBody, - writeFileSync, -} from "./_common.ts" - -const GROUP = "svg" -const BODY_FILE = "diagram.svg" -const RENDER_TIMEOUT_MS = 60_000 - -type RenderDetails = { ok: boolean; path: string; filename?: string } - -let session: Session | null = null - -/** Render an SVG file to PNG via rsvg-convert, falling back to magick. */ -async function renderSvg(svgPath: string, outPath: string, workDir: string) { - // rsvg-convert renders at the SVG's intrinsic size; -z 2 doubles it for crispness. - let res = await run("rsvg-convert", ["-z", "2", svgPath, "-o", outPath], { - cwd: workDir, - timeoutMs: RENDER_TIMEOUT_MS, - }) - if (res.code === 0 && existsSync(outPath)) return { ok: true as const, res } - // Fallback: ImageMagick. -density 192 (~2x of 96dpi) for a crisp raster. - const magick = await run("magick", ["-density", "192", "-background", "white", svgPath, outPath], { - cwd: workDir, - timeoutMs: RENDER_TIMEOUT_MS, - }) - if (magick.code === 0 && existsSync(outPath)) return { ok: true as const, res: magick } - return { ok: false as const, res: res.code !== null ? res : magick } -} - -export default function svgToolsExtension(pi: ExtensionAPI) { - // ── write_svg ────────────────────────────────────────────────────────────── - pi.registerTool({ - name: "write_svg", - label: "Write SVG", - description: - "Write the FULL SVG source to this session's managed file (your first draft " + - "or a complete rewrite). You do NOT name the file — edit_svg and render_svg " + - "act on the same one.\n\n" + - "`source` is a complete `…` document with an explicit width/" + - "height (or viewBox), readable font sizes, and a light or transparent " + - "background. Writing does NOT render — call render_svg when ready. For a " + - "small fix, prefer edit_svg over rewriting.", - parameters: Type.Object({ - source: Type.String({ description: "The complete SVG document, from ``." }), - }), - async execute(_id, params) { - const source = (params.source ?? "").trim() - if (!source) throw new Error("`write_svg` requires a non-empty `source`.") - if (!source.includes("… document.") - session = writeBody(GROUP, BODY_FILE, source) - const lines = source.split("\n").length - return { - content: [ - { type: "text", text: `Wrote ${lines}-line SVG source.\nCall render_svg to render it, or edit_svg to tweak it.` }, - ], - details: { ok: true, path: session.bodyPath, lines }, - } - }, - }) - - // ── edit_svg ─────────────────────────────────────────────────────────────── - pi.registerTool({ - name: "edit_svg", - label: "Edit SVG", - description: - "Make a single exact-match replacement in this session's SVG source — the " + - "same contract as pi's built-in edit, locked to the one managed file. " + - "`old_text` must appear EXACTLY ONCE (include surrounding context for " + - "uniqueness); on 0 or >1 matches the call fails and nothing changes. Call " + - "write_svg first. Editing does NOT render.", - parameters: Type.Object({ - old_text: Type.String({ description: "Exact substring of the current source to replace (must match once)." }), - new_text: Type.String({ description: "Replacement text for `old_text`." }), - }), - async execute(_id, params) { - if (!session || !existsSync(session.bodyPath)) { - throw new Error("edit_svg: no source yet — call write_svg first.") - } - const current = readFileSync(session.bodyPath, "utf8") - const { updated, index } = applyEdit(current, String(params.old_text ?? ""), String(params.new_text ?? "")) - writeFileSync(session.bodyPath, updated, "utf8") - return { - content: [ - { type: "text", text: "Applied edit. Updated region:\n```\n" + snippetAround(updated, index) + "\n```\nCall render_svg to see it." }, - ], - details: { ok: true, path: session.bodyPath }, - } - }, - }) - - // ── render_svg ───────────────────────────────────────────────────────────── - pi.registerTool({ - name: "render_svg", - label: "Render SVG", - description: - "Render the CURRENT session SVG source to a PNG and return it inline so you " + - "can SEE the picture and iterate. You do NOT pass the source here — it comes " + - "from the managed file; call write_svg first.\n\n" + - "Iterate freely with no `save_as` (preview only). When the picture is " + - "correct and clean, call once more with `save_as` set to a short kebab-case " + - "topic slug: that publishes the PNG into /viz with a unique " + - "filename and returns the filename to embed. On a render error this returns " + - "the error text instead of an image — fix with edit_svg and re-render.", - parameters: Type.Object({ - save_as: Type.Optional( - Type.String({ - description: - "Short kebab-case topic slug (e.g. 'number-line'). When set, the " + - "rendered PNG is published to /viz as viz--.png " + - "and the filename is returned. Omit for a preview-only render.", - }), - ), - }), - async execute(_id, params) { - if (!session || !existsSync(session.bodyPath)) { - throw new Error("render_svg: no source yet — call write_svg first.") - } - const { workDir, bodyPath } = session - mkdirSync(workDir, { recursive: true }) - - const outPath = join(workDir, `render-${Date.now()}.png`) - const { ok, res } = await renderSvg(bodyPath, outPath, workDir) - - if (!ok) { - const detail = (res.stderr || res.stdout || "unknown error").split("\n").slice(-30).join("\n") - const note = res.timedOut ? "SVG render timed out.\n\n" : "" - return { - content: [ - { - type: "text", - text: `${note}SVG render FAILED — no image produced (tried rsvg-convert then magick). Fix the source with edit_svg and call render_svg again.\n\nError:\n${detail}`, - }, - ], - details: { ok: false, path: "" } as RenderDetails, - } - } - - const data = readFileSync(outPath).toString("base64") - const content: Array<{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }> = [] - - if (params.save_as) { - const { filename, path } = publish(outPath, String(params.save_as)) - content.push({ - type: "text", - text: `Published to viz/.\nfilename: ${filename}\npath: ${path}\n\nLOOK at the picture below to confirm the geometry is correct before returning it.`, - }) - content.push({ type: "image", data, mimeType: "image/png" }) - return { content, details: { ok: true, path, filename } as RenderDetails } - } - - content.push({ - type: "text", - text: "Preview render (not yet saved). LOOK: are coordinates, angles, directions, and proportions correct? Labels clear and unclipped? Fix with edit_svg, or re-render with `save_as` to publish.", - }) - content.push({ type: "image", data, mimeType: "image/png" }) - return { content, details: { ok: true, path: outPath } as RenderDetails } - }, - }) -} diff --git a/skills/teach/SKILL.md b/skills/teach/SKILL.md index f691fc8..cc13254 100644 --- a/skills/teach/SKILL.md +++ b/skills/teach/SKILL.md @@ -70,6 +70,8 @@ The two principles are *how* you teach. This is *when* — the shape of a teachi **Accuracy is non-negotiable — verify, don't wing it from memory.** He has to be able to trust the teacher completely; one confidently-delivered hallucination poisons that. Working from memory alone is where LLMs invent things, so: **the moment you are even slightly unsure of any fact, name, date, formula, definition, or claim, stop and confirm it with a quick `researcher` subagent before you say it.** Pausing to verify is always acceptable — accuracy beats flow, every time. And if a check changes or corrects what you were about to teach, say so plainly rather than quietly papering over it. A wrong unconditional truth or a wrong "discovered" step doesn't just mislead — it corrupts every node built on top of it. +**Spawning the `researcher`.** Use the `task` tool: `task(category="unspecified-low", run_in_background=false, task_summary="Research: ", prompt="Read /researcher.md and follow it.\n\nQuestion: ")`. Its final message is the brief. + ### Writing quiz options — a construction procedure (applies to every `quiz`) The tool already tells you to keep options even. That rule isn't enough on its own because it's a *post-hoc audit* — you write a good answer plus some throwaway wrongs, then don't re-scrutinise them. The tell is baked in before any check runs. So don't audit afterwards; **build the options so evenness is automatic**: diff --git a/agents/researcher.md b/skills/teach/researcher.md similarity index 89% rename from agents/researcher.md rename to skills/teach/researcher.md index 28a4f5e..40a4711 100644 --- a/agents/researcher.md +++ b/skills/teach/researcher.md @@ -1,11 +1,6 @@ --- name: researcher description: Web researcher — searches the web and synthesizes findings -tools: web_search, web_fetch, safe_bash -model: openrouter/z-ai/glm-5.3 -thinking: medium -system-prompt: append -auto-exit: true --- You are a research specialist. Given a question or topic, conduct thorough web research and produce a focused, well-sourced brief. @@ -16,7 +11,7 @@ Process: 1. Break the question into 2-4 searchable facets 2. Search with `web_search` using varied angles 3. Read the answers. Identify what's well-covered, what has gaps. -4. For the 2-3 most promising source URLs, use `web_fetch` to get full page content +4. For the 2-3 most promising source URLs, use `webfetch` to get full page content 5. Synthesize everything into a brief that directly answers the question Search strategy — always vary your angles: diff --git a/skills/visualize/SKILL.md b/skills/visualize/SKILL.md index b174dc6..9ad77bc 100644 --- a/skills/visualize/SKILL.md +++ b/skills/visualize/SKILL.md @@ -20,7 +20,7 @@ Do NOT visualize when prose or a single equation already carries it. A decorativ ## Choose the maker -Two makers, discovered from `.pi/agents/`: +Two makers, each a brief in this skill's directory (`mermaid-maker.md`, `svg-maker.md`): - **`mermaid-maker`** — structural/relational visuals: dependency graphs, flowcharts, sequence/state/ER/class diagrams, trees, mindmaps, timelines. This is the default and fits the dependency-graph pedagogy directly. - **`svg-maker`** — spatial/geometric visuals Mermaid can't lay out: exact coordinates, geometry figures, number lines, vectors, plots, custom shapes. @@ -40,16 +40,16 @@ Keep the idea intact but trust the maker to compose; if your brief lists more th ## Invoke -Dispatch the maker with the `subagent` tool: +Dispatch the maker with the `task` tool. Use a category whose model can see images (the maker must look at its render): ``` -subagent(agent="mermaid-maker", task="") +task(category="unspecified-high", run_in_background=false, task_summary="mermaid-maker: ", prompt="Read /mermaid-maker.md and follow it exactly.\n\nBrief: ") ``` ``` -subagent(agent="svg-maker", task="") +task(category="unspecified-high", run_in_background=false, task_summary="svg-maker: ", prompt="Read /svg-maker.md and follow it exactly.\n\nBrief: ") ``` -The maker owns its own purpose-built tools (`write_*`/`edit_*`/`render_*`) — it authors the source, renders it to a PNG, **looks at the PNG and iterates until it is correct and clean**, publishes it into the vault with a unique filename, and returns: +The maker authors the source, renders it to a PNG, **looks at the PNG and iterates until it is correct and clean**, publishes it into the vault with a unique filename, and returns: ``` RESULT: @@ -75,4 +75,4 @@ That's all. The `md-log` extension mirrors your reply text verbatim into the lin - PNG embed means **what the maker verified is pixel-identical to what the learner sees** — no re-render drift. - Unique filenames keep Obsidian's by-filename embed resolution unambiguous. -> The makers render through the project's `visual-tools` extension (Mermaid via a bundled `@mermaid-js/mermaid-cli` + installed Chrome; SVG via `rsvg-convert`, fallback ImageMagick). You don't render anything yourself — you only brief the maker and embed the filename it returns. +> The makers render with shell commands (Mermaid via `npx @mermaid-js/mermaid-cli`; SVG via `rsvg-convert`, fallback ImageMagick). You don't render anything yourself — you only brief the maker and embed the filename it returns. diff --git a/agents/mermaid-maker.md b/skills/visualize/mermaid-maker.md similarity index 63% rename from agents/mermaid-maker.md rename to skills/visualize/mermaid-maker.md index 9c2e801..be87ecf 100644 --- a/agents/mermaid-maker.md +++ b/skills/visualize/mermaid-maker.md @@ -1,11 +1,6 @@ --- name: mermaid-maker description: Authors ONE Mermaid diagram from a brief, renders it to a PNG, LOOKS at the result, iterates until it is correct and clean, publishes the PNG into the Obsidian vault, and returns the filename. For structural/relational visuals — dependency graphs, flows, sequences, state machines, trees, ER, timelines. -tools: write_mermaid, edit_mermaid, render_mermaid, read -model: anthropic/claude-sonnet-5 -thinking: medium -system-prompt: append -auto-exit: true --- # Mermaid Maker @@ -14,24 +9,28 @@ You are a **diagram author + renderer**. You receive a brief describing ONE idea You do NOT decide *what* idea to show — the caller (a teacher) already decided that, and you must preserve it exactly. Your job is faithful, legible composition, and — above everything — **correctness**: the diagram must not assert anything false. A wrong arrow direction, a wrong dependency, a mislabeled node is a failure even if it renders beautifully. -You have exactly three authoring tools — `write_mermaid`, `edit_mermaid`, `render_mermaid` — plus `read`. You cannot touch the filesystem any other way, and you don't need to: the tools manage the source file and the output for you. +You author with your file tools and render with the shell. Keep every working file in a staging dir `/tmp/omo-viz//` (create it), never in the project; the only file you ever write into the project is the published PNG. Touch nothing else. + +- **Render:** `npx -y @mermaid-js/mermaid-cli@11 -i /tmp/omo-viz//diagram.mmd -o /tmp/omo-viz//preview.png -s 2 -b white` (the first run can take ~20s). +- **Look:** read `preview.png` with your file-read tool; it shows you the image. +- **Publish:** from the project root (your working directory), `mkdir -p viz && cp /tmp/omo-viz//preview.png "viz/viz--$(date +%s).png"`. ## The one rule that matters most: verify by looking -You are not done when the diagram renders. You are done when you have **looked at the rendered PNG and confirmed it says exactly what the brief means**. `render_mermaid` returns the image inline — actually look at it. Rendering success only proves the syntax parsed; it says nothing about whether the picture is true or readable. +You are not done when the diagram renders. You are done when you have **looked at the rendered PNG and confirmed it says exactly what the brief means**. Reading the rendered PNG shows you the image — actually look at it. Rendering success only proves the syntax parsed; it says nothing about whether the picture is true or readable. ## Workflow (the render-and-inspect loop) 1. **Understand the idea, then cut.** A brief is a wish-list, not a spec. Keep the idea intact but drop any node/label that doesn't earn its place. If you're about to draw more than ~7 nodes, stop and simplify — a diagram of 4 nodes that each pull weight beats one of 12 that fight for space. Cramming is the #1 way these fail. -2. **Write the source** with `write_mermaid({ source })`. Pick the diagram type that fits: `graph TD`/`LR` (dependency graphs, flows), `sequenceDiagram`, `stateDiagram-v2`, `erDiagram`, `mindmap`, `timeline`, `classDiagram`. -3. **Render a preview** with `render_mermaid({})` (no `save_as`). Look at the returned image. +2. **Write the source** to `diagram.mmd` in the staging dir. Pick the diagram type that fits: `graph TD`/`LR` (dependency graphs, flows), `sequenceDiagram`, `stateDiagram-v2`, `erDiagram`, `mindmap`, `timeline`, `classDiagram`. +3. **Render a preview** with the render command, then read `preview.png` and look at it. 4. **LOOK critically:** - Is every arrow pointing the right way? Is every dependency/relationship actually true to the brief? - Are the labels correct and unambiguous? - Is anything overlapping, clipped, cramped, or unreadable? If so the fix is usually **fewer elements**, not more. - Would the learner instantly read the intended idea from this picture alone? -5. **Iterate** with `edit_mermaid({ old_text, new_text })` and re-render. A few passes is normal. If `render_mermaid` returns an error instead of an image, read it, fix the source, re-render. -6. **Publish** once it is correct and clean: call `render_mermaid({ save_as: "" })`. That writes the PNG into the project's `viz` folder (inside the vault) with a unique filename and returns it. Confirm the published image one last time. +5. **Iterate** by editing `diagram.mmd` and re-rendering. A few passes is normal. If the render command fails instead of producing an image, read it, fix the source, re-render. +6. **Publish** once it is correct and clean: run the publish command. That copies the PNG into the project's `viz` folder (inside the vault) with a unique filename. Confirm the published image one last time. ## Your output @@ -39,8 +38,8 @@ End your response with EXACTLY this block (nothing after it): ``` RESULT: -filename: .png filename returned by render_mermaid> -path: +filename: .png filename you published> +path: ``` If you genuinely cannot make a correct, sensible diagram of the brief, return: diff --git a/agents/svg-maker.md b/skills/visualize/svg-maker.md similarity index 62% rename from agents/svg-maker.md rename to skills/visualize/svg-maker.md index 1bfcf18..cff8a84 100644 --- a/agents/svg-maker.md +++ b/skills/visualize/svg-maker.md @@ -1,11 +1,6 @@ --- name: svg-maker description: Authors ONE hand-written SVG from a brief, renders it to a PNG, LOOKS at the result, iterates until it is correct and clean, publishes the PNG into the Obsidian vault, and returns the filename. For spatial/geometric visuals Mermaid can't express — coordinate geometry, number lines, vectors, function plots, physical layouts, custom shapes with exact positions. -tools: write_svg, edit_svg, render_svg, read -model: anthropic/claude-sonnet-5 -thinking: medium -system-prompt: append -auto-exit: true --- # SVG Maker @@ -14,7 +9,11 @@ You are a **diagram author + renderer** for spatial and geometric pictures. You You do NOT decide *what* idea to show — the caller (a teacher) already decided that, and you must preserve it exactly. Your job is faithful, precise composition, and — above everything — **correctness**: the picture must not assert anything false. A right triangle whose right-angle mark is on the wrong corner, a vector pointing the wrong way, a point plotted at the wrong coordinate is a failure even if it renders cleanly. -You have exactly three authoring tools — `write_svg`, `edit_svg`, `render_svg` — plus `read`. You cannot touch the filesystem any other way, and you don't need to: the tools manage the source file and the output for you. +You author with your file tools and render with the shell. Keep every working file in a staging dir `/tmp/omo-viz//` (create it), never in the project; the only file you ever write into the project is the published PNG. Touch nothing else. + +- **Render:** `rsvg-convert -z 2 /tmp/omo-viz//figure.svg -o /tmp/omo-viz//preview.png`. If `rsvg-convert` isn't on PATH, prefix it with `nix shell nixpkgs#librsvg -c`; last resort `magick -density 192 -background white ` (weaker text rendering). +- **Look:** read `preview.png` with your file-read tool; it shows you the image. +- **Publish:** from the project root (your working directory), `mkdir -p viz && cp /tmp/omo-viz//preview.png "viz/viz--$(date +%s).png"`. ## Your superpower: exact control @@ -22,20 +21,20 @@ Unlike auto-laid-out diagrams, you place every element at coordinates you choose ## The one rule that matters most: verify by looking -You are done only when you have **looked at the rendered PNG and confirmed it is true to the brief**. `render_svg` returns the image inline — actually look at it. Rendering success only proves the SVG parsed; it says nothing about whether the geometry is right or the picture is readable. +You are done only when you have **looked at the rendered PNG and confirmed it is true to the brief**. Reading the rendered PNG shows you the image — actually look at it. Rendering success only proves the SVG parsed; it says nothing about whether the geometry is right or the picture is readable. ## Workflow (the render-and-inspect loop) 1. **Plan the coordinate space.** Choose a `viewBox` and sketch where each element sits before drawing. Leave margins so nothing touches the edge. Keep it to ONE idea and few elements. -2. **Write the source** with `write_svg({ source })`: a complete `…` with explicit `width`/`height` (or viewBox), a white or transparent background, readable `font-family="sans-serif"`, and font sizes large enough to read when embedded. -3. **Render a preview** with `render_svg({})` (no `save_as`). Look at the returned image. +2. **Write the source** to `figure.svg` in the staging dir: a complete `…` with explicit `width`/`height` (or viewBox), a white or transparent background, readable `font-family="sans-serif"`, and font sizes large enough to read when embedded. +3. **Render a preview** with the render command, then read `preview.png` and look at it. 4. **LOOK critically:** - Is every coordinate, angle, direction, and proportion actually correct? Re-derive the geometry if unsure. - Are labels placed clearly, not overlapping lines or each other? - Is anything clipped by the viewBox, too small to read, or cramped? - Would the learner instantly read the intended idea from this picture alone? -5. **Iterate** with `edit_svg({ old_text, new_text })` and re-render until correct and clean. If `render_svg` returns an error, read it, fix the source, re-render. -6. **Publish** once it is correct and clean: call `render_svg({ save_as: "" })`. That writes the PNG into the project's `viz` folder (inside the vault) with a unique filename and returns it. Confirm the published image one last time. +5. **Iterate** by editing `figure.svg` and re-rendering until correct and clean. If the render command fails, read it, fix the source, re-render. +6. **Publish** once it is correct and clean: run the publish command. That copies the PNG into the project's `viz` folder (inside the vault) with a unique filename. Confirm the published image one last time. ## Your output @@ -43,8 +42,8 @@ End your response with EXACTLY this block (nothing after it): ``` RESULT: -filename: .png filename returned by render_svg> -path: +filename: .png filename you published> +path: ``` If you genuinely cannot make a correct, sensible picture of the brief, return: