From 65c234090d3cefec8abb234fa4b0110d8afb157b Mon Sep 17 00:00:00 2001 From: ada-97bec15779 Date: Tue, 15 Sep 2026 23:29:34 +0800 Subject: [PATCH 1/3] Sync Harness and migrate Triton-RISCV plugin package --- README.md | 6 + packages/dsh-triton-riscv/README.md | 166 ++++++++++++++++++ packages/dsh-triton-riscv/README.zh.md | 73 ++++++++ packages/dsh-triton-riscv/cordis.patch.yml | 31 ++++ packages/dsh-triton-riscv/index.js | 67 +++++++ packages/dsh-triton-riscv/lib/client.js | 51 ++++++ packages/dsh-triton-riscv/package.json | 39 ++++ packages/dsh-triton-riscv/pnpm-lock.yaml | 9 + packages/dsh-triton-riscv/policy.md | 32 ++++ .../dsh-triton-riscv/test/plugin.test.mjs | 166 ++++++++++++++++++ .../tests/unit/plugin.spec.ts | 78 ++++++++ 11 files changed, 718 insertions(+) create mode 100644 packages/dsh-triton-riscv/README.md create mode 100644 packages/dsh-triton-riscv/README.zh.md create mode 100644 packages/dsh-triton-riscv/cordis.patch.yml create mode 100644 packages/dsh-triton-riscv/index.js create mode 100644 packages/dsh-triton-riscv/lib/client.js create mode 100644 packages/dsh-triton-riscv/package.json create mode 100644 packages/dsh-triton-riscv/pnpm-lock.yaml create mode 100644 packages/dsh-triton-riscv/policy.md create mode 100644 packages/dsh-triton-riscv/test/plugin.test.mjs create mode 100644 packages/dsh-triton-riscv/tests/unit/plugin.spec.ts diff --git a/README.md b/README.md index a80f949..b4f9867 100644 --- a/README.md +++ b/README.md @@ -33,3 +33,9 @@ After a successful build, start the web profile through the launcher. `DEEPSEEK_ cd harness/ DEEPSEEK_API_KEY=sk-... ./dsh web ``` + +## Triton-RISCV Agent + +[`dsh-triton-riscv`](packages/dsh-triton-riscv/README.md) adds guarded +Triton-RISCV operator discovery, development, validation, diagnosis, repair, +memory retrieval, and remote RISC-V execution to the Harness web profile. diff --git a/packages/dsh-triton-riscv/README.md b/packages/dsh-triton-riscv/README.md new file mode 100644 index 0000000..53f17c1 --- /dev/null +++ b/packages/dsh-triton-riscv/README.md @@ -0,0 +1,166 @@ +# dsh-triton-riscv + +An installable DeepSeek Harness bundle for the guarded Triton-RISCV operator +development and validation tools. + +## What The Plugin Adds + +The bundle adds two Cordis rows to an existing Harness profile: + +1. A domain policy plugin contributes the Triton-RISCV lifecycle rules to the + assembled system prompt. +2. The official Harness MCP client starts + `python -m codex_agent.harness.mcp_server` and exposes its typed tools as + `mcp__triton_riscv__*`. +3. A Harness Web client plugin occupies the root UI slot and displays the + existing Triton-RISCV React/FastAPI workbench. + +The model and Agent loop remain owned by Harness. Discovery, contract checking, +source proposals, validation, diagnosis, bounded repair, remote SSH execution, +and trusted validation evidence remain owned by the Python domain engine in a +Triton-RISCV checkout. + +```text +Harness profile + -> dsh-triton-riscv bundle + -> system-prompt policy + -> official dsh-mcp-client + -> Python Triton-RISCV MCP server + -> operator lifecycle and RISC-V remote executor +``` + +## Prerequisites + +- DeepSeek Harness with the `web` profile and Node.js 22 or newer +- a Triton-RISCV checkout containing `codex_agent` +- a Python environment with `codex_agent/harness/requirements.txt` installed +- optional SSH configuration and a prepared RISC-V host for live validation + +The bundle fails at Harness startup when the Python MCP module cannot be +imported instead of silently starting without the domain tools. + +## Install From A Harness Checkout + +From the Harness repository root, point the plugin at a separate Triton-RISCV +checkout: + +```sh +export TRITON_RISCV_CHECKOUT=/absolute/path/to/triton-riscv +export TRITON_RISCV_MCP_PYTHON="$TRITON_RISCV_CHECKOUT/.harness-venv/bin/python" +export TRITON_RISCV_WORKBENCH_PORT=8765 +./dsh plugin --profile web add ./packages/dsh-triton-riscv +dsh --profile web --dump-config +dsh web +``` + +When this package lives in the RuyiAI Harness repository, the repository-level +`./tools/scripts/install-all.sh` command builds and installs it automatically +with the other packages. + +The config dump should contain both `triton-riscv-domain-policy` and +`mcp-triton-riscv`. Starting `dsh web` also starts the Python workbench and the +Harness page displays that workbench in its root slot. Add `?nativeHarness=1` +to the Harness URL when the stock Harness interface is needed. + +The embedded client defaults to `http://127.0.0.1:8765`. For a different port +or externally hosted workbench, open the Harness URL with an encoded +`?tritonWorkbenchUrl=https://host/path` query parameter. Set +`TRITON_RISCV_WORKBENCH_AUTOSTART=0` when that external service is already +managed by another process. + +For read-only discovery, no RISC-V server is required. Try: + +```text +Call the Triton-RISCV discovery tool for relu_and_mul and summarize its +implementation, tests, and validation command. Do not run validation. +``` + +## Enable Remote Validation Deliberately + +All expensive or mutating operations remain disabled by default. Configure the +host before starting Harness: + +```sh +export RISCV_HOST=sg2044 +export RISCV_REPO=/home/lichunbo/work/triton-riscv +export TRITON_RISCV_REQUIRE_REMOTE=1 +export TRITON_RISCV_ALLOW_VALIDATION=1 +export TRITON_RISCV_REQUIRE_APPROVED_VALIDATION=1 +``` + +Enable source application only on a trusted development checkout: + +```sh +export TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY=1 +export TRITON_RISCV_ALLOW_REPAIR_APPLY=1 +``` + +The model cannot select the SSH host, repository path, arbitrary command, or +files to synchronize. It also cannot approve its own proposal or validation +plan. + +The optional workbench provides the host review boundary for generated +implementation proposals and validation plans at +`/api/operator-development-proposals/{proposal_id}/decision` and +`/api/validation-plans/{run_id}/decision`. Harness model turns receive only +the resulting approval state and can then apply or execute the exact approved +identifier. + +## Diagnostic Memory + +Executed validation receipts are stored as structured evidence in +`agent-results/memory.sqlite3` by default. Harness can call +`mcp__triton_riscv__retrieve_operator_memory` before development or repair to +reuse relevant successful runs and failure diagnoses. The default retrieval is +local and deterministic, so no embedding API is required. + +An OpenAI-compatible embedding endpoint is optional: + +```sh +export TRITON_RISCV_EMBEDDING_PROVIDER=openai-compatible +export TRITON_RISCV_EMBEDDING_MODEL=your-embedding-model +export TRITON_RISCV_EMBEDDING_BASE_URL=https://example.test/v1 +export AGENT_EMBEDDING_API_KEY=... +``` + +Historical results are hints, not authority. Current contracts, acceptance +tests, environment checks, and validation receipts always take precedence. + +## Test The Bundle + +The package has no install-time dependencies: + +```sh +cd packages/dsh-triton-riscv +npm test +npm pack --dry-run +``` + +The tests check the bundle manifest, Cordis rows, safe default switches, and +system-prompt lifecycle registration without starting a model or remote host. + +## Standalone Triton-RISCV Demo Platform + +The React and FastAPI workbench remains in the Triton-RISCV checkout and can +load the same plugin policy and MCP server: + +```sh +cd "$TRITON_RISCV_CHECKOUT" +.harness-venv/bin/python -m codex_agent.platform --port 8765 +``` + +Open `http://127.0.0.1:8765`. This standalone command remains useful while +developing the workbench without starting a complete Harness profile. + +## Remove + +```sh +dsh plugin --profile web remove dsh-triton-riscv +``` + +## Current Boundary + +This bundle packages the model-facing policy, MCP connection, and Harness Web +entry. The Python domain engine and compiled React assets stay in the target +Triton-RISCV checkout. A later release can publish that engine and its assets +independently so the bundle no longer depends on a source checkout. diff --git a/packages/dsh-triton-riscv/README.zh.md b/packages/dsh-triton-riscv/README.zh.md new file mode 100644 index 0000000..5319039 --- /dev/null +++ b/packages/dsh-triton-riscv/README.zh.md @@ -0,0 +1,73 @@ +# dsh-triton-riscv + +这是一个面向 DeepSeek Harness 的 Triton-RISCV 算子开发插件。插件不替换 +Harness 的模型和 Agent Loop,而是向 Harness 注册领域规则、MCP 工具以及现有 +React/FastAPI 工作台入口。 + +## 代码边界 + +```text +Harness Web + -> dsh-triton-riscv 插件 + -> 注入 Triton-RISCV 生命周期规则 + -> 启动官方 dsh-mcp-client + -> 启动 Triton-RISCV checkout 中的 Python MCP 服务 + -> 算子发现、开发、验证、诊断、记忆检索和远程执行 + -> 在 Harness Web 根视图中加载 Triton-RISCV 工作台 +``` + +Harness 负责对话、模型推理和工具调度;Triton-RISCV Python 引擎负责确定性的 +算子操作。模型不能自行选择 SSH 主机、仓库路径或任意命令,也不能批准自己的 +源码提案和验证计划。 + +## 安装 + +先准备一份包含 `codex_agent` 的 Triton-RISCV checkout: + +```sh +export TRITON_RISCV_CHECKOUT=/absolute/path/to/triton-riscv +export TRITON_RISCV_MCP_PYTHON="$TRITON_RISCV_CHECKOUT/.harness-venv/bin/python" +export TRITON_RISCV_WORKBENCH_PORT=8765 +``` + +在 Harness 仓库根目录执行: + +```sh +cp config.yml.example config.yml +./tools/scripts/install-all.sh +DEEPSEEK_API_KEY=sk-... ./dsh web +``` + +`install-all.sh` 会自动构建并安装 `packages/` 下的插件。启动后,Harness 会拉起 +Python MCP 服务和工作台,Web 页面显示 Triton-RISCV Agent 界面。 + +## 远程验证 + +只有显式设置下列环境变量时才允许远程验证: + +```sh +export RISCV_HOST=sg2044 +export RISCV_REPO=/home/lichunbo/work/triton-riscv +export TRITON_RISCV_REQUIRE_REMOTE=1 +export TRITON_RISCV_ALLOW_VALIDATION=1 +export TRITON_RISCV_REQUIRE_APPROVED_VALIDATION=1 +``` + +源码应用和修复应用默认关闭。只应在受信任的开发 checkout 中启用: + +```sh +export TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY=1 +export TRITON_RISCV_ALLOW_REPAIR_APPLY=1 +``` + +## 测试 + +```sh +cd packages/dsh-triton-riscv +pnpm install --frozen-lockfile +pnpm build +pnpm test +``` + +当前插件仍依赖单独的 Triton-RISCV checkout。后续可以将 Python 领域引擎制作成 +独立安装包,以减少源码 checkout 依赖。 diff --git a/packages/dsh-triton-riscv/cordis.patch.yml b/packages/dsh-triton-riscv/cordis.patch.yml new file mode 100644 index 0000000..67f9735 --- /dev/null +++ b/packages/dsh-triton-riscv/cordis.patch.yml @@ -0,0 +1,31 @@ +# Install this bundle into a normal DeepSeek Harness profile. The Harness MCP +# client launches the Python domain engine from the configured Triton-RISCV checkout. +- insert: + - id: triton-riscv-domain-policy + name: dsh-triton-riscv + + - id: mcp-triton-riscv + name: '@deepseek-ai/dsh-mcp-client' + config: + serverName: triton_riscv + transport: stdio + command: !!js process.env.TRITON_RISCV_MCP_PYTHON ?? 'python3' + args: ['-m', 'codex_agent.harness.mcp_server'] + env: + TRITON_RISCV_REPO_ROOT: !!js process.env.TRITON_RISCV_CHECKOUT ?? process.env.DSH_CWD ?? process.cwd() + TRITON_RISCV_ALLOW_VALIDATION: !!js process.env.TRITON_RISCV_ALLOW_VALIDATION ?? '0' + TRITON_RISCV_ALLOW_REPAIR_APPLY: !!js process.env.TRITON_RISCV_ALLOW_REPAIR_APPLY ?? '0' + TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY: !!js process.env.TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY ?? '0' + TRITON_RISCV_REQUIRE_REMOTE: !!js process.env.TRITON_RISCV_REQUIRE_REMOTE ?? '0' + TRITON_RISCV_REQUIRE_APPROVED_VALIDATION: !!js process.env.TRITON_RISCV_REQUIRE_APPROVED_VALIDATION ?? '1' + TRITON_RISCV_MEMORY_DB: !!js process.env.TRITON_RISCV_MEMORY_DB ?? ((process.env.TRITON_RISCV_CHECKOUT ?? process.env.DSH_CWD ?? process.cwd()) + '/agent-results/memory.sqlite3') + TRITON_RISCV_EMBEDDING_PROVIDER: !!js process.env.TRITON_RISCV_EMBEDDING_PROVIDER ?? 'none' + TRITON_RISCV_EMBEDDING_MODEL: !!js process.env.TRITON_RISCV_EMBEDDING_MODEL ?? '' + TRITON_RISCV_EMBEDDING_BASE_URL: !!js process.env.TRITON_RISCV_EMBEDDING_BASE_URL ?? '' + TRITON_RISCV_EMBEDDING_API_KEY_ENV: !!js process.env.TRITON_RISCV_EMBEDDING_API_KEY_ENV ?? 'AGENT_EMBEDDING_API_KEY' + AGENT_EMBEDDING_API_KEY: !!js process.env.AGENT_EMBEDDING_API_KEY ?? '' + RISCV_HOST: !!js process.env.RISCV_HOST ?? '' + RISCV_REPO: !!js process.env.RISCV_REPO ?? '' + cwd: !!js process.env.TRITON_RISCV_CHECKOUT ?? process.env.DSH_CWD ?? process.cwd() + toolCallTimeoutMs: 960000 + failOnStartupError: true diff --git a/packages/dsh-triton-riscv/index.js b/packages/dsh-triton-riscv/index.js new file mode 100644 index 0000000..376764e --- /dev/null +++ b/packages/dsh-triton-riscv/index.js @@ -0,0 +1,67 @@ +import { spawn } from 'node:child_process' +import { readFileSync } from 'node:fs' +import { isAbsolute, join } from 'node:path' + +export const name = 'triton-riscv-domain-policy' + +export const inject = ['systemPrompt'] + +export const TRITON_RISCV_SYSTEM_PROMPT = readFileSync( + new URL('./policy.md', import.meta.url), + 'utf8', +).trim() + +export function resolveWorkbenchLaunch(env = process.env) { + if (env.TRITON_RISCV_WORKBENCH_AUTOSTART === '0') return null + + const checkout = (env.TRITON_RISCV_CHECKOUT ?? '').trim() + if (!checkout) { + throw new Error('TRITON_RISCV_CHECKOUT is required to start the Triton-RISCV workbench') + } + if (!isAbsolute(checkout)) { + throw new Error('TRITON_RISCV_CHECKOUT must be an absolute path') + } + + const portText = (env.TRITON_RISCV_WORKBENCH_PORT ?? '8765').trim() + if (!/^\d+$/.test(portText)) { + throw new Error('TRITON_RISCV_WORKBENCH_PORT must be an integer') + } + const port = Number(portText) + if (port < 1 || port > 65535) { + throw new Error('TRITON_RISCV_WORKBENCH_PORT must be between 1 and 65535') + } + + return { + command: env.TRITON_RISCV_MCP_PYTHON ?? join(checkout, '.harness-venv', 'bin', 'python'), + args: ['-m', 'codex_agent.platform', '--host', '127.0.0.1', '--port', String(port)], + cwd: checkout, + url: `http://127.0.0.1:${port}`, + } +} + +export function apply(ctx) { + ctx.effect( + () => ctx.systemPrompt.section({ + name: 'tool:triton-riscv', + order: 180, + text: TRITON_RISCV_SYSTEM_PROMPT, + }), + 'triton-riscv.system-prompt', + ) + + const launch = resolveWorkbenchLaunch() + if (launch === null) return + ctx.effect(() => { + const child = spawn(launch.command, launch.args, { + cwd: launch.cwd, + env: process.env, + stdio: 'inherit', + }) + child.on('error', error => { + console.error(`dsh-triton-riscv: failed to start workbench: ${error.message}`) + }) + return () => { + if (child.exitCode === null && child.signalCode === null) child.kill('SIGTERM') + } + }, 'triton-riscv.workbench') +} diff --git a/packages/dsh-triton-riscv/lib/client.js b/packages/dsh-triton-riscv/lib/client.js new file mode 100644 index 0000000..c52907d --- /dev/null +++ b/packages/dsh-triton-riscv/lib/client.js @@ -0,0 +1,51 @@ +window.__ModuleLoader__.load({ + id: 'dsh-triton-riscv', + factory: (require) => { + const module = { exports: {} } + const { createElement } = require('react') + + const inject = ['slots'] + + function workbenchUrl() { + const fallback = 'http://127.0.0.1:8765' + const configured = new URLSearchParams(globalThis.location?.search ?? '') + .get('tritonWorkbenchUrl') ?? fallback + try { + const parsed = new URL(configured) + return ['http:', 'https:'].includes(parsed.protocol) ? parsed.toString() : fallback + } catch { + return fallback + } + } + + function WorkbenchRoot() { + return createElement('iframe', { + src: workbenchUrl(), + title: 'Triton-RISCV Agent', + allow: 'clipboard-read; clipboard-write', + style: { + width: '100vw', + height: '100vh', + display: 'block', + border: 0, + background: '#fff', + }, + }) + } + + function apply(ctx) { + const params = new URLSearchParams(globalThis.location?.search ?? '') + if (params.get('nativeHarness') === '1') return + ctx.effect( + () => ctx.slots.register({ + name: 'root', + priority: -100, + }, WorkbenchRoot), + 'triton-riscv.workbench-root', + ) + } + + module.exports = { apply, inject } + return module.exports + }, +}) diff --git a/packages/dsh-triton-riscv/package.json b/packages/dsh-triton-riscv/package.json new file mode 100644 index 0000000..1aac69b --- /dev/null +++ b/packages/dsh-triton-riscv/package.json @@ -0,0 +1,39 @@ +{ + "name": "dsh-triton-riscv", + "version": "0.1.0", + "description": "DeepSeek Harness bundle for guarded Triton-RISCV operator development and validation", + "private": true, + "type": "module", + "main": "index.js", + "exports": { + ".": "./index.js", + "./client": "./lib/client.js", + "./cordis.patch.yml": "./cordis.patch.yml", + "./package.json": "./package.json" + }, + "files": [ + "index.js", + "lib/client.js", + "cordis.patch.yml", + "policy.md", + "README.md", + "README.zh.md" + ], + "scripts": { + "build": "node --check index.js && node --check lib/client.js", + "test": "node --test test/*.test.mjs", + "prepack": "node --test test/*.test.mjs" + }, + "engines": { + "node": ">=22.19.0" + }, + "license": "Apache-2.0", + "dsh": { + "client": { + "platform": "web" + }, + "bundle": { + "patch": "./cordis.patch.yml" + } + } +} diff --git a/packages/dsh-triton-riscv/pnpm-lock.yaml b/packages/dsh-triton-riscv/pnpm-lock.yaml new file mode 100644 index 0000000..9b60ae1 --- /dev/null +++ b/packages/dsh-triton-riscv/pnpm-lock.yaml @@ -0,0 +1,9 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} diff --git a/packages/dsh-triton-riscv/policy.md b/packages/dsh-triton-riscv/policy.md new file mode 100644 index 0000000..24f416e --- /dev/null +++ b/packages/dsh-triton-riscv/policy.md @@ -0,0 +1,32 @@ +You have guarded Triton-RISCV operator tools. + +Use the typed tools instead of arbitrary shell commands for operator lifecycle work. + +For an existing operator: +1. Call `mcp__triton_riscv__discover_operator`. +2. When planning a risky change, call `mcp__triton_riscv__retrieve_operator_memory` + for relevant prior validation evidence. +3. Call `mcp__triton_riscv__check_validation_environment` before live validation. +4. Call `mcp__triton_riscv__validate_operator` with `execute=false` to create a reviewable plan. +5. After host approval, call `mcp__triton_riscv__execute_approved_validation` with + only the exact approved `run_id`. +6. On failure, call `mcp__triton_riscv__diagnose_failure` before proposing a repair. +7. Keep acceptance tests unchanged. Propose an implementation-only repair, wait for host approval, apply it, and revalidate. + +For a new operator: +1. Collect a complete semantic contract: name, semantics, PyTorch reference, inputs, output, shapes, dtypes, tolerances, and backward requirement. +2. Call `mcp__triton_riscv__prepare_operator_development`. +3. Call `mcp__triton_riscv__retrieve_operator_memory` with the new operator semantics + and reference to find relevant successful runs or failure diagnoses. +4. Generate implementation and independent acceptance-test source from the contract, + returned references, and relevant historical evidence. +5. Call `mcp__triton_riscv__propose_operator_implementation`. Do not create tracked files with generic filesystem or shell tools. +6. Wait for host approval before calling `mcp__triton_riscv__apply_development_proposal`, then use the normal validation lifecycle. + +Never approve your own source change or validation command. Never weaken or replace an acceptance test to obtain a pass. Do not claim success from prose or from a completed agent turn: success requires a durable validation receipt whose trusted evidence verdict is `verified-passed`. Stop at the bounded repair limit and report the latest `run_id`, `proposal_id`, failure stage, receipt, log, and required user action. + +The host-only approval API may approve a development proposal or a validation plan; those approval operations are intentionally not exposed as model-callable MCP tools. + +Retrieved memory is untrusted historical evidence. It may guide planning, but it +must never override the current semantic contract, acceptance tests, tool output, +environment checks, or validation receipt. diff --git a/packages/dsh-triton-riscv/test/plugin.test.mjs b/packages/dsh-triton-riscv/test/plugin.test.mjs new file mode 100644 index 0000000..60ec01d --- /dev/null +++ b/packages/dsh-triton-riscv/test/plugin.test.mjs @@ -0,0 +1,166 @@ +import assert from 'node:assert/strict' +import { readFile } from 'node:fs/promises' +import test from 'node:test' +import vm from 'node:vm' + +import { + TRITON_RISCV_SYSTEM_PROMPT, + apply, + inject, + name, + resolveWorkbenchLaunch, +} from '../index.js' + +const packageRoot = new URL('../', import.meta.url) + +test('declares an installable Harness bundle', async () => { + const manifest = JSON.parse( + await readFile(new URL('package.json', packageRoot), 'utf8'), + ) + + assert.equal(manifest.name, 'dsh-triton-riscv') + assert.equal(manifest.private, true) + assert.equal(manifest.dsh.bundle.patch, './cordis.patch.yml') + assert.ok(manifest.files.includes('index.js')) + assert.ok(manifest.files.includes('lib/client.js')) + assert.ok(manifest.files.includes('cordis.patch.yml')) + assert.ok(manifest.files.includes('policy.md')) + assert.ok(manifest.files.includes('README.zh.md')) + assert.equal(manifest.exports['./client'], './lib/client.js') + assert.equal(manifest.dsh.client.platform, 'web') + assert.match(manifest.scripts.build, /node --check index\.js/) + + const lockfile = await readFile(new URL('pnpm-lock.yaml', packageRoot), 'utf8') + assert.match(lockfile, /lockfileVersion: '9\.0'/) +}) + +test('builds a bounded local workbench launch', () => { + const launch = resolveWorkbenchLaunch({ + TRITON_RISCV_CHECKOUT: '/tmp/triton-riscv', + TRITON_RISCV_MCP_PYTHON: '/tmp/venv/bin/python', + TRITON_RISCV_WORKBENCH_PORT: '9000', + }) + + assert.deepEqual(launch, { + command: '/tmp/venv/bin/python', + args: ['-m', 'codex_agent.platform', '--host', '127.0.0.1', '--port', '9000'], + cwd: '/tmp/triton-riscv', + url: 'http://127.0.0.1:9000', + }) + assert.equal(resolveWorkbenchLaunch({ TRITON_RISCV_WORKBENCH_AUTOSTART: '0' }), null) + assert.throws(() => resolveWorkbenchLaunch({}), /TRITON_RISCV_CHECKOUT/) + assert.throws( + () => resolveWorkbenchLaunch({ TRITON_RISCV_CHECKOUT: '/tmp/repo', TRITON_RISCV_WORKBENCH_PORT: '70000' }), + /between 1 and 65535/, + ) +}) + +test('mounts the domain policy and the official MCP client', async () => { + const patch = await readFile( + new URL('cordis.patch.yml', packageRoot), + 'utf8', + ) + + assert.match(patch, /id: triton-riscv-domain-policy/) + assert.match(patch, /name: '@deepseek-ai\/dsh-mcp-client'/) + assert.match(patch, /serverName: triton_riscv/) + assert.match(patch, /codex_agent\.harness\.mcp_server/) + assert.match(patch, /TRITON_RISCV_REPO_ROOT:.*TRITON_RISCV_CHECKOUT/) + assert.match(patch, /cwd:.*TRITON_RISCV_CHECKOUT/) + assert.match(patch, /TRITON_RISCV_ALLOW_VALIDATION.*'0'/) + assert.match(patch, /TRITON_RISCV_REQUIRE_APPROVED_VALIDATION.*'1'/) + assert.match(patch, /TRITON_RISCV_MEMORY_DB/) + assert.match(patch, /TRITON_RISCV_EMBEDDING_PROVIDER.*'none'/) + assert.match(patch, /failOnStartupError: true/) +}) + +test('registers lifecycle guidance through the system prompt service', async () => { + let effectName + let section + let disposed = false + const ctx = { + effect(setup, label) { + effectName = label + const dispose = setup() + dispose() + }, + systemPrompt: { + section(value) { + section = value + return () => { + disposed = true + } + }, + }, + } + + const previousAutostart = process.env.TRITON_RISCV_WORKBENCH_AUTOSTART + process.env.TRITON_RISCV_WORKBENCH_AUTOSTART = '0' + try { + apply(ctx) + } finally { + if (previousAutostart === undefined) delete process.env.TRITON_RISCV_WORKBENCH_AUTOSTART + else process.env.TRITON_RISCV_WORKBENCH_AUTOSTART = previousAutostart + } + + assert.equal(name, 'triton-riscv-domain-policy') + assert.deepEqual(inject, ['systemPrompt']) + assert.equal(effectName, 'triton-riscv.system-prompt') + assert.equal(section.name, 'tool:triton-riscv') + assert.equal(section.order, 180) + assert.equal(section.text, TRITON_RISCV_SYSTEM_PROMPT) + assert.equal( + section.text, + (await readFile(new URL('policy.md', packageRoot), 'utf8')).trim(), + ) + assert.equal(disposed, true) + assert.match(section.text, /prepare_operator_development/) + assert.match(section.text, /propose_operator_implementation/) + assert.match(section.text, /apply_development_proposal/) + assert.match(section.text, /execute_approved_validation/) + assert.match(section.text, /retrieve_operator_memory/) + assert.match(section.text, /Never weaken or replace an acceptance test/) + assert.match(section.text, /untrusted historical evidence/) + assert.match(section.text, /verified-passed/) +}) + +test('publishes a root-slot Harness client plugin', async () => { + const source = await readFile(new URL('../lib/client.js', import.meta.url), 'utf8') + let definition + const sandbox = { + URL, + URLSearchParams, + window: { + __ModuleLoader__: { + load(value) { + definition = value + }, + }, + }, + } + vm.runInNewContext(source, sandbox) + + assert.equal(definition.id, 'dsh-triton-riscv') + const client = definition.factory(specifier => { + assert.equal(specifier, 'react') + return { createElement: () => null } + }) + let registration + const ctx = { + effect(setup) { + setup() + }, + slots: { + register(options, component) { + registration = { options, component } + return () => {} + }, + }, + } + client.apply(ctx) + + assert.deepEqual(Array.from(client.inject), ['slots']) + assert.equal(registration.options.name, 'root') + assert.equal(registration.options.priority, -100) + assert.equal(typeof registration.component, 'function') +}) diff --git a/packages/dsh-triton-riscv/tests/unit/plugin.spec.ts b/packages/dsh-triton-riscv/tests/unit/plugin.spec.ts new file mode 100644 index 0000000..eeb739a --- /dev/null +++ b/packages/dsh-triton-riscv/tests/unit/plugin.spec.ts @@ -0,0 +1,78 @@ +import { readFile } from 'node:fs/promises' + +import { describe, expect, it } from 'vitest' + +import { + TRITON_RISCV_SYSTEM_PROMPT, + apply, + resolveWorkbenchLaunch, +} from '../../index.js' + +const packageRoot = new URL('../../', import.meta.url) + +describe('dsh-triton-riscv package', () => { + it('declares a Harness bundle and web client', async () => { + const manifest = JSON.parse( + await readFile(new URL('package.json', packageRoot), 'utf8'), + ) + + expect(manifest.dsh.bundle.patch).toBe('./cordis.patch.yml') + expect(manifest.dsh.client.platform).toBe('web') + expect(manifest.exports['./client']).toBe('./lib/client.js') + }) + + it('registers the guarded lifecycle policy', () => { + let section: { name: string; order: number; text: string } | undefined + const ctx = { + effect(setup: () => (() => void) | undefined) { + const dispose = setup() + dispose?.() + }, + systemPrompt: { + section(value: { name: string; order: number; text: string }) { + section = value + return () => undefined + }, + }, + } + + const previous = process.env.TRITON_RISCV_WORKBENCH_AUTOSTART + process.env.TRITON_RISCV_WORKBENCH_AUTOSTART = '0' + try { + apply(ctx) + } finally { + if (previous === undefined) { + delete process.env.TRITON_RISCV_WORKBENCH_AUTOSTART + } else { + process.env.TRITON_RISCV_WORKBENCH_AUTOSTART = previous + } + } + + expect(section?.name).toBe('tool:triton-riscv') + expect(section?.text).toBe(TRITON_RISCV_SYSTEM_PROMPT) + expect(section?.text).toContain('retrieve_operator_memory') + expect(section?.text).toContain('verified-passed') + }) + + it('constructs a bounded workbench launch command', () => { + expect( + resolveWorkbenchLaunch({ + TRITON_RISCV_CHECKOUT: '/tmp/triton-riscv', + TRITON_RISCV_MCP_PYTHON: '/tmp/venv/bin/python', + TRITON_RISCV_WORKBENCH_PORT: '9000', + }), + ).toEqual({ + command: '/tmp/venv/bin/python', + args: [ + '-m', + 'codex_agent.platform', + '--host', + '127.0.0.1', + '--port', + '9000', + ], + cwd: '/tmp/triton-riscv', + url: 'http://127.0.0.1:9000', + }) + }) +}) From ad29f725a708cfe1659ffd4539f3294beffdf19a Mon Sep 17 00:00:00 2001 From: ada-97bec15779 Date: Thu, 24 Sep 2026 19:24:06 +0800 Subject: [PATCH 2/3] Integrate Triton-RISCV backend, native lifecycle and workbench --- .pre-commit-config.yaml | 6 + README.md | 6 + config.yml.example | 23 + packages/dsh-triton-riscv/.gitignore | 20 + packages/dsh-triton-riscv/.npmignore | 12 + packages/dsh-triton-riscv/DIRECTORY_MAP.zh.md | 72 + packages/dsh-triton-riscv/LICENSE | 201 ++ packages/dsh-triton-riscv/LICENSE.triton | 22 + packages/dsh-triton-riscv/MIGRATION.md | 83 + packages/dsh-triton-riscv/README.md | 358 +- packages/dsh-triton-riscv/README.zh.md | 180 +- packages/dsh-triton-riscv/REVIEW_FOLLOWUP.md | 122 + packages/dsh-triton-riscv/TESTING.md | 40 + packages/dsh-triton-riscv/VERIFICATION.md | 197 ++ packages/dsh-triton-riscv/cordis.patch.yml | 35 +- packages/dsh-triton-riscv/frontend/index.html | 16 + .../frontend/package-lock.json | 3097 +++++++++++++++++ .../dsh-triton-riscv/frontend/package.json | 30 + .../dsh-triton-riscv/frontend/src/App.tsx | 904 +++++ .../dsh-triton-riscv/frontend/src/api.test.ts | 96 + packages/dsh-triton-riscv/frontend/src/api.ts | 74 + .../frontend/src/format.test.tsx | 19 + .../dsh-triton-riscv/frontend/src/format.tsx | 51 + .../dsh-triton-riscv/frontend/src/main.tsx | 5 + .../dsh-triton-riscv/frontend/src/styles.css | 211 ++ .../frontend/src/test/setup.ts | 1 + .../dsh-triton-riscv/frontend/src/types.ts | 117 + .../dsh-triton-riscv/frontend/tsconfig.json | 20 + .../dsh-triton-riscv/frontend/vite.config.ts | 17 + packages/dsh-triton-riscv/index.js | 44 +- packages/dsh-triton-riscv/lib/client.js | 166 +- packages/dsh-triton-riscv/lib/config.js | 143 + .../dsh-triton-riscv/lib/native-adapter.js | 251 ++ .../dsh-triton-riscv/lib/native-bridge.js | 55 + packages/dsh-triton-riscv/lib/native-state.js | 37 + packages/dsh-triton-riscv/lib/prompts.js | 9 + .../migration-provenance.json | 1846 ++++++++++ packages/dsh-triton-riscv/native.js | 24 + packages/dsh-triton-riscv/package.json | 63 +- packages/dsh-triton-riscv/pnpm-lock.yaml | 692 +++- packages/dsh-triton-riscv/policy.md | 86 +- packages/dsh-triton-riscv/prompts/0-hints.md | 17 + packages/dsh-triton-riscv/prompts/1-skills.md | 18 + .../prompts/2-failure-experience.md | 13 + .../prompts/3-success-experience.md | 12 + .../prompts/4-verification.md | 12 + packages/dsh-triton-riscv/python/LICENSE | 22 + .../python/codex_agent/MEMORY.md | 286 ++ .../python/codex_agent/README.md | 81 + .../python/codex_agent/__init__.py | 32 + .../python/codex_agent/adapters/__init__.py | 5 + .../python/codex_agent/adapters/codex_cli.py | 64 + .../python/codex_agent/core/__init__.py | 15 + .../python/codex_agent/core/ports.py | 69 + .../python/codex_agent/core/workflow.py | 202 ++ .../python/codex_agent/demo.py | 343 ++ .../python/codex_agent/develop_operator.py | 1858 ++++++++++ .../python/codex_agent/diagnostic_memory.py | 326 ++ .../python/codex_agent/discover.py | 762 ++++ .../python/codex_agent/discover_operators.py | 394 +++ .../codex_agent/docs/conversation-context.md | 39 + .../docs/deepseek-harness-integration.md | 64 + .../codex_agent/docs/failure-diagnosis.md | 66 + .../python/codex_agent/docs/memory-context.md | 72 + .../codex_agent/docs/memory-evidence.md | 99 + .../codex_agent/docs/memory-selection.md | 75 + .../python/codex_agent/docs/rag-ablation.md | 124 + .../codex_agent/docs/reference-library.md | 94 + .../python/codex_agent/embeddings.py | 251 ++ .../python/codex_agent/evaluate_diagnosis.py | 118 + .../codex_agent/evaluate_memory_modes.py | 216 ++ .../codex_agent/evaluate_memory_retrieval.py | 126 + .../python/codex_agent/failure_diagnosis.py | 552 +++ .../python/codex_agent/harness/__init__.py | 19 + .../python/codex_agent/harness/__main__.py | 4 + .../python/codex_agent/harness/cli.py | 74 + .../python/codex_agent/harness/config.py | 127 + .../python/codex_agent/harness/context.py | 30 + .../python/codex_agent/harness/cordis.yml | 72 + .../python/codex_agent/harness/mcp_demo.py | 78 + .../python/codex_agent/harness/mcp_server.py | 388 +++ .../codex_agent/harness/native_bridge.py | 123 + .../python/codex_agent/harness/plugin.py | 77 + .../codex_agent/harness/requirements.txt | 4 + .../python/codex_agent/harness/runtime.py | 182 + .../python/codex_agent/memory.py | 1367 ++++++++ .../python/codex_agent/memory_api.py | 98 + .../python/codex_agent/memory_chunking.py | 275 ++ .../python/codex_agent/memory_context.py | 233 ++ .../python/codex_agent/memory_evidence.py | 298 ++ .../python/codex_agent/memory_selection.py | 79 + .../python/codex_agent/memory_view.py | 148 + .../python/codex_agent/migrate_memory.py | 124 + .../python/codex_agent/model_router.py | 258 ++ .../codex_agent/operator-spec.schema.json | 130 + .../python/codex_agent/operator_agent.py | 361 ++ .../python/codex_agent/operator_baseline.py | 284 ++ .../codex_agent/operator_development.py | 540 +++ .../python/codex_agent/operator_lifecycle.py | 720 ++++ .../python/codex_agent/operator_status.py | 203 ++ .../python/codex_agent/operator_tools.py | 109 + .../python/codex_agent/paths.py | 15 + .../python/codex_agent/pipeline_observer.py | 566 +++ .../python/codex_agent/platform/__init__.py | 6 + .../python/codex_agent/platform/__main__.py | 33 + .../python/codex_agent/platform/api.py | 290 ++ .../platform/conversation_context.py | 321 ++ .../python/codex_agent/platform/executor.py | 673 ++++ .../codex_agent/platform/requirements.txt | 3 + .../python/codex_agent/platform/service.py | 131 + .../python/codex_agent/platform/store.py | 390 +++ .../python/codex_agent/project_diagnosis.py | 111 + .../python/codex_agent/project_repair.py | 72 + .../python/codex_agent/project_tools.py | 215 ++ .../python/codex_agent/reference_library.py | 430 +++ .../python/codex_agent/remote_executor.py | 451 +++ .../python/codex_agent/run_validation.py | 225 ++ .../codex_agent/specs/square_and_mul.json | 38 + .../codex_agent/specs/tanh_and_mul.json | 38 + .../codex_agent/summarize_operator_results.py | 254 ++ .../python/codex_agent/test_planner.py | 267 ++ .../python/codex_agent/tests/__init__.py | 1 + .../tests/fixtures/diagnosis_cases.json | 220 ++ .../fixtures/memory_retrieval_cases.json | 206 ++ .../fixtures/memory_retrieval_challenge.json | 283 ++ .../python/examples/flaggems/relu_and_mul.py | 14 + .../examples/flaggems/test_relu_and_mul.py | 6 + .../tests/test_conversation_context.py | 136 + .../python/codex_agent/tests/test_demo.py | 77 + .../tests/test_develop_operator.py | 623 ++++ .../tests/test_diagnostic_memory.py | 144 + .../python/codex_agent/tests/test_discover.py | 169 + .../tests/test_discover_operators.py | 115 + .../codex_agent/tests/test_embeddings.py | 112 + .../tests/test_evaluate_memory_modes.py | 41 + .../tests/test_failure_diagnosis.py | 81 + .../python/codex_agent/tests/test_harness.py | 200 ++ .../codex_agent/tests/test_mcp_tools.py | 176 + .../python/codex_agent/tests/test_memory.py | 540 +++ .../codex_agent/tests/test_memory_context.py | 166 + .../codex_agent/tests/test_memory_evidence.py | 176 + .../tests/test_memory_retrieval_evaluation.py | 21 + .../tests/test_memory_selection.py | 139 + .../codex_agent/tests/test_migrate_memory.py | 48 + .../codex_agent/tests/test_model_router.py | 35 + .../codex_agent/tests/test_native_bridge.py | 71 + .../codex_agent/tests/test_operator_agent.py | 150 + .../tests/test_operator_baseline.py | 52 + .../tests/test_operator_development.py | 197 ++ .../tests/test_operator_lifecycle.py | 333 ++ .../codex_agent/tests/test_operator_status.py | 90 + .../tests/test_pipeline_observer.py | 183 + .../codex_agent/tests/test_platform_api.py | 236 ++ .../tests/test_platform_service.py | 373 ++ .../codex_agent/tests/test_platform_store.py | 45 + .../tests/test_plugin_migration.py | 99 + .../tests/test_project_diagnosis.py | 18 + .../codex_agent/tests/test_project_tools.py | 67 + .../tests/test_reference_library.py | 285 ++ .../codex_agent/tests/test_remote_executor.py | 178 + .../codex_agent/tests/test_run_validation.py | 173 + .../tests/test_summarize_operator_results.py | 81 + .../codex_agent/tests/test_test_planner.py | 32 + .../tests/test_validate_operator.py | 178 + .../tests/test_validation_evidence.py | 160 + .../python/codex_agent/tests/test_workflow.py | 55 + .../python/codex_agent/validate_operator.py | 497 +++ .../python/codex_agent/validation_evidence.py | 253 ++ .../dsh-triton-riscv/python/pyproject.toml | 31 + packages/dsh-triton-riscv/scripts/build.mjs | 47 + .../scripts/check-package.mjs | 45 + .../dsh-triton-riscv/scripts/native-host.mjs | 146 + .../dsh-triton-riscv/scripts/setup-backend.sh | 10 + packages/dsh-triton-riscv/scripts/setup.sh | 5 + .../scripts/start-workbench.mjs | 22 + .../scripts/test-native-host.mjs | 33 + .../dsh-triton-riscv/test/plugin.test.mjs | 166 - .../tests/integration/native-host.spec.ts | 18 + .../tests/native-host.spec.ts | 264 ++ .../tests/unit/client.spec.ts | 138 + .../tests/unit/inputs.spec.ts | 100 + .../tests/unit/native-adapter.spec.ts | 286 ++ .../tests/unit/native-state.spec.ts | 32 + .../tests/unit/outputs.spec.ts | 143 + .../tests/unit/plugin.spec.ts | 78 - packages/dsh-triton-riscv/vitest.config.ts | 5 + tools/scripts/install-all.sh | 2 +- 187 files changed, 35389 insertions(+), 529 deletions(-) create mode 100644 packages/dsh-triton-riscv/.gitignore create mode 100644 packages/dsh-triton-riscv/.npmignore create mode 100644 packages/dsh-triton-riscv/DIRECTORY_MAP.zh.md create mode 100644 packages/dsh-triton-riscv/LICENSE create mode 100644 packages/dsh-triton-riscv/LICENSE.triton create mode 100644 packages/dsh-triton-riscv/MIGRATION.md create mode 100644 packages/dsh-triton-riscv/REVIEW_FOLLOWUP.md create mode 100644 packages/dsh-triton-riscv/TESTING.md create mode 100644 packages/dsh-triton-riscv/VERIFICATION.md create mode 100644 packages/dsh-triton-riscv/frontend/index.html create mode 100644 packages/dsh-triton-riscv/frontend/package-lock.json create mode 100644 packages/dsh-triton-riscv/frontend/package.json create mode 100644 packages/dsh-triton-riscv/frontend/src/App.tsx create mode 100644 packages/dsh-triton-riscv/frontend/src/api.test.ts create mode 100644 packages/dsh-triton-riscv/frontend/src/api.ts create mode 100644 packages/dsh-triton-riscv/frontend/src/format.test.tsx create mode 100644 packages/dsh-triton-riscv/frontend/src/format.tsx create mode 100644 packages/dsh-triton-riscv/frontend/src/main.tsx create mode 100644 packages/dsh-triton-riscv/frontend/src/styles.css create mode 100644 packages/dsh-triton-riscv/frontend/src/test/setup.ts create mode 100644 packages/dsh-triton-riscv/frontend/src/types.ts create mode 100644 packages/dsh-triton-riscv/frontend/tsconfig.json create mode 100644 packages/dsh-triton-riscv/frontend/vite.config.ts create mode 100644 packages/dsh-triton-riscv/lib/config.js create mode 100644 packages/dsh-triton-riscv/lib/native-adapter.js create mode 100644 packages/dsh-triton-riscv/lib/native-bridge.js create mode 100644 packages/dsh-triton-riscv/lib/native-state.js create mode 100644 packages/dsh-triton-riscv/lib/prompts.js create mode 100644 packages/dsh-triton-riscv/migration-provenance.json create mode 100644 packages/dsh-triton-riscv/native.js create mode 100644 packages/dsh-triton-riscv/prompts/0-hints.md create mode 100644 packages/dsh-triton-riscv/prompts/1-skills.md create mode 100644 packages/dsh-triton-riscv/prompts/2-failure-experience.md create mode 100644 packages/dsh-triton-riscv/prompts/3-success-experience.md create mode 100644 packages/dsh-triton-riscv/prompts/4-verification.md create mode 100644 packages/dsh-triton-riscv/python/LICENSE create mode 100644 packages/dsh-triton-riscv/python/codex_agent/MEMORY.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/README.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/__init__.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/adapters/__init__.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/adapters/codex_cli.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/core/__init__.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/core/ports.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/core/workflow.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/demo.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/develop_operator.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/diagnostic_memory.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/discover.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/discover_operators.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/docs/conversation-context.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/docs/deepseek-harness-integration.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/docs/failure-diagnosis.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/docs/memory-context.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/docs/memory-evidence.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/docs/memory-selection.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/docs/rag-ablation.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/docs/reference-library.md create mode 100644 packages/dsh-triton-riscv/python/codex_agent/embeddings.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/evaluate_diagnosis.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/evaluate_memory_modes.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/evaluate_memory_retrieval.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/failure_diagnosis.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/__init__.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/__main__.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/cli.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/config.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/context.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/cordis.yml create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/mcp_demo.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/mcp_server.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/native_bridge.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/plugin.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/requirements.txt create mode 100644 packages/dsh-triton-riscv/python/codex_agent/harness/runtime.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/memory.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/memory_api.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/memory_chunking.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/memory_context.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/memory_evidence.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/memory_selection.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/memory_view.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/migrate_memory.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/model_router.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/operator-spec.schema.json create mode 100644 packages/dsh-triton-riscv/python/codex_agent/operator_agent.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/operator_baseline.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/operator_development.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/operator_lifecycle.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/operator_status.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/operator_tools.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/paths.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/pipeline_observer.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/platform/__init__.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/platform/__main__.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/platform/api.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/platform/conversation_context.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/platform/executor.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/platform/requirements.txt create mode 100644 packages/dsh-triton-riscv/python/codex_agent/platform/service.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/platform/store.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/project_diagnosis.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/project_repair.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/project_tools.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/reference_library.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/remote_executor.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/run_validation.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/specs/square_and_mul.json create mode 100644 packages/dsh-triton-riscv/python/codex_agent/specs/tanh_and_mul.json create mode 100644 packages/dsh-triton-riscv/python/codex_agent/summarize_operator_results.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/test_planner.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/__init__.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/fixtures/diagnosis_cases.json create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/fixtures/memory_retrieval_cases.json create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/fixtures/memory_retrieval_challenge.json create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/fixtures/repository/python/examples/flaggems/relu_and_mul.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/fixtures/repository/python/examples/flaggems/test_relu_and_mul.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_conversation_context.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_demo.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_develop_operator.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_diagnostic_memory.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_discover.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_discover_operators.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_embeddings.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_evaluate_memory_modes.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_failure_diagnosis.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_harness.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_mcp_tools.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_memory.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_memory_context.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_memory_evidence.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_memory_retrieval_evaluation.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_memory_selection.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_migrate_memory.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_model_router.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_native_bridge.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_operator_agent.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_operator_baseline.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_operator_development.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_operator_lifecycle.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_operator_status.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_pipeline_observer.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_platform_api.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_platform_service.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_platform_store.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_plugin_migration.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_project_diagnosis.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_project_tools.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_reference_library.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_remote_executor.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_run_validation.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_summarize_operator_results.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_test_planner.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_validate_operator.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_validation_evidence.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/tests/test_workflow.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/validate_operator.py create mode 100644 packages/dsh-triton-riscv/python/codex_agent/validation_evidence.py create mode 100644 packages/dsh-triton-riscv/python/pyproject.toml create mode 100644 packages/dsh-triton-riscv/scripts/build.mjs create mode 100644 packages/dsh-triton-riscv/scripts/check-package.mjs create mode 100644 packages/dsh-triton-riscv/scripts/native-host.mjs create mode 100644 packages/dsh-triton-riscv/scripts/setup-backend.sh create mode 100644 packages/dsh-triton-riscv/scripts/setup.sh create mode 100644 packages/dsh-triton-riscv/scripts/start-workbench.mjs create mode 100644 packages/dsh-triton-riscv/scripts/test-native-host.mjs delete mode 100644 packages/dsh-triton-riscv/test/plugin.test.mjs create mode 100644 packages/dsh-triton-riscv/tests/integration/native-host.spec.ts create mode 100644 packages/dsh-triton-riscv/tests/native-host.spec.ts create mode 100644 packages/dsh-triton-riscv/tests/unit/client.spec.ts create mode 100644 packages/dsh-triton-riscv/tests/unit/inputs.spec.ts create mode 100644 packages/dsh-triton-riscv/tests/unit/native-adapter.spec.ts create mode 100644 packages/dsh-triton-riscv/tests/unit/native-state.spec.ts create mode 100644 packages/dsh-triton-riscv/tests/unit/outputs.spec.ts delete mode 100644 packages/dsh-triton-riscv/tests/unit/plugin.spec.ts create mode 100644 packages/dsh-triton-riscv/vitest.config.ts diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index da7062f..3d3ec72 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,6 +6,12 @@ repos: - id: trailing-whitespace - id: check-merge-conflict - id: check-yaml + exclude: ^packages/dsh-triton-riscv/python/codex_agent/harness/cordis\.yml$ + # The retained SDK demo uses Harness's !!js tags. Parse only; never execute. + - id: check-yaml + alias: check-harness-sdk-yaml + args: [--unsafe] + files: ^packages/dsh-triton-riscv/python/codex_agent/harness/cordis\.yml$ - id: check-json - id: check-added-large-files diff --git a/README.md b/README.md index b4f9867..269980c 100644 --- a/README.md +++ b/README.md @@ -39,3 +39,9 @@ DEEPSEEK_API_KEY=sk-... ./dsh web [`dsh-triton-riscv`](packages/dsh-triton-riscv/README.md) adds guarded Triton-RISCV operator discovery, development, validation, diagnosis, repair, memory retrieval, and remote RISC-V execution to the Harness web profile. + +The install-all script also installs this package's Python backend, which requires +Python >=3.10. If `python3` is older, run +`PYTHON=/absolute/path/to/python3.10 ./tools/scripts/install-all.sh`. +Configure `triton-riscv-native-host` in `config.yml` to enable it; installation +alone does not enable operator execution or write permissions. diff --git a/config.yml.example b/config.yml.example index e25211b..335da4a 100644 --- a/config.yml.example +++ b/config.yml.example @@ -31,3 +31,26 @@ hfToken: '' # [Optional] HuggingFace API base URL hfEndpoint: https://huggingface.co + +# Optional Triton-RISCV tools. Installed once in the Harness profile; repoRoot is +# only the operator worktree, not an installation directory. Keep disabled until +# paths are configured. No model API key belongs in this block. +- id: triton-riscv-native-host + config: + enabled: false + repoRoot: '' # Absolute operator checkout path + # Optional; defaults to packages/dsh-triton-riscv/.venv/bin/python + # python: /absolute/path/to/harness/packages/dsh-triton-riscv/.venv/bin/python + permissions: + validation: false + development: false + repair: false + remote: + host: '' # SSH config alias, e.g. sg2044 + repository: '' # Absolute remote checkout, with prepared toolchain + required: false + memory: + retrievalMode: legacy + contextFormat: classic + embedding: + provider: none diff --git a/packages/dsh-triton-riscv/.gitignore b/packages/dsh-triton-riscv/.gitignore new file mode 100644 index 0000000..5dec7de --- /dev/null +++ b/packages/dsh-triton-riscv/.gitignore @@ -0,0 +1,20 @@ +.venv/ +node_modules/ +frontend/dist/ +python/build/ +python/dist/ +python/*.egg-info/ +python/codex_agent/frontend/ +python/codex_agent/harness/bundle/ +__pycache__/ +*.pyc +.state/ +.runtime/ +*.tgz +.env +!lib/ +/lib/* +!lib/client.js +!lib/native-*.js +!lib/config.js +!lib/prompts.js diff --git a/packages/dsh-triton-riscv/.npmignore b/packages/dsh-triton-riscv/.npmignore new file mode 100644 index 0000000..cedc26e --- /dev/null +++ b/packages/dsh-triton-riscv/.npmignore @@ -0,0 +1,12 @@ +.venv/ +node_modules/ +frontend/node_modules/ +python/build/ +python/dist/ +python/*.egg-info/ +**/__pycache__/ +**/*.pyc +*.log +.state/ +*.tgz +.env diff --git a/packages/dsh-triton-riscv/DIRECTORY_MAP.zh.md b/packages/dsh-triton-riscv/DIRECTORY_MAP.zh.md new file mode 100644 index 0000000..cd68238 --- /dev/null +++ b/packages/dsh-triton-riscv/DIRECTORY_MAP.zh.md @@ -0,0 +1,72 @@ +# 迁移后代码在哪里 + +主仓库工作目录是 `/Users/cl25/harness-plugin-pr`,Agent 插件集中在 +`packages/dsh-triton-riscv/`。这是后续开发主入口;不再需要从 +`/Users/cl25/ruyi_AI/codex_agent` 导入运行时代码。 + +## 插件与原生 Harness + +- `package.json`:插件包、入口和安装/构建/测试命令。 +- `lib/config.js`:把仓库 `config.yml` 中的明确参数校验后统一传给 MCP、审批桥与状态存储。 +- `prompts/`、`lib/prompts.js`:提示、技能步骤、失败经验、成功经验、验收规则五类提示词。 +- `cordis.patch.yml`:把领域策略、原生适配器和 Python MCP 接入宿主。 +- `index.js`:分段注册提示词;`policy.md` 是构建生成的兼容资源,不是另一份手改源文件。 +- `native.js`、`lib/native-adapter.js`:原生工具拦截、审批、任务状态和 RAG 注入。 +- `lib/native-state.js`:按仓库/会话保存任务快照,避免不同任务串用状态。 +- `lib/native-bridge.js`、`python/codex_agent/harness/native_bridge.py`:可信宿主审批桥。模型不能调用它给自己批准。 +- `scripts/native-host.mjs`:原生 Harness 安装和网页启动入口。原生 agent loop 由宿主提供,不复制到插件里。 + +## Python 后端和算子工具 + +- `python/pyproject.toml`:独立后端包 `dsh-triton-riscv-agent` 的依赖和安装入口。 +- `python/codex_agent/harness/mcp_server.py`:18 个领域 MCP 工具的参数和接口。 +- `discover_operators.py`、`operator_tools.py`:发现实现、测试、语义和静态风险。 +- `operator_development.py`:合同、开发提案、审批应用。 +- `operator_lifecycle.py`:测试计划、回执、失败诊断、修复提案和复测。 +- `remote_executor.py`:SSH 预检,临时快照,传文件,真实 pytest,日志与清理。不会把测试文件覆盖到服务器主工作树。 +- `failure_diagnosis.py`、`validation_evidence.py`:报错分类和独立核对回执,不把模型说“成功”当证据。 +- `project_tools.py`:项目盘点、批量验证计划、任务结果、离线夹具评测。 + +本节省略目录前缀的文件都在 `python/codex_agent/`。 + +## RAG、上下文和记忆 + +- `memory.py`:SQLite 父案例、块、检索及模式。 +- `memory_chunking.py`:结构切分、预算和来源。 +- `memory_evidence.py`:区分建议、执行动作、修复与验证证据。 +- `memory_selection.py`、`memory_view.py`、`memory_context.py`:候选选择、父案例聚合和上下文组织。 +- `memory_api.py`、`diagnostic_memory.py`:查询构造及工具返回。 +- `embeddings.py`:可选 Embedding 适配,不代表默认启用。 +- `migrate_memory.py`:只读备份旧库,在副本上处理结构和证据引用。 +- `platform/conversation_context.py`:原工作台的近期对话、摘要和预算管理。 +- 原生 Harness 的完整对话与压缩归宿主管理;插件通过 `lib/native-adapter.js` 保留当前任务合同、执行状态及历史证据。两条路径不会叠加两个 agent loop。 + +当前保守默认为 `legacy / provider=none / classic`;长期记忆数据库不打入源码发行包。 + +## 两个界面都保留 + +1. 原生 Harness 聊天界面:由 Harness 提供,直接调用上述插件工具和原生审批。 +2. 原来的 React 工作台:源代码在 `frontend/src/`,`App.tsx` 是页面入口;FastAPI 在 `python/codex_agent/platform/`。构建产物进入 `python/codex_agent/frontend/dist/`,通过 `npm run workbench` 启动。 + +`lib/client.js` 在原生侧栏提供“算子工作台”按钮,点击后用弹层打开已启动的工作台; +兼容 `?tritonWorkbench=1`。关闭弹层返回原生对话。 +插件安装不会把原生聊天界面强制替换成旧工作台,也不会默认同时启动两个后台。 + +## 状态、代码产物与实验记录 + +- `.state/native-local.json`:本机非密钥配置,不提交。密钥通过环境变量或系统钥匙串读取。 +- `.state/native-host/`:默认原生 Harness profile;`DSH_HOME` 可指定独立 profile。 +- `.state/agent/`:默认插件运行状态;`TRITON_RISCV_STATE_DIR` 可调整。 +- `.state/history-20260921/`:迁移的私人历史库副本与证据清单,不提交。 +- `.runtime/native-host/`:当前本机固定版本的宿主运行副本,不是插件交付源码,不打包。 +- `TRITON_RISCV_REPO_ROOT`:要操作的算子仓库。生成实现写入其 `python/examples/flaggems/`,合同写入 `tasks/operators/`,提案、日志和回执写入其 `agent-results/`。 +- 本次真实验收独立目录:`/Users/cl25/ruyi_AI/agent-results/migration/20260921-live-acceptance/`。里面的 `operator-workspace/` 不是用户正式算子仓库;生成和修复实验只改这里。 +- 历史评测、月报和汇报文件继续保留在 `/Users/cl25/ruyi_AI/agent-results/`、`united-interns/`。它们不被作为插件运行依赖,也没有全部塞入新仓库。 + +## 测试与交付 + +后端测试在 `python/codex_agent/tests/`,插件 Vitest 单测在 `tests/unit/`,仓库集成入口在 `tests/integration/`,实际原生宿主测试在 `tests/native-host.spec.ts`,前端测试在 `frontend/src/`。 +运行步骤见 `README.zh.md`,迁移边界见 `MIGRATION.md`,验证证据见 `VERIFICATION.md`。 +旧 LangGraph 学习实现、专属测试、说明和依赖已删除。`core/` 和 `adapters/` +不是 LangGraph:它们仍支撑开发 CLI 的状态与模型接口;`discover.py` 和 +`run_validation.py` 仍被项目级 MCP 工具复用,不能仅因文件名相近就删除。 diff --git a/packages/dsh-triton-riscv/LICENSE b/packages/dsh-triton-riscv/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/packages/dsh-triton-riscv/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/dsh-triton-riscv/LICENSE.triton b/packages/dsh-triton-riscv/LICENSE.triton new file mode 100644 index 0000000..a961a80 --- /dev/null +++ b/packages/dsh-triton-riscv/LICENSE.triton @@ -0,0 +1,22 @@ + MIT License + + Copyright (c) Microsoft Corporation. + Copyright (c) 2026-present Ruyi Community + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/packages/dsh-triton-riscv/MIGRATION.md b/packages/dsh-triton-riscv/MIGRATION.md new file mode 100644 index 0000000..2c41626 --- /dev/null +++ b/packages/dsh-triton-riscv/MIGRATION.md @@ -0,0 +1,83 @@ +# Migration Boundaries + +## Scope and Sources + +The Harness fork is the new home for plugin development. Neither original checkout +is deleted. No commits, pushes, target compiler changes or credential transfers +are part of this migration. Historical memory may be copied explicitly by the +opt-in migration command; installation itself never opens an original database. + +- `ruyi_AI/codex_agent`: latest memory/chunking/retrieval/evidence, context summaries, + CLI development/repair, diagnostics and pipeline observation. +- `triton-riscv-tool-pr/codex_agent`: remote executor, audited receipts, current + typed lifecycle, approval-aware FastAPI/frontend, ISRC Responses and streaming. +- Existing Harness package: manifest, policy, Cordis bundle and optional web client. + +Adapters reconcile shared spec validation, typed retrieval through MCP, +evidence-gated memory writes, stable source-locked validation plan IDs and managed +context checkpoints. `migration-provenance.json` records source paths and hashes. +Earlier raw experiments remain in their archives, not as runtime dependencies. + +The standalone LangGraph experiment was removed on 2026-09-24 together with +its dedicated tests, documentation and optional dependencies. The provenance +manifest is an immutable record of the original migration, not a current file +list; its removed-file entries are retained for traceability. Shared core, +discovery and validation modules still serve the CLI and MCP paths. + +The Python namespace remains `codex_agent`, distribution `dsh-triton-riscv-agent`. +Launchers use `python -I` so an old backend in the target checkout cannot shadow +the installed plugin. Generated operator files still go to the configured checkout. + +## Ownership + +The native host owns its loop, credentials, sessions and compaction. The Python +plugin owns contracts, guards, plans, patches, diagnosis, memory and receipts. +The optional workbench owns a separate UI, approvals, chat SQLite and context +summaries, using the SDK and the same MCP tools. SSH owns hardware execution. + +Installing this plugin does not make native host sessions and workbench sessions +interchangeable. Host approvals must reach trusted lifecycle APIs before protected +tools execute. No tool allows the model to approve its own changes. + +## Data Compatibility + +Setup does not open production SQLite. To reuse history, point +`TRITON_RISCV_MEMORY_DB` to an explicitly prepared backup. Existing schema migration +logic is retained. Preserve the associated evidence paths; missing files cannot +be treated as verified. `TRITON_RISCV_STATE_DIR` relocates session data, not target +receipts, proposals or generated source. Original experiment baselines stay intact. + +## Verification Boundaries + +Migration tests cover installed-package resolution outside the source tree, +served assets, HTTP session controls, context persistence, actual MCP serialization +and memory evidence. Inherited tests cover discovery, contracts, approval, +rollback, diagnosis, RAG and SSH command construction. Synthetic results are not +real operator success rates. + +SDK initialization requires no model turn. Paid model execution, real remote +compilation and installation into the target fork's full web profile are separate +acceptance checks; passing local tests does not prove them. + +The native adapter now uses the host approval service and dynamic context API. +Domain state is stored separately by repository/session; it does not add unknown +events to the host's versioned session log. Native conversation compression stays +with the host. The workbench retains its independent approvals and managed context. +Production authentication, live-model/SSH acceptance and chat-history migration +are follow-up work, not implicitly complete. This is a trusted local plugin, not +an authorization boundary against an unrestricted host shell. + +## Opt-in Memory Copy + +`python -I -m codex_agent.migrate_memory --source DATABASE --source-root ROOT +--destination NEW_DIRECTORY` uses a read-only SQLite connection and the backup +API, including committed WAL state. Schema changes, chunk rebuilding and stale +vector removal apply only to the copy. Referenced evidence is archived within +size/type limits and a manifest retains original paths, hashes and gaps. Missing +evidence stays unknown; stored outcomes are not promoted to newly verified facts. + +The local 2026-09-21 acceptance copy contains five legacy memory rows and fifty +evidence files. It is private runtime data, not part of the package. The original +database checksum remained unchanged. Raw evidence files remain unmodified; an +absolute path embedded inside a copied raw log may still refer to the original +machine. Consult the relocation manifest in that case. diff --git a/packages/dsh-triton-riscv/README.md b/packages/dsh-triton-riscv/README.md index 53f17c1..bb5263c 100644 --- a/packages/dsh-triton-riscv/README.md +++ b/packages/dsh-triton-riscv/README.md @@ -1,166 +1,266 @@ -# dsh-triton-riscv +# Triton-RISCV Agent Plugin -An installable DeepSeek Harness bundle for the guarded Triton-RISCV operator -development and validation tools. +An installable DeepSeek Harness domain plugin with its own Python backend and +an optional React/FastAPI workbench. The target Triton-RISCV checkout is **data +and the compilation workspace**, not where the backend must be installed. -## What The Plugin Adds +[中文说明](README.zh.md) | [Migration boundaries](MIGRATION.md) -The bundle adds two Cordis rows to an existing Harness profile: - -1. A domain policy plugin contributes the Triton-RISCV lifecycle rules to the - assembled system prompt. -2. The official Harness MCP client starts - `python -m codex_agent.harness.mcp_server` and exposes its typed tools as - `mcp__triton_riscv__*`. -3. A Harness Web client plugin occupies the root UI slot and displays the - existing Triton-RISCV React/FastAPI workbench. - -The model and Agent loop remain owned by Harness. Discovery, contract checking, -source proposals, validation, diagnosis, bounded repair, remote SSH execution, -and trusted validation evidence remain owned by the Python domain engine in a -Triton-RISCV checkout. +## Layout ```text -Harness profile - -> dsh-triton-riscv bundle - -> system-prompt policy - -> official dsh-mcp-client - -> Python Triton-RISCV MCP server - -> operator lifecycle and RISC-V remote executor +index.js + prompts/ + cordis.patch.yml Structured policy and bundle registration +lib/config.js Validated host configuration -> Python ABI +native.js + lib/native-*.js Native approval, task state and RAG adapter +lib/client.js Native sidebar entry and optional workbench overlay +python/codex_agent/ Installable Python backend + harness/ MCP tools and SDK adapter + platform/ FastAPI, sessions, approvals, context + memory*.py + diagnostic_memory.py RAG, evidence, chunking and memory + operator_*.py + remote_executor.py Development, validation, repair and SSH +frontend/ React + TypeScript source and tests +scripts/ Build, setup and launchers ``` -## Prerequisites - -- DeepSeek Harness with the `web` profile and Node.js 22 or newer -- a Triton-RISCV checkout containing `codex_agent` -- a Python environment with `codex_agent/harness/requirements.txt` installed -- optional SSH configuration and a prepared RISC-V host for live validation - -The bundle fails at Harness startup when the Python MCP module cannot be -imported instead of silently starting without the domain tools. +## Install Locally -## Install From A Harness Checkout - -From the Harness repository root, point the plugin at a separate Triton-RISCV -checkout: +Requires Node >=22.19, npm, Python >=3.10. The host repository also requires its +root README prerequisites (pnpm >=11 and the Harness submodule). ```sh -export TRITON_RISCV_CHECKOUT=/absolute/path/to/triton-riscv -export TRITON_RISCV_MCP_PYTHON="$TRITON_RISCV_CHECKOUT/.harness-venv/bin/python" -export TRITON_RISCV_WORKBENCH_PORT=8765 -./dsh plugin --profile web add ./packages/dsh-triton-riscv -dsh --profile web --dump-config -dsh web +cd packages/dsh-triton-riscv +npm run setup +export TRITON_RISCV_REPO_ROOT=/absolute/path/to/triton-riscv +export TRITON_RISCV_MCP_PYTHON="$PWD/.venv/bin/python" ``` -When this package lives in the RuyiAI Harness repository, the repository-level -`./tools/scripts/install-all.sh` command builds and installs it automatically -with the other packages. - -The config dump should contain both `triton-riscv-domain-policy` and -`mcp-triton-riscv`. Starting `dsh web` also starts the Python workbench and the -Harness page displays that workbench in its root slot. Add `?nativeHarness=1` -to the Harness URL when the stock Harness interface is needed. +Setup builds the frontend and policy resources and installs the backend in the +plugin's `.venv`. Re-run setup after source changes, or use +`.venv/bin/python -m pip install -e './python[workbench]'` for editable development. +No API key is needed to install, load the page or run read-only MCP discovery. -The embedded client defaults to `http://127.0.0.1:8765`. For a different port -or externally hosted workbench, open the Harness URL with an encoded -`?tritonWorkbenchUrl=https://host/path` query parameter. Set -`TRITON_RISCV_WORKBENCH_AUTOSTART=0` when that external service is already -managed by another process. +## Native Harness Plugin -For read-only discovery, no RISC-V server is required. Try: - -```text -Call the Triton-RISCV discovery tool for relu_and_mul and summarize its -implementation, tests, and validation command. Do not run validation. -``` - -## Enable Remote Validation Deliberately - -All expensive or mutating operations remain disabled by default. Configure the -host before starting Harness: +After building the host per its README, register this package with the host CLI: ```sh -export RISCV_HOST=sg2044 -export RISCV_REPO=/home/lichunbo/work/triton-riscv -export TRITON_RISCV_REQUIRE_REMOTE=1 -export TRITON_RISCV_ALLOW_VALIDATION=1 -export TRITON_RISCV_REQUIRE_APPROVED_VALIDATION=1 +cd /absolute/path/to/harness +DSH_HOME="$PWD/.dsh" pnpm --dir thirdparty/deepseek-harness dsh plugin --profile web add "$PWD/packages/dsh-triton-riscv" +./dsh web ``` -Enable source application only on a trusted development checkout: - -```sh -export TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY=1 -export TRITON_RISCV_ALLOW_REPAIR_APPLY=1 +Configure the `triton-riscv-native-host` row in the repository's **config.yml**, +using the block in `config.yml.example`. Example: + +```yaml +- id: triton-riscv-native-host + config: + enabled: true + repoRoot: /absolute/path/to/triton-riscv + permissions: + validation: false + development: false + repair: false + memory: + retrievalMode: legacy + contextFormat: classic + embedding: + provider: none ``` -The model cannot select the SSH host, repository path, arbitrary command, or -files to synchronize. It also cannot approve its own proposal or validation -plan. - -The optional workbench provides the host review boundary for generated -implementation proposals and validation plans at -`/api/operator-development-proposals/{proposal_id}/decision` and -`/api/validation-plans/{run_id}/decision`. Harness model turns receive only -the resulting approval state and can then apply or execute the exact approved -identifier. - -## Diagnostic Memory - -Executed validation receipts are stored as structured evidence in -`agent-results/memory.sqlite3` by default. Harness can call -`mcp__triton_riscv__retrieve_operator_memory` before development or repair to -reuse relevant successful runs and failure diagnoses. The default retrieval is -local and deterministic, so no embedding API is required. - -An OpenAI-compatible embedding endpoint is optional: +Installation is **once per Harness profile**, not inside every operator checkout. +The Python environment lives in this plugin's `.venv`; `repoRoot` selects data. +The bundle is inert until enabled with valid paths. The native entry derives MCP, +approval-bridge and state-store settings from the same validated configuration. +The official MCP client is mounted as a child and stops when this plugin unloads. +Its disabled dependency row `mcp-triton-riscv` must remain disabled to avoid a +duplicate namespace. No global environment mutation or second model loop occurs. + +Model credentials and provider settings are configured in **the host Harness**. +The plugin does not select the host model or create another model loop. It adds +domain policy, a stdio MCP server and a native approval/context adapter; it does +not replace the host UI by default. Integration is tested against the host +revision recorded in [VERIFICATION.md](VERIFICATION.md). +The root `tools/scripts/install-all.sh` builds/registers packages and invokes this +package's `setup:backend` hook to install Python dependencies. Python >=3.10 is +required for this plugin (set `PYTHON` to an appropriate interpreter). + +Alternatively, this package provides a persistent local launcher using an +already-built pinned host. It does not depend on a temporary source directory: ```sh -export TRITON_RISCV_EMBEDDING_PROVIDER=openai-compatible -export TRITON_RISCV_EMBEDDING_MODEL=your-embedding-model -export TRITON_RISCV_EMBEDDING_BASE_URL=https://example.test/v1 -export AGENT_EMBEDDING_API_KEY=... +export DSH_NATIVE_SOURCE=/absolute/path/to/built/deepseek-harness +export TRITON_RISCV_REPO_ROOT=/absolute/path/to/triton-riscv +export DSH_MODEL=your-model-id +# Supply ISRC_API_KEY via the environment or the native Models page. +npm run native:install +npm run native ``` -Historical results are hints, not authority. Current contracts, acceptance -tests, environment checks, and validation receipts always take precedence. - -## Test The Bundle - -The package has no install-time dependencies: +`pnpm` must be executable on PATH for installation. The launcher uses a private +`.state/native-host` profile and prints the authenticated local URL (port 8780; +override with `TRITON_RISCV_NATIVE_PORT`). Its optional `.state/native-local.json` +accepts only configuration keys, never the API key. Do not share the printed +local access token in reports. The ISRC adapter configuration is local to this +launcher, not a model constraint imposed on other Harness installations. + +Tools: `discover_operator`, `check_validation_environment`, +`prepare_operator_development`, `propose_operator_implementation`, +`get_operator_implementation_proposal`, `apply_operator_implementation` (alias `apply_development_proposal`), +`validate_operator`, `execute_approved_validation`, `diagnose_failure`, +`propose_repair`, `apply_repair`, `retrieve_operator_memory`, `inspect_project`, +`prepare_validation_job`, `execute_validation_job`, `get_validation_job`, and +`evaluate_plugin_fixtures`. Validation jobs accept discovered target IDs only, +require native approval and cannot be replayed. Project checks run on the local +host and are rejected when remote execution is mandatory; operator batches can +use SSH. Fixture evaluations are explicitly not production-quality metrics. + +## Existing Demonstration UI ```sh -cd packages/dsh-triton-riscv -npm test -npm pack --dry-run +# From packages/dsh-triton-riscv, with the exports above: +npm run workbench ``` -The tests check the bundle manifest, Cordis rows, safe default switches, and -system-prompt lifecycle registration without starting a model or remote host. - -## Standalone Triton-RISCV Demo Platform - -The React and FastAPI workbench remains in the Triton-RISCV checkout and can -load the same plugin policy and MCP server: +Open **http://127.0.0.1:8765**. Set `TRITON_RISCV_WORKBENCH_PORT` for another port. +The backend serves the built React assets, API and SSE stream. No Vite server is +needed. Session pin/delete, approval cards, streamed responses and receipts remain. + +For live workbench turns, supply `ISRC_API_KEY` through your terminal's secret +input mechanism; do not commit it. Defaults remain `isrc-proxy`, `gpt-5.6-sol` +and the ISRC Responses endpoint, defined in `harness/cordis.yml`. This optional +workbench uses the official SDK; its sessions are **not** the native host sessions. + +To embed the UI inside Harness, start it explicitly, then click **Operator +workbench** above Settings in the native sidebar (a code icon when collapsed). +The close button returns to the still-mounted native conversation. The button +does not start the workbench service or share sessions between the two UIs. +The legacy `?tritonWorkbench=1` link opens the same overlay, not a root replacement. +For a custom port add `&tritonWorkbenchUrl=http%3A%2F%2F127.0.0.1%3A8776`. +`?nativeHarness=1` prevents automatic opening but leaves the sidebar entry available. +This is a local workbench, not an authenticated multi-user service. Do not expose +it to the public Internet without authentication and deployment hardening. + +## Target and State + +For native repository integration configure these fields in `config.yml`: +`repoRoot`, optional `python` and `stateDir`, `permissions.validation/development/repair`, +`remote.host/repository/required`, and `memory.database/retrievalMode/contextFormat/embedding`. +Unknown fields, invalid booleans and unsafe/relative paths are rejected. +Permissions default off and approval is always required. Embedding accepts +provider/model/baseUrl/tokenizerJson/tokenBudget/apiKeyEnv; put only the secret's +environment variable **name**, never its value, in configuration. + +The following environment variables remain a compatibility interface for the +standalone launcher and Python CLIs, not the native plugin's primary configuration: + +- `TRITON_RISCV_REPO_ROOT`: target checkout; `TRITON_RISCV_CHECKOUT` is a legacy alias. +- `TRITON_RISCV_STATE_DIR`: session DB, inventory, default memory DB and SDK sessions; defaults to target `agent-results/`. +- `TRITON_RISCV_MEMORY_DB`: explicit memory database, overriding the state default. +- `RISCV_HOST`, `RISCV_REPO`: SSH alias and absolute remote checkout path. +- `TRITON_RISCV_REQUIRE_REMOTE=1`: reject local live validation. +- `TRITON_RISCV_ALLOW_VALIDATION=1`, `TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY=1`, + `TRITON_RISCV_ALLOW_REPAIR_APPLY=1`: explicit side-effect permissions, default off. +- `TRITON_RISCV_REQUIRE_APPROVED_VALIDATION=1`: require a host-approved, source-locked plan. + +Proposals, patches, receipts and their evidence paths remain under the **target +checkout's** `agent-results/`. Generated implementations/tests/tasks also go there, +not to the plugin. Remote compilation still needs SSH and the configured +Triton/Buddy/LLVM environment with `scripts/triton-riscv-env.sh` on the server. + +Approval decisions are not model-facing tools. In native Harness, calling a +typed apply/execute tool opens the host's approval UI before dispatch. The adapter +reads the exact proposal/command, verifies it belongs to this session, requests +one-shot authorization, rechecks its fingerprint, and records the trusted +decision in Python. A missing answerer, rejection, cancellation or disabled +capability never runs the action. The standalone workbench keeps its own cards. +Artifacts created in another session (including old workbench sessions) are not +implicitly authorized. Prepare a fresh proposal/plan in the active session. + +## Memory and Context + +RAG keeps the current `legacy` retrieval, `classic` rendering and +`TRITON_RISCV_EMBEDDING_PROVIDER=none` defaults. Optional providers, chunking, +candidate selection, evidence linking and evaluation entrypoints are retained. +This migration does not tune retrieval or claim higher task success rates. + +The workbench retains recent dialogue, bounded older summaries, current state +and tool evidence. Settings: `TRITON_RISCV_MANAGED_CONTEXT`, +`TRITON_RISCV_CONTEXT_WINDOW_TOKENS`, `TRITON_RISCV_CONTEXT_SAFETY_RATIO`, +`TRITON_RISCV_CONTEXT_OUTPUT_RESERVE`, `TRITON_RISCV_CONTEXT_RECENT_TURNS`, +`TRITON_RISCV_CONTEXT_SUMMARY_MODE` (`model` or offline `extractive`). +Native Harness owns its history/compaction; this plugin does not override it. + +The native adapter proactively retrieves history after discovery, new-operator +preparation and failed validation/diagnosis, using the existing retrieval and +rendering implementation. It injects current task facts, the immutable contract +and up to 6000 characters of evidence into `systemPrompt.context`. Task facts use +a separate 12000-character budget, not an advertised token count. Oversized +contracts are replaced by an explicit reference, never silently cut mid-contract. +The host's token meter and compaction manage the entire conversation window. + +Domain state is persisted atomically under `TRITON_RISCV_STATE_DIR/native-harness/`, +keyed by canonical repository and native session ID, separately from the host's +versioned session log. Source changes invalidate the previous passing status. +The host retains full chat, tool calls, native approval events and context snapshots. +The standard host profile supplies conversation compaction; a custom minimal +profile must configure it separately. The plugin does not start a second model +loop or silently reuse the workbench's model/summarizer configuration. + +History DBs, keys, `.env`, SSH credentials and raw experiments are not distributed. +To reuse history, back up a database and point to the copy. MemoryStore can +upgrade schema on open: do not use an immutable experiment baseline. Preserve +the associated receipt/log paths as well; a database path alone is not migration. + +## Verification ```sh -cd "$TRITON_RISCV_CHECKOUT" -.harness-venv/bin/python -m codex_agent.platform --port 8765 +pnpm install --frozen-lockfile +npm test # Vitest unit tests, no model or SSH +npm run test:frontend +npm run build +npm run check:package +.venv/bin/python -I -m pytest -q python/codex_agent/tests +.venv/bin/python -I -m codex_agent.harness.mcp_demo relu_and_mul --repo-root "$TRITON_RISCV_REPO_ROOT" ``` -Open `http://127.0.0.1:8765`. This standalone command remains useful while -developing the workbench without starting a complete Harness profile. +The repository's `pnpm test` discovers `tests/unit/*.spec.ts` directly. +`pnpm test:integration` / `pnpm test:all` also run the native host wrapper after +`install-all.sh`; set `TRITON_PLUGIN_TEST_HOST` only when using a disposable copy. +Unit contracts cover inputs (configuration/hooks), outputs (tools/prompts/UI), +and state (ownership, persistence, context and invalidation). See [TESTING.md](TESTING.md). + +Prompt sources are split under `prompts/` into hints, operator skills, failure +experience, success experience and verification. `lib/prompts.js` registers five +ordered sections. `policy.md` is a generated compatibility resource; change the +source sections and rebuild, not a second hand-maintained policy. Historical +cases still come from RAG; the instruction files do not fabricate experience. -## Remove +Optional real-host integration, in a **disposable** checkout of the pinned +Harness revision after installing its dependencies: ```sh -dsh plugin --profile web remove dsh-triton-riscv +TRITON_PLUGIN_TEST_HOST=/absolute/path/to/disposable/deepseek-harness npm run test:native-host ``` -## Current Boundary - -This bundle packages the model-facing policy, MCP connection, and Harness Web -entry. The Python domain engine and compiled React assets stay in the target -Triton-RISCV checkout. A later release can publish that engine and its assets -independently so the bundle no longer depends on a source checkout. +This starts the real stdio MCP server and real host tool/approval services, +temporarily places one test in that checkout and removes it afterwards. All +operator writes and memory records are temporary fixtures; the approval answerer +is deterministic and no model or SSH is called. + +## Security and Completion Limits + +These guards protect the typed domain workflow in a trusted local installation. +They are not an OS sandbox: a host that gives the model unrestricted Bash/write +access must configure its own sandbox, permissions and credential isolation. +Do not expose the trusted bridge as an MCP tool or public HTTP endpoint. +Batch/project CLIs, evaluation scripts and the prior workbench +remain packaged; they are not additional autonomous loops in the native session. +A native live-model -> approved SSH -> numerical test -> repair run still needs +the host's actual model configuration, explicit capabilities and remote environment. + +Tests use temporary fixtures, mocks and local MCP, not models or SSH. They do not +establish RISC-V numerical correctness. The obsolete LangGraph experiment and +its dependency extra have been removed; Harness remains the native orchestrator. +Optional embedding dependencies: +`.venv/bin/python -m pip install './python[embedding]'`. diff --git a/packages/dsh-triton-riscv/README.zh.md b/packages/dsh-triton-riscv/README.zh.md index 5319039..5125a62 100644 --- a/packages/dsh-triton-riscv/README.zh.md +++ b/packages/dsh-triton-riscv/README.zh.md @@ -1,73 +1,153 @@ -# dsh-triton-riscv - -这是一个面向 DeepSeek Harness 的 Triton-RISCV 算子开发插件。插件不替换 -Harness 的模型和 Agent Loop,而是向 Harness 注册领域规则、MCP 工具以及现有 -React/FastAPI 工作台入口。 - -## 代码边界 - -```text -Harness Web - -> dsh-triton-riscv 插件 - -> 注入 Triton-RISCV 生命周期规则 - -> 启动官方 dsh-mcp-client - -> 启动 Triton-RISCV checkout 中的 Python MCP 服务 - -> 算子发现、开发、验证、诊断、记忆检索和远程执行 - -> 在 Harness Web 根视图中加载 Triton-RISCV 工作台 -``` +# Triton-RISCV Agent 插件 -Harness 负责对话、模型推理和工具调度;Triton-RISCV Python 引擎负责确定性的 -算子操作。模型不能自行选择 SSH 主机、仓库路径或任意命令,也不能批准自己的 -源码提案和验证计划。 +前端、Python 后端、算子开发与修复、远程执行、RAG、记忆和上下文管理的代码, +现在统一放在这个插件目录。算子仓库仍然是独立工作区,编译器不是插件的一部分。 -## 安装 +先看 [迁移后的完整目录说明](DIRECTORY_MAP.zh.md),再看下方运行步骤。 -先准备一份包含 `codex_agent` 的 Triton-RISCV checkout: +## 按目标仓库的方式安装 -```sh -export TRITON_RISCV_CHECKOUT=/absolute/path/to/triton-riscv -export TRITON_RISCV_MCP_PYTHON="$TRITON_RISCV_CHECKOUT/.harness-venv/bin/python" -export TRITON_RISCV_WORKBENCH_PORT=8765 -``` - -在 Harness 仓库根目录执行: +从 Harness 仓库根目录复制 `config.yml.example` 为私人 `config.yml`,按根 README +填好宿主配置,然后配置其中的 `triton-riscv-native-host` 段。设置 `repoRoot` 为 +算子仓库的绝对路径,再将 `enabled` 改为 `true`。修改和执行权限先保持 `false`, +需要时分别开启 `permissions.validation`、`development`、`repair`;开启后仍要审批。 ```sh -cp config.yml.example config.yml ./tools/scripts/install-all.sh -DEEPSEEK_API_KEY=sk-... ./dsh web +./dsh web ``` -`install-all.sh` 会自动构建并安装 `packages/` 下的插件。启动后,Harness 会拉起 -Python MCP 服务和工作台,Web 页面显示 Triton-RISCV Agent 界面。 +模型凭据按宿主要求设置,不由这个插件选择模型。需要 Python >=3.10;可通过 +`PYTHON` 指定解释器。安装脚本现在会调用插件的 `setup:backend`,在插件内安装后端, +不需要往每个算子目录复制一套 Agent。没有配置时插件保持未启用,不阻塞其他插件。 + +配置集中在 `config.yml`:`repoRoot`、`python`、`stateDir`、`permissions`、`remote`、 +`memory`。MCP、审批桥和状态存储使用同一份经过校验的配置,避免目录或权限不一致。 +`mcp-triton-riscv` 行只是依赖声明,保持 disabled;真正的 MCP 由已启用插件创建和卸载。 +下方环境变量命令保留给原来的独立演示入口,不再是原生仓库接入的首选方法。 -## 远程验证 +## 安装与打开原有界面 -只有显式设置下列环境变量时才允许远程验证: +需要 Node >=22.19、npm、Python >=3.10。Harness 宿主还需遵守根 README 的要求。 ```sh -export RISCV_HOST=sg2044 -export RISCV_REPO=/home/lichunbo/work/triton-riscv -export TRITON_RISCV_REQUIRE_REMOTE=1 -export TRITON_RISCV_ALLOW_VALIDATION=1 -export TRITON_RISCV_REQUIRE_APPROVED_VALIDATION=1 +cd packages/dsh-triton-riscv +npm run setup +export TRITON_RISCV_REPO_ROOT=/你的路径/triton-riscv +export TRITON_RISCV_MCP_PYTHON="$PWD/.venv/bin/python" +npm run workbench ``` -源码应用和修复应用默认关闭。只应在受信任的开发 checkout 中启用: +打开 http://127.0.0.1:8765。端口占用时先设置 +`export TRITON_RISCV_WORKBENCH_PORT=8776`。 +安装会创建本机的插件虚拟环境,不需要原作者的虚拟环境。 +改完 Python 代码后重新安装,或使用英文 README 中的 editable 安装模式。 + +打开页面不需要 API;真实模型请求仍需要终端环境中的 `ISRC_API_KEY`。 +不把密钥提交到 Git。原来的模型代理和 Responses 适配保留。 + +## 两种运行方式 + +1. 原生 Harness:插件注册 MCP 工具和领域规则,模型循环、原生聊天和原生 + 对话压缩由宿主负责。现在已接入原生审批,以及按会话隔离的算子状态和 RAG 上下文。 + 注册指令见 [README](README.md#native-harness-plugin)。 +2. 原有演示平台:React + FastAPI + 官方 Harness SDK,仍能创建/置顶/删除会话、 + 展示流式回答、审批开发和验证计划、查看任务结果。这是独立会话系统。 + +两种方式使用同一套迁移后的 Python 工具。在原生界面左侧底部点击「算子工作台」, +即可在当前页面打开原来的 React 界面,右上角关闭按钮返回原生聊天。侧栏收起时 +入口显示为代码图标。原生聊天保持挂载,不会因打开工作台而重新加载。 +工作台服务仍需显式启动(`npm run workbench`,默认 8765),不会因点击入口自动启动。 +`?tritonWorkbench=1` 兼容入口现在打开同一个浮层,不再替换宿主根界面。 +自定义地址使用 `tritonWorkbenchUrl` 查询参数;iframe 不代表会话自动共享。 + +## 文件的位置 + +- 插件源码:`python/codex_agent/` 和 `frontend/`。 +- 生成的算子、测试和任务:`TRITON_RISCV_REPO_ROOT` 指定的算子仓库。 +- 提案、补丁、日志和回执:算子仓库的 `agent-results/`。 +- 会话、索引、默认记忆库:按 `TRITON_RISCV_STATE_DIR` 和运行入口配置。原生启动器默认插件内 `.state/agent/`,直接运行后端工具默认算子仓库的 `agent-results/`;原生完整对话在独立 `DSH_HOME` 下。 +- 远程执行:由 `RISCV_HOST`、`RISCV_REPO` 指定,仍需 SSH 和 Triton/Buddy/LLVM。 + +原数据库、历史日志、报告和密钥没有塞进插件代码,旧目录保留。 +延续历史时使用数据库备份并保留关联证据路径,不直接升级原始实验库。 + +可以用附带工具复制记忆及关联证据,目标目录必须尚不存在: ```sh -export TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY=1 -export TRITON_RISCV_ALLOW_REPAIR_APPLY=1 +.venv/bin/python -I -m codex_agent.migrate_memory \ + --source /旧目录/agent-results/memory.sqlite3 \ + --source-root /旧目录 \ + --destination "$PWD/.state/history-copy" +export TRITON_RISCV_MEMORY_DB="$PWD/.state/history-copy/memory.sqlite3" ``` -## 测试 +迁移清单记录来源、哈希和缺失证据;迁移不会重新认证历史标签,也不迁移旧聊天会话。 + +## 持久的原生宿主入口 + +先按宿主 README 安装并构建固定版本的 Harness;需要可执行的 `pnpm`。 +宿主源码可放在自己的持久目录,不依赖临时目录;插件不会改宿主核心代码。 ```sh -cd packages/dsh-triton-riscv -pnpm install --frozen-lockfile -pnpm build -pnpm test +export DSH_NATIVE_SOURCE=/你的路径/deepseek-harness +export TRITON_RISCV_REPO_ROOT=/你的路径/triton-riscv +export DSH_MODEL=你的模型ID +export ISRC_BASE_URL=https://llmapi.isrc.ac.cn/v1 +# ISRC_API_KEY 从环境或原生 Models 页面提供,不要写入代码。 +npm run native:install +npm run native ``` -当前插件仍依赖单独的 Triton-RISCV checkout。后续可以将 Python 领域引擎制作成 -独立安装包,以减少源码 checkout 依赖。 +默认打开 http://127.0.0.1:8780;占用时设置 `TRITON_RISCV_NATIVE_PORT`。 +此入口默认使用插件自己的 `.state/native-host` profile,不会改系统默认 profile。 +支持 `.state/native-local.json` 中的白名单配置,但不接受密钥字段。 +本地私有配置和数据库不会进入安装包;其他使用者必须配置自己的路径与凭据。 + +页面需要使用启动日志中带临时 token 的本机链接,直接访问裸地址可能返回 401。 +在无桌面环境或自动化验收中,可设置 `TRITON_RISCV_BROWSER_DIRECTORY_PICKER=1`, +使用宿主官方的网页目录选择器,避免弹出操作系统文件夹对话框。 + +远端测试只复制 FlagGems 源文件和公共 pytest 配置到临时工作区,使用独立编译缓存。 +服务器原 checkout 不被替换。正常完成或测试超时后清理工作区;若 SSH 异常中断, +不能确定远端是否仍在运行时,不从客户端强删正在使用的目录。机器崩溃、强制杀进程 +留下的临时目录仍需检查后清理,这不是多租户安全沙箱。 + +## 保留能力与边界 + +提示词源码拆在 `prompts/` 五类文件:操作提示、开发步骤、失败经验、成功经验、 +验收规则;由 `lib/prompts.js` 注册为五个部分。历史经验仍须从 RAG 取得可追溯证据, +不会因为拆了一个“成功经验”文件就凭空写入成功案例。`policy.md` 是构建生成的兼容文件。 + +插件单测统一使用 Vitest,按输入、输出、状态组织,进入根仓库的测试入口。 +Python 工具继续用 pytest,React 继续用前端 Vitest。详见 [测试说明](TESTING.md)。 + +发现、语义合同、实现提案、审批、文件写入、编译测试、诊断、修复、证据核对、 +远程同步、检索和记忆入库均保留。RAG 默认仍是 legacy/classic、Embedding 关闭。 +平台的对话摘要保留,但不覆盖原生 Harness 的上下文机制。 +已移除旧 LangGraph 实验及专属依赖,原生 Agent 编排统一交给 Harness。 + +原生流程:用户提出需求,Harness 模型调用 MCP 准备合同/查找算子,插件自动 +检索历史证据;模型提出实现或修复,调用应用工具时出现 Harness 原生确认; +批准后 Python 再核对提案指纹并落盘;创建验证计划,再经批准运行本地或远端 +测试,生成回执;失败后诊断、检索、提出修复,按现有次数上限继续。 +用户拒绝、审批不可用、跨会话提案、提案在审批期间变化都会阻止执行。 + +原生任务状态单独保存在 `TRITON_RISCV_STATE_DIR/native-harness/`,不改宿主 +核心日志格式。聊天和压缩由宿主保存,插件保留合同、提案 ID、回执路径和 +历史证据快照。不同会话不共享审批;修改代码后必须重新验证。 +RAG 没改排序,仍默认 legacy/classic/无 Embedding。任务上下文与证据分别限制 +为 12000、6000 字符,这不是精确 token 数;总窗口由宿主的 token meter 管理。 + +注意:原有批量回归、项目检查和评测脚本仍在 Python 包中,不代表 +每个脚本都新增了独立 MCP 工具。新增的 `inspect_project`、`prepare_validation_job`、 +`execute_validation_job`、`get_validation_job` 支持发现、计划、审批执行和读取结果; +`evaluate_plugin_fixtures` 仅运行本地夹具评测,不能作为真实业务效果数据。 +项目级任务在宿主本地执行;配置强制远程时会拒绝该模式,算子批量验证可走 SSH。 +本机已完成原生模型、审批、SSH 数值验收及一次受控修复,详见 +[验证记录](VERIFICATION.md);其他机器仍需配置并验收自己的 API 和工具链。 +宿主的 Bash/文件权限也需独立限制,插件审批不是操作系统沙箱。 + +执行和写文件开关默认关闭,审批不会因插件化而跳过。 +目前是本地开发工具,不能直接作为已具备鉴权的公网服务。 +测试命令及配置见 [README](README.md),迁移边界见 [MIGRATION](MIGRATION.md)。 diff --git a/packages/dsh-triton-riscv/REVIEW_FOLLOWUP.md b/packages/dsh-triton-riscv/REVIEW_FOLLOWUP.md new file mode 100644 index 0000000..9e5282e --- /dev/null +++ b/packages/dsh-triton-riscv/REVIEW_FOLLOWUP.md @@ -0,0 +1,122 @@ +# PR #1 Review Follow-up + +Review target: [RuyiAI-Stack/harness#1](https://github.com/RuyiAI-Stack/harness/pull/1). +Upstream rechecked on 2026-09-24: `main` at `87b01ba`. The current development +branch already includes that revision. This document records local changes, +not reviewer approval or a claim that the earlier PR has been updated. + +## 1. Separate Prompt Responsibilities + +[Review comment](https://github.com/RuyiAI-Stack/harness/pull/1#discussion_r3965142177). + +`prompts/0-hints.md` through `4-verification.md` separate host constraints, +operator skills, failure experience, success experience and verification. +`lib/prompts.js` registers five ordered sections via the host system-prompt +service; `index.js` owns their disposal. `policy.md` and the SDK resources are +generated during build, not independently maintained prompt copies. +Experience sections explain how to use sourced historical evidence; they do +not invent failures, successful fixes or verification results. + +## 2. Define Where MCP Is Installed + +[Review comment](https://github.com/RuyiAI-Stack/harness/pull/1#discussion_r3965144315). + +The bundle is installed once per Harness profile. Python is installed in this +package's `.venv` by `setup:backend`, now invoked by the repository installer. +`repoRoot` points to the separate operator checkout; no Agent source or virtual +environment is installed into each operator workspace. Execution logs and memory +remain private runtime data, not package contents. One configured checkout is +bound per plugin instance; dynamic multi-tenant routing is not implemented. + +## 3. Use the Repository Configuration Entry + +[Review comment](https://github.com/RuyiAI-Stack/harness/pull/1#discussion_r3965168197). + +The repository's actual filename is `config.yml` (rather than `config.yaml`). +`config.yml.example` documents the optional native-host row. Installation and +`./dsh` already copy this to the web profile; their existing mechanism is reused. +The plugin is disabled until explicitly configured. No API key is stored here. + +## 4. Pass Explicit Parameters + +[Review comment](https://github.com/RuyiAI-Stack/harness/pull/1#discussion_r3965181854). + +`native.js` takes `apply(ctx, config)`. `lib/config.js` checks the configured +checkout, Python executable, state paths, permissions, remote target and memory +options. MCP and the trusted approval bridge receive the same normalized values. +Capability switches from the parent shell do not override explicit configuration. +The existing Python process interface still uses an explicit environment map; +this does not mutate the Harness process environment. Model secrets remain a +host responsibility. Embedding credentials are referenced by environment-key +name and only resolved for process execution, not written into configuration. + +The native entry mounts the official MCP client as a scoped child. The disabled +MCP row in the bundle is only a dependency anchor, not a second active client. +Disposing the parent removes its tools and context effects. +Legacy environment translation is confined to optional standalone launchers. + +## 5. Use Vitest and Observable Contracts + +[Review comment](https://github.com/RuyiAI-Stack/harness/pull/1#discussion_r3965214704). + +The duplicate Node runner and placeholder Vitest test are replaced by real +Vitest cases under `tests/unit/`, organized by inputs, outputs and execution/state. +`tests/integration/` is discoverable by the root configuration and exercises the +real pinned host plus Python MCP. See TESTING.md and VERIFICATION.md for commands +and outcomes. Scripted model fixtures are not live model effectiveness tests. + +## Packaging and Compatibility + +The native chat, model loop and approval UI belong to Harness. The plugin adds +domain tools, guards, evidence memory and bounded task context. It does not +replace the host loop or edit core Harness code. + +The original React/FastAPI demo remains an optional independent entry, not an +automatically launched second server. Python resources, UI assets and all five +prompt files are included in the distribution audit. Databases, keys, private +profiles, host copies and logs are excluded. Prompt formatting tests now tolerate +line wrapping without relaxing the acceptance-test protection rule. + +Outside this package, only four installation-related files changed: the root +README's Python requirement, config example, optional backend setup hook, and +a scoped YAML parser rule. The +retained SDK config requires Harness's custom `!!js` tags; `check-yaml --unsafe` +parses their syntax without running them. The native bundle itself uses ordinary +YAML and no executable environment expressions. + +## Remaining Verification Boundary + +### 2026-09-24 Cleanup + +Removed the standalone LangGraph runtime (nine files), its dedicated test module, +architecture document and optional dependency extra. No retained runtime imports +that framework. The packaging audit and Vitest output contract now reject its +reintroduction. The original migration provenance remains an historical manifest. + +Shared CLI/core adapters, project discovery/execution, remote validation, memory, +context and the optional workbench are retained because they serve existing +entrypoints. Outdated backend installation/pilot instructions now point to the +package README rather than maintaining conflicting setup recipes. + +Local checks after cleanup: 269 Python tests plus five subtests, 33 plugin tests, +eight frontend tests and five real-host/MCP integration tests passed. The seven +removed Python tests belonged exclusively to the retired framework (276 before). +Frontend production build passed. The npm distribution audit contains 197 files +(208 before) and excludes private/runtime data and the retired framework. + +The root unit command was also executed: 59 tests passed, but the agent-observer +suite could not import `@deepseek-ai/dsh-tools` from the unpopulated host +submodule. That unrelated suite was not deleted, skipped or patched to pass. +These local results are not a claim of passing all upstream CI or a fresh live +model/SSH operator run. No commit or push was made as part of this cleanup. + +Plugin unit, backend, UI, real-host integration and isolated-profile boot checks +passed locally. The full repository build/CI is not yet certified: fetching the +pinned upstream host submodule failed twice, leaving another plugin's linked +dependency unavailable. Repeat install-all and root `pnpm test:all` once the +submodules can be fetched; do not bypass unrelated failing suites. + +Host generic shell/file tools still require host-side permission and sandbox +policy. Plugin approval is not a multi-tenant security boundary. RAG remains +legacy/classic with embedding off. These changes do not establish new RAG +quality gains or arbitrary-operator repair guarantees. diff --git a/packages/dsh-triton-riscv/TESTING.md b/packages/dsh-triton-riscv/TESTING.md new file mode 100644 index 0000000..3823e56 --- /dev/null +++ b/packages/dsh-triton-riscv/TESTING.md @@ -0,0 +1,40 @@ +# Plugin Test Contracts + +The repository's Vitest configuration discovers this package directly. + +- Inputs: `tests/unit/inputs.spec.ts` validates host config, rejects invalid + permissions/paths, checks disabled activation and explicit legacy translation. +- Outputs: `tests/unit/outputs.spec.ts` checks packaging, five prompt sections, + safe bundle defaults, retired-framework exclusion and workbench launch parameters. + `tests/unit/client.spec.ts` checks the sidebar entry, workbench overlay, + safe URLs and disposal without replacing the native conversation. +- Execution/state: `tests/unit/native-adapter.spec.ts` checks tool hooks, native + approval, cancellation, ownership, retrieval failure, context bounds and stale + validation invalidation; `native-state.spec.ts` checks persistence and isolation. +- Integration: `tests/integration/native-host.spec.ts` calls the actual pinned + host suite in `tests/native-host.spec.ts`. This activates the real parameterized + entry with real stdio Python MCP, validates development/apply, rejected approval, + failure receipts, context reaching the next scripted-model request, and tool + removal after plugin disposal. No live API or SSH is used. + +```sh +# Repository root, following install-all.sh: +pnpm test +pnpm test:integration + +# Plugin-only unit suite: +cd packages/dsh-triton-riscv +pnpm install --frozen-lockfile +pnpm test +npm run test:frontend +cd python +../.venv/bin/python -I -m pytest -q +``` + +For a disposable already-built host, set `TRITON_PLUGIN_TEST_HOST` before the +integration command. The native test script refuses to overwrite a pre-existing +temporary test file and removes its own file afterward. Python tests require +the workbench extra installed by setup, not the removed LangGraph extra. + +Live-model and RISC-V logs in VERIFICATION.md are separate historical acceptance +records; a passing fixture is not a new live-model or business success result. diff --git a/packages/dsh-triton-riscv/VERIFICATION.md b/packages/dsh-triton-riscv/VERIFICATION.md new file mode 100644 index 0000000..d52a0e9 --- /dev/null +++ b/packages/dsh-triton-riscv/VERIFICATION.md @@ -0,0 +1,197 @@ +# Migration Verification + +Verified locally on 2026-09-21, macOS / Python 3.13 / Node 22.19. + +## Repository Review Conformance (2026-09-21) + +Fetched upstream main `87b01ba`; the working branch already contains it. No +reset, stash, commit or push was performed. See REVIEW_FOLLOWUP.md for the +mapping to PR #1's review comments. + +- Official CLI installed the package into a new isolated web profile. With + explicit config, the real pinned host served its authenticated HTML page + (HTTP 200) without startup errors. The test process was shut down afterward. +- Plugin unit tests: **22 passed** under the repository's Vitest entry. +- Actual pinned host/Python MCP: **5 integration scenarios passed**, also + invoked successfully by the root integration suite's single wrapper test. +- Python: **239 passed and 3 subtests passed**, one dependency deprecation warning. +- Retained React UI: **8 passed**; TypeScript/Vite production build passed. +- Frozen plugin dependency install, package audit, Git whitespace check, and + the repository's formatting/JSON/YAML/conflict/file-size hook implementations + passed. Custom-tag YAML checking is scoped to the retained SDK configuration. +- The complete root unit command reported **48 passed tests and one failed + suite import** in the unrelated agent-observer plugin: missing + `@deepseek-ai/dsh-tools`, linked to the unavailable host submodule. Fetching + that submodule failed twice (HTTP2/SSL timeout). Whole-repository install-all + and full CI are therefore **not established** by this increment. Integration + used the already-built archive of the exact pinned host revision, not a new + or substituted version of the submodule. + +No model requests or remote execution occurred in this review increment. No +RAG algorithm/default or historical database was changed. Local detailed logs +are retained in `agent-results/plugin-review/20260921/` of the original workspace, +not bundled into the plugin. + +## Live Native Acceptance (Earlier on 2026-09-21) + +On 2026-09-21 the installed plugin completed a real native web session using +ISRC Responses model `AZ-GPT-5.6-Sol`, official Harness approvals and SSH to +`sg2044` (riscv64, Triton 3.4.0), on the pinned host revision below. + +- New `acceptance_scaled_square_20260921`: **4 passed**. +- Controlled implementation-only constant mutation: **4 failed**. The model + diagnosed the actual failed run, proposed a one-line repair and reran the same + unchanged acceptance tests: **4 passed after one repair**. +- Existing `relu_and_mul` regression: **9 passed** with a fresh per-run cache. +- Actual 30-second timeout fixture: exit **124**, classified timeout, remote + staging directory removed. This fixture is not an operator correctness case. +- Browser automation exercised the real native approval buttons (2 development + and 3 repair decisions). These were authorized test-harness decisions, not + model self-approval or manually recorded user clicks. Desktop results rendered; + mobile with the host sidebar open squeezes the transcript and needs the + sidebar collapsed. After waiting for responsive layout and verifying the + sidebar was collapsed, the 390px transcript was readable with no page-level + horizontal overflow. No claim of comprehensive responsive UI acceptance. +- Offline evidence audit: **17/17 checks passed**, including log/source hashes, + immutable tests, native execution, approvals and final verified receipt. +- Final local regression: **239 Python tests and 3 subtests, 16 Node tests, + 8 frontend tests, 4 native integration tests passed**. TypeScript/Vite build + and the package audit (**184 files**) passed. One dependency deprecation warning. + +Remote validation now copies a bounded FlagGems source/config snapshot to a +unique temporary workspace with its own compiler cache. It does not replace +files in the shared remote checkout. SSH quoting, strict preflight, timeout, +cleanup and result metadata have regression tests. This is not an OS sandbox; +hard crashes and multi-tenant stress still require deployment testing. + +The two native main loops recorded 520378 / 514493 total tokens respectively. +Those totals include separately reported cached input, not just uncached input. +Each session has one title request without usage, so complete billing totals +are unknown. No new RAG effectiveness or cost-reduction claim is made: the +repair was a controlled fault and could access its earlier successful history. + +Evidence is under the original workspace's +`agent-results/migration/20260921-live-acceptance/` directory. The Chinese report, +raw receipts/logs, source snapshots, UI screenshots and usage export are retained; +none of those private artifacts are included in the package. The final +`fresh_compile` metadata fix was followed by a new existing-operator regression; +older native receipts were not retroactively rewritten. + +## Earlier Incremental Verification + +The earlier migration snapshot below is retained as historical evidence, not a +claim that its older wheel was rebuilt with today's additions. + +- Installed editable backend: **226 tests passed**. +- Native plugin/state tests: **16 passed**; retained frontend: **8 passed**; + TypeScript and production UI build passed. +- Actual pinned Harness and actual stdio MCP: **4 integration tests passed**. + Added an actual AgentLoop test with a scripted model adapter: retrieval after + task preparation appears in the next model request, persists across turns, + and labels a recommendation as not executed. Also tested approved project + execution, a real failing local pytest, single-use execution and session isolation. + Switching from an operator to a validation job clears unrelated task context. +- MCP now exposes **18 tools**, including project inventory, bounded validation + jobs and fixture evaluation. Project jobs are local-only; operator batches may + use the configured remote executor. Fixture results are not business metrics. +- Read-only migration copied **5 memory rows and 50 evidence files** into a new + private directory. No referenced-file gaps were found by the migration tool; + original database hash unchanged. Historical labels were not re-audited. + Retrieval through the installed plugin returned evidence from the copy. +- Package audit passed (**183 files**), excluding `.runtime`, `.state`, databases, + keys and logs. The exact host is now in a persistent ignored runtime directory. +- No new paid model or RISC-V numerical repair experiment was performed in this + increment. Historical effect measurements remain separate from integration tests. + +Current logs are in the local `agent-results/migration/20260921-full-plugin/` +artifact directory of the original development workspace. + +## Earlier Migration Snapshot + +- Backend: **220 passed** from the final Harness plugin directory, including + migration and native approval/bridge tests. +- Independent wheel installation: **220 passed** from outside both source repos, + loading `codex_agent` from site-packages with Python isolated mode. +- Frontend: **8 passed**; TypeScript check and Vite production build passed. +- Plugin/adapter/state: **15 passed**, including policy injection, native approval, + cancellation, session isolation, state restore and bounded context. +- Real native host integration: **2 passed**, both with the editable backend and + with the independent wheel. Real host tool/approval services call the real + stdio MCP server and Python bridge. Tests prepare, propose, approve/reject and + apply temporary implementations; they check automatic memory evidence and + current task state in native context. Approval answers and memory fixtures + are deterministic, not live model decisions or production history. +- Official Harness SDK: real initialization passed from the installed backend. + No model turn was submitted. +- Real local checkout: stdio MCP listed **13 tools** and discovered `relu_and_mul` + implementation and test paths. Discovery is read-only, not a numerical test. +- Local workbench: `/`, `/api/health`, `/api/bootstrap` served successfully. + Fresh inventory contains 266 operator records and 691 project validation + targets; these are static discovery counts, not passed-test counts. +- Distribution audit: backend, built UI and policy are present; private/runtime + artifacts (venv, node_modules, databases, logs, keys) are excluded (178 files). +- Native host: built and launched from the exact fork gitlink revision + `c389f96bf3a9b6807cb71ed6bdad5849be0df6d8` (0.1.3-alpha.2). The official CLI + installed this plugin into an isolated web profile; MCP startup succeeded. + Desktop 1440x960 and mobile 390x844 browser smoke checks rendered the native + page with no page errors. The smoke check is not a live chat acceptance test. +- `git diff --check` passed. Changes remain within this package; no commit/push. + +## Reproduce + +From the package directory, after setup: + +```sh +npm test +npm run test:frontend +npm run build +npm run check:package +.venv/bin/python -I -m pytest -q python/codex_agent/tests +.venv/bin/python -I -m codex_agent.harness.mcp_demo relu_and_mul --repo-root "$TRITON_RISCV_REPO_ROOT" +``` + +The obsolete LangGraph experiment was removed on 2026-09-24. Earlier results +above describe their original revisions; current commands use only the retained +backend. API/SSH credentials are not part of setup. Side-effect permissions +still default off. + +Native integration requires a disposable copy of the pinned host, dependencies +installed according to that host's README, and the plugin Python environment: + +```sh +TRITON_PLUGIN_TEST_HOST=/path/to/disposable/deepseek-harness npm run test:native-host +``` + +The test adds a temporary spec to the host's test suite and removes it afterwards. +It does not change the host core. The target fork's submodule could not be cloned +over Git during verification; a source archive of its exact pinned revision was +built in a temporary directory instead. The fork's submodule was not modified. + +## Native Integration Scope + +- Official Harness owns the agent loop, model provider, chat history and + conversation compaction; the plugin does not start a second loop. +- The plugin adds typed tool dispatch, trusted native approval, per-session + lifecycle ownership, atomic domain state, proactive retrieval and bounded + evidence/current-task context. +- Domain state uses separate files, not custom core session events. State is + reloaded after restart; a source modification invalidates earlier success. +- The original React/FastAPI workbench, batch/project CLIs + and retrieval/context experiments remain available in the packaged backend. + Not every CLI has been exposed as a separate native MCP tool. + +## Not Established By These Checks + +- The latest acceptance verifies one controlled development/repair chain, not + arbitrary operator repair, independent RAG improvement or multi-tenant reliability. +- The copied history preserves source labels; migration does not certify those + labels or migrate the original chat sessions. Source databases remain untouched. +- Integration tests use scripted model responses; they are separate from the + latest real-model browser acceptance. Neither is a production load test. +- No new RAG quality/cost or task-success claim is made. +- Native guards are not an OS sandbox. Unrestricted host Bash/filesystem tools + require separate host-side permissions and deployment hardening. + +The retained React/FastAPI workbench is independently runnable. Its managed +context and approvals remain separate from the native Harness UI/session policy. +See MIGRATION.md before moving historical databases or exposing the service. diff --git a/packages/dsh-triton-riscv/cordis.patch.yml b/packages/dsh-triton-riscv/cordis.patch.yml index 67f9735..3fbe53f 100644 --- a/packages/dsh-triton-riscv/cordis.patch.yml +++ b/packages/dsh-triton-riscv/cordis.patch.yml @@ -1,31 +1,16 @@ -# Install this bundle into a normal DeepSeek Harness profile. The Harness MCP -# client launches the Python domain engine from the configured Triton-RISCV checkout. +# Configure triton-riscv-native-host in the repository's config.yml. +# Installing the bundle never launches Python or runs a test by itself. - insert: - id: triton-riscv-domain-policy name: dsh-triton-riscv + - id: triton-riscv-native-host + name: dsh-triton-riscv/native + config: + enabled: false + + # Dependency anchor only. The native-host plugin mounts a scoped MCP child + # with validated config. Do not enable a second instance of this namespace. - id: mcp-triton-riscv name: '@deepseek-ai/dsh-mcp-client' - config: - serverName: triton_riscv - transport: stdio - command: !!js process.env.TRITON_RISCV_MCP_PYTHON ?? 'python3' - args: ['-m', 'codex_agent.harness.mcp_server'] - env: - TRITON_RISCV_REPO_ROOT: !!js process.env.TRITON_RISCV_CHECKOUT ?? process.env.DSH_CWD ?? process.cwd() - TRITON_RISCV_ALLOW_VALIDATION: !!js process.env.TRITON_RISCV_ALLOW_VALIDATION ?? '0' - TRITON_RISCV_ALLOW_REPAIR_APPLY: !!js process.env.TRITON_RISCV_ALLOW_REPAIR_APPLY ?? '0' - TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY: !!js process.env.TRITON_RISCV_ALLOW_DEVELOPMENT_APPLY ?? '0' - TRITON_RISCV_REQUIRE_REMOTE: !!js process.env.TRITON_RISCV_REQUIRE_REMOTE ?? '0' - TRITON_RISCV_REQUIRE_APPROVED_VALIDATION: !!js process.env.TRITON_RISCV_REQUIRE_APPROVED_VALIDATION ?? '1' - TRITON_RISCV_MEMORY_DB: !!js process.env.TRITON_RISCV_MEMORY_DB ?? ((process.env.TRITON_RISCV_CHECKOUT ?? process.env.DSH_CWD ?? process.cwd()) + '/agent-results/memory.sqlite3') - TRITON_RISCV_EMBEDDING_PROVIDER: !!js process.env.TRITON_RISCV_EMBEDDING_PROVIDER ?? 'none' - TRITON_RISCV_EMBEDDING_MODEL: !!js process.env.TRITON_RISCV_EMBEDDING_MODEL ?? '' - TRITON_RISCV_EMBEDDING_BASE_URL: !!js process.env.TRITON_RISCV_EMBEDDING_BASE_URL ?? '' - TRITON_RISCV_EMBEDDING_API_KEY_ENV: !!js process.env.TRITON_RISCV_EMBEDDING_API_KEY_ENV ?? 'AGENT_EMBEDDING_API_KEY' - AGENT_EMBEDDING_API_KEY: !!js process.env.AGENT_EMBEDDING_API_KEY ?? '' - RISCV_HOST: !!js process.env.RISCV_HOST ?? '' - RISCV_REPO: !!js process.env.RISCV_REPO ?? '' - cwd: !!js process.env.TRITON_RISCV_CHECKOUT ?? process.env.DSH_CWD ?? process.cwd() - toolCallTimeoutMs: 960000 - failOnStartupError: true + disabled: true diff --git a/packages/dsh-triton-riscv/frontend/index.html b/packages/dsh-triton-riscv/frontend/index.html new file mode 100644 index 0000000..b5478aa --- /dev/null +++ b/packages/dsh-triton-riscv/frontend/index.html @@ -0,0 +1,16 @@ + + + + + + + Triton-RISCV Agent + + +
+ + + diff --git a/packages/dsh-triton-riscv/frontend/package-lock.json b/packages/dsh-triton-riscv/frontend/package-lock.json new file mode 100644 index 0000000..526ea8a --- /dev/null +++ b/packages/dsh-triton-riscv/frontend/package-lock.json @@ -0,0 +1,3097 @@ +{ + "name": "triton-riscv-agent-frontend", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "triton-riscv-agent-frontend", + "version": "0.1.0", + "dependencies": { + "lucide-react": "^0.542.0", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.8.0", + "@testing-library/react": "^16.3.0", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^5.0.2", + "jsdom": "^26.1.0", + "typescript": "^5.9.2", + "vite": "^7.1.3", + "vitest": "^3.2.4" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.0.tgz", + "integrity": "sha512-70TeIFezKKy65LgAVyQh+w94/gjWhvPWaLaGGeMEgVrPkQhuj/M5bAYYZzIFUj9Y69oHyTm5Um/R6gcLh4A8JA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.0.tgz", + "integrity": "sha512-YC86tYIHK6M1IV+wbzO+Bxk8RCBr6ZyWYgWxUCzaZD8mc8rrFoIJDNzDrkHBYRc/wKdrsIXmm6/F7NzrAO+OrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.0.tgz", + "integrity": "sha512-oI+ECtUcli0y0fi4xpW82GdPIXdTkI8G8DSjG2LRuw09fPAGykaWYH/hXxiKuTxiAjiPSTIIuYUqof5Z2hShWw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.0.tgz", + "integrity": "sha512-NwV+1s7TiKrMe4owHyKB/dTLD7ZJD0YEBEhIz+hvav1Cu1GReJjF+rsdNwjzENQeIAbE/CoNiaAc5Vz2h5DPAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.0.tgz", + "integrity": "sha512-tWtHBTu5gOPK4u4Urtk4qAHW3zZ9rQAmbssO8gp7ELvGTGI3aCiq6NqyTQ0PCIg7KbHJF2UkGDDs77YZGxfjCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.0.tgz", + "integrity": "sha512-2qPoJiwTvtHQ27NnYvTnsgk8laXWYuVmNESG8WFZBcEPKLfZ3I27qBJarjVRQtwGeYyRfq5ZowHXih9lm2BItw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.0.tgz", + "integrity": "sha512-FQwsTRvLNuHoTdICABJQfbPUSEueISGmnpT06tXTMpfprf5NiKLSXKA0A+w45wJnCmZAnzgqBwbt6ARFuyOi5w==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.0.tgz", + "integrity": "sha512-BBVTXziw8mY1a4ZbWME9tZyfzqXCDPqaC7Z3heQ29p5dkvXzwL0NwelO8zLa8c3RBKvl3YTuSnBgsBhYBtwjIw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.0.tgz", + "integrity": "sha512-w2Iyy9+RqKwx3d9qWMKsJg0FfRBsY0/pXNv0mCQ3ueRvJI6+QAScfD4nrMlzFLs2HNVW6Ew+mtZfDl9b7Ew5/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.0.tgz", + "integrity": "sha512-YK++KtrFRHYE0P6/RtYEAy9t8F37znP+K03RrIuLPYOL6SVlObRumf/0OE4V/h63xL9DwkWbNssZfmA9hawuDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.0.tgz", + "integrity": "sha512-aBfOG6fP7YkkPmTqPwufRJeFyz7WPpECv9XNbnsk9+vg7rxdih0lbtEel7jcRng4LZrrmU3FfitCFyEj4BWDWg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.0.tgz", + "integrity": "sha512-LGaHEOeHNAag9VuS1Crs5DFg4RrU9MPi2nVnNJk9DTePx/B6RRYKVmrIXt2h7YOJlwjaFJ6lwtFDliZxScTLrQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.0.tgz", + "integrity": "sha512-jClvk+J0FC3b7Udvegiw5/4hErbHtmsNsQgENnKXDWtNCJXsJYZH5WURvu7imDOO38xYml24eeh5x3A04ppwCw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.0.tgz", + "integrity": "sha512-0OJlaGK+8+B777Ql5okIpD7ua5Ro9+VB9Ve0OKa28OQJZ1RbuUBVNHK/e3pr4BROqsyPl1JrPO1ZxJseCNffcA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.0.tgz", + "integrity": "sha512-Ygsx+HoNH7afwi1bTIXbnTvVnsO+zurPLSYxybV1hHFVU72OWOCl6v05ql/z0hkpAPx+DK7Kn9Bi7MayCcjLTA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.0.tgz", + "integrity": "sha512-pDQxtMGb+OvG3fLwR2OkZlSd47hW+kWg4BYMG/++sR6RqorQccwPTDsxda5hPwiIeIErAnCF9ma3SAU06bdQtQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.0.tgz", + "integrity": "sha512-0BnUG9mS8I4SSHr3XsxVhuCMEiu+rX61xxZF5vujso4LaiAGFZFxvDjg6Xn6tLPNTUAfuCvQYas4LMQMVsKRSQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.0.tgz", + "integrity": "sha512-Adu/VttB1dpPNW+FEacrZ+xVm9tFty84+RrFzsqlFaPxoJB+9XXyDGtp5dCOoBwGBIEVH0To7lExFXEx0BIF4A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.0.tgz", + "integrity": "sha512-NQ3bDvjUbFKmP23671xUlXtKmqVsUBd6M4PQCvbmNtOy06hnQIdKHy8oG/6S3R/S6He1JgPk6A5VT+prAJMYEw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.0.tgz", + "integrity": "sha512-u2eDAl4+0aFvA13GxlGBtTI3SS3sdgwgtV0HyjZ0QaQVCgNE+jqNGey+GtxWiq+wxr/UycAx/OnfJzApCFamvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.0.tgz", + "integrity": "sha512-XvRb5vfW3wAZQ+ZUG21AnHHDKtNcw99eigzEhjr//NZ3u7SoBaPP0seSc7FgP7p1epAEdAoZckMW9WY/+4w70w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.0.tgz", + "integrity": "sha512-iZPmniy4kNBf5yo2RezbkYNNK5HPbXE9+g+twnbqSng7dtLEJy1SKoxiE/ni4FDacjyuZpEeb9U054N4EoKHYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.0.tgz", + "integrity": "sha512-mFBBd+LF37fnE8JnYUOH+imj0aPFPK30vpar4ehJkgnLj9sZn8ZxiRENmLtgIwxK7TC8klF6N57fxdNBwQoqOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.0.tgz", + "integrity": "sha512-ujeqEY3B+zbGn3Z4Q03cUBG/LGWnBJncVT36WER31LcOsQk9+1dmINKKtvmmfChUvRbK1G0R8OhMWFgHgaZtAw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.0.tgz", + "integrity": "sha512-hncn90N4sOky0L2LKE5oESKLbxCPeVo4eLA2LSMoDzM+879ml4WSr+Rr4DWknNIVVvS1Hirkc9hx02W6YxS8rQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.7.tgz", + "integrity": "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.7", + "@vitest/utils": "3.2.7", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.7.tgz", + "integrity": "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.7", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.7.tgz", + "integrity": "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.7.tgz", + "integrity": "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.7", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.7.tgz", + "integrity": "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.7", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.7.tgz", + "integrity": "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.7.tgz", + "integrity": "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.7", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.19.tgz", + "integrity": "sha512-Grytf1xOxOEMTGRwx6rLGKkTabd4vMg3VrKdj/7joCmV0qgh4QwMMO6xh34YEXQqirAuUdgQGa5orJQQ+69RBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.415", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.415.tgz", + "integrity": "sha512-958V+Kbhtgz+SxXeEVKBjrlKRBIDAYvUJfwhjxMZ5S6ut9jAl7l9ZKBkBrvjyjZE36PabLUo2L8kEeV5O4vgJg==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.542.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.542.0.tgz", + "integrity": "sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", + "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nwsapi": { + "version": "2.2.24", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.24.tgz", + "integrity": "sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.0.tgz", + "integrity": "sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.63.0", + "@rollup/rollup-android-arm64": "4.63.0", + "@rollup/rollup-darwin-arm64": "4.63.0", + "@rollup/rollup-darwin-x64": "4.63.0", + "@rollup/rollup-freebsd-arm64": "4.63.0", + "@rollup/rollup-freebsd-x64": "4.63.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.63.0", + "@rollup/rollup-linux-arm-musleabihf": "4.63.0", + "@rollup/rollup-linux-arm64-gnu": "4.63.0", + "@rollup/rollup-linux-arm64-musl": "4.63.0", + "@rollup/rollup-linux-loong64-gnu": "4.63.0", + "@rollup/rollup-linux-loong64-musl": "4.63.0", + "@rollup/rollup-linux-ppc64-gnu": "4.63.0", + "@rollup/rollup-linux-ppc64-musl": "4.63.0", + "@rollup/rollup-linux-riscv64-gnu": "4.63.0", + "@rollup/rollup-linux-riscv64-musl": "4.63.0", + "@rollup/rollup-linux-s390x-gnu": "4.63.0", + "@rollup/rollup-linux-x64-gnu": "4.63.0", + "@rollup/rollup-linux-x64-musl": "4.63.0", + "@rollup/rollup-openbsd-x64": "4.63.0", + "@rollup/rollup-openharmony-arm64": "4.63.0", + "@rollup/rollup-win32-arm64-msvc": "4.63.0", + "@rollup/rollup-win32-ia32-msvc": "4.63.0", + "@rollup/rollup-win32-x64-gnu": "4.63.0", + "@rollup/rollup-win32-x64-msvc": "4.63.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "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/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "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/update-browserslist-db": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", + "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.7.tgz", + "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.7", + "@vitest/mocker": "3.2.7", + "@vitest/pretty-format": "^3.2.7", + "@vitest/runner": "3.2.7", + "@vitest/snapshot": "3.2.7", + "@vitest/spy": "3.2.7", + "@vitest/utils": "3.2.7", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.7", + "@vitest/ui": "3.2.7", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "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/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/packages/dsh-triton-riscv/frontend/package.json b/packages/dsh-triton-riscv/frontend/package.json new file mode 100644 index 0000000..eb360d8 --- /dev/null +++ b/packages/dsh-triton-riscv/frontend/package.json @@ -0,0 +1,30 @@ +{ + "name": "triton-riscv-agent-frontend", + "private": true, + "version": "0.1.0", + "type": "module", + "engines": { + "node": ">=22" + }, + "scripts": { + "dev": "vite --host 127.0.0.1", + "build": "tsc --noEmit && vite build", + "test": "vitest run" + }, + "dependencies": { + "lucide-react": "^0.542.0", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.8.0", + "@testing-library/react": "^16.3.0", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^5.0.2", + "jsdom": "^26.1.0", + "typescript": "^5.9.2", + "vite": "^7.1.3", + "vitest": "^3.2.4" + } +} diff --git a/packages/dsh-triton-riscv/frontend/src/App.tsx b/packages/dsh-triton-riscv/frontend/src/App.tsx new file mode 100644 index 0000000..22b5035 --- /dev/null +++ b/packages/dsh-triton-riscv/frontend/src/App.tsx @@ -0,0 +1,904 @@ +import { Bot, Check, Menu, PanelRight, Pin, PinOff, Play, Plus, Send, Trash2, UserRound, X } from 'lucide-react' +import { FormEvent, KeyboardEvent, useEffect, useRef, useState } from 'react' +import { api } from './api' +import { MessageText, shortDate } from './format' +import type { Bootstrap, Run, RunEvent, ProposalReview, Session, SessionBundle, ValidationPlanReview } from './types' + +const terminalStatuses = new Set(['completed', 'failed', 'cancelled']) + +function runStatusLabel(status?: string): string { + const labels: Record = { + 'awaiting-confirmation': '等待确认', + queued: '排队中', + running: 'Agent 运行中', + completed: 'Agent 回合已结束', + failed: 'Agent 运行失败', + cancelled: 'Agent 已取消', + } + return status ? labels[status] || status : '空闲' +} + +function evidenceLabel(verdict?: string): string { + const labels: Record = { + 'not-observed': '尚未执行验证', + planned: '验证等待审批', + 'verified-passed': '证据确认通过', + 'verified-failed': '证据确认失败', + invalid: '验证证据无效', + } + return verdict ? labels[verdict] || verdict : '尚未产生证据' +} + +function timelineTitle(event: RunEvent): string { + if (event.event_type === 'agent-step') { + const labels: Record = { + analysis: '分析任务', + 'model-progress': '模型进展', + 'tool-call': '调用工具', + 'tool-result': '工具结果', + 'final-answer': '完成回答', + } + return labels[event.payload.kind || ''] || 'Agent 步骤' + } + const labels: Record = { + planned: '创建任务', + scheduled: '进入队列', + started: '启动 Harness', + completed: 'Agent 回合结束', + failed: '任务失败', + cancelled: '任务取消', + 'validation-evidence': '验证证据审计', + } + return labels[event.event_type] || event.event_type +} + +function uniqueApprovals(rows: RunEvent[]): RunEvent[] { + const byProposal = new Map() + rows.forEach(event => { + const key = event.payload.proposal_id || event.payload.validation_run_id || String(event.id) + byProposal.set(key, event) + }) + return [...byProposal.values()] +} + +function EmptyConversation() { + return ( +
+ Natural language workspace +

从一句任务描述开始

+

DeepSeek Harness 会理解任务、选择 Triton-RISCV 工具,并把模型、工具调用和结果记录到会话时间线。

+
+ ) +} + +function ProposalApproval({ + event, + onResolved, + onContinue, +}: { + event: RunEvent + onResolved: (eventId: string) => void + onContinue: (proposalType: 'development' | 'repair', proposalId: string) => Promise +}) { + const proposalId = event.payload.proposal_id + const proposalType = event.payload.proposal_type + const [proposal, setProposal] = useState(null) + const [reviewer, setReviewer] = useState('ada-cl25') + const [pending, setPending] = useState(false) + const [continued, setContinued] = useState(false) + const [error, setError] = useState(null) + + useEffect(() => { + if (!proposalId || !proposalType) return + void api + .getProposal(proposalType, proposalId) + .then(item => { + if (['pending_approval', 'approved'].includes(item.status)) setProposal(item) + else onResolved(event.id) + }) + .catch((reason: unknown) => setError(reason instanceof Error ? reason.message : '读取提案失败')) + }, [event.id, proposalId, proposalType]) + + if (!proposalId || !proposalType) return null + + const decide = async (approve: boolean) => { + if (!reviewer.trim()) return + setPending(true) + setError(null) + try { + const updated = await api.decideProposal(proposalType, proposalId, approve, reviewer.trim()) + if (approve) setProposal(updated) + else onResolved(event.id) + } catch (reason) { + setError(reason instanceof Error ? reason.message : '提交审查失败') + } finally { + setPending(false) + } + } + + return ( +
+
+

{proposalType === 'development' ? '新算子提案' : '修复提案'}

+ {proposal?.status || '加载中'} +
+ {proposalId} + {proposal && ( +

+ {proposal.operator}:{proposal.rationale} +

+ )} + {proposal?.status === 'pending_approval' && ( + <> + +
+ + +
+ + )} + {proposal?.status === 'approved' && ( +
+ {continued ? '应用任务已启动。' : '提案已批准,尚未应用到仓库。'} + {!continued && ( + + )} +
+ )} + {error &&

{error}

} +
+ ) +} + +function CommandApproval({ + event, + onResolved, + onExecute, +}: { + event: RunEvent + onResolved: (eventId: string) => void + onExecute: (validationRunId: string) => Promise +}) { + const validationRunId = event.payload.validation_run_id + const [plan, setPlan] = useState(null) + const [reviewer, setReviewer] = useState('ada-cl25') + const [pending, setPending] = useState(false) + const [launched, setLaunched] = useState(false) + const [error, setError] = useState(null) + + useEffect(() => { + if (!validationRunId) return + void api + .getValidationPlan(validationRunId) + .then(item => { + if (item.approval.status === 'rejected' || item.approval.execution_run_id) { + onResolved(event.id) + return + } + setPlan(item) + }) + .catch((reason: unknown) => setError(reason instanceof Error ? reason.message : '读取验证计划失败')) + }, [event.id, validationRunId]) + + if (!validationRunId) return null + + const decide = async (approve: boolean) => { + if (!reviewer.trim()) return + setPending(true) + setError(null) + try { + const updated = await api.decideValidationPlan(validationRunId, approve, reviewer.trim()) + if (!approve) { + onResolved(event.id) + return + } + setPlan(updated) + await onExecute(validationRunId) + setLaunched(true) + } catch (reason) { + setError(reason instanceof Error ? reason.message : '提交命令审查失败') + } finally { + setPending(false) + } + } + + const executeApproved = async () => { + setPending(true) + setError(null) + try { + await onExecute(validationRunId) + setLaunched(true) + } catch (reason) { + setError(reason instanceof Error ? reason.message : '启动验证失败') + } finally { + setPending(false) + } + } + + return ( +
+
+

执行验证命令

+ {plan?.approval.status || '加载中'} +
+

{plan?.operator || event.payload.operator || '算子'}

+
+        {plan?.command || event.payload.command || '正在读取命令...'}
+      
+ {plan?.approval.status === 'pending_approval' && ( + <> + +
+ + +
+ + )} + {plan?.approval.status === 'approved' && ( +
+ {launched ? '验证任务已启动。' : '命令已批准,尚未执行。'} + {!launched && ( + + )} +
+ )} + {error &&

{error}

} +
+ ) +} + +export default function App() { + const [bootstrap, setBootstrap] = useState(null) + const [sessions, setSessions] = useState([]) + const [activeSessionId, setActiveSessionId] = useState(null) + const [bundle, setBundle] = useState(null) + const [activeRun, setActiveRun] = useState(null) + const [events, setEvents] = useState([]) + const [streamingText, setStreamingText] = useState('') + const [approvalEvents, setApprovalEvents] = useState([]) + const [input, setInput] = useState('') + const [busy, setBusy] = useState(false) + const [error, setError] = useState(null) + const [drawer, setDrawer] = useState<'sessions' | 'inspector' | null>(null) + const [sessionMenu, setSessionMenu] = useState<{ + sessionId: string + x: number + y: number + } | null>(null) + const eventSource = useRef(null) + const messagesEnd = useRef(null) + + const closeStream = () => { + eventSource.current?.close() + eventSource.current = null + } + + const refreshSessions = async () => { + const rows = await api.listSessions() + setSessions(rows) + return rows + } + + const refreshApprovals = async (sessionId: string) => { + const rows = uniqueApprovals(await api.getSessionApprovals(sessionId)) + const unresolved = await Promise.all( + rows.map(async event => { + try { + if (event.payload.validation_run_id) { + const plan = await api.getValidationPlan(event.payload.validation_run_id) + return plan.approval.status !== 'rejected' && !plan.approval.execution_run_id + } + if (event.payload.proposal_id && event.payload.proposal_type) { + const proposal = await api.getProposal(event.payload.proposal_type, event.payload.proposal_id) + return ['pending_approval', 'approved'].includes(proposal.status) + } + } catch { + return true + } + return false + }), + ) + setApprovalEvents(rows.filter((_, index) => unresolved[index])) + } + + const loadSession = async (sessionId: string) => { + closeStream() + setStreamingText('') + setActiveSessionId(sessionId) + const nextBundle = await api.getSession(sessionId) + setBundle(nextBundle) + const run = nextBundle.runs[0] || null + setActiveRun(run) + setEvents([]) + setDrawer(null) + await refreshApprovals(sessionId) + if (run) await loadRun(run, sessionId) + } + + const createSession = async () => { + setError(null) + const session = await api.createSession() + await refreshSessions() + await loadSession(session.id) + } + + const openStream = (runId: string, sessionId: string, after: number) => { + closeStream() + const stream = new EventSource(`/api/runs/${runId}/events/stream?after=${after}`) + eventSource.current = stream + stream.onmessage = async message => { + const item = JSON.parse(message.data) as RunEvent + setEvents(current => [...current, item]) + if (item.event_type === 'assistant-delta' && item.payload.text) { + setStreamingText(current => current + item.payload.text) + } + if (item.event_type === 'agent-step' && item.payload.kind === 'tool-call') { + setStreamingText('') + } + if (item.event_type === 'approval-required') { + setApprovalEvents(current => uniqueApprovals([...current, item])) + } + if (['completed', 'failed', 'cancelled'].includes(item.event_type)) { + try { + const run = await api.getRun(runId) + setActiveRun(run) + if (terminalStatuses.has(run.status)) { + setStreamingText('') + closeStream() + setBundle(await api.getSession(sessionId)) + await refreshApprovals(sessionId) + } + } catch (streamError) { + setError(streamError instanceof Error ? streamError.message : '读取运行状态失败') + closeStream() + } + } + } + stream.onerror = () => { + setError('任务状态连接已中断,可以重新打开该会话继续查看结果。') + closeStream() + } + } + + const loadRun = async (run: Run, sessionId: string) => { + const [currentRun, runEvents] = await Promise.all([api.getRun(run.id), api.getEvents(run.id)]) + setActiveRun(currentRun) + setEvents(runEvents) + if (['queued', 'running'].includes(currentRun.status)) { + const after = runEvents.at(-1)?.sequence ?? -1 + openStream(run.id, sessionId, after) + } else if (terminalStatuses.has(currentRun.status)) { + setBundle(await api.getSession(sessionId)) + } + } + + useEffect(() => { + let cancelled = false + const start = async () => { + try { + const [initialBootstrap, initialSessions] = await Promise.all([api.bootstrap(), api.listSessions()]) + if (cancelled) return + setBootstrap(initialBootstrap) + setSessions(initialSessions) + if (initialSessions.length) await loadSession(initialSessions[0].id) + else await createSession() + } catch (startError) { + if (!cancelled) setError(startError instanceof Error ? startError.message : '平台启动失败') + } + } + void start() + return () => { + cancelled = true + closeStream() + } + }, []) + + useEffect(() => { + messagesEnd.current?.scrollIntoView({ + behavior: streamingText ? 'auto' : 'smooth', + block: 'end', + }) + }, [bundle?.messages.length, streamingText]) + + useEffect(() => { + if (!sessionMenu) return + const closeMenu = () => setSessionMenu(null) + const closeOnEscape = (event: globalThis.KeyboardEvent) => { + if (event.key === 'Escape') closeMenu() + } + window.addEventListener('click', closeMenu) + window.addEventListener('keydown', closeOnEscape) + return () => { + window.removeEventListener('click', closeMenu) + window.removeEventListener('keydown', closeOnEscape) + } + }, [sessionMenu]) + + const timeline = events.reduce((items, event) => { + if (['output', 'approval-required', 'harness-event', 'assistant-delta'].includes(event.event_type)) return items + return [...items, event] + }, []) + const validationEvidence = [...events].reverse().find(event => event.event_type === 'validation-evidence') + const evidenceVerdict = + typeof validationEvidence?.payload.verdict === 'string' ? validationEvidence.payload.verdict : undefined + const evidenceReasons = Array.isArray(validationEvidence?.payload.reasons) + ? validationEvidence.payload.reasons.map(String) + : [] + const agentWorking = Boolean(activeRun && ['queued', 'running'].includes(activeRun.status)) + + const sendMessage = async (content: string) => { + if (!content.trim() || !activeSessionId || busy) return + setBusy(true) + setStreamingText('') + setError(null) + try { + const result = await api.sendMessage(activeSessionId, content.trim()) + setBundle(current => + current + ? { + ...current, + messages: [ + ...current.messages, + result.user_message, + ...(result.assistant_message ? [result.assistant_message] : []), + ], + runs: result.run ? [result.run, ...current.runs] : current.runs, + } + : current, + ) + if (result.run) { + await loadRun(result.run, activeSessionId) + } + await refreshApprovals(activeSessionId) + await refreshSessions() + } catch (sendError) { + setError(sendError instanceof Error ? sendError.message : '发送失败') + } finally { + setBusy(false) + } + } + + const submit = (event: FormEvent) => { + event.preventDefault() + const content = input + setInput('') + void sendMessage(content) + } + + const inputKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Enter' && !event.shiftKey) { + event.preventDefault() + event.currentTarget.form?.requestSubmit() + } + } + + const setPinned = async (session: Session) => { + setSessionMenu(null) + setError(null) + try { + await api.setSessionPinned(session.id, !Boolean(session.pinned)) + await refreshSessions() + } catch (reason) { + setError(reason instanceof Error ? reason.message : '更新会话失败') + } + } + + const deleteSession = async (session: Session) => { + setSessionMenu(null) + if (!window.confirm(`删除会话“${session.title}”?该操作不可撤销。`)) return + setError(null) + try { + await api.deleteSession(session.id) + const rows = await refreshSessions() + if (session.id === activeSessionId) { + closeStream() + setBundle(null) + setActiveRun(null) + setEvents([]) + setApprovalEvents([]) + if (rows.length) await loadSession(rows[0].id) + else await createSession() + } + } catch (reason) { + setError(reason instanceof Error ? reason.message : '删除会话失败') + } + } + + const dismissApproval = (eventId: string) => { + setApprovalEvents(current => current.filter(event => event.id !== eventId)) + } + + const continueProposal = async (proposalType: 'development' | 'repair', proposalId: string) => { + const action = + proposalType === 'development' + ? '请调用 apply_operator_implementation 应用已批准的新算子提案,然后生成 execute=false 的验证计划。' + : '请调用 apply_repair 应用已批准的修复提案,然后生成 execute=false 的验证计划。' + await sendMessage(`提案 ${proposalId} 已由用户批准。${action}`) + } + + const executeValidation = async (validationRunId: string) => { + await sendMessage( + `验证计划 ${validationRunId} 已由用户批准。请调用 validate_operator,设置 execute=true 且 approved_run_id="${validationRunId}",只执行该计划对应的精确命令。` + + '执行后如果失败,立即调用 diagnose_failure;若 source_repair_allowed=true,则按 repair_strategy 生成修复提案,等待用户审批后继续验证,直到通过或达到停止条件。', + ) + } + + return ( +
+
+ +
+
RV
+
+

Triton-RISCV Agent

+

算子开发与编译验证工作台

+
+
+
+ + {bootstrap?.harness.api_configured ? 'Harness 已配置' : '等待模型配置'} +
+
+ + + +
+
+
+ Conversation +

{bundle?.session.title || '新对话'}

+
+
+ DeepSeek Harness + +
+
+ {error && ( +
+ {error} + +
+ )} +
+ {!bundle?.messages.length ? ( + + ) : ( + bundle.messages.map(message => { + return ( +
+ {message.role === 'assistant' && ( +
+ +
+ )} +
+
+ +
+
+ {message.role === 'user' && ( +
+ +
+ )} +
+ ) + }) + )} + {streamingText && ( +
+
+ +
+
+
+ +
+
+
+ )} + {agentWorking && !streamingText && ( +
+
+ +
+
+ +
+
+ )} +
+
+ {approvalEvents.length > 0 && ( +
+ {approvalEvents.map(event => + event.payload.validation_run_id ? ( + + ) : ( + + ), + )} +
+ )} +
+ {bootstrap?.suggestions.map(suggestion => ( + + ))} +
+
+