diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4675ee6..254b129 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,26 @@ jobs: - run: npm ci - name: Run Vitest run: npm run test:ci + - name: Verify Harness DSL generated sources + run: npm run harness:generated + - name: Build Harness DSL package + run: npm run harness:build + - name: Test Harness DSL package + run: npm run harness:test + - name: Build Harness UI package + run: npm run harness-ui:build + - name: Test Harness UI package + run: npm run harness-ui:test + - name: Build Harness Studio package + run: npm run harness-studio:build + - name: Test Harness Studio package + run: npm run harness-studio:test + - name: Install Chromium for Harness Studio browser test + if: ${{ matrix.os == 'ubuntu-latest' && matrix.node == '22.20.0' }} + run: npx playwright install --with-deps chromium + - name: Test Harness Studio browser interaction + if: ${{ matrix.os == 'ubuntu-latest' && matrix.node == '22.20.0' }} + run: npm run harness-studio:test:browser - name: Upload JUnit test results if: ${{ always() }} uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index df20143..ef78f29 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,6 +2,17 @@ name: Publish npm on: workflow_dispatch: + inputs: + package: + description: Package to publish + required: true + default: better-harness + type: choice + options: + - better-harness + - harness + - harness-ui + - harness-studio permissions: contents: read @@ -20,8 +31,14 @@ jobs: registry-url: https://registry.npmjs.org package-manager-cache: false - run: npm ci - - run: npm test - - run: npm run pack:verify - - run: npm publish --access public + - run: npm run check + - name: Publish Better Harness + if: ${{ inputs.package == 'better-harness' }} + run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Publish selected Harness workspace + if: ${{ inputs.package != 'better-harness' }} + run: npm publish --workspace "@qoder-ai/${{ inputs.package }}" --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 2258779..c387213 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,6 @@ skills/**/.plugin-eval/ assets/wasm dev/terminal-demo/*.cast /.codex/better-harness/ +/harness-readme-compare-evidence/ +/harness-qoder-profile-evidence/ design-qa.md diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4eb5035..855291d 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -21,6 +21,14 @@ the target journey, contract, evidence, governance, and DX-measurement system. supplied copy, but they do not compose or translate it; host UIs render the persisted semantic copy instead of rebuilding it from structural metadata. - Keep host evidence adapters separate from packaging, and keep all automation cross-platform. +- Keep Harness as Code dependencies directed `core <- adapters <- devtools`: + the package root owns browser-safe grammar, IR, revision, and resolution; + source locking, host execution, compare execution, and highlighting are + explicit subpath boundaries. UI protocol layers accept injected executors. +- Bridge persisted Harness runs into Inspector through the `harness-run` + session adapter. Harness owns revision and receipt schemas; session-analysis + owns `NormalizedToolActivityV1`; the bridge is one-way and never merges the + two contracts. See [ADR-0003](adrs/harness-run-evidence-bridge.md). - Keep stable host identity, display, home-option, and support-slice metadata in `scripts/host-support/`. Executable adapter imports and construction remain in capability-local registries; do not introduce a global host service locator. diff --git a/docs/adrs/README.md b/docs/adrs/README.md index 43ae536..e0bbd5f 100644 --- a/docs/adrs/README.md +++ b/docs/adrs/README.md @@ -13,6 +13,10 @@ deprecated. | --- | --- | --- | --- | --- | | `ADR-0001` | [AI-Optimized Directory Structure](directory-structure.md) | Proposed | 2026-07-16 | Directory ownership, artifact routing, migration gates, and target-directory activation | | `ADR-0002` | [Developer Experience System](developer-experience-system.md) | Proposed | 2026-07-31 | Journeys, federated contracts, projections, native evidence, governance, support, and DX measurement | +| `ADR-0003` | [Harness Run Evidence Bridge](harness-run-evidence-bridge.md) | Proposed | 2026-08-15 | Harness revision and run evidence ingestion into the Inspector normalization chain | +| `ADR-0004` | [Harness Checkpoint Experiment Compare](harness-checkpoint-experiment-compare.md) | Proposed | 2026-08-17 | Checkpoint-anchored mixed-origin experiments, derived treatment axes, per-contrast verdicts, and the Studio experiment lifecycle | +| `ADR-0005` | [Checkpoint-backed Compare Sources and Materialization](checkpoint-backed-compare-sources.md) | Proposed | 2026-08-17 | Source-neutral checkpoint discovery, request provenance, adapter projections, and per-lane materialization | +| `ADR-0006` | [Session Notebook Trace and Outcome Projection](session-notebook-evidence-projection.md) | Proposed | 2026-08-18 | Ordered Turn evidence, response availability, evidence-bounded outcomes, and session-scoped patch requirements | ## Lifecycle diff --git a/docs/adrs/checkpoint-backed-compare-sources.md b/docs/adrs/checkpoint-backed-compare-sources.md new file mode 100644 index 0000000..40f386d --- /dev/null +++ b/docs/adrs/checkpoint-backed-compare-sources.md @@ -0,0 +1,120 @@ +# Checkpoint-backed Compare Sources and Materialization + +## Traceability + +- ADR ID: `ADR-0005` +- Status: Proposed +- Decision date: 2026-08-17 +- Related ADR: [Harness Checkpoint Experiment Compare](harness-checkpoint-experiment-compare.md) +- Implementation spec: [Checkpoint-anchored multi-lane harness + experiments](../specs/2026-08-17-harness-studio-checkpoint-compare.md) + +## Context + +The first Harness Studio experiment runner uses a +`session-execution-plan-v1` checkpoint. That plan happens to identify a Git +repository, commit, tree, and agent-session position, and its current +materializer creates detached Git worktrees. Those facts are sufficient for the +first executable adapter, but they are not the product boundary. + +Compare must also be able to start from other resources that retain historical +state. A presentation can have a versioned PPTX checkpoint and isolated file +copies; a document, design, notebook, or remote workspace can expose different +revision locators and materialization mechanisms. Naming the product or its +browser contract `git-backed` would leak the first adapter into every future +source and force non-Git histories to pretend to be repositories. + +The experiment layer also needs to keep three facts distinct: + +- the immutable checkpoint shared by the experiment; +- the user request that fresh lanes execute, whether imported from history or + entered for a new comparison; +- the runtime-owned isolated materialization created for each fresh lane. + +## Decision + +- **Harness Studio Compare is checkpoint-backed.** A Compare locks one + checkpoint and one request before execution. Git is the first checkpoint + source adapter, not the product identity or a required field in the generic + Studio model. +- **`checkpointRef` remains opaque and authoritative.** The experiment manifest + continues to store the checkpoint plan reference and digest. It does not copy + repository, document, revision, slide, session, or worktree fields. The + checkpoint-owning adapter validates and interprets the referenced bytes. +- **Source adapters project a generic descriptor for Studio.** A validated + adapter may expose display-oriented `adapter`, `resource`, `revision`, + optional `history`, and `materialization` facts. Labels and values belong to + the adapter: the Git adapter can say `Repository`, `Commit`, `Session + position`, and `Detached worktree`; a PPTX adapter can say `Presentation`, + `Version`, `Edit history`, and `Isolated document copy`. Studio renders the + descriptor and does not branch on those labels or require Git-shaped fields. +- **The descriptor is a projection, not a second checkpoint.** It is derived + from a validated checkpoint for selection and preflight UX. Evidence and + execution continue to cite the checkpoint digest and adapter receipts rather + than trusting browser-authored display values. +- **Discovery, lock, and materialization are separate phases.** A source adapter + may browse projects or document histories and resolve a mutable selection + into an immutable checkpoint. Locking creates no sandbox, worktree, document + copy, or result ref. Only execution invokes the adapter's materializer for + each fresh lane. +- **Materialization is capability-based.** An adapter describes whether it can + create isolated copies, replay an observed history, preserve a result, and + clean up. The current Git adapter materializes a detached worktree at the + locked commit. A future PPTX adapter may copy a versioned file plus required + sidecars into an isolated directory. Neither mechanism changes what a + checkpoint means. +- **Request provenance is independent of checkpoint provenance.** Historical + Replay locks the exact imported user request and its source locator; New + Request Compare locks newly entered request bytes. Editing an imported + historical request creates a new request identity instead of silently + rewriting the historical episode. +- **Studio follows `Draft -> Lock -> Materialize -> Execute -> Evaluate`.** The + mutable Builder selects a scenario, checkpoint source, request source, and + variants. Lock produces the existing experiment/checkpoint references and a + comparability preview. The compact Workbench starts after lock and retains the + source identity while it streams ACP and result evidence. +- **Comparison semantics remain those of ADR-0004.** Every fresh lane starts + from a materialization of the same checkpoint; observed history is contextual + unless its identity is complete; treatment axes and verdict strength remain + derived from evidence. + +## First Adapter Boundary + +The first implementation projects `session-execution-plan-v1` as: + +| Generic field | Git adapter value | +| --- | --- | +| Adapter | Git + agent session | +| Resource | Repository display name | +| Revision | Base commit, with tree as secondary identity | +| History | Session id and selected entry | +| Materialization | One detached worktree per fresh trial, created on Run | + +The projection deliberately does not become `GitCheckpointSourceV1` in the +browser. Provider-specific validation, absolute paths, Git commands, locks, and +cleanup stay in the Node adapter and runner. + +## Consequences + +Studio can explain the real Git/worktree plan today without making Git a +permanent product dependency. Future versioned resources can join by supplying +the same descriptor and lifecycle capabilities, while their canonical +checkpoint formats remain adapter-owned. The extra boundary requires an +adapter registry, explicit unsupported-checkpoint errors, and tests proving the +browser UI contains no Git-specific branching. A generic projection cannot by +itself guarantee that two historical environments are reproducible; checkpoint +completeness and runtime receipts remain required evidence. + +## Rejected Alternatives + +- **Call the product Git-backed.** Rejected because it makes repository + vocabulary part of product identity and excludes versioned non-code + resources. +- **Add a universal checkpoint object containing every source field.** Rejected + because optional Git, PPTX, document, design, and remote-workspace fields + would duplicate adapter contracts and weaken validation. +- **Create one checkpoint per lane.** Rejected because it removes the shared + starting condition. Lanes receive separate materializations of one checkpoint. +- **Create worktrees or file copies while the Builder is edited.** Rejected + because mutable selection is not execution authority and abandoned drafts + would leak resources. diff --git a/docs/adrs/harness-checkpoint-experiment-compare.md b/docs/adrs/harness-checkpoint-experiment-compare.md new file mode 100644 index 0000000..7730722 --- /dev/null +++ b/docs/adrs/harness-checkpoint-experiment-compare.md @@ -0,0 +1,127 @@ +# Harness Checkpoint Experiment Compare + +## Traceability + +- ADR ID: `ADR-0004` +- Status: Proposed +- Decision date: 2026-08-17 +- Related specs: [Harness Coding Compare](../specs/2026-08-15-harness-coding-compare.md), + [Session Checkpoint Executor PoC](../specs/2026-08-16-session-checkpoint-executor-poc.md), + [Harness UI Studio](../specs/2026-08-15-harness-ui-studio.md) +- Implementation spec: [Checkpoint-anchored multi-lane harness + experiments](../specs/2026-08-17-harness-studio-checkpoint-compare.md) +- Source abstraction: [Checkpoint-backed Compare Sources and + Materialization](checkpoint-backed-compare-sources.md) + +## Context + +Two evidence systems exist today and neither can express a mixed-origin, +multi-lane experiment: + +- `harness-compare.v1` freezes a fixture, runs exactly two variants + (`baseline`/`candidate`) serially against a synthetic Git repository, and + derives a single verdict. The manifest carries one global `runtime.model`, + so per-lane model variation is inexpressible, and the treatment axis is + limited to `harness | runtime-profile`. +- The session executor owns the checkpoint contract + (`session-execution-plan-v1`): base commit and tree plus session file + digest, entry id, and branch digest. Execution results land on + `refs/better-harness/session-executions` namespaced refs and never switch + the user's branch. + +Studio users want to pick a checkpoint, replay the observed historical +trajectory, run two fresh agents (different harness or different model) from +the same checkpoint in parallel, and compare the three trajectories side by +side. The first executable adapter resolves a Git commit and materializes +detached worktrees, but ADR-0005 keeps those mechanics out of the generic +product contract. The temptation is to add a "sandbox checkpoint" type, copy +source-specific fields into a new experiment schema, or let a single global +verdict summarize a three-lane view. Each of those blurs provenance or +fabricates attribution. + +## Decision + +- **One checkpoint definition per adapter.** The current session-executor plan + is the first checkpoint contract. Future source adapters may own other + versioned checkpoint formats under ADR-0005. A sandbox is a materialization + of the referenced checkpoint for one lane's execution, never a new checkpoint + type. Experiment documents hold a `checkpointRef` (path plus digest) and never + copy or reinterpret checkpoint fields. +- **The `.harness` grammar does not change.** The upgrade lives entirely in + the experiment and compare layer. `harness-compare.v1` remains the frozen + fixture, two-variant path; it is not extended to cover checkpoints. +- **New `harness-experiment.v1` manifest.** The version starts at v1; no + prior experiment schema exists. It declares one shared task (prompt hash, + grader) and N lanes. A lane has `origin: "observed"` (a recorded trajectory + reference plus its starting checkpoint digest; no sandbox is created) or + `origin: "execute"` (a harness id plus a per-lane runtime profile and model; + a sandbox is materialized from the shared checkpoint). The host, the visible + tool set, and the run policy are shared across lanes rather than per-lane, so + a lane cannot move the host and confound every contrast at once. +- **Treatment axes are derived, never author-declared.** A contrast names + only the lanes it compares. The runner computes the axis by diffing the + lanes' harness id, runtime profile, and model. Exactly one differing axis + (`harness`, `runtime-profile`, or `model` — extending the existing + taxonomy) permits an attribution verdict; more than one yields + `multi-axis`, which is descriptive only and can never produce a harness + accept/reject. +- **The statistical evidence bar is preserved.** Execute lanes carry a trial + count, and per-contrast verdicts are decided by the existing matched-pair + decision policy, including the two-matched-pair floor. A contrast whose + lanes ran once each is attributable in principle but reports + `insufficient_evidence`, never a promotion; the experiment schema is not a + bypass for the compare evidence bar. +- **An identically configured pair is descriptive, not invalid.** Where + `harness-compare.v1` rejects a manifest whose variants move nothing, an + experiment accepts it and reports `no-axis-moved`. Two identical lanes from + one checkpoint measure run-to-run variance, which is the noise floor every + other contrast is read against. +- **Checkpoint completeness is a gate, not an assumption.** A checkpoint + anchors a commit and tree, not the untracked files or dirty state the + historical trajectory may have started from. Materialization records a + completeness receipt: either a clean-tree assertion or a captured + dirty-state patch applied to every fresh lane. Without it, fresh lanes may + not claim to share the historical lane's starting condition. +- **Observed lanes are contextual evidence by default.** A historical + trajectory participates in an attribution verdict only when its runtime, + model, harness revision, environment receipts, and task identity (prompt + and prior session context) all match the fresh lanes. Absent any of those + — and the prompt almost never matches — it is displayed as context in a + descriptive contrast. Grades are optional on observed lanes. +- **Execution discipline for parallel lanes.** All lanes pass preflight + (checkpoint digest, base commit/tree, session digest) before any lane + starts. Worktree materialization is serialized to avoid Git lock + contention; execution then runs in parallel with `Promise.allSettled`, so + one lane's failure never discards another lane's evidence. Every event + carries `experimentId`, `laneId`, and `runId`. Each lane persists its own + `HarnessRevision`, runtime/model receipt, sandbox receipt, trajectory, + patch, and grade. Results stay on namespaced refs; adopting a result is a + later explicit action. +- **Studio hosts experiments, not one global verdict.** The stateless + run-per-request `/agui` endpoint is insufficient. Studio gains a + server-side experiment registry (create an experiment, subscribe to + per-lane event streams, cancel), persists evidence per experiment + directory, previews which axes a configuration moves before running, and + renders one verdict per contrast. A three-lane view never shows a single + aggregate verdict. +- **Tool-chain correlation is explicit evidence, not a similarity score.** + Studio normalizes each ACP-derived tool call into tool name, resource target, + and canonical arguments, then aligns lane sequences one-to-one and in order. + The UI labels a counterpart `exact`, `same-resource`, `same-tool`, or `none` + and shows the neighbouring calls around it. This makes a shared file read and + a shared Read → Edit → Test path visible without presenting fuzzy similarity + as provenance or causal proof. + +## Consequences + +Mixed-origin comparison becomes expressible without expanding the core +`.harness` DSL or forking the checkpoint contract. The compare aggregate +taxonomy gains a `model` axis and per-contrast decisions; consumers of +`harness-compare-result.v1` are unaffected because `harness-compare.v1` +remains frozen. Observed trajectories gain a principled, limited role: +context by default, baseline only under full identity. The cost is a second +manifest schema to maintain, a Studio server that now holds run state, and +the obligation to keep the derived-axis rule and evidence floor enforced in +the runner rather than trusted from the document. Implementation still +requires the dated spec, acceptance scenarios, and test evidence mandated by +`AGENTS.md`. diff --git a/docs/adrs/harness-run-evidence-bridge.md b/docs/adrs/harness-run-evidence-bridge.md new file mode 100644 index 0000000..ce01afa --- /dev/null +++ b/docs/adrs/harness-run-evidence-bridge.md @@ -0,0 +1,44 @@ +# Harness Run Evidence Bridge + +## Traceability + +- ADR ID: `ADR-0003` +- Status: Proposed +- Decision date: 2026-08-15 +- Spec: [Harness as Code Architecture Hardening](../specs/2026-08-15-harness-as-code-architecture-hardening.md) + +## Context + +Harness as Code owns immutable configuration and execution evidence through +`HarnessRevision`, `MaterializationReceipt`, `HarnessRunEvent`, and persisted +compare artifacts. The Inspector already owns the provider-neutral historical +analysis contract `NormalizedToolActivityV1`. Merging those schemas would blur +configuration provenance, live event transport, and historical observation. + +## Decision + +- `packages/harness` remains the canonical owner of revisions, + materialization receipts, run events, compare verdicts, and the on-disk + harness evidence directory. +- `scripts/session-analysis` and `scripts/harness-inspector` remain the canonical + owners of normalized historical activity and report projections. +- The bridge direction is one-way: persisted `trace.jsonl` harness events are + ingested by the `harness-run` session adapter and normalized into + `NormalizedToolActivityV1`. Inspector schemas never flow back into revision + resolution or execution. +- A compare evidence directory is self-contained: variant directories retain + the revision, resolution report, and materialization receipt; trial + directories retain trace, runtime, sandbox, and permission receipts. +- `componentSnapshotRef` is an optional hashed cross-reference on a revision. + It links configuration provenance to project inventory without merging the + `HarnessRevision` and `HarnessComponentSnapshotV1` contracts. +- Studio uses live `HarnessRunEvent` transport while a run is active and reads + the same persisted evidence directory for history. It does not own another + persistence schema. + +## Consequences + +Harness runs can enter the existing Inspector evidence chain without inventing +a second report model. The adapter must map only facts retained in the trace; +missing timing, input, or tool-family evidence remains unobserved. Any future +evidence consumer must preserve the same owner and bridge direction. diff --git a/docs/adrs/session-notebook-evidence-projection.md b/docs/adrs/session-notebook-evidence-projection.md new file mode 100644 index 0000000..e066fd1 --- /dev/null +++ b/docs/adrs/session-notebook-evidence-projection.md @@ -0,0 +1,101 @@ +# Session notebook trace and outcome projection + +## Status + +Proposed + +## Context + +Harness Inspector projects privacy-filtered host events into a read-only Session +Notebook. The retained source can contain prompts, assistant messages, tool-call +requests, correlated commits, and partial timing. It does not necessarily retain +tool results, a patch snapshot, a final assistant response, or enough evidence to +prove that an edit or verification succeeded. + +The initial notebook presentation treated the last retained assistant message as +the Turn result and independently grouped assistant messages and tool calls for +display. That made a visually tidy notebook, but it could move an intermediate +assistant message after later tool calls and could present an unfinished sentence +as `Out`. Deriving a diff from the current worktree would be worse: the worktree is +mutable, can contain unrelated user changes, and is not session-scoped evidence. + +The Inspector and Harness Studio may share a notebook visual grammar, but their +authority differs. Inspector presents retained evidence and must remain read-only. +Studio owns checkpoint-backed execution and comparison through its existing +contracts. + +## Decision + +### Preserve one canonical Turn event order + +The session-analysis projection owns the ordered Turn stream. Assistant messages +and tool requests enter that stream in observed source order after existing +deduplication and privacy filtering. Presentation code may collapse contiguous +tool-call runs, but it must not regroup all events by kind or otherwise reconstruct +chronology. + +An assistant message is promoted from the ordered stream to the terminal response +only when it is the final retained event in the Turn. If a later tool request was +observed, the Turn is incomplete in retained evidence and the earlier assistant +message remains an intermediate response. Missing timestamps remain missing; the +projection does not manufacture exact times for assistant messages. + +### Separate process, response, and outcome + +`Process` is an ordered evidence trace: + +- assistant messages render as privacy-filtered, sanitized Markdown; +- tool calls retain structured identity, operation, status, paths, and observed + timing where available; +- compact grouping is limited to adjacent tool calls and preserves their order. + +`Assistant response` is optional retained prose, not proof of success. + +`Outcome` is an evidence-bounded summary of what the Turn retained. It may include +observed edit paths, verification calls, correlated commit statistics, and the +terminal assistant response. A code diff appears only when a session-scoped patch +or equivalent immutable artifact was captured by the report contract. Until that +artifact exists, the notebook states that the patch is unavailable and must not +substitute the current worktree diff. + +### Keep the report boundary bounded and read-only + +The report model carries explicit response availability and ordered steps into the +self-contained Inspector document. This is a private projection contract unless a +second external consumer requires versioned public ownership. Existing selection, +deep-link, privacy, and redaction boundaries remain authoritative. + +Inspector does not gain Continue, Fork, rollback, checkpoint mutation, or replay +execution. Studio does not consume Inspector's dialogue projection merely to share +the notebook appearance. + +## Consequences + +- A Turn can end with `responseStatus: incomplete` even when an assistant message + was retained earlier. +- Counts distinguish intermediate assistant responses, tool calls, and total + retained process events instead of labeling tool calls as intermediate events. +- Process views become longer in highly interleaved sessions. The UI may collapse + adjacent tool runs and keep Process closed by default, but ordering stays visible + when expanded. +- Existing reports without the new status field remain readable through a + conservative compatibility projection. +- A true code-diff output requires a later capture and schema decision; this ADR + explicitly prevents a misleading worktree-derived shortcut. + +## Validation gates + +- Parser tests cover tool -> assistant -> tool order, terminal response promotion, + deduplication, truncation, and incomplete Turns. +- Report-model tests assert ordered steps and explicit response availability. +- Browser verification checks sanitized Markdown, adjacent tool-run ordering, + evidence-bounded Outcome copy, selection/deep links, and desktop/narrow controls. +- Privacy tests continue to prove that secrets and non-repository paths are not + retained in the notebook projection. + +## Traceability + +- ADR ID: ADR-0006 +- Decision date: 2026-08-18 +- Spec: [Make session review and harness comparison read like a notebook](../specs/2026-08-18-notebook-session-and-studio.md) + diff --git a/docs/specs/2026-08-14-harness-as-code-v0.1.md b/docs/specs/2026-08-14-harness-as-code-v0.1.md new file mode 100644 index 0000000..6067b9f --- /dev/null +++ b/docs/specs/2026-08-14-harness-as-code-v0.1.md @@ -0,0 +1,126 @@ +# Make Harness as Code safe to install and execute + +## Traceability + +- Spec ID: harness-as-code-v0.1 +- Status: Implemented + +## Intent + +Ship the first production-ready `@qoder-ai/harness` package as a parseable, +lockable, and explainable assembly language for coding-agent harnesses. A +resolved revision must distinguish the strength declared by a host binding from +the strength the v0.1 executor can actually materialize, reject unsafe or +ambiguous assemblies before execution, and install, build, test, and pack from +the repository's normal dependency and CI workflow. + +The v0.1 executors materialize components as prompt instructions. They may +therefore realize at most `advisory` strength. Bindings may declare future +`wired` or `enforced` host mechanisms, but those declarations are reported as +degraded rather than presented as observed runtime guarantees. + +## Acceptance Scenarios + +- AC-1: One or more `.harness` sources compile into schema-valid versioned IR, + with stable diagnostics for parser, linker, semantic, and cross-file + declaration conflicts. +- AC-2: Duplicate component ids, composition ids, exact plugin versions, or + component/host bindings fail compilation even when the conflicting + declarations are split across source files. Invalid exact semantic versions, + duplicate plugin includes, and repeated component inputs/outputs also fail + before resolution. +- AC-3: Resolution records both declared and materialized strength. The v0.1 + runtime caps materialized strength at `advisory`, applies `minimum`, + `preferred`, and `on-degrade` to that effective strength, and never describes + an unmaterialized `wired` or `enforced` mechanism as realized. +- AC-4: An executor rejects a revision whose target host differs from the + executor host before starting an SDK session or child process. +- AC-5: Qoder execution uses the official Agent SDK with explicit authentication, + cwd, streaming output, and tool-authorization seams. Pi execution uses the + current non-deprecated SDK and `ModelRuntime` API, honors the task working + directory, disables native tools in the advisory-only v0.1 path, and reports + a missing optional runtime dependency with actionable guidance. Pi model + failures propagate through the run result and sessions are disposed after a + run. Qoder streams that terminate without a result message fail closed. +- AC-6: Pi package materialization emits `SKILL.md` only for advisory + skill-kind contracts, produces valid front matter for arbitrary DSL string + descriptions, stamps revision provenance, and fails closed when the target + directory already contains files. +- AC-7: The repository's root install and CI workflow installs this workspace, + regenerates the Langium sources, type-checks/builds the package, runs its + behavior tests on Windows, macOS, and Linux, and detects stale generated + artifacts. +- AC-8: `npm pack` contains the documented public exports, declarations, + example, README, and license without source-local dependencies, caches, or + absolute paths; a clean temporary install can import and exercise the public + API. +- AC-9: The package development guide describes supported Node and Pi SDK + versions, the declared-versus-materialized strength boundary, focused + commands, and current v0.1 limitations without claiming native host evidence. + +## Non-goals + +- Installing or managing native Qoder hooks or Pi extensions in v0.1. +- Claiming `wired` or `enforced` runtime strength without a future native + materialization and evidence-receipt contract. +- Adding another Coding Agent host adapter. +- Publishing the package to the npm registry in this change. +- Changing Better Harness release notes, versions, roadmaps, or changelog. +- Providing a full CLI, language server, editor extension, remote registry, or + dependency solver beyond the in-bundle semver selection API. + +## Plan and Tasks + +1. Tighten compiler semantic validation across the complete source set and + keep diagnostics source/line-qualified. +2. Extend realization IR with declared strength and make the v0.1 resolver + compute effective advisory materialization before applying degradation + policy. +3. Add shared executor host validation, integrate the official Qoder and Pi + SDKs, and make Pi skill materialization kind-safe and front-matter-safe. +4. Add the package as a root npm workspace, refresh the lockfile, expose root + build/test/generated-source gates, and wire them into the OS matrix CI. +5. Expand behavior tests for every repaired failure mode, public exports, + clean-pack import, and generated artifacts. +6. Validate a clean install, build, focused tests, root gates, package contents, + temporary consumer import, and locally available host surfaces. + +## Test and Review Evidence + +- AC-1/AC-2: package compiler tests use multi-source duplicate fixtures and + assert structured diagnostics; they pass as part of the 38-test package run. +- AC-3: resolver tests cover satisfied, degraded-report, degraded-fail, and + below-minimum paths against declared and materialized strengths. +- AC-4/AC-5: executor tests assert that mismatched hosts never invoke SDK + loaders, that Qoder uses explicit auth/tool options, and that Pi uses + `ModelRuntime.create` with the task cwd, selected model, and `noTools: "all"`. + Installed-package contract tests load both SDKs. A native Qoder SDK smoke + returned exactly `HARNESS_QODER_REVIEW_OK`; native Pi inference was not run + because this process had neither `DEEPSEEK_API_KEY` nor configured DeepSeek + authentication. +- AC-6: temporary-directory tests inspect the returned file set and parse-safe + generated front matter for skill and non-skill contracts. +- AC-7: `npm ci --ignore-scripts --registry=https://registry.npmjs.org`, an + explicit Qoder SDK rebuild to restore its intentionally skipped worker + postinstall, and `npm run check` passed. The final run covered 1,324 + repository tests, 38 package tests, generated-source verification, + TypeScript build, and pack verification. CI runs package gates on Windows, + macOS, and Linux with Node 22.20.0 plus Linux with Node 24. +- AC-8: `npm pack --workspace @qoder-ai/harness` ran the package prepack gate + and produced a 36-file, 27.2 kB tarball without the removed executor or + source-local artifacts. A clean temporary install audited 160 dependencies + with zero vulnerabilities and completed a Node ESM import/compile/resolve + smoke through the public API. +- AC-9: README review against the package manifest and observed validation + commands. +- Full regression: `npm run check` passed; root pack verification reported 523 + npm entries and 545 runtime-zip entries. The focused documentation link graph + passed all six assertions, and `npm audit --audit-level=high` reported zero + vulnerabilities after upgrading Pi to 0.84.2. +- Risk: generated Langium output can drift from its grammar. CI regenerates and + rejects a non-empty generated-source diff. +- Risk: adding a root workspace changes the lockfile and install graph. Review + the final lockfile diff and keep package dependencies scoped to the workspace. +- Risk: native host and model availability vary by machine. Deterministic tests + remain authoritative; native smoke is reported separately and never replaces + package or fixture evidence. diff --git a/docs/specs/2026-08-15-harness-as-code-architecture-hardening.md b/docs/specs/2026-08-15-harness-as-code-architecture-hardening.md new file mode 100644 index 0000000..10c16ab --- /dev/null +++ b/docs/specs/2026-08-15-harness-as-code-architecture-hardening.md @@ -0,0 +1,466 @@ +# Harness as Code Architecture Hardening: Sandbox, Grammar, Boundaries, Evidence + +## Traceability + +- Spec ID: `SPEC-2026-08-15-harness-as-code-architecture-hardening` +- Story: none (review-driven follow-up on `feat/harness-as-code-package`) +- Status: Implemented + +## Intent + +The source-level review of `feat/harness-as-code-package` raised four High +findings beyond the four merge blockers. The blockers are closed by +[Harness Execution Closure](2026-08-15-harness-execution-closure-blockers.md), +which explicitly deferred these four items as non-goals: + +1. **Execution boundary** — the compare pipeline claims "network deny", but only + the Quick Start example and export probe run under `node --permission` with a + scrubbed environment; the `npm test` validation step inherits the full host + `process.env` with no permission flags. +2. **Adapter facts in the core DSL** — `binding strength` (other than + `unsupported`) and `runtime execution` claims are author declarations about + adapter implementation facts; today they are silently ignored or trusted. +3. **Package boundary** — the main `@qoder-ai/harness` entry re-exports + exec/compare/highlight, so a consumer that only parses `.harness` must + install the Qoder SDK and Shiki; `harness-ui` imports concrete executors. +4. **Second evidence platform** — `HarnessRevision` / receipts / run traces / + compare verdicts have no bridge to the existing + `HarnessComponentSnapshotV1` / `NormalizedToolActivityV1` / Inspector chain. + +The outcome of this spec: safety claims become recorded evidence rather than +prose, the DSL cannot state facts it does not own, the dependency direction +`core ← adapters ← devtools` is enforced by tests, and harness runs land in the +same evidence chain the Inspector already reads. + +## Non-goals + +- Publishing new npm packages (`@qoder-ai/harness-core`, `adapter-qoder`, …). + This spec fixes the dependency **direction** inside the existing package; + physical package splitting is a later, mechanical step. +- A container/VM sandbox implementation. This spec defines the `TrialSandbox` + seam and ships the trusted-fixture policy; an isolated-container policy is a + separate deliverable behind the same interface. +- Changing verdict statistics (matched pairs, `insufficient_evidence`, + cost-per-trial) — already implemented by the execution-closure spec. +- Making Qoder/Pi adapters materialize MCP, multi-session agents, or + programmatic workflows. +- Migrating existing Inspector reports or session-analysis storage formats. +- A `HarnessLock` artifact between IR and Revision (still deferred). + +--- + +## High 1 — Execution boundary: `TrialSandbox` and `SandboxReceipt` + +### Problem + +`packages/harness/src/compare/grader.ts` hardens the Quick Start example and +the export probe (`node --permission --allow-fs-read=` plus +`safeExampleEnvironment()`, a 7-key env allowlist), but the `package-tests` +check calls `runCommand(npmTest.command, …)` with no `env` option, and +`runCommand` in `packages/harness/src/compare/process.ts` defaults to +`env: process.env`. Package scripts run with full host credentials, network, +and filesystem. The agent-facing allowlist in `compare/permissions.ts` bounds +the *tool surface*, not the *process capability surface*. The honest current +claim is "bounded tool surface over a trusted fixture", not "network denied". + +### Design + +Promote the execution boundary to a first-class seam owned by the compare +runner, not scattered options inside the grader: + +```text +Grader / Runner + │ never spawns directly + ▼ +TrialSandbox (interface) + └── run(command, args, { cwd, timeoutMs }): Promise + └── describe(): SandboxReceipt +Policies: + trusted-fixture → env allowlist + node --permission where applicable + (future) isolated → disposable container / clean fs + network namespace +``` + +`SandboxReceipt` is persisted into the trial evidence and surfaced in the +verdict: + +```ts +interface SandboxReceipt { + policy: "trusted-fixture" | "isolated"; + envPolicy: "allowlist" | "inherited"; + envKeys: string[]; // exact keys passed through + networkPolicy: "denied" | "unverified"; // never claim more than enforced + fsScope: "trial-root" | "host"; + permissionFlags: string[]; // e.g. ["--permission", "--allow-fs-read=…"] +} +``` + +Rules: + +- The trusted-fixture policy runs **every** subprocess (including `npm test`) + with the env allowlist. `npm`/`node` operational keys (`PATH`, `TEMP`/`TMP`/ + `TMPDIR`, `SystemRoot`, `ComSpec`, `PATHEXT`, `HOME` for npm cache resolution, + and explicit `npm_config_*` needed for offline install) are the whitelist; + everything else — tokens, cloud credentials, proxy settings — is dropped. +- `node --permission` is applied where the command is a direct `node` + invocation; `npm test` cannot carry it (npm spawns arbitrary scripts), so its + receipt records `networkPolicy: "unverified"` — which is the honest fact. +- The verdict gains a `sandbox` field carrying the receipt. Report rendering + must label any `networkPolicy: "unverified"` run as + **"trusted-fixture only — network not denied"**. `README.md` and package + README wording is corrected to match. +- `runCommand` loses its `process.env` default: `env` becomes a required + option, so a future call site cannot silently reintroduce inheritance. + +### Acceptance + +- AC1.1 Every subprocess spawned during a compare trial goes through a + `TrialSandbox`; a direct `runCommand` call from grader/runner without an + explicit `env` fails to compile. +- AC1.2 Under the trusted-fixture policy, the env passed to `npm test` contains + only allowlisted keys; a canary variable (e.g. `AWS_SECRET_ACCESS_KEY`, + `GITHUB_TOKEN`) set in the parent env is absent from the child env. +- AC1.3 Each trial directory contains `sandbox-receipt.json`; parsing a verdict + whose trials lack a sandbox receipt fails schema validation. +- AC1.4 The verdict HTML/CLI rendering shows the sandbox policy and labels + `networkPolicy: "unverified"` runs as trusted-fixture only; no rendered + output uses the phrase "network denied" for such runs. +- AC1.5 The Quick Start example and export probe keep their existing + `node --permission` hardening and now also produce receipt entries with + `permissionFlags` recorded. + +--- + +## High 2 — Remove adapter facts from the core DSL + +### Problem + +The grammar (`packages/harness/src/language/harness.langium`) lets authors +declare `binding … { mechanism strength }` and +`runtime … { execution programmatic. }`. Since the execution-closure +work, `materializeAgainstAdapter` (`resolver/resolve.ts`) only honors +`strength unsupported` as an author veto; any other declared strength is +ignored and the adapter descriptor decides. That makes `strength enforced` a +silent no-op — the worst kind of grammar surface. Similarly, whether a runtime +can execute `programmatic.deno` is an adapter observation, not an authoring +decision, yet the resolver trusts the DSL's `execution` claim +(`resolve.ts` workflow checks). + +Ownership model (from the review, already partially realized): + +```text +Harness DSL → declares what a run needs (requirements, veto) +Adapter descriptor → declares what a runtime can provide (facts) +Receipt → records what this run actually got (observations) +``` + +### Design + +1. **Binding becomes veto-only.** Grammar keeps `binding for + { unsupported? notes? }`. `strength` and `mechanism` are removed + from the binding rule. During a deprecation window the validator reports a + **compile error** (not a silent drop) for `strength`/`mechanism` with a + fix-it message pointing at the adapter descriptor; the tokens are removed + from the grammar in the following minor version. +2. **`execution` moves to the descriptor.** `AdapterRealizationDescriptor` + (`resolver/adapter-descriptor.ts`) gains + `programmaticLanguages: readonly string[]` alongside `workflowModes`. The + resolver's programmatic-workflow gate reads the descriptor, not + `runtime.execution`. The DSL keeps only the requirement side: a workflow may + declare `program deno "./loop.ts"`, and resolution fails closed when no + descriptor supports that language (behavior already tested for unsupported + adapters; the source of truth moves). +3. **Descriptor registry.** A pure-data registry + (`resolver/adapter-registry.ts`) maps adapter package id → descriptor, + loadable **without importing any host SDK**. `QoderSdkAdapter.describe()` / + `PiSdkAdapter.describe()` return the same frozen descriptor objects the + registry ships, and `doStart` asserts registry/instance descriptor equality + so the two cannot drift. +4. `RuntimeDeclaration.adapter` stays: choosing which adapter package to bind + is a deployment decision the author legitimately owns. + +Affected v0.2 example files and `skills/` DSL snippets are migrated in the same +change. + +### Acceptance + +- AC2.1 Compiling a `.harness` source containing `strength wired` or + `strength enforced` in a binding produces a compile **error** whose message + names the adapter descriptor as the owner of realization strength. +- AC2.2 `binding for { unsupported }` still vetoes the capability on + that runtime (existing behavior preserved; regression-tested). +- AC2.3 A programmatic workflow resolves only when the registry descriptor for + the target adapter lists the language in `programmaticLanguages`; a DSL + `runtime … execution` claim alone can no longer satisfy the gate. During the + deprecation window, `execution` in a runtime block compiles with a + deprecation diagnostic and has no resolution effect. +- AC2.4 `resolveHarness` can produce a revision for the built-in Qoder and Pi + targets in a process that has never loaded `@qoder-ai/qoder-agent-sdk` or + `@earendil-works/pi-coding-agent` (registry is pure data). +- AC2.5 For each shipped adapter, the registry descriptor deep-equals the + live `describe()` output (drift test), and `doStart` fails closed on + mismatch. + +--- + +## High 3 — Enforce the `core ← adapters ← devtools` dependency direction + +### Problem + +`compiler/`, `resolver/`, `ir/` already avoid host SDK imports, and +`package.json` already exposes `./ir`, `./exec`, `./compare`, +`./compare/verdict`, `./highlight` subpaths. Four leaks defeat the layering: + +1. `src/index.ts` re-exports `./exec/index.js`, `./compare/index.js`, and + `./highlight/shiki.js`, so the main entry's module graph pulls in the Qoder + SDK, `node:child_process`, and Shiki. `@qoder-ai/qoder-agent-sdk` and + `shiki` are hard `dependencies`. +2. `packages/harness-ui/src/run.ts` imports `QoderSdkExecutor` / + `PiSdkExecutor` as **values** from the main entry, hard-binding the AG-UI + layer to both hosts. +3. Adapter descriptors live in the same modules as adapter implementations + (resolved by High 2's registry). +4. `resolver/source-lock.ts` imports `node:fs/promises`, so the core entry is + not browser-safe. + +### Design + +Fix the direction inside the existing package; do not split npm packages yet. + +```text +"." core only: grammar, compile, IR, revision, canonical hash, + resolver, adapter-descriptor types + registry (browser-safe) +"./lock" source locking (node:fs) [moved out of core] +"./exec" adapter contract + Qoder/Pi adapters (host SDKs via dynamic import) +"./compare" runner, grader, sandbox, verdict (node:child_process) +"./compare/verdict" verdict parsing only (pure, browser-safe — Studio reads it) +"./highlight" shiki +``` + +- `src/index.ts` drops the `exec`/`compare`/`highlight` re-exports and the + `source-lock` value exports; consumers use subpaths. `./lock` is added as a + new subpath export for `lockCapabilitySources` / `verifyRevisionSourceLocks`. +- `@qoder-ai/qoder-agent-sdk` moves from `dependencies` to an **optional + peerDependency** (mirroring the existing Pi arrangement); `exec/qoder-sdk.ts` + already loads it by module id at runtime. `shiki` stays a dependency but is + reachable only via `./highlight`. +- `harness-ui` becomes injection-only: it keeps the existing + `HarnessUiExecutorFactory` seam and stops importing concrete executors; the + built-in Qoder/Pi factory moves to `harness-studio`'s server (which already + owns host wiring) and to the `harness-ui` CLI entry, both of which import + `@qoder-ai/harness/exec` explicitly. +- An import-graph invariant test (see Test Evidence) makes the direction + survivable. Per the repository test convention it must assert on the + **resolved module graph** of the built entry points, not grep source text. + +### Acceptance + +- AC3.1 Resolving the module graph of the built `.` entry + (`dist/index.js`) reaches no module from `dist/exec/`, `dist/compare/` + (except nothing), `dist/highlight/`, `shiki`, `@qoder-ai/qoder-agent-sdk`, + `@earendil-works/pi-coding-agent`, `node:child_process`, or `node:fs`. +- AC3.2 The graph of `./compare/verdict` is equally pure (Studio can bundle it + for the browser). +- AC3.3 `npm install` of `@qoder-ai/harness` without the Qoder SDK peer + succeeds, and `compileHarness` + `resolveHarness` work; loading `./exec` and + constructing a Qoder adapter without the peer fails with the existing + actionable module-load error. +- AC3.4 The module graph of `@qoder-ai/harness-ui`'s main entry contains no + concrete executor module; `handleAguiRun` requires an injected + `HarnessUiExecutorFactory` and its tests pass with a fake factory only. +- AC3.5 `harness-studio` continues to run end-to-end (its server provides the + factory), verified by the existing studio Playwright suite. + +--- + +## High 4 — One evidence chain: bridge runs into the Inspector platform + +### Problem + +Two disjoint evidence platforms exist. Existing chain (canonical owners per +ADR-0002 federation): `HarnessComponentSnapshotV1` +(`scripts/harness-component-snapshot/`), `NormalizedToolActivityV1` + report +model (`scripts/harness-inspector/`), session platform adapters +(`scripts/session-analysis/platforms/{claude,codex,cursor,qoder}.mjs`), +commit-session-link. New chain: `HarnessRevision`, materialization receipt, +`HarnessRunEvent`, per-trial `trace.jsonl` / `runtime-receipt.json`, compare +`verdict.json`, Studio. No bridge code exists in either direction, and a +compare evidence directory is not self-contained (trials record `revisionId` +but the directory holds no revision or resolution report). + +### Design + +Converge at the persistence layer; do not merge schemas. + +```text +HarnessRevision + MaterializationReceipt (config provenance; owner: packages/harness) + ↓ run +HarnessRunEvent (live streaming only; owner: packages/harness) + ↓ persisted as +trace.jsonl ──ingested by──▶ NormalizedToolActivityV1 (owner: session-analysis/inspector) + ↓ +Inspector / Controlled Eval reports +``` + +1. **Self-contained evidence directory.** The compare runner writes + `revision.json` (the full deep-frozen revision), `resolution-report.json`, + and `materialization-receipt.json` at the variant level; each trial keeps + `trace.jsonl`, `runtime-receipt.json`, `sandbox-receipt.json` (High 1), and + `permission-decisions.json`. `parseHarnessCompareVerdict` gains a + directory-level validation mode that fails when the revision file is absent + or its `revisionId` disagrees with the trials. +2. **New platform adapter.** `scripts/session-analysis/platforms/harness-run.mjs` + ingests a harness evidence directory the same way `claude.mjs` ingests + Claude session files: it maps `trace.jsonl` events to + `NormalizedToolActivityV1` (tool calls, families, segments, timeline) and + exposes the run as one more provider. The Inspector then reports harness + runs with zero new report surface. +3. **Cross-reference, not schema merge.** `HarnessRevision` gains an optional + `componentSnapshotRef` (snapshot id + digest) and + `HarnessComponentSnapshotV1` consumers may record `revisionId` in their + population references. The snapshot answers "what exists in the project"; + the revision answers "what this run was configured with". +4. **Studio positioning.** Studio remains the authoring/run workspace; live + views consume `HarnessRunEvent` over SSE, historical views read the + persisted evidence directory. Studio grows no second persistence format. +5. A short ADR under `docs/adrs/` records the canonical owners of the two + contracts and the bridge direction, extending the ADR-0002 federation, so a + third platform does not appear later. + +### Acceptance + +- AC4.1 After a compare run, the evidence directory contains `revision.json`, + `resolution-report.json`, and `materialization-receipt.json` per variant; + directory-level verdict validation fails on a missing or mismatched + `revision.json`. +- AC4.2 The `harness-run` platform adapter converts a fixture `trace.jsonl` + into a `NormalizedToolActivityV1` whose call counts, tool families, and + timeline match the fixture events (asserted on the parsed structure, not on + rendered text). +- AC4.3 An Inspector report generated over a workspace containing a harness + evidence directory lists the run as a session from provider `harness-run`, + linked to the `revisionId`. +- AC4.4 A revision carrying `componentSnapshotRef` round-trips through + canonical hashing and revision-integrity checks (the ref is part of the + hashed body). +- AC4.5 The ADR exists, names both contracts, their owners, and the bridge + direction, and is reachable from `docs/adrs/README.md`. + +--- + +## Plan and Tasks + +Order chosen so grammar breaks land early and evidence contracts freeze last: + +1. **High 3 first** (mechanical, unblocks High 2): + - move source-lock exports to `./lock`; trim `src/index.ts`; add subpath; + demote Qoder SDK to optional peer; adjust `harness-ui` to injection-only; + move built-in factory to studio server + `harness-ui` CLI. + - add the import-graph invariant test. + - files: `packages/harness/src/index.ts`, `packages/harness/package.json`, + `packages/harness-ui/src/run.ts`, `packages/harness-ui/src/cli.ts`, + `packages/harness-studio/src/server/server.ts`. +2. **High 2** (breaking grammar change, cheapest now): + - grammar: veto-only binding, deprecation diagnostics for + `strength`/`mechanism`/`execution`; regenerate Langium artifacts + (`npm run langium:generate`, `check:generated` stays green). + - `programmaticLanguages` on the descriptor; registry module; drift test; + migrate examples and `skills/` snippets. + - files: `packages/harness/src/language/harness.langium`, + `language/harness-validator.ts`, `resolver/adapter-descriptor.ts`, + `resolver/adapter-registry.ts` (new), `resolver/resolve.ts`, + `exec/qoder-sdk.ts`, `exec/pi-sdk.ts`, `examples/`, `skills/`. +3. **High 1** (verdict schema addition — before evidence freeze): + - `TrialSandbox` interface + trusted-fixture policy; make `env` required on + `runCommand`; thread sandbox through grader/runner; `sandbox-receipt.json`; + verdict schema + rendering labels; README wording fix. + - files: `packages/harness/src/compare/sandbox.ts` (new), `process.ts`, + `grader.ts`, `runner.ts`, `verdict.ts`, `aggregate.ts`, report templates, + `packages/harness/README.md`, root `README.md` (compare claims paragraph). +4. **High 4 last** (consumes contracts from 1–3): + - self-contained evidence directory + directory validation; `harness-run` + platform adapter; `componentSnapshotRef`; Studio historical view reads the + directory; ADR. + - files: `packages/harness/src/compare/runner.ts`, `verdict.ts`, + `packages/harness/src/ir/index.ts` + `ir/revision.ts`, + `scripts/session-analysis/platforms/harness-run.mjs` (new), + `scripts/harness-inspector/` (provider registration), + `docs/adrs/` (new ADR), `docs/adrs/README.md`. + +Each step remains independently reviewable so the cross-platform Node matrix, +package tests, and the Studio browser suite can serve as merge evidence. + +Decision rationale: + +- Dependency direction before grammar work: the registry (High 2) must live in + a core that provably does not load host SDKs, so the graph invariant comes + first. +- Deprecation-diagnostic window instead of instant token removal: existing + `.harness` sources in examples, skills, and early adopters get one actionable + compile error before the tokens disappear; silent acceptance is the failure + mode being removed, so the diagnostic is an error, not a warning. +- Bridge at `NormalizedToolActivityV1` rather than a new shared schema: the + Inspector's platform-adapter seam already absorbs four providers; adding a + fifth is the lowest-cost, lowest-risk convergence and keeps ADR-0002 + federation intact. + +## Test and Review Evidence + +Repository conventions apply: assert on behavior and parsed structures, never +on source text patterns; no repo-wide literal scans. + +| AC | Evidence | +| --- | --- | +| AC1.1 | TypeScript compile: `env` required on `runCommand`; grader/runner call-site test with a fake sandbox recording every spawn | +| AC1.2 | Trial test sets `GITHUB_TOKEN` in parent env, asserts child env (captured by fake sandbox / echo probe) lacks it and matches the allowlist exactly | +| AC1.3 | Verdict schema test: verdict without sandbox receipts fails `parseHarnessCompareVerdict` | +| AC1.4 | Render test parses the generated report model (not HTML text) and asserts the policy label field for an `unverified` receipt | +| AC2.1–AC2.3 | Compiler tests: fixture sources with `strength wired`, veto binding, programmatic workflow with/without registry support; assert diagnostics and resolution results | +| AC2.4 | Test spawns a child Node process that imports only the core entry, resolves the Qoder target, and asserts `require.cache`/loaded-modules contains no host SDK | +| AC2.5 | Deep-equal test between registry descriptor and `describe()` per adapter | +| AC3.1–AC3.2 | Import-graph test: resolve the built entry's ESM graph (e.g. `node --experimental-import-meta-resolve` walker or `es-module-lexer` walk over `dist/`) and assert the forbidden-module set is unreachable | +| AC3.3 | CI job (or test with temporarily hidden peer) exercising compile+resolve without the Qoder SDK installed | +| AC3.4 | `harness-ui` tests run with fake factory only; module-graph assertion on its entry | +| AC3.5 | Existing `packages/harness-studio` Playwright suite | +| AC4.1 | Runner integration test over a fake executor; assert directory contents and directory-level validation failure on deleted `revision.json` | +| AC4.2 | Fixture `trace.jsonl` → adapter → assert `NormalizedToolActivityV1` fields | +| AC4.3 | Inspector report-model test over a workspace fixture containing a harness evidence directory | +| AC4.4 | Revision canonical-hash round-trip test including `componentSnapshotRef` | +| AC4.5 | Doc-link test (`npx vitest run test/skills-docs/doc-link-graph.test.mjs`) after adding the ADR | + +Risk notes: + +- **R1 (High 1)**: over-tight env allowlist can break `npm test` on Windows + (`SystemRoot`, `ComSpec`, `PATHEXT`) or on npm cache resolution (`HOME`, + `LOCALAPPDATA`). Mitigation: allowlist is platform-aware and CI runs the + compare suite on the existing four-platform matrix. +- **R2 (High 2)**: grammar break invalidates existing `.harness` files. + Mitigation: deprecation diagnostic with fix-it text; examples and skills + migrate in the same commit; `check:generated` guards Langium artifacts. +- **R3 (High 3)**: demoting the Qoder SDK to an optional peer changes install + behavior for current consumers. Mitigation: `./exec` keeps the existing + actionable module-load error; README installation snippet updated in the + same PR. +- **R4 (High 4)**: `trace.jsonl` event vocabulary may not cover everything + `NormalizedToolActivityV1` expects. Mitigation: the adapter maps only what + the trace proves and leaves absent fields empty rather than inventing them; + gaps are recorded in the adapter's fixture tests. +- **R5 (cross-cutting, deferred policy decision)**: whether `npm test` + validation must eventually require the isolated-container policy before a + compare verdict may render `accept`. This implementation preserves the + specified trusted-fixture behavior and labels network denial as unverified. + +## Implementation Evidence + +- `npm test`: 95 files and 1325 tests passed, including the new harness-run + provider and Inspector integration coverage. +- Harness packages: build plus 127 harness, 21 harness-ui, and 29 + harness-studio tests passed. +- `npm run harness-studio:test:browser`: the Studio Playwright interaction test + passed in Chromium. +- `npm run pack:verify`: npm and runtime package contents passed verification. +- Cold install: the packed `@qoder-ai/harness` installed with `--omit=peer`; + core compile and resolve succeeded without the Qoder SDK. +- `npm run preview`: `/health` and `/canvas-module.js` both returned + successfully from `http://127.0.0.1:58575`. +- `npx vitest run test/skills-docs/doc-link-graph.test.mjs`, generated Langium + checks, module-graph invariants, and `git diff --check` passed. diff --git a/docs/specs/2026-08-15-harness-coding-compare.md b/docs/specs/2026-08-15-harness-coding-compare.md new file mode 100644 index 0000000..7ba7a30 --- /dev/null +++ b/docs/specs/2026-08-15-harness-coding-compare.md @@ -0,0 +1,176 @@ +# Compare harnesses with real coding outcomes + +## Traceability + +- Spec ID: harness-coding-compare +- Status: Implemented + +## Intent + +Add a reproducible Qoder-backed comparison workflow to `@qoder-ai/harness` so +maintainers can compare two DSL compositions by letting each one modify the +same isolated repository fixture and grading the resulting files. The first +benchmark creates a repository-grounded `README.md`; success is based on the +file diff and deterministic validation, not on whether an SDK returned text. + +Keep the `.harness` language responsible for agent-harness assembly. A separate +versioned experiment manifest owns tasks, trials, runtime budgets, graders, and +artifact locations so evaluation policy does not become authored composition +syntax. + +## Acceptance Scenarios + +- AC-1: A full-surface `.harness` fixture exercises every component kind, + permission domain/access, binding strength, degradation policy, and + configuration value type. Tests assert compiled IR and resolution behavior, + while focused invalid fixtures assert structured diagnostics. +- AC-2: A `harness-compare.v1` manifest parser rejects unknown fields, unsafe + paths, unsupported hosts, invalid trial counts, missing compositions, and + runtime settings that do not provide a bounded Qoder coding tool policy. +- AC-3: A comparison run copies the frozen task repository into a fresh + directory for every variant and trial, resolves each composition, invokes + the Qoder SDK, captures before/after file state, runs deterministic graders, + and emits parser-safe JSON artifacts without changing the source fixture. +- AC-4: Qoder execution can receive explicit visible tools, auto-approved tools, + disallowed tools, permission mode, model, turn limit, and a permission + callback. Its result records the exact non-secret runtime receipt, SDK event + trace, duration, turns, token usage, cost, session id, and terminal reason. +- AC-5: The README benchmark requires only `README.md` to change, parses its + structure, resolves local links, executes its JavaScript example against the + fixture package, checks documented public API and behavior against executable + package contracts, rejects stale or invented capabilities, and runs the + package's existing tests. +- AC-6: A deterministic fake-SDK end-to-end test proves the compare runner + creates and grades real files. A native Qoder smoke, when local authentication + is available, runs the same public compare command and retains its artifacts; + unavailable authentication is reported separately from product correctness. +- AC-7: Package documentation explains the assembly/evaluation boundary, safe + tool policy, CLI command, artifact layout, limitations, and validation + commands. The package build, tests, generated-source check, document-link + graph, and pack surface pass before commit. + +## Non-goals + +- Enabling Pi coding tools; the Pi v0.1 executor remains advisory and + `noTools: "all"`. +- Treating one README task as proof of general coding-agent improvement. +- Adding a new Coding Agent host adapter or changing existing support claims. +- Allowing arbitrary shell commands, network access, destructive operations, + or writes outside an isolated trial directory. +- Publishing a package, changing package versions, or editing release metadata. +- Using an LLM grader as the primary correctness decision. + +## Plan and Tasks + +1. Add a full-surface language fixture and behavior-focused compiler/resolver + coverage. +2. Extend the Qoder executor with explicit coding options, a bounded + permission callback seam, trace capture, usage metrics, and runtime receipt. +3. Add the versioned compare manifest contract, isolated trial runner, + filesystem snapshot/diff evidence, command grader, aggregation, and CLI. +4. Add the frozen README fixture and a deterministic Markdown/package grader. +5. Test manifest failure modes, source-fixture immutability, variant isolation, + real file creation, grader failures, artifacts, and safe tool decisions. +6. Document and run the focused package gates, native Qoder smoke when + available, full repository gates, link graph regeneration, and pack checks. + +The compare implementation remains under `packages/harness/src/compare/` and +uses only public compiler, resolver, and executor surfaces. It uses Node and Git +argument arrays for cross-platform execution and never invokes a shell string. + +## Test and Review Evidence + +- AC-1: `examples/full-surface.harness` compiles into schema-valid IR and + resolves the satisfied and degraded requirement paths. The package suite + asserts all eight component kinds, four strengths, permission alternatives, + degradation policies, and configuration value types. +- AC-2/AC-3/AC-5: `test/compare.test.ts` exercises manifest policy failures, + bounded tool decisions, real isolated file creation, standard Git patches, + source-fixture immutability, deterministic README grading, redacted paths, + and rejection of generated examples that request host capabilities. +- AC-4: `test/exec.test.ts` passes explicit Qoder SDK options through the + injectable SDK seam and asserts runtime receipts, duration, turns, dollar + cost, credits, usage, session/termination data, and recursive credential + redaction. +- AC-6: A native SDK run used the frozen `performance` model for one H0 and one + H1 trial. Both changed only `README.md`, both executable Quick Starts passed, + both package test runs passed 3/3, and both deterministic scores were 100. + H0 used 6 turns, 519,923 ms, and 82.219797 credits; H1 used 5 turns, + 63,633 ms, and 10.768145 credits. The result correctly remained + `need_more_work` because a one-trial tie does not establish improvement. + Evidence hashes were manifest + `a2fc04c095c71152441f2095d731d0c4662f005d1b2970871a09cc364c1e66b5`, + fixture `d70ee5ff320be019be3590e78792d262ed70e76139cf93cf88c1b048472453ba`, + and harness + `d522506d80f2bad6c6dfd4ffdcd0780193825ce461bf64c707d336940b6432df`. + The H1 native patch was then replayed through the final Node permission-model + grader and again scored 100 with its example and package tests passing. +- AC-7: `npm run check` passed 1,324 root tests, 52 package tests, generated + source verification, package build, and pack verification (525 npm entries, + 547 runtime-zip entries). The focused documentation link graph passed six + assertions. The final tarball contained 65 files (51.9 kB, shasum + `82401bc9ca61f5df0ba872b2b5d485f224d10302`), installed into a + clean temporary consumer, exposed a working `harness-compare` npm bin, and + compiled/resolved the shipped full-surface DSL plus loaded the shipped + `harness-compare.v1` manifest. +- Risk: Agent nondeterminism can create misleading one-shot wins. Preserve each + trial independently and require multiple trials before an improvement claim. +- Risk: Tool approval mistakes can escape the fixture. Resolve every path + against the trial root, allow only a narrow command vocabulary, deny network + tools, and record every permission decision. +- Risk: Authentication, model availability, SDK workers, and machine resources + can fail independently. Classify these as infrastructure failures and retain + stderr/trace evidence rather than scoring them as task failures. +- Risk: SDK messages may contain sensitive data. Persist structured protocol + events only after recursively redacting token/key/authorization fields; never + store injected credentials in manifests, receipts, traces, or fixtures. + +## Post-Review Corrections + +A review of the merged change found eight defects. All are fixed, and each +behavioral fix is covered by a test in the package suite. + +1. Validation commands spawned `npm` without a shell, which cannot start the + Windows `npm.cmd` shim and aborted the whole comparison. `npmInvocation()` + now resolves an `npm-cli.js` entry point, and a test runs it on the host. +2. A timed-out command killed only the direct child. Commands now run in their + own process group and are stopped together with their children. +3. The shared task prompt stated the required README sections, grounding rules, + install command, and validation duty, so the baseline received the candidate + composition's content and the native AC-6 run tied at score 100. The prompt + now states only the goal and the runtime tool policy; the documentation + standard moved into the candidate composition's components. The runtime + profile experiment keeps its explicit prompt because both of its arms share + one composition. +4. Tests derived filesystem paths from `URL.pathname`, which is not a valid path + on Windows. They now use `fileURLToPath()`. +5. Trace redaction shared one cycle set across sibling values, so an object + referenced twice was recorded as `[Circular]`. Only the ancestor chain is + tracked now. +6. The grader imported the agent-modified package entry point into its own + process. Exports are now read by a separate `--permission` Node process, and + a test proves a tampered entry point is graded without executing inside the + grader. +7. Fixture copy, Git setup, patch capture, and grader breakage propagated out of + a trial and discarded the whole run. Such failures are now recorded as that + trial's `infrastructure_error` with retained evidence. +8. `runtime.network` was validated but never used, and `metrics.json` duplicated + the full check list. Network denial now drives the web-tool requirement, and + `metrics.json` keeps the grade summary while `validation.json` keeps checks. + +The AC-6 native manifest, harness, and fixture hashes above belong to the +pre-correction prompt and harness files. They remain the honest record of that +run, but they no longer describe the current experiment: a fresh native run is +required before any comparative claim, and the baseline is now expected to score +lower than the candidate rather than tie. + +Re-verified after the corrections: `npm run harness:generated`, +`npm run harness:build`, `npm run harness:test` (60 package tests), +`npx vitest run test/skills-docs/doc-link-graph.test.mjs` (6 assertions), and +root `npm test` (1,322 of 1,324; `test/plugins/host-support.test.mjs` and +`test/reporting/report-source-review.test.mjs` hit the 120 s limit under full +suite load and both pass in isolation). `npm run harness:generated` and +`npm pack --dry-run` were not re-established after these corrections: a separate +uncommitted change to the grammar, resolver, and `test/sugar.test.ts` is in +flight in the same worktree, so the generated-source diff is dirty and one sugar +test is red. Re-run both gates once that change is complete. diff --git a/docs/specs/2026-08-15-harness-dsl-generation-skill.md b/docs/specs/2026-08-15-harness-dsl-generation-skill.md new file mode 100644 index 0000000..b90890a --- /dev/null +++ b/docs/specs/2026-08-15-harness-dsl-generation-skill.md @@ -0,0 +1,102 @@ +# Teach agents to generate valid Harness DSL + +## Traceability + +- Spec ID: harness-dsl-generation-skill +- Status: Implemented + +## Intent + +Ship a package-local skill that teaches coding agents to author complete, +valid Harness as Code v0.1 documents. The skill must route agents to the +canonical language contract, require deterministic compiler and resolver +validation, and preserve the runtime's declared-versus-materialized strength +boundary. + +The skill belongs to `packages/harness/skills/` so it evolves with the DSL and +is included in the `@qoder-ai/harness` tarball. It is generation guidance, not +an executor: it must not start Qoder or Pi sessions, handle model credentials, +or claim native enforcement without runtime evidence. + +## Acceptance Scenarios + +- AC-1: Invoking `$generate-harness-dsl` gives an agent a concise workflow for + eliciting a target, declaring components, bindings, plugins, and + compositions, and returning a complete `.harness` document. +- AC-2: The routed reference documents the v0.1 grammar, semantic constraints, + version and identifier rules, configuration value types, and the + declared-versus-materialized strength boundary without duplicating runtime + ownership. +- AC-3: A portable Node script compiles a supplied `.harness` file with the + package public API, resolves all or selected compositions, emits structured + JSON diagnostics, and exits non-zero for invalid or unresolved input. +- AC-4: Behavior tests exercise the validator with valid and invalid files; + the skill package passes the system skill validator and repository agent + asset lint. +- AC-5: The npm package manifest includes the package-local skill, and an npm + pack inspection confirms `SKILL.md`, its reference, validator, and generated + UI metadata are present without secrets or source-local dependencies. +- AC-6: A fresh AI forward test, run outside the repository worktree, follows + the skill to produce DSL that passes the deterministic validator and reports + any resolution degradation honestly. +- AC-7: Relative Markdown links remain valid and the repository documentation + link graph stays green. + +## Non-goals + +- Changing the Harness DSL grammar, IR, resolver, or executor behavior. +- Running Qoder or Pi SDK inference as part of DSL generation or validation. +- Storing API keys, authentication material, or other secrets in the skill or + generated DSL. +- Installing the skill globally or adding a new Coding Agent host adapter. +- Claiming `wired` or `enforced` materialization from declarations alone. +- Publishing a package, changing versions, release notes, or the changelog. + +## Plan and Tasks + +1. Initialize the package-local skill with the standard skill scaffolder and + generate its UI metadata. +2. Write a compact `SKILL.md`, a routed v0.1 contract reference, and a portable + compiler/resolver validation script. +3. Include the skill directory in the package tarball and add behavior tests + for the validator's success and failure contracts. +4. Run skill, package, documentation, and pack validation, then forward-test + the instructions with a fresh AI agent from a neutral directory. +5. Record observed evidence and review the final staged/unstaged boundary. + +## Test and Review Evidence + +- AC-1/AC-2: `SKILL.md` routes to one focused v0.1 contract reference and the + package example. System `quick_validate.py` accepted the skill structure and + metadata; `agent-lint --profile agent-assets-review` reported one skill with + zero findings, errors, warnings, or advisories. +- AC-3/AC-4: `npm run harness:build` and the 42-test package suite passed. The + behavior tests execute the shipped Node validator against both the package + example and invalid temporary input, asserting parsed JSON, exit status, and + declared-versus-realized strength rather than source text. +- AC-5: package `npm pack` prepack gates passed and produced a 40-entry tarball + containing `SKILL.md`, `agents/openai.yaml`, `references/dsl-contract.md`, and + `scripts/validate.mjs`. A clean temporary install of that tarball ran the + installed validator successfully against the installed Qoder example. +- AC-6: an isolated fresh agent used the skill to create + `safe-repository-change` outside the repository. Independent validation + compiled and resolved it with no diagnostics, satisfying repository impact + at advisory strength and reporting verification honestly degraded from + declared `enforced` to materialized `advisory`. An attempted Qoder CLI run + stopped before inference because the isolated config was not logged in; it + is not counted as forward-test evidence. +- AC-7: the focused documentation link graph passed all six assertions, and + root pack verification passed with 524 npm entries and 546 runtime-zip + entries. Generated Langium source verification also passed. +- Full regression: the root test run passed 1,322 of 1,324 tests. Two unrelated + governance tests timed out at their 120-second limit; a focused rerun passed + 52 of 54 but timed out in two different test cases, indicating an unstable + baseline timing issue rather than a deterministic assertion or changed DSL + package behavior. Package, generated-source, documentation, validator, and + pack gates all completed successfully when run separately. +- Risk: the validator imports `dist/` relative to the packaged skill. The clean + tarball install smoke proves this layout; source-tree contributors must build + before invoking it, and the failure message gives that command. +- Risk: generated DSL can overstate a host binding. The reference, workflow, + behavior test, and fresh-agent output all preserve the v0.1 advisory ceiling + and expose degradation in the resolution report. diff --git a/docs/specs/2026-08-15-harness-dsl-v0.2-resource-model.md b/docs/specs/2026-08-15-harness-dsl-v0.2-resource-model.md new file mode 100644 index 0000000..c102712 --- /dev/null +++ b/docs/specs/2026-08-15-harness-dsl-v0.2-resource-model.md @@ -0,0 +1,127 @@ +# Converge the Harness DSL on a standard resource model + +## Traceability + +- Spec ID: harness-dsl-v0.2-resource-model +- Status: Implemented + +## Intent + +Replace the v0.1 authored surface (`component` / `binding` / `plugin` / +`composition`) with a resource model whose core semantics are host-neutral: + +- `harness` — the complete assembly of how an agent run works: workflow, + agent roles, capability requirements, and configuration. +- `workflow` — control flow, part of a harness, not the harness itself. + Either a declarative graph (`author -> verifier`, `on verifier.failed -> + author`, `stop when verifier.passed`) or a programmatic controller + (`program deno "./flows/coding-loop.ts"`). +- `agent` — a logical role inside a harness (`author`, `reviewer`). Qoder + and Pi are not agents; they are runtimes. +- `runtime` — a concrete host (Qoder, Pi, DeepSeek Harness, Prime Agent) + with an adapter package and an execution style: `tool-calling` or + `programmatic.` (Prime's persistent IPython, DeepSeek's + TypeScript plugin runtime). +- `skill` / `tool` / `mcp` — the three standard capability kinds. A skill is + progressive knowledge (Agent Skills standard, `source` directory) or + inline guidance (`description` only). A tool is an atomic callable with + input/output identifiers. An MCP entry is a connection (transport + + endpoint), not a tool itself. +- `target` — deployment statement selecting a runtime (`target qoder uses + adapter.qoder`). +- `binding` — adapter-layer mapping of one capability onto one runtime, + carrying `mechanism` (now a dotted name so host-native assets such as + `qoder.plugin`, `pi.extension`, `deepseek.plugin`, `prime.python-skill` + are expressible), `strength`, and `notes`. + +The core DSL no longer defines a generic `plugin`. Host plugin/extension +concepts live behind adapters as binding mechanisms in a host namespace. +"Everything is a Plugin" (DeepSeek/Cordis) and "Package vs Extension" (Pi) +remain host implementation details, isolated behind the adapter boundary. + +What is deliberately kept from v0.1: the strength ladder +(`unsupported < advisory < wired < enforced`), requirement degradation +policy (`preferred` / `minimum` / `on-degrade`), the declared-versus- +materialized strength boundary (v0.x executors still materialize prompt +guidance capped at `advisory`), permission merging with deny-wins, canonical +hashing, and the immutable resolved revision. + +## Acceptance Scenarios + +- AC-1: `.harness` sources using the v0.2 surface (`harness`, `workflow`, + `agent`, `skill`, `tool`, `mcp`, `runtime`, `target`, `binding`) compile + into schema-valid versioned IR (`irVersion` 0.2.0); the tokens `plugin` + and `composition` are no longer part of the grammar and fail to parse. +- AC-2: Compilation rejects, with source/line-qualified diagnostics: + duplicate capability ids across skills/tools/mcps, duplicate + harness/workflow/runtime ids, duplicate agent names in a harness, + duplicate requirements per agent, duplicate capability/runtime bindings, + verb–kind mismatches (`use skill` on a tool, `require tool` on an MCP, + `connect mcp` on a skill), workflow statements naming agents a using + harness does not declare, workflows mixing `program` with graph + statements, empty declarative workflows, skills with neither `source` nor + `description`, and `target ... uses adapter.X` conflicting with a declared + runtime's adapter. +- AC-3: Resolution of a harness for a runtime records declared and + materialized strength per (agent, capability). The v0.2 executors still + cap materialization at `advisory`; `minimum`, `preferred`, and + `on-degrade` apply to the effective strength exactly as in v0.1. +- AC-4: A programmatic workflow only resolves against a runtime whose + execution is `programmatic` in the same language; the resolution error + names external driving (ACP) or a matching runtime as the fix. + Declarative workflows resolve against any runtime. +- AC-5: The revision captures the harness content hash, the target runtime + (id, adapter, execution style), the workflow mode and hash, each agent's + resolved capability list, per-(agent, capability) realizations, merged + permissions (deny wins; MCP transports contribute implicit `network` / + `process` grants), and settings. Revision ids remain `hr_`. +- AC-6: Executors, Pi skill materialization, and the compare runner operate + on the new bundle/revision shapes: host checks compare + `revision.target.runtime`, the run preamble derives from agent roles, + workflow guidance, and capability text, and compare manifests name + harness ids in `variants`. +- AC-7: Examples, the `generate-harness-dsl` skill contract, the TextMate + highlight grammar, and the package README describe only the v0.2 surface; + `npm run build` and the package test suite pass with regenerated Langium + sources. + +## Non-goals + +- Implementing real adapter packages (`@harness/adapter-qoder` etc.) or + executing programmatic workflows; v0.2 records execution style and + enforces deployability only. +- Wiring native MCP connections, host plugins, or extensions; materialized + strength stays capped at `advisory` until an evidence-receipt contract. +- A migration tool for v0.1 sources; v0.1 documents fail to parse and are + rewritten by hand (the surface shipped in one prior spec cycle). +- Registry, versioned capability distribution, or a dependency solver + (removed together with `plugin`; distribution returns via `bundle` later). +- Changing root-level scripts (`harness-component-snapshot` uses an + unrelated "component" notion) or release metadata. + +## Plan and Tasks + +1. Rewrite `harness.langium` to the v0.2 declarations and regenerate. +2. Replace the IR entities and bump `IR_VERSION` to 0.2.0. +3. Rewrite compiler lowering and cross-file semantic diagnostics. +4. Update Langium validator checks (preferred≥minimum, verb–kind match, + unique bindings per runtime). +5. Rewrite the resolver as `resolveHarness(bundle, harnessId, runtime?)` + with the execution-model deployability check. +6. Update executors, Pi skill materialization, compare runner/manifest, + highlight grammar, examples, skill contract, and README. +7. Rewrite package tests against the new behavior with equivalent coverage. + +## Test and Review Evidence + +- AC-1/AC-2: `test/compile.test.ts` compiles v0.2 fixtures to schema-valid + IR and asserts each rejection listed above via structured diagnostics. +- AC-3/AC-4/AC-5: `test/resolve.test.ts` covers satisfied, degraded-report, + degraded-fail, below-minimum, programmatic-mismatch, runtime synthesis + from `target`, permission merging with MCP transport grants, and revision + shape/id stability. +- AC-6: `test/exec.test.ts` and `test/skill.test.ts` assert host checks and + preamble/skill output from the new shapes; `test/compare.test.ts` runs the + compare pipeline over a rewritten two-harness experiment. +- AC-7: `npm run build && npm test` in `packages/harness`, plus + `npm run check:generated`. diff --git a/docs/specs/2026-08-15-harness-execution-closure-blockers.md b/docs/specs/2026-08-15-harness-execution-closure-blockers.md new file mode 100644 index 0000000..0bfd2ac --- /dev/null +++ b/docs/specs/2026-08-15-harness-execution-closure-blockers.md @@ -0,0 +1,202 @@ +# Harness Execution Closure: Revision, Materialization, Session, Evidence + +## Traceability + +- Spec ID: `SPEC-2026-08-15-harness-execution-closure` +- Story: none (review-driven blocker fix on `feat/harness-as-code-package`) +- Status: Implemented + +## Intent + +A source-level review of `feat/harness-as-code-package` accepted the v0.2 resource model but +blocked the merge on four contracts that were not closed between +`Authored Harness → Locked Revision → Runtime Materialization → Execution Evidence`. + +This spec covers only those four blockers. The reviewer's larger restructuring asks — a separate +`HarnessLock` artifact, splitting `@qoder-ai/harness` into core/adapters/devtools packages, moving +binding strength out of the core DSL, and bridging `HarnessRevision` to +`HarnessComponentSnapshotV1` — are explicit non-goals here. + +## Non-goals + +- Introducing a standalone `HarnessLock` artifact between IR and Revision. +- Splitting the package boundary along runtime dependencies. +- Removing `binding strength` / `runtime execution` claims from the core DSL grammar. +- Making Qoder or Pi materialize MCP connections, multi-session agents, or programmatic workflows. +- Unifying Studio/Compare evidence with the existing Inspector normalized trace. +- Hardening the `harness-ui` bind address (the review's separate High item on non-loopback serving + requiring explicit auth or an unsafe flag). + +## Blocker 1 — `HarnessRevision` must be an execution closure + +Problem: `execute(revision, bundle, task)` re-reads workflows and capabilities from whatever bundle +the caller passes, without checking them against the hashes recorded in the revision. A revision +resolved from bundle A could drive execution content from bundle B while still reporting A's +`revisionId`. The revision was also a plain mutable object, `assertRevisionHost` ignored +`target.adapter`, and capability `source` paths were never content-locked. + +### Acceptance + +- AC1.1 `validateRevisionAgainstBundle(revision, bundle)` recomputes the harness, workflow, and + every resolved capability content hash from the bundle and throws + `HarnessRevisionBundleMismatchError` on any drift, naming the drifted entities. +- AC1.2 `assertRevisionIntegrity(revision)` recomputes `revisionId` from the revision body and + throws `HarnessRevisionTamperedError` when a field was mutated after resolution. +- AC1.3 `resolveHarness` returns a deep-frozen revision; a mutation attempt does not change the + observed value (and throws in strict mode). +- AC1.4 `assertRevisionAdapter(revision, adapterId)` throws `HarnessAdapterMismatchError` when + `revision.target.adapter` names a different adapter package. +- AC1.5 `doStart` on both shipped adapters runs host, adapter, integrity, and bundle validation + **before** the host SDK is loaded. +- AC1.6 Source locking: `lockCapabilitySources(bundle, { root })` digests each declared + `skill.source` file or directory tree; a source-backed revision is verified at `doStart` and + fails closed when the on-disk content drifted. +- AC1.7 A revision cannot resolve while a resolved source-backed capability lacks exactly one + matching source lock. Locks digest raw bytes and are verified against an explicit source root, + independent from the task working directory. +- AC1.8 Every public materializer runs revision integrity, adapter, bundle, and source-lock + preflight before writing output; a Pi package cannot carry bundle B content under bundle A's + `revisionId`. +- AC1.9 The revision locks the adapter contract version, implementation version, and descriptor + hash; execution fails before SDK load when any of those facts drift. + +## Blocker 2 — Declared run semantics must not exceed adapter materialization + +Problem: `materializeV02()` mapped every non-`unsupported` binding to `advisory` / +`prompt-preamble`, so `require tool`, `connect mcp`, and programmatic workflows all resolved +successfully while the executor only emitted a prompt line — and Qoder/Pi passed no tools at all. + +### Acceptance + +- AC2.1 Materialization is capability-kind aware and adapter-owned. An + `AdapterRealizationDescriptor` declares skill delivery, the DSL-tool → host-tool exposure map, + MCP support, drivable workflow modes, agent isolation, and consumed setting keys. +- AC2.2 A `tool` requirement is never satisfied by prompt guidance. Without descriptor-declared + exposure it realizes `unsupported` and resolution fails; with exposure it realizes `wired` + through mechanism `host-tool:`. +- AC2.3 `connect mcp` fails closed: no shipped adapter opens MCP connections in v0.2. +- AC2.4 A programmatic workflow fails resolution against a descriptor that can only drive + declarative workflows, instead of resolving into a silent no-op. +- AC2.5 The Qoder adapter really exposes the host tools its revision requires (visible `tools` plus + the run-time receipt), so an exposed tool requirement has a runtime effect. +- AC2.6 A multi-agent harness on a single-session adapter is recorded as an explicit workflow + degradation with a run warning, not as satisfied orchestration. +- AC2.7 `revision.permissions` is renamed `revision.requestedPermissions`; a + `HarnessMaterializationReceipt` records, per capability, `materialized | degraded | unsupported` + plus mechanism, and separates requested from enforced permissions and consumed from ignored + settings. Executors attach the receipt to `HarnessRunResult.materialization`. +- AC2.8 Public validators resolve against the selected built-in adapter descriptor. Published + examples target only adapters that can realize their required capabilities. + +## Blocker 3 — Qoder adapter must be a real multi-turn session + +Problem: every `doPromptTurn` called `sdk.query()` again with a fresh string prompt and no +`resume`/`session_id`, so `persistSession: true` only suppressed the preamble; there was no proof +turn 2 saw turn 1. There was also no in-flight turn mutex, `doStop`/`doDestroy` never closed or +interrupted the query, and `runOnce` skipped `doDestroy` when `doStop` failed with a non-capability +error. + +### Acceptance + +- AC3.1 `doStart` opens exactly one `query({ prompt: AsyncIterable })`; each turn + pushes a user message onto that queue and drains the shared stream to its `result` message. +- AC3.2 A fake SDK that models the official Query lifecycle proves turn 2 can answer with + information supplied only in turn 1, with a single `query()` call for the whole session. +- AC3.3 Concurrent `doPromptTurn` calls are rejected with `HarnessConcurrentTurnError`; the + contract's "turns are sequential" claim is enforced, not documented. +- AC3.4 `doStop` ends the queue and awaits `query.close()`; `doDestroy` interrupts best-effort and + then closes. A per-turn `abortSignal` calls `query.interrupt()`. +- AC3.5 The session exposes the host `sessionId`; a turn that arrives after the host terminated the + query reopens it with `resume: sessionId` and is delivered once, instead of being reported as a + turn nobody ran or replaying a fresh context. +- AC3.6 `runOnce` destroys the session best-effort when `doStop` throws any error. +- AC3.7 The Qoder session does not impose a one-turn default on the whole query. Tests assert that + an omitted `maxTurns` stays unbounded while explicit limits remain visible in the runtime receipt. + +## Blocker 4 — Compare must not `accept` on insufficient evidence + +Problem: `decideVerdict()` accepted on any pass-rate or 5-point score improvement with no minimum +sample size, compared two independent aggregates instead of paired trials, excluded infrastructure +errors from the denominator (so one lucky completed trial could beat 20 real ones), compared total +cost across unequal completed counts, allowed a manifest to move harness *and* runtime profile at +once, and re-validated persisted verdicts without recomputing aggregates from trial rows. + +### Acceptance + +- AC4.1 `CompareStatus` gains `insufficient_evidence`. +- AC4.2 A manifest must move exactly one treatment axis (harness *or* runtime profile); moving both + is rejected at load. The verdict records the axis. +- AC4.3 Verdicts are decided on matched pairs (same trial index, both variants completed). + Fewer than the required pairs → `insufficient_evidence`. A single matched pair can never + `accept`, whatever the configured policy. +- AC4.4 An infrastructure error ratio above the policy threshold → `infrastructure_error`. +- AC4.5 Aggregates report `costPerAttemptedTrialUsd`, `costPerCompletedTrialUsd`, and + `costPerPassedTrialUsd`; the cost guardrail compares cost per completed trial. +- AC4.6 `parseHarnessCompareVerdict()` recomputes `completedTrials`, `passedTrials`, + `infrastructureErrors`, `passRate`, `meanScore`, `totalCostUsd`, `totalCredits`, the per-trial + cost fields, and the matched-pair counts from the trial rows, and rejects any hand-edited + aggregate that disagrees. +- AC4.7 Persisted `status` and `reason` are also recomputed from the validated policy and trial + rows; a two-pair result cannot be relabelled `accept` under a five-pair policy. + +## Plan + +1. `src/ir/revision.ts` — integrity, bundle validation, deep freeze, adapter assertion. +2. `src/resolver/source-lock.ts` — mandatory capability source digests and explicit-root + verification for source-backed revisions. +3. `src/resolver/adapter-descriptor.ts` — adapter realization facts and the shipped descriptors. +4. `src/resolver/resolve.ts` — kind-aware materialization, `requestedPermissions`, receipt input. + `ResolveOptions.adapter` also accepts a lookup keyed by the selected runtime, for callers that + let the bundle choose its target; `src/exec/built-in.ts` exposes `describeBuiltInAdapter`. +5. `src/exec/*` — descriptor-driven preflight, materialization receipt, Qoder Query session, + turn mutex, `runOnce` teardown. +6. `src/compare/*` — treatment axis, decision policy, paired verdict, recomputed parse. +7. `packages/harness-ui` resolves against the descriptor of the adapter that will run the revision; + `packages/harness-studio` renders the treatment axis, matched-pair evidence with its threshold, + and cost per completed trial, and styles `insufficient_evidence`. + +## Test evidence + +The four tests the review asked for first, each failing before the change: + +1. `refuses execution against a bundle the revision was not resolved from` + (`packages/harness/test/revision.test.ts`). +2. `detects a mutated revision before the host SDK loads` + (`packages/harness/test/revision.test.ts`). +3. `answers the second turn from first-turn context inside one query` + (`packages/harness/test/adapter.test.ts`). +4. `reports insufficient_evidence when a single matched pair is all the evidence there is` + (`packages/harness/test/compare.test.ts`). + +Follow-ups also covered: a programmatic workflow fails resolution on a declarative-only adapter and +a tool requirement cannot be satisfied by prompt-only realization +(`packages/harness/test/resolve.test.ts`); missing/incomplete locks, raw-byte drift, bundle swaps at +the public Pi materializer, adapter contract drift, and locked-source drift all fail closed before +SDK load or package output (`packages/harness/test/revision.test.ts`, +`packages/harness/test/resolve.test.ts`); the Qoder adapter refuses a tool exposure it cannot +reproduce (`packages/harness/test/exec.test.ts`); concurrent turns, stop/destroy close and +interrupt, `resume` after a terminated query, an unbounded omitted `maxTurns`, and a non-capability +stop failure still tearing the session down (`packages/harness/test/adapter.test.ts`); and a +persisted verdict whose aggregate, status, reason, or policy the trial rows do not support +(`packages/harness/test/compare.test.ts`, `packages/harness-studio/test/compare-model.test.ts`). + +Verified on 2026-08-15: + +- Harness focused tests: 101 passed; full Harness tests: 120 passed; Harness build and typecheck + passed. +- Harness UI: 20 passed; Harness Studio: 29 passed; repository suite: 94 files / 1,324 tests + passed; doc-link graph: 6 passed and regenerated without stale output. +- Root preview returned `ok` from `/health` and served a 100,449-byte `/canvas-module.js`. +- Harness Studio production build and Playwright browser test passed. The Compare fixture was also + opened at 1440x1000: the derived verdict, two matched pairs, cost guardrail, and trial rows + rendered with zero console or page errors. +- A live Qoder SDK smoke kept the nonce `cobalt-7319` across two `doPromptTurn()` calls in one + adapter session and exposed one host session id. + +## Risk + +- Resolution now fails closed for `require tool` on adapters without exposure and for + `connect mcp`. Harnesses that previously resolved into a prompt-only no-op now need an adapter + that really exposes the capability. This is the intended semantic correction. +- `revision.permissions` → `revision.requestedPermissions` is a breaking IR field rename inside the + unreleased v0.2 surface. diff --git a/docs/specs/2026-08-15-harness-executor-session-adapter.md b/docs/specs/2026-08-15-harness-executor-session-adapter.md new file mode 100644 index 0000000..d309b5d --- /dev/null +++ b/docs/specs/2026-08-15-harness-executor-session-adapter.md @@ -0,0 +1,128 @@ +# Evolve harness executors into a versioned session adapter contract + +## Traceability + +- Spec ID: harness-executor-session-adapter +- Status: Implemented + +## Intent + +The v0.2 execution layer is a one-shot batch surface: `HarnessExecutor` +exposes a single `execute(revision, bundle, task)` that runs one prompt to +completion and returns a `HarnessRunResult`. This blocks three outcomes: + +- Interactive surfaces (harness-studio, TUIs) cannot hold a conversation + against a resolved revision; every exchange pays full session startup. +- The executor interface is unversioned, so any change to its shape couples + DSL/IR evolution to adapter evolution. +- Runtime-time capability gaps are reported as free-form `warnings[]` + strings instead of typed signals the resolver's degradation model can + consume. + +Reshape the execution layer after the adapter design of AI SDK 7's +`HarnessV1` specification (versioned spec tag, harness/session/turn split, +capability signalling via optional-method presence plus a typed +capability-unsupported error, framework-owned working directory), while +keeping what is deliberately different: our adapters bind to natively +running hosts, so there is no sandbox-ownership requirement, and the DSL, +IR, and resolver semantics do not change. + +## Acceptance Scenarios + +- AC-1: A `HarnessAdapterV1` interface exists with + `specificationVersion: "harness-adapter-v1"` (literal), a stable + `adapterId` matching the runtime's adapter package convention, and + `doStart(options)` returning a session. The existing `HarnessExecutor` + batch surface remains exported and behaviourally unchanged, reimplemented + as a wrapper that starts a session, runs one prompt turn, and stops. +- AC-2: A `HarnessAdapterSession` supports multiple sequential + `doPromptTurn` calls against one live host session (conversation state is + owned by the host runtime), plus `doStop()` and `doDestroy()`. Each turn + accepts an abort signal and an event listener; per-turn events reuse the + `HarnessRunEmitter` framing invariants (one `run-started` first, one + `run-finished` last, framed text, paired tool calls). +- AC-3: A typed `HarnessCapabilityUnsupportedError` (carrying `adapterId` and + `capability`) signals a behaviour that is unavailable at run time — for + example a turn `abortSignal` on the Pi SDK, which exposes no abort surface + (`turn-abort`). The batch wrapper degrades an unsupported graceful stop to + a `doDestroy()` fallback plus a `warnings[]` entry on the result instead of + failing the run; the per-turn event stream is already sealed by + `run-finished` at that point, so the degradation is carried on the result, + not as a late event. +- AC-4: The framework, not the adapter, owns the working directory: + `doStart` receives a `workDir` (defaulting to the caller's cwd exactly as + today) and adapters use it without deriving their own paths. Behavioural + parity: for a single-prompt run, `HarnessRunResult` (receipt, metrics, + events, exit codes) is unchanged for both existing executors. +- AC-5: The Qoder SDK and Pi SDK executors are reimplemented on the adapter + contract, and the existing package test suites for exec and compare pass + without weakening assertions. +- AC-6: `assertRevisionHost` still guards every turn: a session started for + a revision rejects turns when `revision.target.runtime` does not match + the adapter's host, with the same `HarnessHostMismatchError`. + +## Non-goals + +- No sandbox provider, bridge mode, or remote execution; adapters keep + running in-process against local hosts. Sandbox contracts are a separate + future spec if ever needed. +- No interop wrapper for `@ai-sdk/harness-*` packages in this cycle; this + spec only makes our contract shape-compatible so such a wrapper stays + cheap later. +- No turn suspension/continuation (`doSuspendTurn` / `doContinueTurn` + equivalents) or durability across process restarts. +- No DSL grammar, IR version, resolver, or binding-strength change; + materialized strength stays capped at `advisory`. +- No change to harness-studio or harness-ui in this spec; they adopt the + session surface in follow-up work. + +## Plan and Tasks + +1. Add `src/exec/adapter.ts`: `HarnessAdapterV1`, `HarnessAdapterSession`, + `HarnessAdapterStartOptions` (revision, bundle, workDir, listener), + `HarnessCapabilityUnsupportedError`, and the `runOnce` batch wrapper + (placed here rather than in `executor.ts` because `events.ts` already + imports from `executor.ts`, and the wrapper needs the emitter at runtime). +2. Keep `src/exec/executor.ts` unchanged: `HarnessExecutor`, + `HarnessRunResult`, receipt/metrics types, and the preamble builders stay + the shared vocabulary of both surfaces. +3. Reimplement `src/exec/qoder-sdk.ts` and `src/exec/pi-sdk.ts` as + `HarnessAdapterV1` implementations; their exported executor factories + delegate to the wrapper. Preserve runtime profiles, receipts, redaction, + and metrics mapping. +4. Extend `src/exec/events.ts` only if turn framing requires it; reuse the + existing emitter invariants per turn rather than inventing a second + event vocabulary. +5. Update `src/exec/index.ts` exports; deprecate nothing silently — the + README section for programmatic execution documents both surfaces. +6. Port `test/exec.test.ts` coverage to the adapter path and add session + tests: multi-turn sequencing, host mismatch per turn, capability + unsupported mapping, abort propagation. + +Decision rationale: the session split follows AI SDK 7's `HarnessV1` +(`packages/harness/src/v1` in the upstream repo) because it is the closest +proven contract for wrapping third-party coding-agent runtimes; we drop its +sandbox-ownership precondition because binding to natively running hosts is +this DSL's core scenario, and we omit suspend/continue because no current +consumer needs slice-boundary recovery. + +## Test and Review Evidence + +- AC-1/AC-4/AC-5: `npm run build && npx vitest run` in `packages/harness` — + 10 files, 103 tests pass; the pre-existing `test/exec.test.ts` (17 tests), + `test/skill.test.ts`, and `test/compare.test.ts` pass against the wrapper + without assertion changes. +- AC-2/AC-3/AC-6: new `test/adapter.test.ts` (10 tests) drives stub host + SDKs through multi-turn sessions, asserting event framing invariants per + turn (`expectFramedTurns`), preamble policy per host (`persistSession` + false re-sends, true and Pi send first-turn only), typed + capability-unsupported rejection (`turn-abort` on Pi), graceful-stop + degradation to destroy-plus-warning, abort-signal bridging onto the Qoder + abort controller, host mismatch before SDK load, turn rejection after + stop, and the legacy start-failure event sequence. +- Risk: the Qoder/Pi SDK message loops move from per-run functions into + session objects; regression risk is bounded by keeping the batch result + shape identical and asserting receipt/metrics equality in existing tests. +- Risk: interface naming (`harness-adapter-v1`) is new public API surface in + `@qoder-ai/harness`; the README documents the session surface as + experimental until harness-studio adopts it. diff --git a/docs/specs/2026-08-15-harness-ui-studio.md b/docs/specs/2026-08-15-harness-ui-studio.md new file mode 100644 index 0000000..39ebee4 --- /dev/null +++ b/docs/specs/2026-08-15-harness-ui-studio.md @@ -0,0 +1,261 @@ +# Harness UI and Studio: streaming run events, AG-UI adapter, React studio + +## Traceability + +- Spec ID: `2026-08-15-harness-ui-studio` +- Status: Implemented + +## Intent + +The Harness DSL currently runs only in batch mode: `compileHarness → +resolveHarness → executor.execute()` returns one `HarnessRunResult` after the +run ends, and the compare CLI writes evidence JSON to disk. Neither path gives +a user any live view of a running harness, and the compare/inspector evidence +has no interactive UI. + +This spec adds three bounded layers without changing DSL semantics: + +1. **Streaming run-event seam** in `@qoder-ai/harness`: executors emit + host-neutral `HarnessRunEvent` values while a run is in flight. +2. **`@qoder-ai/harness-ui`**: a protocol adapter that translates neutral run + events into [AG-UI protocol](https://docs.ag-ui.com/) events and serves + them over SSE, so any AG-UI-compatible frontend (CopilotKit, custom + clients) can drive a harness run. +3. **`@qoder-ai/harness-studio`**: a React application (bundled with esbuild, + served by a small Node CLI) with a live Run view fed by the AG-UI stream + and a Compare view fed by `harness-compare.v1` evidence directories. + +The DSL core stays UI-free: no grammar, IR, or resolver change. The existing +static-HTML harness inspector remains the zero-dependency offline report; the +studio is an additive, richer surface, not a replacement. + +## Acceptance scenarios + +- **AC-1 (neutral event seam)**: `QoderSdkExecutor` accepts an + `onRunEvent` listener, requests the SDK's partial-message stream, and emits + text deltas as they arrive rather than waiting for a completed assistant + turn. The lifecycle-ordered sequence contains one `run-started` first, + framed `message-started`/`text-delta`/`message-finished` text, paired + `tool-call-started`/`tool-call-finished` events, `run-error` only on + failure, and exactly one final neutral `run-finished` with the exit code and + metrics. When Qoder exposes a retained `tool_result`, the seam correlates it + back to the originating tool-call id without leaking credential-shaped + fields (the existing trace redaction applies before mapping). +- **AC-2 (event mapping is deterministic and tested)**: the lifecycle emitter + and SDK-message mapping (`applyQoderSdkMessage`) are exported and covered by + unit tests using scripted partial and completed SDK messages, with no live + SDK required. Completed assistant payloads do not duplicate text already + emitted from partial messages, and completed-only messages remain a fallback + for older or injected SDK implementations. +- **AC-3 (AG-UI translation)**: `@qoder-ai/harness-ui` translates a neutral + event sequence into a valid AG-UI event sequence: `RUN_STARTED`, paired + `TEXT_MESSAGE_START`/`TEXT_MESSAGE_CONTENT`/`TEXT_MESSAGE_END`, + `TOOL_CALL_START`/`TOOL_CALL_ARGS`/`TOOL_CALL_END`, optional correlated + `TOOL_CALL_RESULT`, and exactly one terminal + event: `RUN_FINISHED` on success or `RUN_ERROR` on failure. Open text + messages are always closed before a tool call, an error, or run completion. + Message and tool-call ids are namespaced by `runId`, so repeated runs in one + thread cannot overwrite earlier AG-UI entities. +- **AC-4 (SSE endpoint)**: the harness-ui server accepts an AG-UI + `RunAgentInput` POST (threadId, runId, messages) and responds with an SSE + stream (`data: \n\n` frames) of the translated events, echoing the + caller's threadId/runId. The run layer owns the outer lifecycle: failures + while constructing or invoking an injected executor still produce + `RUN_STARTED` followed by one `RUN_ERROR`. Browser requests are same-origin + by default; explicitly allowlisted origins receive an exact CORS response, + while untrusted origins, non-loopback `Host`/matching-`Origin` pairs, and + non-JSON POST bodies are rejected before an executor is created. A request + larger than 1 MiB receives a structured HTTP 413 response rather than a + reset socket. Verified by in-process and raw-HTTP tests with injected fake + executors; no network or live SDK in tests. +- **AC-5 (interactive studio run trace)**: the studio's AG-UI event reducer + folds an event stream into UI state (messages, tool calls, results, run + status, error). Run renders workbench-style, keyboard-expandable tool cards + with a compact argument preview, formatted arguments, retained result, call + id, and preparing/running/completed/failed/result-unavailable/interrupted + status. Tool-result error metadata survives the neutral and AG-UI seams; a + successful run without a retained result is not labelled as a completed + result. Retained results are capped at 64 KiB with explicit truncation + metadata. Pure model tests cover streamed arguments, result correlation, + terminal settlement, failure/truncation metadata, and malformed/plain-text + payload formatting; browser verification expands a real rendered tool card. +- **AC-6 (studio compare view)**: the studio server exposes the evidence + directory's `verdict.json` via `/api/evidence`, and the compare summary + model derives per-variant rows (pass rate, mean score, cost) from a + core-validated `HarnessCompareVerdict` value. Malformed aggregates or trial + rows produce a readable evidence error rather than crashing React. Both are + covered by tests against fixture and malformed data. +- **AC-7 (pipeline parity)**: both new packages follow the existing + `packages/harness` pipeline rules: npm workspace membership, root + `:build` / `:test` scripts, CI build+test steps, `prepack` build + and test, `publishConfig.access: public`, MIT license, repo `engines` range. +- **AC-8 (CLI help contract)**: `harness-ui --help` and `harness-studio + --help` print usage and exit 0 without reading the workspace, compiling a + harness, or opening a port. +- **AC-9 (responsive studio shell)**: Run controls and Compare tables remain + usable at desktop and 390px-wide browser viewports. Wide evidence tables + scroll inside labelled containers without increasing the document width; + browser verification records console/page errors and screenshots. +- **AC-10 (automated interaction regression)**: a Playwright test drives the + built Studio through its real HTTP server, starts a scripted run, expands and + collapses a failed/truncated Tool Call with the keyboard, verifies its + retained details and status, checks 390px document containment, and fails on + browser console/page errors. CI runs this gate once on Ubuntu/Node 22 after + installing Chromium; package unit tests remain cross-platform and do not + require a browser download. +- **AC-11 (GitHub-owned publication)**: `.github/workflows/release.yml` remains + the only publication entrypoint. Its manual dispatch selects exactly one of + the root package, `@qoder-ai/harness`, `@qoder-ai/harness-ui`, or + `@qoder-ai/harness-studio`, runs the complete repository check first, and + publishes with the protected `npm` environment and repository secret. Local + development commands build, test, pack, and dry-run only; this change never + executes a local `npm publish`. + +## Non-goals + +- No change to DSL grammar, IR version, resolver semantics, or the + `advisory` materialization cap. +- No dependency on `@ag-ui/core` (0.0.x, pre-stable, pulls rxjs/zod). The + adapter implements the AG-UI **wire format** with local types; conformance + is asserted by tests on the emitted JSON shapes. Revisit when AG-UI reaches + a stable major. +- No replacement of the static-HTML harness inspector or the compare + `verdict.html`; the studio reads the same evidence, it does not own it. +- No Pi live-run view in the studio (the seam is executor-generic; the Qoder + executor is the first emitter, and the Pi executor emits text deltas only). +- No local publication or registry mutation. Package versions and the selected + release target must be reviewed in git, then publication is dispatched from + the repository's protected GitHub Actions `Publish npm` workflow. +- No authentication or remote deployment story for the SSE server; it binds + to `127.0.0.1` by default and is a local development surface. This does not + waive browser-origin protection: cross-origin access requires an explicit + exact-origin allowlist. + +## Design + +```text +.harness ── @qoder-ai/harness ── HarnessRunEvent (neutral, streaming) + │ + @qoder-ai/harness-ui: AG-UI translator + SSE server + │ + any AG-UI client ◄── SSE ──┤ + │ + @qoder-ai/harness-studio: React Run view + Compare view + (verdict.json / evidence) +``` + +- `packages/harness/src/exec/events.ts`: `HarnessRunEvent` union plus + `HarnessRunEmitter`, the lifecycle guard that enforces the framing + invariants (single started/finished, message frames, paired tool calls). + `QoderSdkExecutor` and `PiSdkExecutor` gain `onRunEvent`; the mapping from + redacted SDK messages lives in `applyQoderSdkMessage()`. Qoder enables SDK + partial messages and keeps per-parent mapping state so the later completed + assistant message is a fallback, not duplicate output. +- `packages/harness-ui`: `protocol.ts` (AG-UI wire types), `translate.ts` + (stateful neutral→AG-UI translator), `sse.ts` (frame encoding), `run.ts` + (compile+resolve+execute with an injected executor factory), `server.ts` + (`POST /agui`, `GET /healthz`, origin/content-type policy), `cli.ts` + (`harness-ui serve`, repeatable `--allow-origin`). +- `packages/harness-studio`: React app under `src/app/` (pure state modules + `agui-store.ts`, `compare-model.ts` kept separate from components), Node + server under `src/server/` serving the esbuild bundle, `/api/evidence`, and + an embedded harness-ui `/agui` route when a `.harness` file is provided. + +## Plan and tasks + +1. Tighten the neutral Qoder mapper around the SDK's `stream_event` contract, + retain completed-message fallback behavior, and test de-duplication. +2. Make the AG-UI run layer own start/terminal framing and namespace protocol + entity ids with the caller's run id. +3. Add a shared local-browser request policy to the standalone and embedded + `/agui` handlers, plus an explicit origin allowlist for external local UIs. +4. Move verdict validation to the core compare owner and make Studio consume + that validated contract. +5. Add workbench-style interactive tool cards, correlated result rendering, + responsive table containers, and verify Run/Compare in a real browser at + desktop and narrow viewports. +6. Keep the truncated-declaration compiler diagnostic fix as a supporting + robustness change: malformed harness input must reach the AG-UI error path + as diagnostics rather than an uncaught compiler exception. +7. Harden the browser boundary against client-controlled Host trust and make + oversized request handling return a real 413 response without destroying the + socket before the response is written. +8. Carry tool-result error/truncation metadata through a namespaced AG-UI custom + event, distinguish failed and result-unavailable cards, memoize payload + formatting, and add one built-app Playwright regression to CI. +9. Extend the existing GitHub Actions publication workflow with a constrained + package selector so each Harness workspace is publishable without adding a + local release path. + +## Risks + +- **Duplicate streaming text:** Qoder emits both partial events and a completed + assistant message. Mapping state must suppress only the matching completed + text and reset at the assistant boundary. +- **Browser-triggered runs:** a loopback listener is reachable from arbitrary + webpages. Reject untrusted `Origin` values, DNS-rebinding-shaped + non-loopback `Host` values, and simple non-JSON POSTs before reading or + executing the harness; never derive trust from an arbitrary client-supplied + Host or emit wildcard CORS. +- **Protocol identity collisions:** neutral emitter counters are run-local. + The AG-UI adapter must namespace every correlated message/tool id + consistently without changing the neutral contract. +- **Evidence drift:** Studio consumes persisted JSON that can be stale, + truncated, or hand-edited. Validate the core verdict contract before + deriving render rows and return bounded diagnostics. +- **Layout regression:** compare tables are intentionally wide. Constrain + overflow to the table region and verify both desktop and narrow viewports. +- **False tool completion:** `TOOL_CALL_END` ends the streamed argument + declaration, not necessarily execution. Keep the card in a running state + until `TOOL_CALL_RESULT` or the run terminal settles it; retain failed and + result-unavailable as distinct terminal states. +- **Large retained results:** tool output can be megabytes and otherwise + amplify SSE buffering, React state, JSON parsing, and DOM work. Bound retained + output at the neutral event owner, carry the original byte length, and memoize + Tool Call rendering so unrelated text deltas do not reformat settled cards. + +## Test evidence + +- `packages/harness/test/events.test.ts` — AC-1, AC-2, including partial/full + de-duplication and completed-message fallback +- `packages/harness-ui/test/translate.test.ts` — AC-3, including run-id + namespacing and mutually exclusive terminal events +- `packages/harness-ui/test/server.test.ts` — AC-4, AC-8, including factory + failure, same-origin/allowlisted CORS, and rejected hostile/simple requests +- `packages/harness-studio/test/agui-store.test.ts`, + `packages/harness-studio/test/tool-call-model.test.ts` — AC-5, including + result correlation, interrupted calls, and payload formatting +- `packages/harness-studio/test/compare-model.test.ts`, + `packages/harness-studio/test/server.test.ts` — AC-6, AC-8, including + malformed verdict rejection +- CI: `harness-ui:build` / `harness-ui:test` / `harness-studio:build` / + `harness-studio:test` steps in `.github/workflows/ci.yml` — AC-7 +- Release: manual `Publish npm` workflow package choices plus its protected + environment, full-check, and workspace-scoped publish steps — AC-11 +- Browser: built Studio Run and Compare views at desktop and 390px width, + console/page error inspection, and saved screenshots — AC-5, AC-6, AC-9 + +## Validation record + +- `npm run check` passed on 2026-08-15: root 94 files / 1324 tests, + harness 9 files / 93 tests, harness-ui 2 files / 20 tests, harness-studio + 4 files / 25 tests, plus generated-source and package verification gates. +- `npx vitest run test/skills-docs/doc-link-graph.test.mjs` passed after + regenerating `docs/better-harness-doc-links.mmd`. +- Browser fixture verification exercised an expanded `Read` tool card with + formatted arguments and correlated result. At an exact 390px content + viewport, the document remained 390px wide; tool cards stayed within their + container and Compare tables scrolled inside their labelled regions. + Browser console/page logs were empty. +- Automated Playwright verification exercised a failed 64 KiB-truncated Bash + result through the built Studio server at 390px, expanded and collapsed the + card by keyboard, asserted document containment, saved a screenshot, and + observed no console/page errors. +- Raw HTTP tests reject a matching attacker Host/Origin pair and return JSON + 413 responses for both declared-length and chunked bodies over 1 MiB. The + GitHub `Publish npm` workflow parsed successfully with constrained package + choices; no local publication command was executed. +- Workspace `npm pack --dry-run` gates passed without registry mutation: + Harness UI contained 17 entries (12.2 kB) including the browser-safe protocol + entrypoint; Harness Studio contained 28 entries (296.1 kB) including the + built React application. diff --git a/docs/specs/2026-08-15-qoder-minimal-runtime-profile.md b/docs/specs/2026-08-15-qoder-minimal-runtime-profile.md new file mode 100644 index 0000000..6f9761d --- /dev/null +++ b/docs/specs/2026-08-15-qoder-minimal-runtime-profile.md @@ -0,0 +1,104 @@ +# Compare a minimal Qoder coding runtime + +## Traceability + +- Spec ID: qoder-minimal-runtime-profile +- Status: Implemented + +## Intent + +Provide a named, evidence-bearing Qoder runtime profile that presents the model +with the same four fundamental coding tools as Pi while suppressing optional SDK +context sources. Let one harness comparison hold the task and composition fixed +while assigning different named runtime profiles to the baseline and candidate, +so a successful README artifact can test the profile rather than merely prove +that the SDK returned a result. + +## Acceptance Scenarios + +- AC-1: `QoderSdkExecutor` accepts `qoder-minimal-v1` and sends exactly `Read`, + `Write`, `Edit`, and `Bash`, an explicit minimal system prompt, no filesystem + setting sources, empty SDK selections for skills/plugins/extensions, no + configured MCP servers, strict MCP isolation, an ephemeral session, and the + existing bounded permission callback to the official Qoder Agent SDK. +- AC-2: The runtime receipt names the selected profile and records non-secret + context-isolation facts without persisting the system-prompt body or any + credential. Contradictory options that would weaken the named minimal profile + fail before the SDK is loaded. +- AC-3: A `harness-compare.v1` manifest may explicitly assign a named Qoder + profile to each variant. The comparison resolves the effective runtime per + trial, records the profile in trial evidence, and permits both variants to use + the same composition only when the profile assignment differs. +- AC-4: Existing manifests with no per-variant profile assignment retain their + current tool set, runtime behavior, and validation policy. Their existing + evidence fields remain intact, with `qoder-default-v1` added explicitly. +- AC-5: Deterministic tests prove profile forwarding, fail-closed validation, + variant routing, and backward compatibility. A real SDK smoke runs the frozen + README task once under each profile and grades the resulting file and changed + file scope. + +## Non-goals + +- Replacing Qoder's qodercli/worker agent loop with a bare model loop. +- Implementing host-owned `read`, `patch`, or `run` MCP tools in this change. +- Claiming that one README trial establishes general coding quality or a + statistically significant performance improvement. +- Changing the `.harness` grammar, adding a host adapter, publishing a package, + or editing release metadata. + +## Plan and Tasks + +1. Add a public Qoder runtime-profile type and a frozen `qoder-minimal-v1` + contract to the executor, including conflict validation and evidence fields. +2. Extend the additive `harness-compare.v1` manifest surface with explicit + baseline/candidate profile assignment and resolve it per trial. +3. Add an isolated profile-comparison example that holds the grounded + composition, fixture, prompt, grader, model, permissions, and trial order + constant. +4. Add behavior tests and documentation for profile semantics and comparison + limits. +5. Run focused package checks, repository gates, and one real SDK trial per + profile; retain generated evidence outside the source tree. + +## Test and Review Evidence + +- AC-1/AC-2: the isolated staged checkout passed 56 package behavior tests. The executor test + observes the exact four-tool SDK options, empty optional context sources, + strict MCP configuration, cwd-bearing system prompt, prompt-free receipt, + and fail-closed conflict validation. +- AC-3/AC-4: manifest and runner tests prove that an unchanged v1 manifest + keeps `qoder-default-v1`, while the isolated profile experiment routes the + same composition through six-tool default and four-tool minimal runtimes and + records each profile in trial evidence. +- AC-5: a real Qoder SDK trial under each profile changed only `README.md` and + passed all nine deterministic grader checks with score 100. After repairing + missing cwd context found by the first smoke, both final trials completed in + five turns with no permission denial. The observed credits were 12.449909 for + default and 9.785649 for minimal; one trial is insufficient to claim a stable + efficiency improvement, so the aggregate verdict remains `need_more_work`. + The minimal init event exposed exactly `Bash`, `Edit`, `Read`, and `Write` as + tools. It still inventoried installed skill metadata, which is not treated as + proof that the files were absent; `skills: []` and the missing `Skill` tool + are the bounded model-context/invocation evidence. + Trial artifacts were retained outside the repository for local review and + were not added to the package or source tree. +- Isolated staged-checkout verification: `harness:generated` and + `harness:build` passed; all seven package test files / 56 tests passed; and + the documentation link graph passed six checks. Earlier whole-tree gates also + passed 94 root test files / 1,324 tests and root pack verification with 526 npm + and 548 runtime-zip entries; those whole-tree counts include concurrent local + work and are supporting evidence rather than the staged-slice proof. +- Verification qualification: the composite `npm run check` cannot report a + zero exit while a concurrent, uncommitted DSL grammar change legitimately + differs from `HEAD`, because `check:generated` rejects every generated diff. + Its root-test stage passed, and all remaining stages were run individually. +- Risk: four tools may increase discovery attempts because `Glob` and `Grep` + are hidden. The first smoke confirmed this risk when missing cwd context led + to five denied path guesses; the repaired profile made the working directory + explicit and the final smoke had no denials. +- Risk: filesystem settings and optional SDK resources can silently expand + context. The executor sends explicit empty collections and strict MCP config, + and the runtime receipt records those values. +- Risk: the working tree contains concurrent DSL sugar and compare-hardening + changes. Final review must preserve them and distinguish their ownership from + this profile slice rather than staging the complete dirty tree. diff --git a/docs/specs/2026-08-16-harness-review-remediation.md b/docs/specs/2026-08-16-harness-review-remediation.md new file mode 100644 index 0000000..86b88f3 --- /dev/null +++ b/docs/specs/2026-08-16-harness-review-remediation.md @@ -0,0 +1,93 @@ +# Close the harness review's honesty and boundary gaps + +## Traceability + +- Spec ID: harness-review-remediation +- Status: Implemented + +## Intent + +A review of `packages/harness` found that the package's central claim — a +resolved revision states what a run *really* got, not what its author hoped for +— was not upheld on several paths. The largest gap sat exactly where the design +invested most: a `source`-backed skill was locked byte-for-byte, resolved as +`advisory` guidance, and recorded in the materialization receipt as +`delivered / materialized`, while the executor put nothing but the source +*path* into the prompt. The lock protected content no code ever read. + +This change makes the recorded facts true, and closes the smaller boundary and +validation gaps found alongside them. + +## Non-goals + +- Making any shipped adapter materialize MCP connections, per-agent sessions, or + programmatic workflows. Those stay declaration-only, as before. +- Adding authentication to the `harness-ui` AG-UI endpoint. This change makes + the missing authentication a bind-time decision instead of a silent default. +- Replacing the portable SHA-256 in `ir/canonical.ts`. `test/module-graph.test.ts` + keeps the core and browser-verdict entries free of `node:` imports, so that + implementation is a requirement, not duplication. + +## Acceptance scenarios + +- **AC-1** — A revision realizing a `source`-backed skill delivers that skill's + `SKILL.md` text into the run preamble, names the remaining files in the tree + as further reading, and truncates an oversized body with an explicit run + warning. +- **AC-2** — A skill source that cannot be delivered (no entry file, unreadable + path, missing source root) fails the run before the host SDK loads, rather + than degrading into a path reference. +- **AC-3** — `buildRunPreamble` called without deliveries still reports a + source-backed skill as undelivered, so a third-party executor cannot + accidentally reproduce the original gap through the public API. +- **AC-4** — `materializePiPackage` writes a source-backed skill's real bytes + and copies its reference files, instead of a generated stub naming the path. +- **AC-5** — `resolveHarness` fails when the supplied realization descriptor's + `adapterId` differs from the adapter the selected runtime declares. +- **AC-6** — A declarative workflow with no `stop when` fails compilation, as + does a harness agent role its declarative workflow never references. +- **AC-7** — `resolveHarness` freezes only the revision: the caller's bundle and + the returned `ResolutionReport` stay mutable and unaliased. +- **AC-8** — A caller-supplied `toolExposure` entry the standard map does not + contain is honoured through `doStart`; a standard capability remapped to a + different host tool is still rejected as registry drift. +- **AC-9** — A permission grant counts as enforced only when the adapter + declares that exact domain/access pair. +- **AC-10** — `startHarnessUiServer` and `startHarnessStudioServer` refuse a + non-loopback bind address unless the caller passes `allowRemote` + (CLI: `--unsafe-allow-remote`), which also prints a warning. + +## Changes + +| Area | Change | +| --- | --- | +| `exec/skill-delivery.ts` (new) | Reads declared skill sources under the locked root, bounded at 32 KiB, sharing the lock module's containment checks | +| `exec/executor.ts` | Preamble inlines delivered skill bodies; warns when a source-backed skill arrives undelivered | +| `exec/qoder-sdk.ts`, `exec/pi-sdk.ts` | Load deliveries in `doStart`; Pi package materialization copies real skill files | +| `resolver/resolve.ts` | Descriptor/runtime adapter identity check; revision cloned before freezing; single-realization return | +| `resolver/source-lock.ts` | Exported `resolveContainedSource`; file digests use `node:crypto` on this Node-only path | +| `resolver/adapter-descriptor.ts` | `enforcedPermissionDomains` → `enforcedPermissions` (grants); added `descriptorsEqual` | +| `compiler/compile.ts` | Reject a declarative workflow with no stop condition, and an unreferenced agent role | +| `ir/canonical.ts` | Added `contentEquals`; documented why the digest is not `node:crypto` | +| `harness-ui`, `harness-studio` | Bind-address boundary with explicit opt-in | +| package scripts | `pretest` builds, so a clean checkout no longer fails on a missing `dist/` | + +## Test evidence + +- `packages/harness`: 143 tests pass, including a new `test/skill-delivery.test.ts` + (6 cases) and new cases in `compile`, `resolve`, and `exec` suites. +- `packages/harness-ui`: 26 tests pass, including the bind-address boundary. +- `packages/harness-studio`: 29 tests pass. +- End-to-end: a stubbed Qoder host records the prompt it received and shows the + skill's `SKILL.md` body inlined, where it previously received only the path. + +## Risk + +- **AC-6 is a breaking compile change.** Existing `.harness` documents with a + stop-free declarative workflow or an unreferenced agent role now fail to + compile. Both were previously silent defects; the diagnostics name the fix. +- **AC-5 is a breaking resolve change** for callers that passed a descriptor not + matching the runtime's declared adapter. Those resolutions produced + self-contradicting revisions. +- `enforcedPermissions` renames a descriptor field. No shipped adapter enforced + anything, so every shipped descriptor's value is unchanged (`[]`). diff --git a/docs/specs/2026-08-16-harness-ui-studio-compare-source-skill-delivery.md b/docs/specs/2026-08-16-harness-ui-studio-compare-source-skill-delivery.md new file mode 100644 index 0000000..ba37782 --- /dev/null +++ b/docs/specs/2026-08-16-harness-ui-studio-compare-source-skill-delivery.md @@ -0,0 +1,96 @@ +# Thread source-backed skill delivery through harness-ui, harness-studio, and compare + +## Traceability + +- Spec ID: harness-ui-studio-compare-source-skill-delivery +- Status: Implemented +- Refs: [2026-08-16-harness-review-remediation.md](./2026-08-16-harness-review-remediation.md) + +## Intent + +The prior remediation made `resolveHarness` and the core executors honest about +`source`-backed skills: a revision only records `delivered` guidance once the +declared `SKILL.md` was actually read and inlined, and a caller who skips +`loadSkillDeliveries()` gets a run warning instead of a silent gap. + +That fix covered `packages/harness`'s own executors. It did not cover the +package's three real callers of those executors: +`@qoder-ai/harness-ui` (the AG-UI HTTP server), `@qoder-ai/harness-studio` +(the local React studio, which embeds the same endpoint), and +`packages/harness/src/compare/runner.ts` (the benchmark pipeline). None of the +three ever called `lockCapabilitySources()` or passed a `sourceRoot` to the +executor, so a harness declaring a `source`-backed skill failed resolution +outright (`"requires exactly one content lock"`) the moment it reached any of +these three surfaces — the only places most users actually run a harness. + +This change closes that gap by threading the same root through all three, +using the same convention already used elsewhere in the codebase: relative +paths in a document resolve against that document's own directory. + +## Non-goals + +- Changing the `harness-compare.v1` manifest schema. The compare pipeline's + source root is the directory containing the manifest-selected `.harness` + file, matching the UI and Studio convention without a new manifest field. +- Supporting a source root that differs from the harness file's directory in + `harness-ui`/`harness-studio` without an explicit flag. The default is a + convenience, not a constraint: `--source-root` overrides it. + +## Acceptance scenarios + +- **AC-1** — `POST /agui` against a harness with a `source`-backed skill and + no `--source-root` fails the run with a "content lock" error instead of a + silently undelivered skill. +- **AC-2** — The same request with `--source-root` (or the CLI default: the + harness file's own directory) resolves, locks, and delivers the skill; the + executor receives a revision with a non-empty `sourceLocks` entry for it. +- **AC-3** — `harness-studio`'s embedded `/agui` endpoint (and its own + `--source-root`, defaulting from `--harness`) behaves identically. +- **AC-4** — `runHarnessComparison` locks every source-backed skill declared + by the compared harness against the harness file's own directory before + resolving either variant, and passes that same root to the executor for + every trial. +- **AC-5** — `loadSkillDeliveries`, `SkillDelivery`, `SkillDeliveryMap`, + `HarnessSkillDeliveryError`, `MAX_DELIVERED_SKILL_BYTES`, and + `SKILL_ENTRY_FILE` are exported from `@qoder-ai/harness/exec`, so a + third-party `HarnessAdapterV1` implementation can build correct delivery + without reaching into the package's internal module paths. + +## Changes + +| Area | Change | +| --- | --- | +| `packages/harness/src/exec/index.ts` | Export the `skill-delivery` module's public surface | +| `packages/harness-ui/src/run.ts` | `HarnessAguiRunOptions.sourceRoot`; locks sources before resolving, forwards the root to the executor | +| `packages/harness-ui/src/server.ts` | `HarnessUiServerOptions.sourceRoot`, forwarded to `runHarnessAgui` | +| `packages/harness-ui/src/cli.ts` | `--source-root `, defaulting to the harness file's own directory | +| `packages/harness-studio/src/server/server.ts` | `HarnessStudioServerOptions.sourceRoot`, forwarded to `handleAguiRun` | +| `packages/harness-studio/src/server/cli.ts` | `--source-root `, defaulting from `--harness`'s directory | +| `packages/harness/src/compare/runner.ts` | Locks sources against the harness file's directory before resolving either variant; forwards the root to every trial's executor call | + +## Test evidence + +- Root suite: 1,325 tests pass. +- `packages/harness`: 152 tests pass (`compare.test.ts` proves a nested harness + resolves its source relative to its own directory and the executor can load + the locked `SKILL.md` body from the forwarded root). The test authors its + source-backed harness fixture directly, so Windows CRLF checkout settings do + not control whether the required skill binding is inserted. +- `packages/harness-ui`: 29 tests pass (fail-closed without a root, successful + `SKILL.md` delivery with one, and CLI default/override resolution). +- `packages/harness-studio`: 31 tests pass (embedded `SKILL.md` delivery and + CLI default/override resolution are covered directly). +- `npx tsc --noEmit` passes for all three packages. +- Generated Langium sources are current; package verification passes with 528 + npm entries and 550 runtime-zip entries. + +## Risk + +- None of these changes alter behavior for a harness whose skills are + `description`-only (the shipped `readme-compare` benchmark and every + existing `harness-ui`/`harness-studio` test fixture): `lockCapabilitySources` + and `loadSkillDeliveries` are no-ops when no skill declares a `source`. +- The CLI default (harness file's own directory) is new behavior for anyone + who *does* declare a `source` skill and serves it through `harness-ui` or + `harness-studio` — previously that combination always failed, so there is no + working prior behavior to preserve. diff --git a/docs/specs/2026-08-16-session-checkpoint-executor-poc.md b/docs/specs/2026-08-16-session-checkpoint-executor-poc.md new file mode 100644 index 0000000..0285b96 --- /dev/null +++ b/docs/specs/2026-08-16-session-checkpoint-executor-poc.md @@ -0,0 +1,123 @@ +# Continue a Pi session checkpoint into a new Git commit + +## Traceability + +- Spec ID: session-checkpoint-executor-poc +- Status: Implemented + +## Intent + +Prove the smallest safe execution path that combines an immutable Git source +checkpoint with one exact point in a coding-agent session. Given a repository, +a base commit, a Pi session JSONL file, a session entry id, and a continuation +prompt, Better Harness creates an isolated detached worktree, continues the Pi +conversation from that entry, and records the resulting file changes as a new +commit whose single parent is the resolved base commit. + +The POC treats the Git commit and the Pi entry as a caller-supplied checkpoint +pair. It records and revalidates both halves, but it cannot infer that the +historical worktree used by the original session exactly matched the supplied +commit. The resulting commit is kept reachable through a namespaced ref; no +user branch, index, or working tree is switched or updated. + +## Acceptance Scenarios + +- AC-1: `harness-session-executor plan` resolves the repository, base commit + and tree, parses the Pi JSONL session without rewriting it, validates the + selected entry's parent chain, and writes a versioned plan containing full + immutable ids and SHA-256 digests. Planning does not create a worktree, + commit, or ref. +- AC-2: `harness-session-executor run --plan --yes` revalidates the plan + digest, base commit/tree, source session digest, session identity, selected + entry, and output-ref absence before invoking a model or mutating Git state. +- AC-3: execution forks the Pi JSONL into execution-owned metadata, selects the + exact entry as the active leaf, and continues it inside a detached worktree at + the base commit. The live Pi runtime exposes only repository-contained read, + list, edit, and write tools; shell commands, extensions, skills, prompt + templates, deletion, and paths through `.git` are unavailable. The runner + also aborts after 64 tool calls or 15 minutes. +- AC-4: when the continuation changes files, the executor stages only the + isolated worktree and creates a commit with exactly one parent (the base + commit), deterministic provenance trailers, and a + `refs/better-harness/session-executions/` ref. The caller's current + branch, index, and worktree remain unchanged. +- AC-5: the executor stores the validated plan, continued Pi JSONL, and a + versioned receipt under Git-common-dir metadata. The receipt identifies the + source checkpoint, execution session, result commit/tree/ref, and changed + paths without embedding the continuation prompt. +- AC-6: a missing or changed checkpoint, an existing output ref, model/tool + failure, or an empty diff fails closed without creating the output ref. A + failed run removes its execution-owned worktree and incomplete artifact + directory when possible. +- AC-7: focused tests exercise plan validation, Pi branch selection, path + containment, commit parent/ref creation, no-change failure, and source + worktree preservation without making a model request. + +## Non-goals + +- Supporting Codex, Qoder, Claude, Grok, or arbitrary JSONL formats in this + first slice. The plan names `provider: "pi"`; later providers need explicit + checkpoint adapters with equivalent validation and continuation semantics. +- Reconstructing dirty files, untracked files, the index, environment state, or + external side effects that existed between historical Git commits. An + arbitrary POC checkpoint means one Pi entry paired with one committed Git + tree, not a byte-for-byte machine snapshot. +- Moving, force-updating, merging, cherry-picking, or checking out a user + branch. Consumers decide how to adopt the namespaced result ref. +- A hardened multi-tenant sandbox. Path containment and an isolated worktree + bound model-driven file effects for a local trusted-user POC; they are not an + OS security boundary against a concurrent hostile process. +- Bash, test execution, dependency installation, network tools, file deletion, + rename support, parallel runs of the same plan, crash recovery, or automatic + retry. These require a later capability and durability contract. +- Inferring or repairing the semantic relationship between the supplied base + commit and session entry. + +## Plan and Tasks + +1. Add a provider-neutral plan/apply core under + `packages/harness/src/session-executor/` so the checkpoint contract can + compose with the DSL/IR and existing executor adapters. It owns canonical + plan hashing, Git fact resolution, immutable preflight, an isolated + worktree lifecycle, commit creation, a namespaced ref, and receipts. +2. Add a Pi checkpoint adapter that forks the source JSONL, branches to the + selected entry, and runs the continuation with contained custom tool + definitions and project extensions disabled. +3. Add a package-owned `harness-session-executor` CLI with `plan` and `run` + subcommands. Require an explicit plan output, continuation prompt or prompt + file, commit message, and `--yes` for run. Keep CLI parsing outside the core + API so a future DSL compiler can create the same typed plan directly. +4. Export the Node-only contract as `@qoder-ai/harness/session-executor`. + Keep it out of the browser-safe package root (the Git executor owns Node + process and filesystem APIs), and do not couple the root Better Harness + script bundle to an unpublished workspace build. +5. Add behavior tests with temporary Git repositories and an injected fake + continuation runner; use the installed Pi SDK only to verify real session + branch semantics without contacting a model. + +## Test and Review Evidence + +- AC-1/AC-2/AC-4/AC-5/AC-6/AC-7: + `npm test -w @qoder-ai/harness` — 15 files and 152 tests pass. The eight + session-executor tests use temporary Git repositories to prove plan + tamper/session-change rejection, one-parent commit and namespaced-ref + creation, caller worktree preservation, no-change cleanup, and the CLI + confirmation gate without making a model request. +- AC-3/AC-7: the same focused suite calls Pi's installed public + `SessionManager.forkFrom()` and `branch()` against a branched JSONL fixture, + then proves the selected entry is the active leaf and the source JSONL is + unchanged. Containment tests cover repository paths, lexical escapes, + `.git`, and symlink escapes on platforms that support the fixture. +- Packaging: `npm pack --dry-run --ignore-scripts -w @qoder-ai/harness --json` + includes the compiled `dist/session-executor` API, declarations, and CLI. +- Live model execution was not used as test evidence. The real runner is built + and type-checked against Pi 0.84.2; its model/auth availability remains a + local run-time precondition. +- Risk: Pi JSONL is a host-owned evolving format. The POC records the source + header version and delegates execution-session creation to Pi's public + `SessionManager` API instead of rewriting JSONL itself. +- Risk: a model can make broad source edits inside the isolated repository. + The run requires an explicit confirmation, excludes shell and extension + surfaces, and leaves adoption of the result ref to a separate user action. +- Risk: Git object creation precedes the atomic ref update. A failed ref race + can leave an unreachable commit object, but it cannot move an existing ref. diff --git a/docs/specs/2026-08-17-harness-dsl-v0.3-semantic-contraction.md b/docs/specs/2026-08-17-harness-dsl-v0.3-semantic-contraction.md new file mode 100644 index 0000000..d6b8c11 --- /dev/null +++ b/docs/specs/2026-08-17-harness-dsl-v0.3-semantic-contraction.md @@ -0,0 +1,167 @@ +# Make the Harness DSL state only executable contracts + +## Traceability + +- Spec ID: `harness-dsl-v0.3-semantic-contraction` +- Status: Implemented + +## Intent + +Replace the v0.2 authoring surface that mixes executable requirements with +prompt-only intent. The v0.3 language keeps the existing +`Source -> IR -> Revision -> Materialization -> Receipt` trust chain, but makes +the authored contract smaller and falsifiable: + +- source files identify their language version; +- deployments bind one harness to one runtime in source; +- a workflow either describes the single session the shipped adapters really + run, names a programmatic controller, or declares a state machine that only a + proven orchestration adapter may accept; +- capability requirements are satisfied in their native dimension + (`delivered`, `exposed`, or `connected`) instead of sharing a synthetic + strength ladder; and +- tool contracts have an identity that an adapter exposure must match. + +Author-facing permissions, free-form settings, capability bindings, and tool +input/output name lists are removed because no shipped adapter enforces or +consumes them. Runtime permission callbacks and executor options remain owned by +the runtime APIs that actually apply them. + +## Acceptance Scenarios + +- **AC-1 — Versioned source:** every v0.3 source starts with `language 0.3`. + Compilation rejects a missing or unsupported source version with a structured, + source-qualified diagnostic, and the lowered bundle uses `irVersion: 0.3.0`. +- **AC-2 — Honest workflow modes:** `workflow x { session coder }` is the + portable single-session form. It must name exactly the one agent in every + using harness. A state-machine workflow declares an entry agent and typed + outcomes; compilation rejects unknown outcomes, missing entries, unreachable + agents, and stop-free graphs. Shipped Qoder and Pi descriptors support only + `session`, so a state machine fails resolution instead of becoming prompt + prose. Programmatic workflows retain descriptor-owned language gating. +- **AC-3 — Kind-specific satisfaction:** requirement syntax contains no + `preferred`, `minimum`, or `on-degrade`. A skill resolves only when delivered, + a tool only when an exact tool contract is exposed, and an MCP only when + connected. Missing realization fails resolution. Revision, report, and receipt + entries record dimension, state, mechanism, and reason without a cross-kind + strength value. +- **AC-4 — Explicit composition:** a named `deployment` references exactly one + harness and one declared runtime. Compilation rejects duplicate deployment ids + and duplicate harness/runtime pairs. Resolution accepts only a pair declared + by a deployment and records the deployment id/hash in the revision. +- **AC-5 — Tool contract identity:** the standard tool ids have frozen builtin + contract ids and may be referenced without a local declaration. Any other tool + must declare a non-empty `contract` string. Adapter tool exposure states both + the host tool and contract id; a missing or mismatched contract fails + resolution. The removed input/output identifier lists no longer imply a schema + the runtime does not validate. +- **AC-6 — Removed inert syntax:** v0.3 rejects `binding`, `target`, runtime + `execution`, requirement strength/degradation blocks, capability `permissions`, + harness `configure`, and tool `input`/`output`. No v0.3 IR or materialization + receipt carries author settings or requested/enforced permission claims. +- **AC-7 — Trust-chain preservation:** revisions remain deeply frozen and bind + harness, deployment, runtime/adapter descriptor, workflow, capabilities, + source locks, and optional component snapshot provenance. Executor preflight + still rejects revision, bundle, adapter, or source drift before SDK load. +- **AC-8 — One teaching contract:** package examples, README, highlighting, + generation skill, validator, tests, and current in-repo consumers describe + only v0.3 syntax and distinguish core, adapter, and devtool ownership. + +## Non-goals + +- Implementing a state-machine scheduler, per-agent host sessions, structured + outcome extraction, or handoff payloads. The language may describe that + contract, but shipped adapters must reject it until an executor proves it. +- Adding MCP support, new host adapters, or new standard tool contracts. +- Designing a general policy language, adapter configuration language, package + registry, dependency solver, or JSON-Schema transport for custom tools. +- Migrating persisted v0.2 revisions or compare evidence. Their `irVersion` + remains the discriminator; v0.3 code must reject them rather than reinterpret + them. +- Changing npm package versions, release metadata, changelog, roadmap, or + publication workflow. + +## Plan and Tasks + +1. Change the Langium grammar and generated artifacts: add the language header, + session/state-machine workflow forms, agent outcomes, tool contracts, and + deployment; remove target, binding, strength, permissions, settings, and + tool input/output syntax. +2. Bump the IR contract to 0.3.0. Replace target/binding/strength data with + deployments, kind-specific realization state, tool contract ids, and the + deployment-bound revision shape. +3. Update compiler validation/lowering for source version, workflow outcome and + reachability checks, standard tool synthesis, custom tool contracts, and + deployment uniqueness. +4. Update resolver and adapter descriptors so exact capability facts decide + availability. Preserve source locks, adapter identity/hash checks, deep + freezing, and component snapshot provenance. +5. Update executor materialization and preamble generation. Session workflows + add no fake control-flow prompt; unsupported workflow modes fail before SDK + load. +6. Migrate all package examples, the generation skill and validator, package + docs, highlighting grammar, compare/experiment/UI consumers, and fixtures. +7. Regenerate Langium sources and validate focused behavior, package gates, + module boundaries, documentation links, and the repository test surface + proportionate to the changed public contract. + +## Test and Review Evidence + +- **AC-1/AC-2/AC-4/AC-5/AC-6:** compiler tests assert parsed IR and structured + diagnostics from behavior, including missing version, invalid workflow + outcome/reachability, undeclared custom tool, contract mismatch, undeclared + deployment pair, and removed v0.2 syntax. +- **AC-3:** resolver tests cover delivered skill, exposed exact-contract tool, + connected MCP, and each unavailable/mismatched path. Receipt tests assert the + dimension/state/mechanism shape with no strength fields. +- **AC-7:** existing revision, source-lock, adapter drift, executor preflight, + and source-delivery tests remain green after fixture migration. +- **AC-8:** compile and resolve every shipped `.harness` example, run the + generation-skill tests, `npm run check:generated`, package build/typecheck/test, + targeted package consumers, and the Markdown doc-link graph after docs move or + link changes. +- **Risk — breaking source language:** all v0.2 files fail under v0.3. Mitigate + with the explicit header, actionable diagnostics where parsing permits, a + before/after README example, and migration of every in-repo source in the same + change. +- **Risk — false orchestration claim:** a descriptor could claim state-machine + support before an executor implements it. Mitigate by keeping shipped + descriptors session-only and preserving registry/live-descriptor drift tests; + adding support requires its own execution spec and runtime evidence. +- **Risk — consumer shape drift:** UI/compare/experiment fixtures may embed + revision or receipt shapes. Validate parsed persisted artifacts and consumer + tests rather than relying on TypeScript compilation alone. +- **Risk — cross-platform generated output:** regenerate through the repository + Langium command and run existing Windows-portable behavior tests; do not add + shell-dependent runtime behavior. + +## Implementation Evidence + +- **AC-1/AC-2/AC-4/AC-5/AC-6:** `packages/harness/test/compile.test.ts`, + `resolve.test.ts`, and `sugar.test.ts` exercise the language header, workflow + modes/outcomes/reachability, explicit deployments, exact tool contracts, and + rejection of removed v0.2 syntax through compiler/resolver behavior. +- **AC-3/AC-7:** resolver, revision, materialization, executor, adapter, and + skill-delivery tests cover kind-specific facts, deployment/content hashes, + descriptor drift, source locks, deep freezing, and pre-SDK failure. +- **AC-8:** examples, README, Shiki grammar, generation skill/reference/ + validator, harness-ui fixtures, and compare/experiment fixtures use v0.3. +- `npm run harness:test`: 17 test files, 156 tests passed. +- `npm run harness-ui:test`: 3 test files, 29 tests passed. +- `npm test`: 95 root test files, 1325 tests passed. +- `npx vitest run test/skills-docs/doc-link-graph.test.mjs`: 1 test file, + 6 tests passed after regenerating the routing graph (no graph diff). +- `npm run pack:verify`: npm and runtime-zip verification passed. +- `node skills/generate-harness-dsl/scripts/validate.mjs` resolves both + `minimal.harness` and `standard-coding.harness`; `full-surface.harness` exits + non-zero with explicit state-machine, MCP, custom-tool, and program-controller + limitations, as intended. +- Two consecutive `npm run langium:generate` runs produced identical SHA-256 + hashes for all generated files. The repository `check:generated` wrapper + compares against `HEAD`, so it reports the intended uncommitted generated + diff until this change is staged or committed. +- Current harness-studio verification is unavailable because unrelated + concurrent checkpoint-history edits changed `/api/config` without updating + its existing exact-shape assertion: the build passes and 44 of 45 tests pass, + while `test/server.test.ts` still expects no `historyEnabled` field. Before + those edits changed during this work, all 45 tests passed. diff --git a/docs/specs/2026-08-17-harness-studio-checkpoint-compare.md b/docs/specs/2026-08-17-harness-studio-checkpoint-compare.md new file mode 100644 index 0000000..82c8ede --- /dev/null +++ b/docs/specs/2026-08-17-harness-studio-checkpoint-compare.md @@ -0,0 +1,535 @@ +# Checkpoint-anchored multi-lane harness experiments + +## Traceability + +- Spec ID: harness-studio-checkpoint-compare +- ADR: [Harness Checkpoint Experiment Compare](../adrs/harness-checkpoint-experiment-compare.md) +- Source ADR: [Checkpoint-backed Compare Sources and Materialization](../adrs/checkpoint-backed-compare-sources.md) +- Status: Slices 1, 3, 4, 5, and 6 implemented; Slice 2 dirty-state replay pending + +## Intent + +Let a Studio user pick one Git checkpoint, replay the observed historical +trajectory beside two freshly executed lanes from that same checkpoint, and read +one attribution verdict per comparison instead of a single global verdict. + +The `.harness` grammar and the `session-execution-plan-v1` checkpoint contract do +not change. A sandbox stays a per-lane materialization of the one checkpoint. The +new surface is an experiment manifest that references a checkpoint, declares N +lanes of mixed origin, and lets the runner *derive* what each comparison is +allowed to conclude. + +This spec covers three slices. Slice 1 is the evidence semantics: the manifest +contract, derived treatment axes, observed-lane degradation, and per-contrast +decisions. Slices 2 and 3 add checkpoint materialization and the Studio +experiment lifecycle on top of the same contract. + +## Acceptance Scenarios + +### Slice 1 — experiment contract and evidence semantics + +- AC-1: `harness-experiment.v1` validates a manifest holding a `checkpointRef` + (plan path plus digest) and never a copy of checkpoint fields. Loading resolves + manifest-owned relative paths, rejects absolute, backslash, and `..` paths, and + rejects any path escaping the manifest directory. +- AC-2: a lane is either `origin: "observed"` (trajectory path plus the + checkpoint digest it started from, and optional identity evidence) or + `origin: "execute"` (harness id, trial count, and per-lane runtime profile and + model). Host, visible tools, and the run policy stay shared across lanes, so a + lane cannot silently move the host. +- AC-3: a contrast declares only its `id` and the lane ids it compares. A + manifest that declares `axis` or `mode` on a contrast is rejected, because the + axis is a derived fact about lane configuration, not an author's claim. +- AC-4: `deriveContrastAttribution` computes the moved axes by diffing the + contrast lanes' harness id, runtime profile, and model. Exactly one moved axis + over exactly two execute lanes yields `attributable` with that axis. Zero moved + axes, more than one moved axis, more than two lanes, or an unmatched observed + lane yields `descriptive` with a named reason and the full moved-axis list. +- AC-5: an observed lane is matched baseline evidence only when every identity + fact is present and equal to the fresh lanes — harness id, revision id, runtime + profile, model, environment receipt — its prompt hash equals the experiment task + prompt hash, and the checkpoint completeness receipt is not `unverified`. + Otherwise it is contextual evidence and the contrast is descriptive. + `evaluateObservedLane` names each missing fact so a reader can see why. +- AC-6: an attributable contrast is decided by the existing + `harness-compare.v1` ladder — `aggregateVariant`, `summarizeMatchedPairs`, and + `decideVerdict` under `normalizeDecisionPolicy` — so the two-matched-pair floor + still applies. A contrast whose lanes ran once each therefore reports + `insufficient_evidence`, never `accept`. A descriptive contrast reports status + `descriptive` and can never report `accept` or `reject`. +- AC-7: `buildExperimentCompareSet` emits `harness-compare-set.v2` with one + aggregate per lane, one result per contrast, the shared checkpoint digest and + completeness receipt, the task prompt and grader hashes, and the decision + policy the contrasts were judged under. Observed lanes may carry no grade, so + they aggregate as observed rows without inventing a score. +- AC-8: focused tests cover manifest acceptance and each rejection reason, axis + derivation for the harness, runtime-profile, model, multi-axis, and no-axis + cases, observed-lane degradation per missing fact, single-run contrasts + reporting insufficient evidence, and descriptive contrasts never carrying a + promotion status. + +### Slice 2 — checkpoint materialization and parallel lanes + +- AC-9: every lane clears preflight (checkpoint digest, base commit and tree, + session digest and entry) before any lane starts executing. +- AC-10: materialization records a checkpoint completeness receipt: a clean-tree + assertion or a captured dirty-state patch applied identically to every fresh + lane. An `unverified` receipt keeps observed lanes contextual. +- AC-11: worktree creation is serialized to avoid Git lock contention; lane + execution then runs in parallel and one lane's failure preserves the other + lanes' evidence. +- AC-12: every emitted event carries `experimentId`, `laneId`, and `runId`; each + lane persists its own revision, runtime and sandbox receipts, trajectory, + patch, and grade under a per-lane evidence directory. Results stay on + namespaced refs and no user branch is switched. + +### Slice 3 — Studio experiment lifecycle + +- AC-13: Studio creates an experiment, streams per-lane events, and supports + cancellation, instead of the single stateless `/agui` run. +- AC-14: the configuration surface shows which axes the current lane setup moves + and marks a comparison descriptive before it runs. +- AC-15: the three-column view synchronizes turn, tool call, file, and patch + selection, pins the shared checkpoint and task identity, and renders one + verdict per contrast with no global aggregate verdict. +- AC-16: live ACP-derived tool events are normalized into an inspectable + cross-lane key (tool name, resource target, and canonical arguments). Selecting + a tool call in any lane locates its best one-to-one match in the other lanes + and labels the relation `exact`, `same-resource`, `same-tool`, or `none`; a + numeric similarity score alone is never presented as provenance. +- AC-17: Studio visualizes the local tool chain around the selection — previous, + selected, and next call — so a reviewer can distinguish “both read the same + file” from “both followed the same read → edit → test path.” Matching remains + monotonic within a lane, preventing one repeated `Read` call from being reused + as the apparent counterpart of several calls. +- AC-18: the experiment view defaults to monitoring-console density. At a + 1200×900 viewport the shared identity, attribution preview, all three lane + headers, and at least six tool rows are visible without page-level horizontal + scrolling. At narrower widths, horizontal scrolling is contained by the trace + matrix rather than widening the document. Shared identity and lane runtime + facts are each rendered once; the selected local chain is an inline inspector, + not a second full-size comparison board. +- AC-19: Studio may replay a real imported trajectory whose starting Git + checkpoint was not recorded. Such a lane omits `startCheckpointDigest`, is + labelled `checkpoint unknown`, and is always contextual evidence with a named + `startCheckpointDigest` gap. A recorded digest that differs from the shared + checkpoint remains a manifest error. The UI must never turn an absent digest + into a claim that history and fresh lanes share a start. +- AC-20: the experiment surface adopts the Inspector Workbench information + architecture rather than stacking independently floating cards: a fixed or + collapsible context rail owns checkpoint, task, lane, and contrast setup; a + 42 px workspace header owns navigation and aggregate metrics; and one + continuous workbench owns the selected call, three adjacent lanes, local + chain, and contrast results. At 1024×576, the workbench begins within 12 px of + the workspace header, lane rows are at most 30 px high, adjacent lanes have no + card gap or separate shadow, and the document does not scroll horizontally. + At narrow widths, the context rail collapses and horizontal scrolling remains + inside the lane board. +- AC-21: the comparison object bar gives every lane an evidence role instead of + presenting three interchangeable columns. An imported trajectory is + `Context`; the first fresh lane is the default `Baseline`; the second fresh + lane is the default `Candidate`. The baseline and candidate can be selected + without mutating the manifest or creating another sandbox. +- AC-22: a persistent comparability summary classifies the focused pair as + `Controlled`, `Partial`, `Observational`, or `Incomparable`, and names the + decisive limitation. One trial per fresh lane is therefore `Partial` even + when exactly one treatment axis moved; an unmatched historical trajectory is + `Observational`, never a baseline claim. +- AC-23: the focused comparison exposes five working views — `Summary`, + `Activities`, `Calls`, `Changes`, and `Evidence` — while preserving the live + ACP stream. Switching views does not reset lane data or selection. Summary + keeps outcome, process, efficiency, and evidence confidence above the raw + trace rather than below a long log wall. +- AC-24: Calls defaults to the focused baseline/candidate pair and provides a + call-name/resource filter, synchronized selection, `Diff only`, and a compact + overview strip. Rows retain one-to-one monotonic alignment and expose the + relation basis (`exact`, `same-resource`, `same-tool`, or `none`). The UI does + not invent timestamps, duration, token, or cost fields that the ACP evidence + did not record. +- AC-25: multi-lane context remains reachable from the object bar, but the + detailed work area compares one pair at a time. Choosing a different + baseline or candidate recomputes the focused relations from existing lane + evidence and does not change the experiment contract, checkpoint, or run. +- AC-26: Activities groups observable tool calls into derived engineering + phases (`Orient`, `Discover`, `Change`, `Execute`, `Diagnose`, `Recover`, + `Verify`, and `Deliver`) and highlights the first divergent phase. A phase is + a UI projection from tool names, resources, statuses, and commands; it is not + presented as agent intent or causal proof. +- AC-27: Changes and Evidence separate observed facts from explanations and + conclusions. Shared file/resource access states its matching basis and + limitation; verdicts retain their per-contrast status and reason. A shared + path never becomes an authorship, correctness, or causality claim. +- AC-28: at 1024×576 the object roles, comparability, view tabs, focused pair + headers, and at least six call rows are reachable without document-level + horizontal scrolling. At 390 px the rail collapses, controls wrap without + clipping, and horizontal overflow is contained by the focused comparison. + Primary controls are semantic buttons or inputs with visible focus states, + and trace text is at least 11 px. + +### Slice 4 — checkpoint-backed Compare Builder + +- AC-29: Studio introduces a Builder before the Workbench. It presents + `Historical Replay` and `New Request Compare` as distinct scenarios, shows the + locked request and variants, and enters the existing compact Workbench only + after the user reviews and locks the draft. A scenario choice never creates a + sandbox or isolated copy. +- AC-30: the server derives a source-neutral checkpoint preview from the + validated checkpoint adapter. The browser receives display-oriented adapter, + resource, revision, optional history, and materialization facts; it does not + receive or require a Git-shaped checkpoint schema. +- AC-31: the first adapter projects the current session execution plan as a + repository resource, commit/tree revision, session/entry history position, + and detached-worktree materialization. Studio renders those facts through the + generic projection and contains no `source.kind === "git"` layout branch. +- AC-32: Builder preflight names how many isolated lane materializations will be + created and states that they are created only on Run. It exposes missing + historical checkpoint or identity facts before execution and never promotes + an unmatched observed lane to a baseline. +- AC-33: the Variant matrix exposes every lane's evidence role, origin, harness, + model, profile, and trial count in one dense table. The current slice reviews + the loaded locked definition; authoring arbitrary providers and persisting a + new manifest remain follow-up work and are not simulated by controls that do + not affect execution. +- AC-34: focused model tests prove scenario derivation, generic source rendering + inputs, materialization counts, and historical identity gaps. Server tests + prove the projected setup contract, and Playwright proves Builder -> lock -> + Run -> live Workbench against the real project fixture without console or page + errors. + +### Slice 5 — history discovery, resolve, and durable lock + +- AC-35: Studio consumes history through a server-side checkpoint history + adapter. The browser sees opaque item ids, adapter-owned labels, request + previews, and timestamps; it never receives source filesystem paths or a + Git-, session-, or PPTX-shaped discovery record. +- AC-36: `GET /api/checkpoint-history` lists bounded project history and + `POST /api/checkpoint-history/resolve` resolves one opaque id into a generic + checkpoint projection plus request provenance. Resolve validates the + checkpoint digest and referenced prompt/trajectory bytes but creates no + worktree, sandbox, document copy, result ref, or experiment evidence. +- AC-37: `POST /api/experiment/lock` is same-origin and locks the selected + resolved item against the currently loaded experiment template. It writes an + immutable, content-addressed lock directory containing the manifest, + checkpoint plan, request, observed trajectory, harness, grader contract, and + source-backed skill trees required by the harness. A partial write never + becomes active. +- AC-38: Studio switches its active experiment only after the locked manifest + passes the existing `harness-experiment.v1` loader. Subsequent preview and Run + requests use that locked manifest; a failed resolve or lock leaves the prior + experiment active. +- AC-39: the compact Builder exposes loading, empty, resolving, resolved, + locking, locked, and error states for the History picker. Selecting another + item updates checkpoint and request previews before lock, while the Variants + matrix remains the loaded template. The primary action names the selected + lock operation and remains disabled until preflight is ready. +- AC-40: a history adapter explicitly marks whether its request bytes and + starting checkpoint were verified by the source. Studio sets `promptHash` + and `startCheckpointDigest` on the observed lane only for the respective + verified facts; unverified imports retain named evidence gaps. +- AC-41: the first file-backed catalog adapter accepts + `checkpoint-history.v1`, enforces portable catalog-owned paths, unique ids, + bounded item count, SHA-256 checkpoint identity, and readable prompt and + trajectory sources. `--history-catalog` enables it without making that file + format the generic adapter contract. +- AC-42: focused tests cover catalog traversal rejection, resolve without + materialization, verified and unverified provenance, atomic lock output, + active-manifest switching, same-origin mutation guards, Builder selection and + lock interaction, and a non-Git injected adapter projection. + +### Slice 6 — compare vocabulary and browser boundary hardening + +Slice 6 supersedes the presentation-specific portions of AC-21, AC-23, AC-26, +and AC-27: `Reference` replaces `Context`, and the five top-level views become +three views with phase and resource projections inside Trace. Their evidence +semantics and limitations remain unchanged. + +- AC-43: Studio names the checkpoint-backed workflow `Compare` and the frozen + `harness-compare-result.v1` reader `Results`; it never presents adjacent + `Experiment` and `Compare` tabs whose relationship is unexplained. +- AC-44: one role vocabulary spans Builder and Workbench: the imported run is + `Reference`, the first focused fresh run is `Baseline`, and the other is + `Candidate`. Primary UI copy says `run` or `comparison`; `lane`, `contrast`, + `materialization`, and provider adapter identifiers stay in technical details. +- AC-45: Builder's visible setup summary names the actual derived treatment + axis and values, such as `Profile · default vs minimal`. Equal harness ids are + not presented as the difference between fresh runs. If no single axis is + isolated, the summary says so before Run. +- AC-46: Builder behaves as a compact confirmation surface rather than a false + multi-step authoring wizard. A history-backed draft has one primary choice, + one comparison summary, and one truthful action. A disabled history adapter + may open an already loaded definition; loading or failed history cannot expose + an action labelled as a lock that performs no lock request. +- AC-47: Workbench exposes `Summary`, `Trace`, and `Evidence`. Trace groups calls + by observable phase and offers `Calls` and `Resources` lenses without losing + selection, filters, or one-to-one tool alignment. The removed Activities and + Changes tabs do not retain duplicate projections elsewhere. +- AC-48: one title-bar control owns Run and Cancel. Run identity is rendered + once per visible run, checkpoint identity once in the shared context, and + role cards themselves select the focused Baseline and Candidate without a + second pair of dropdowns. +- AC-49: provider-specific observed trajectory shapes are normalized on the + server. The browser receives only canonical tool-call projections for loaded + history and canonical stream events for fresh runs; React code contains no + ACP, AG-UI, or Anthropic provider-shape branches. +- AC-50: comparability, role selection, pair-result lookup, relation counts, + resource ledgers, and canonical event folding live in pure tested modules. + The React controller reuses the shared SSE parser rather than owning another + blank-line framing implementation, and Builder and Workbench are separate + reviewable components. + +## Non-goals + +- Extending `harness-compare.v1`. It stays the frozen-fixture, two-variant path, + and its persisted `harness-compare-result.v1` consumers are untouched. +- Changing the `.harness` grammar, the IR, or the checkpoint contract. +- Defining Git as the generic checkpoint source contract. Git/worktree is the + first adapter; versioned PPTX and other resource adapters retain their own + canonical checkpoint and materialization formats. +- A `host` treatment axis. A single experiment runs one host; cross-host + comparison needs its own confounding analysis. +- Reconstructing environment state the historical trajectory depended on beyond + what the completeness receipt can capture as a patch. +- Promoting or adopting any lane's result commit. Adoption stays an explicit + later user action against the namespaced ref. +- Grading observed trajectories that predate the grader contract. +- Scanning raw Qoder, Codex, or other host-private session stores inside the + Studio package. Host/session analyzers may produce a catalog or implement the + adapter interface; Studio owns selection and locking, not provider storage. +- Editing the locked historical prompt in place. Any edited request becomes a + New Request Compare with a new request identity. +- Removing evidence degradation, the matched-pair floor, per-contrast verdicts, + or the frozen `harness-compare-result.v1` reader. Slice 6 reduces presentation + duplication; it does not weaken comparison semantics or migrate old results. + +## Plan and Tasks + +1. Split the contract by runtime need. `packages/harness/src/experiment/contract.ts` + owns the `harness-experiment.v1` TypeBox schema, lane types, and pure lane + predicates with no Node imports; + `packages/harness/src/experiment/manifest.ts` owns + `loadHarnessExperimentManifest` and the validation that needs real paths — + unique lane and contrast ids, contrast lane references, at least one execute + lane, observed lanes starting from the referenced checkpoint, and portable + manifest-owned paths. +2. Add `packages/harness/src/experiment/axis.ts` with the derived + `ExperimentTreatmentAxis`, `deriveContrastAttribution`, and + `evaluateObservedLane`. Keep the axis derived from lane configuration so a + manifest cannot label a multi-axis comparison as single-axis. +3. Add `packages/harness/src/experiment/compare-set.ts` with + `ExperimentTrialResult`, per-lane aggregation, contrast projection onto the + existing baseline/candidate pair shape, `decideContrast`, and + `buildExperimentCompareSet`. Reuse the `compare/aggregate.ts` ladder rather + than restating thresholds, so the matched-pair floor cannot drift. +4. Add `packages/harness/src/experiment/checkpoint.ts` with the + `CheckpointCompleteness` receipt union that slice 2 will produce and slice 1 + already consumes in the observed-lane rule. +5. Export two entries: `@qoder-ai/harness/experiment/evidence` for the + browser-safe semantics Studio will render, and `@qoder-ai/harness/experiment` + for the same surface plus the Node loader. Mirror the boundary + `compare/verdict` already draws, and extend `test/module-graph.test.ts` to + enforce it. Ship an example manifest under + `packages/harness/examples/checkpoint-experiment/`. +6. Add `packages/harness/test/experiment.test.ts` covering AC-1 through AC-8 by + calling the exported functions and asserting returned shapes and statuses. +7. Add a Studio experiment stream with lane-scoped lifecycle and ACP events. + Normalize tool calls in a pure browser module, align calls monotonically, and + render the selected cross-lane relation and local chain in a three-column + trace matrix before showing per-contrast result cards. +8. Add a Node experiment runner that verifies the referenced plan bytes and + `session-execution-plan-v1` contents before materialization, creates detached + worktrees serially, executes prepared jobs through an injectable executor in + parallel, and persists lane-scoped evidence and namespaced refs. The current + implementation records a dirty source workspace as `unverified`; applying a + captured dirty-state patch identically to every fresh lane remains open. +9. Tighten the Studio information hierarchy into one compact experiment bar, + one three-lane trace matrix, an inline selection inspector, and compact + per-contrast result rows. Add viewport measurements to the browser test so + “compact” is a behaviour contract rather than a screenshot impression. +10. Permit checkpoint provenance to be absent on imported observed lanes, + propagate that absence into observed-lane eligibility, and exercise the UI + with a real Better Harness Qoder transcript. Keep external transcript paths + as demo/runtime input rather than shipping user history in the repository. +11. Recompose the experiment view from the Inspector Workbench primitives: one + collapsible context rail, one 42 px workspace header, and one continuous + lane board with divider-separated columns and an integrated evidence + footer. Verify the source and implementation at the same 1024×576 viewport. +12. Replace the fixed equal-weight three-lane board with an object-role bar and + a focused pair model. Derive `Context`, `Baseline`, and `Candidate` from the + existing manifest; keep role changes local to the Studio view. +13. Add a source-neutral checkpoint setup projection at the Studio server + boundary. Keep provider-specific plan validation in Node and pass only + adapter-owned labels, revision values, history position, capabilities, and + materialization timing to the browser. +14. Add a pure Builder model and compact setup surface before the Workbench. + Derive the initial scenario from observed history, expose the loaded request + and Variant matrix, name preflight gaps, and require an explicit Lock action + before Run without pretending the first slice can persist arbitrary drafts. +15. Add Summary, Activities, Calls, Changes, and Evidence projections over the + same normalized ACP calls. Calls owns filtering, synchronized selection, + diff-only alignment, and the overview strip. Activities and Evidence must + label their derivation and limitations rather than claiming hidden intent. +16. Add behaviour tests for role selection, comparability, view persistence, + filtering, diff-only alignment, focused synchronization, semantic phases, + evidence boundaries, and responsive overflow. Repeat visual QA against the + selected W&B Weave comparison reference while retaining Better Harness + checkpoint and attribution semantics. +17. Add a browser-safe history-list and resolved-draft model plus a server-only + `CheckpointHistoryAdapter` interface. Implement the first bounded + `checkpoint-history.v1` catalog adapter without exposing its paths to the + browser. +18. Add list, resolve, and lock endpoints. Keep resolution read-only; make lock + content-addressed and atomic, copy the template's executable assets and + source-backed skills, validate the resulting manifest, and only then switch + the server's active experiment path. +19. Add the compact History picker to the existing Builder. Preserve the + current template's Variants matrix, project the selected checkpoint/request + before lock, and reinitialize lane evidence from the locked preview before + opening Workbench. +20. Add catalog, lock, server, CLI, and browser behavior tests, then repeat the + real-project browser run with an actual catalog item and verify that no lane + materialization exists before Run. +21. Rename the checkpoint-backed navigation entry to Compare and the frozen + evidence reader to Results. Use Reference/Baseline/Candidate consistently + and move implementation vocabulary out of primary labels. +22. Derive a Builder treatment summary from the server-projected contrasts and + lane runtime values. Collapse the setup to history selection, comparison + summary, and a state-truthful action. +23. Extract Builder, Workbench, shared view types, and pure comparison helpers + from the React controller. Add behavior tests for comparability and display + roles instead of matching source text. +24. Normalize imported and live provider events at the server boundary, return + canonical calls/events, and consume the existing SSE parser in the browser. +25. Merge Activities and Changes into Trace lenses, remove duplicate run + controls and identity strings, make role cards select the focused pair, and + repeat real-project browser QA at the compact viewport. + +## Test and Review Evidence + +- AC-1 through AC-8 and AC-19: `npm test -w @qoder-ai/harness` — 17 files and + 156 tests pass. The experiment tests load real manifest fixtures from a temporary + directory and assert loader results, derived attribution objects, + observed-lane missing-fact lists, and contrast statuses. AC-6 is proved by a + counterfactual: one set of trial rows judged twice, reaching `accept` when the + lanes move one axis and `descriptive` when they move two. +- Repository suite: `npm test` — 95 files and 1325 tests pass, so the new + subpath exports do not disturb CLI, governance, or doc-link checks. +- Module boundary: `test/module-graph.test.ts` asserts the emitted + `dist/experiment/evidence.js` graph reaches neither `node:` builtins nor the + manifest loader, so slice 3 can import the evidence semantics into Studio's + browser bundle. It asserts the built artifact deliberately, because `import + type` is indistinguishable from a real import when lexing TypeScript source. +- Packaging: `npm pack --dry-run --ignore-scripts -w @qoder-ai/harness --json` + includes `dist/experiment/*` with declarations and the + `examples/checkpoint-experiment/` manifest. +- Risk: a second manifest schema invites drift from `harness-compare.v1`. The + mitigation is that slice 1 owns no thresholds of its own; every promotion + decision is delegated to `decideVerdict` under `normalizeDecisionPolicy`. +- Risk: an experiment with one run per lane looks like a comparison but is a + smoke test. The mitigation is structural rather than documentary: the shared + ladder returns `insufficient_evidence` below two matched pairs. +- Risk: an observed trajectory is easy to mistake for a matched baseline. The + mitigation is that eligibility requires every identity fact including prompt + hash equality, which historical sessions almost never satisfy, and the missing + facts are reported rather than silently ignored. +- Risk: slice 1 validates the `checkpointRef` digest and path but does not open + the referenced plan, so a manifest can name a checkpoint that no longer + resolves. Slice 2's preflight (AC-9) is where that becomes an error; until + then the reference is a recorded claim, not a verified one. +- Risk: fuzzy matching can look like causal proof. Studio therefore exposes the + matching basis (`tool`, `resource`, canonical arguments, and neighbouring + calls), reserves `exact` for identical normalized inputs, and renders `none` + rather than forcing every call into a pair. +- AC-9, AC-11, and the clean-tree portion of AC-10/AC-12: + `packages/harness/test/experiment-runner.test.ts` creates a real temporary Git + repository and Pi checkpoint plan, proves two prepared lanes overlap in + execution, reads the persisted compare set, checks namespaced result refs, and + confirms temporary worktrees were removed. The dirty-state-patch branch of + AC-10 remains pending; dirty workspaces deliberately produce `unverified`. +- AC-13, AC-14, AC-16, and AC-17: Studio tests cover preview, same-origin SSE, + lane identity fields, cancellation, exact/same-resource/same-tool/none + normalization, one-to-one monotonic alignment, and local chain projection. + The Playwright flow starts a scripted two-lane executor, correlates both fresh + traces against the recorded history trace, inspects per-contrast results, and + asserts no console or page errors at 1200 px. AC-15 is complete for tool and + resource synchronization; turn and patch-detail synchronization remain open. +- AC-18, AC-20, and AC-28: `npm test -w @qoder-ai/harness-studio` passes 5 files and 41 + tests; `npm run test:browser -w @qoder-ai/harness-studio` passes three flows. + The 1024×576 flow measures the 230 px context rail, 42 px workspace header, + compare surface at y=52 or above, adjacent focused-lane gap at most 1 px, + a tool row no taller than 30 px with at least 11 px text, and more than six-row + viewport capacity. The 390 px flow crosses the responsive breakpoint, proves + the rail collapses to 46 px, and keeps the 720 px compare surface inside the + workspace scroller without widening the document. A successful run also + proves that completion metadata is not rendered as an error detail. +- AC-21 through AC-27: the browser flow asserts `Context`, `Baseline`, and + `Candidate` object roles; the `Controlled` focused pair; two-column Calls; + synchronized resource selection; filtering from six visible calls to one; + `Diff only` reducing the pair from six rows to four; and working Summary, + Activities, Changes, and Evidence tabs. It changes the candidate to history + and observes `Observational`, then restores the fresh pair without rerunning. + Unit tests prove phase projection for Discover, Change, Verify, Deliver, + Diagnose, and Recover from recorded call facts. +- In-app browser QA repeated the completed deterministic experiment in the + user's visible Studio surface. The core interaction readback matched the + automated flow (`Diff only`: four rows; `npm test` filter: one row), all five + views retained the same stream state, the history focus exposed its + observational limitation, and the browser log contained no errors. +- Real-project runtime smoke: `test/fixtures/real-project-experiment-server.mjs` + built a checkpoint plan at Better Harness commit + `1a6b0a134f229a786e0338d86de440fc50dc05a0`, imported 84 real Qoder Tool Calls + with unknown checkpoint provenance, and executed the default and minimal + Qoder profiles in parallel detached worktrees. The final visual-QA run + finished with 26 and 33 Tool Calls. The one-pair profile contrast correctly returned + `insufficient_evidence`; the historical contrast remained `descriptive`. + This live smoke supplements rather than replaces the credential-independent + deterministic browser test. +- Real-project compare-workbench revalidation: the same Better Harness fixture + streamed 84 imported historical calls while the redesigned Calls view updated + both fresh lanes live. The final fresh traces contained 27 and 24 calls; both + lanes finished, the focused pair remained `Partial` because it had one trial + per lane, failure/recovery phases and same-resource links were visible, and + the in-app browser log contained no errors. +- AC-29 through AC-34: `npm test -w @qoder-ai/harness-studio` passes 6 files and + 45 tests. The pure setup tests derive Historical Replay versus New Request + Compare, count one materialization per fresh trial, retain unverified request + provenance, and accept a PPTX-shaped versioned-file projection without any Git + fields. Server tests cover the source projection in the experiment preview; + the browser flow covers Builder -> Lock -> Workbench -> Run. +- Checkpoint-backed real-project smoke: the in-app browser loaded the current + Better Harness checkout at `b80dccd3e3cc`, rendered repository, commit/tree, + session position, and two detached-worktree materializations through generic + adapter-owned labels, then ran the default and minimal Qoder lanes. Both lanes + finished with two and three fresh calls beside 84 imported historical calls; + the browser log contained no warnings or errors. Evidence persisted complete + per-lane revision, materialization, runtime, sandbox, trajectory, patch, grade, + and Git receipts on namespaced refs `cc89096` and `7759fc6`. No temporary + experiment worktree remained. Because the source checkout was dirty and each + lane had one trial, the compare set correctly retained `unverified`, + `insufficient_evidence`, and `descriptive` limitations instead of promotion. +- Builder layout QA at 1024×576 measured document width 1024 px, content bottom + 492 px, and fixed footer top 509 px, so Scenario, Checkpoint, Request, Variants, + historical gaps, and the Lock action remain visible without document-level + horizontal scrolling. At the narrow in-app viewport, document width matched + viewport width and the Variant matrix kept its overflow inside its section. +- Visual QA: the source-to-implementation comparison was repeated at the same + 1024×576 viewport. The Inspector source and Studio both use the fixed + context rail, 42 px header, and one workbench beginning at y=52. The real run + additionally exercised streaming status/count updates, a selected shared + resource and its local chain, collapse behavior, and completed verdicts. +- AC-43 through AC-50: `npm test -w @qoder-ai/harness-studio` passes 9 files and + 59 tests, including pure treatment/comparability/role/resource projections, + ACP/AG-UI/Anthropic server normalization, canonical browser folding, and the + source-neutral lock/server cases. A run completion settles only the calls of + the run that finished, so one lane's parallel trials cannot mark each other's + in-flight calls unavailable. `npm run test:browser -w @qoder-ai/harness-studio` + passes three flows. `npm test` passes 95 files and 1325 tests; + typecheck, doc-link graph, and `git diff --check` also pass. In-app browser QA + against the real Better Harness catalog showed `Profile · qoder-default-v1 vs + qoder-minimal-v1`, one Run control, Reference/Baseline/Candidate roles, three + top-level views, Calls/Resources lenses, and no console errors or document + overflow. Both Qoder runs finished with canonical exact/same-resource links + and a visible failed-read recovery chain. +- Known gap: `roleFor` labels a fresh run that is neither the focused baseline + nor the focused candidate as `Candidate`. Every shipped manifest has exactly + two fresh runs, so the case is unreachable today; a third fresh run needs its + own unfocused role before that configuration is offered. diff --git a/docs/specs/2026-08-18-harness-studio-code-rendering.md b/docs/specs/2026-08-18-harness-studio-code-rendering.md new file mode 100644 index 0000000..86185a4 --- /dev/null +++ b/docs/specs/2026-08-18-harness-studio-code-rendering.md @@ -0,0 +1,134 @@ +# Render session code and diffs with language-aware tooling + +## Traceability + +- Spec ID: harness-studio-code-rendering +- Status: Implemented + +## Intent + +Replace Harness Studio's hand-built code and Before/After presentation with +dedicated, language-aware renderers. Recorded and live session evidence should +remain readable as code, preserve exact source text, and use bounded work so a +collapsed Tool Call or an unopened Diff does not eagerly tokenize unrelated +content. + +This change also closes the real-session usability and scale gaps found while +loading historical JSONL: restore a 13px body / 12px metadata / 14px primary +action floor, keep Live and Recorded on one semantic phase vocabulary, and +bound server parsing, browser state updates, list DOM, and minimap DOM. + +The implementation follows the existing Qoder workspace boundary: use +`@pierre/diffs` for read-only patch rendering and Shiki core with the JavaScript +regex engine plus lazily loaded grammars for code highlighting. CodeMirror and +Monaco remain editor dependencies and are not appropriate for this read-only +surface. + +## Acceptance Scenarios + +- AC-1: Recorded file changes render through `@pierre/diffs` as a real split + patch with line numbers, addition/deletion backgrounds, word-level changes, + and language-aware tokens inferred from the changed path. +- AC-2: The Notebook and dedicated Diff view share the same Diff renderer and + preserve the existing file path, addition/deletion counts, selection, and + read-only state boundary. +- AC-3: Expanded Tool Call input/result, terminal output, and Raw ACP JSON use a + reusable Shiki-backed code renderer. JSON, JavaScript, TypeScript, TSX, CSS, + HTML, and shell-family paths are recognized; unknown languages fall back to + escaped plain text without losing content. +- AC-4: Shiki initializes once per browser session and grammar loads are cached. + Highlighting starts only when the corresponding code surface is mounted; + unopened Tool Calls and hidden inspector tabs are not tokenized. +- AC-5: The code renderer uses a 13px monospace floor and retains local + scrolling/wrapping. Syntax color never replaces the semantic Diff background + or makes the unhighlighted fallback unreadable. +- AC-6: The production build emits the heavy Diff/highlighting implementation + and language grammars as browser chunks while preserving `assets/app.js` as + the stable entry point served by the existing Studio server. +- AC-7: Focused tests cover language inference, plain-text fallback, token + preservation, and patch construction. Browser verification opens both Diff + surfaces and an expanded Tool Call, observes highlighted tokens, checks for + page/console errors, and keeps document-level horizontal overflow absent. +- AC-8: Debugger and Experiment surfaces enforce a 13px body, 12px metadata, + and 14px primary-action floor. Weak text uses a contrast-safe neutral rather + than the 7–9px low-contrast prototype styling. +- AC-9: Live tool observations project to the same Explore, Change, Verify, + and Response vocabulary as Recorded events. When Live has no Evidence Cursor, + the Step Toolbar is absent and the UI states that stepping is unavailable. +- AC-10: Historical JSONL is parsed incrementally by the server without + retaining raw lines. The initial response and subsequent pages return at most + 100 calls by default and reject unsafe lane ids/cursors. +- AC-11: The client merges pages by stable call id. Streaming AG-UI updates use + a keyed store so token/result patches do not linearly scan the timeline. +- AC-12: Consecutive equivalent Tool Calls aggregate into semantic Tool Groups; + call rows over the threshold use a fixed-window virtual list. +- AC-13: Session minimaps use at most 64 fixed bins independent of event count; + live notebook rendering is bounded to the latest retained window. +- AC-14: Reproducible 100, 1,000, and 10,000 event gates assert bounded server + parsing, Tool Group count, virtual DOM window size, and minimap bin count. + +## Non-goals + +- Adding an editable code editor, merge controls, inline commenting, or + accept/reject patch actions. +- Highlighting arbitrary binary content, ANSI terminal emulation, or every + language Shiki can ship. +- Changing recorded evidence, reconstructing omitted source, or claiming a + restorable workspace checkpoint. +- Persisting a cross-process JSONL index or adding search across unloaded pages. + +## Plan and Tasks + +1. Restore readable typography/contrast and remove misleading Live stepping. +2. Add an incremental server JSONL index, paged endpoint, and keyed client + merge/store seams. +3. Add Tool Group aggregation, a fixed virtual window, and fixed minimap bins. +4. Add the Qoder-aligned `@pierre/diffs` and Shiki core dependencies. +5. Add pure path/language and patch construction seams with focused tests. +6. Add lazy React renderers for split Diff and highlighted code, with explicit + fallback states and token-preserving output. +7. Replace hand-built Diff rows and selected code blocks without changing the + session debugger cursor/state model. +8. Enable build splitting for dynamic libraries and language grammars, then + measure the stable entry and emitted chunks. +9. Run all three scale gates, package, browser, doc-link, and visual checks + before marking this spec + Implemented. + +## Test and Review Evidence + +- AC-1 through AC-5: focused Vitest tests for patch/language/token contracts, + plus existing Session Debugger model coverage. +- AC-1 through AC-7: built-app Playwright flow covering Diff view, Notebook + Diff, expanded Tool Call highlighting, overflow, and browser errors. +- AC-6: production build output inspection records `assets/app.js` and lazy + chunk sizes; a server smoke confirms every requested chunk returns 200. +- AC-8 through AC-14: server index, keyed-store, grouping, virtual-window, and + minimap unit tests at 100 / 1,000 / 10,000 events, plus real JSONL browser QA. +- Risk: Diff/highlight libraries can inflate the initial bundle. Keep the + heavyweight renderer and grammars behind dynamic imports and verify emitted + chunk boundaries. +- Risk: async highlighting can reorder or lose text. Render escaped plain text + first and assert concatenated tokens equal the input exactly. +- Risk: third-party Diff Shadow DOM styling can conflict with the Studio + palette. Use bounded library CSS variables and verify both split panes in the + browser rather than relying on build success. + +## Validation Record + +- `npm run typecheck -w @qoder-ai/harness-studio` passed. +- `npm test -w @qoder-ai/harness-studio` passed 75 tests across 14 files, + including 100 / 1,000 / 10,000 event gates and a 10,000-tool keyed update. +- `npm run test:browser -w @qoder-ai/harness-studio` passed four Chromium flows + with Pierre Diff, Shiki tokens, typography floors, Live toolbar semantics, + narrow containment, and zero captured console/page errors. +- A retained 6,210-line, 661,854,903-byte Codex JSONL session projected 2,032 + keyed events and 1,479 Tool Calls at `http://127.0.0.1:3317/`. The finished + page exposed 1,161 + semantic groups while mounting 16 virtual rows, with 64 minimap bins, + 83,801px of accessible scroll history, and no document-level overflow. +- `npm run preview` served the Canvas preview; `/health` and + `/canvas-module.js` both returned 200. +- `node scripts/doc-link-graph/cli.mjs skills/better-harness` completed without + a graph diff; `npx vitest run test/skills-docs/doc-link-graph.test.mjs` passed + six checks. diff --git a/docs/specs/2026-08-18-harness-studio-information-architecture.md b/docs/specs/2026-08-18-harness-studio-information-architecture.md new file mode 100644 index 0000000..5420379 --- /dev/null +++ b/docs/specs/2026-08-18-harness-studio-information-architecture.md @@ -0,0 +1,164 @@ +# Organize Harness Studio as a harness control plane + +## Traceability + +- Spec ID: harness-studio-information-architecture +- Status: Implemented + +## Intent + +Make Harness Studio read as a repository-native Harness Engineering control +plane instead of a collection of generic `Compare`, `Run`, and `Results` +pages. The primary information architecture should expose the durable product +objects and lifecycle described by the Studio research report: + +`Observe -> Compose -> Experiment -> Explain -> Promote`. + +Existing experiment, live-run, verdict, Session Debugger, and Inspector +Workbench behavior remains authoritative. Studio may organize and embed those +surfaces, but it must not merge their data models, turn observed associations +into causal claims, or present roadmap capabilities as implemented. + +The supplied research report is treated as a product-direction brief, not as a +source-backed competitor benchmark. Its useful organizing unit is retained: +`Harness Revision x Task Suite x Runtime Envelope`; statistical evaluation, +promotion, collaboration, and registry maturity remain unproven roadmap scope. + +## Information Architecture + +```mermaid +flowchart TD + Studio["Harness Studio · local control plane"] --> Overview["Overview · operating model and loaded inputs"] + Studio --> Inspector["Inspector · Observe"] + Studio --> Harnesses["Harnesses · Compose · foundation"] + Studio --> Suites["Task Suites · Compose · foundation"] + Studio --> Experiments["Experiments · Validate"] + Studio --> Registry["Registry · Govern · foundation"] + + Inspector --> Delivery["Delivery Workbench"] + Delivery --> Evidence["Capability or Date → Session → Commit or File"] + Delivery -. "sandboxed read-only document" .-> Report["HarnessInspectorReportV1 HTML"] + + Experiments --> Bench["Harness Bench · design and comparison notebook"] + Experiments --> Live["Live trial · AG-UI observation"] + Experiments --> Results["Frozen evidence results"] + + Harnesses -. "future contract" .-> Revision["Harness Revision"] + Suites -. "future contract" .-> TaskSuite["Task Suite"] + Revision -. "analysis unit" .-> Bench + TaskSuite -. "analysis unit" .-> Bench + Bench -. "fixed runtime envelope" .-> Runtime["Runtime Envelope"] + Results -. "future evidence bundle" .-> Registry +``` + +The navigation order follows the operating loop `Observe -> Compose -> +Experiment -> Explain -> Promote`. `Builder`, `Run`, `Compare`, `Results`, and +`Workbench` are modes within those durable objects, not peer applications. + +## Acceptance Scenarios + +- AC-1: Studio has one persistent primary navigation with `Overview`, + `Inspector`, `Harnesses`, `Task Suites`, `Experiments`, and `Registry`. + `Builder`, `Run`, `Compare`, `Results`, and `Workbench` are presented as + contextual actions or secondary experiment/inspection surfaces rather than + competing top-level product concepts. +- AC-2: Overview explains the control loop and reports only capabilities + enabled by `/api/config`. It does not invent a promoted revision, Task Suite, + statistical result, evidence freshness, or governance state that the server + does not provide. +- AC-3: A self-contained Harness Inspector HTML report can be supplied with an + explicit CLI option and opened inside the `Inspector` workspace. The report + remains read-only and authoritative behind a sandboxed document boundary; + Studio does not duplicate its report model or rewrite its Workbench in React. + When no report is supplied, the UI names the missing retained-evidence input. + A live AG-UI endpoint remains under `Experiments`; it must not make the + hard-coded Session Debugger fixture appear to be real Inspector evidence. +- AC-4: Existing experiment Builder, checkpoint lock, Run/Cancel, synchronized + comparison selection, Trace, Evidence, live AG-UI run, and frozen verdict + behavior remain reachable. Their current request, reducer, comparison, and + evidence contracts are unchanged; the recorded Session Debugger sample is + no longer a default Studio destination. +- AC-5: `Harnesses`, `Task Suites`, and `Registry` pages expose the intended + object hierarchy and the current implementation boundary. Unsupported source + editing, suite curation, promotion, rollback, and revalidation controls are + not rendered as working actions. +- AC-6: At desktop width the control-plane navigation and the selected work + surface are simultaneously legible. At 390 px the primary navigation can be + opened and closed, all destinations remain reachable, and overflow stays + inside dense notebook, debugger, or report regions rather than widening the + document. +- AC-7: Navigation uses buttons, current-page state, landmark labels, visible + focus, and text labels in addition to icons. Focused tests assert config-driven + routing and server behavior rather than source-code strings; browser checks + exercise Overview -> Experiments and Overview -> Inspector at desktop and + narrow widths. +- AC-8: The optional Inspector route serves only the explicitly configured + report file as HTML, returns a bounded 404 when absent, and does not expose a + directory or accept a browser-provided filesystem path. + +## Non-goals + +- Implementing Harness source editing, semantic IR diff, Task Suite storage, + statistical evaluation, automatic ablation, a Registry state machine, CI + gates, promotion, rollback, or revalidation. +- Merging Inspector's cross-delivery report model with Studio's live run or + experiment state, or moving execution controls into the read-only report. +- Claiming authorship, causality, correctness, replay, resumability, or restored + workspace state from path, timing, trace, or checkpoint proximity. +- Adding a host adapter, authentication layer, collaboration backend, or remote + deployment surface. +- Replacing the current light visual system, notebook comparison, Session + Debugger, or Inspector Workbench interaction model. + +## Plan and Tasks + +1. Add a small application-shell model that derives destination availability, + default next actions, and secondary surfaces from the existing config flags. +2. Recompose `App.tsx` around a responsive control-plane navigation and add + honest Overview/foundation/Registry readiness views while mounting existing + feature components without changing their contracts. +3. Add an optional configured Inspector report path to the server and CLI, + expose a fixed `/inspector` route, and render it in a sandboxed iframe. +4. Extend the existing stylesheet with shell, lifecycle, readiness, iframe, and + narrow-navigation styles while preserving component-owned dense layouts. +5. Add focused model/server tests, update CLI/package documentation, then run + build, package tests, browser interaction checks, and desktop/narrow visual + review. + +## Test and Review Evidence + +- AC-1/AC-2/AC-5/AC-7: focused application-shell model tests plus built-page + browser interactions and DOM landmark checks. +- AC-3/AC-8: server tests for `/api/config`, `/inspector`, missing-report 404, + and CLI parsing; browser checks confirm the iframe loads the self-contained + Workbench and remains sandboxed. +- AC-4: existing Harness Studio model/server coverage remains green; built-app + browser checks cover experiment locking/running, comparison selection, live + AG-UI, Inspector drill-down, and evidence rendering. +- AC-6: browser screenshots and measured document widths at 1440 by 900 and + 390 by 844, with console/page errors inspected. +- Risk: primary navigation can imply unsupported products. Mitigation: every + destination derives a visible availability state from current config or is + explicitly labeled as a foundation with no active controls. +- Risk: an embedded report could be mistaken for Studio-owned mutable state. + Mitigation: the Inspector surface says `Read-only evidence`, preserves the + report's branding, and runs in a sandboxed document without same-origin + privileges. +- Risk: the outer shell can reduce the space available to dense workbenches. + Mitigation: use a compact rail on desktop, an overlay navigation on narrow + screens, local scrolling, and direct desktop/narrow browser measurements. + +### Implementation evidence + +- `npm run build -w @qoder-ai/harness-studio` — passed. +- `npm run typecheck -w @qoder-ai/harness-studio` — passed. +- `npm test -w @qoder-ai/harness-studio` — 15 files / 79 tests passed. +- `npx vitest run test/skills-docs/doc-link-graph.test.mjs` — 6 tests passed; + the routing graph was regenerated and remained unchanged. +- `npm run test:browser -w @qoder-ai/harness-studio` — 4 Chromium flows passed, + including desktop and 390 px interaction and overflow checks. +- In-app Playwright checks at 1440 x 900 and 390 x 844 exercised Overview, + primary navigation, Bench, the mobile Bench / Live trial switch, checkpoint + overlay, live-run composer, real Inspector Workbench, and Inspector session + drill-down. Measured document width matched viewport width and inspected + browser logs contained no errors or warnings. diff --git a/docs/specs/2026-08-18-harness-studio-session-debugger.md b/docs/specs/2026-08-18-harness-studio-session-debugger.md new file mode 100644 index 0000000..a3751fc --- /dev/null +++ b/docs/specs/2026-08-18-harness-studio-session-debugger.md @@ -0,0 +1,124 @@ +# Inspect an agent session as a debugger notebook + +## Traceability + +- Spec ID: harness-studio-session-debugger +- Status: Implemented + +## Intent + +Redesign the live Run surface in `@qoder-ai/harness-studio` as a +session-oriented debugging workbench. The surface should make an Agent Session +readable as semantic work stages while keeping retained ACP/AG-UI facts +inspectable. It is a debugger for observed session state, not a time-based +Replay player and not a claim that the current workspace can be restored. + +The supplied ACP Debugger screenshot defines the IDE-scale information density, +three-column composition, light visual system, and synchronized selection +language. Harness Studio keeps its own product identity, navigation, local-run +boundary, and evidence wording. + +## Acceptance Scenarios + +- AC-1: The Run view opens as a full-screen workbench with a product/session + header, semantic debug toolbar, Execution Tree, Session Notebook, State + Inspector, and Timeline Minimap. It does not present Play, playback speed, or + any other Replay transport. +- AC-2: The default recorded sample is named `优化 Replay UI` and contains one + Prompt, one Plan, an Explore group with nine retained calls, a + `workbench.js` change, a failed test, a CSS fix, a passing test, and a final + Response. Read/search/inspect calls are grouped rather than rendered as nine + peer cards. +- AC-3: Selecting a tree node, notebook event, or timeline marker updates one + shared evidence cursor and visibly synchronizes all three regions. Previous + Stop, Continue, Next Stop, Step Into, Step Over, Step Out, and Previous State + update that cursor according to their labels; Step Into expands the current + Explore group. +- AC-4: Stop Conditions for Changes, Failures, Permissions, Tests, and Responses + can be toggled. Continue and stop navigation skip events whose stop types are + disabled without mutating the retained session or workspace. +- AC-5: The notebook is organized by Prompt, Plan Revision, Execution Group, + File Diff, Validation, and Final Response. Exploration details remain + collapsed by default; file changes show a Before/After diff; failed and + passing validations show command, status, and retained duration. +- AC-6: State Inspector exposes Changes, Files, Artifacts, Tests, Terminal, + Plan, Evidence, and Raw ACP tabs. Changes answers what changed since the prior + stop. Evidence distinguishes Exact, Correlated, and Inferred relationships; + Raw ACP includes direction, method, ids, and trace context for the selected + event. +- AC-7: The state boundary explicitly names the current cursor and available + checkpoint evidence. The recorded sample offers Previous State and View + History only; it does not expose Restore or Fork from Here because no + restorable Workspace or Runtime checkpoint exists. Live inspection labels a + UI-only pause as Soft Pause rather than claiming the Agent is stopped. +- AC-8: Existing AG-UI run submission remains reachable from the redesigned Run + view. Starting a run uses the existing endpoint and terminal/tool-call + reducer; the recorded sample is clearly labeled and cannot be mistaken for + live backend evidence. +- AC-9: At 1440 by 900 the three primary columns and timeline remain visible + without document-level horizontal scrolling. At narrower widths the + inspector and tree can be collapsed or stacked, controls remain reachable, + and overflow stays inside dense code/trace regions. +- AC-10: Focused tests exercise the semantic cursor model and built-page + interactions. Browser verification checks synchronized selection, stop + toggles, Step Into, inspector tabs, diff rendering, live-run entry, responsive + containment, console errors, and a screenshot comparison against the supplied + reference. + +## Non-goals + +- Building a generic ACP Gateway, recorder, JSON-RPC proxy, or persistent + session store. +- Rerunning retained tool calls, restoring Git state, resuming a native Coding + Agent session, or adding Workspace/Runtime checkpoint infrastructure. +- Replacing the existing Experiment Builder, comparison Workbench, Results + surface, evidence contracts, or server endpoints. +- Claiming hidden intent, causality, token usage, cost, exact duration, or file + state when the current protocol evidence does not provide it. +- Adding a new host adapter or changing the supported host set. + +## Plan and Tasks + +1. Add a pure session-debugger model for the recorded sample, semantic stops, + tree projection, cursor movement, and inspector facts. +2. Recompose the Run view into the debugger shell while preserving the existing + AG-UI request and reducer path behind an explicit `New live run` action. +3. Add icon-library-backed controls and a compact light visual system in the + existing bundled application stylesheet. Avoid custom SVG/CSS icon art. +4. Add focused model tests and extend the built-app Playwright flow for + synchronized cursor behavior, tabs, diff, responsive layout, and the live + run path. +5. Build, inspect at desktop and narrow viewports, compare against the reference, + fix actionable visual gaps, and record browser/design evidence. + +## Test and Review Evidence + +- AC-2 through AC-7: `packages/harness-studio/test/session-debugger-model.test.ts` + passes four focused tests for the eight-stage sample, nine-call Explore group, + enabled-stop traversal, hierarchy stepping, node resolution, and cumulative + file state. +- AC-1/AC-3 through AC-10: `npm run harness-studio:test:browser` passes four + built-app flows. The Session Debugger flow selects the shared cursor, enters + and exits Explore, disables Changes, continues to the failed Test, opens Raw + ACP and Diff view, checks the read-only state boundary, and verifies a 1440 by + 900 shell with no document overflow or console/page errors. The existing 390 + px live-run flow still completes and expands a retained Tool Call. +- Package gate: `npm run harness-studio:test` passes 10 files and 63 tests after + the production build. `npx vitest run + test/skills-docs/doc-link-graph.test.mjs` passes six checks after regenerating + `docs/better-harness-doc-links.mmd`; the generated graph is unchanged. + `git diff --check` passes. +- Visual gate: the same-state desktop and focused comparison boards are recorded + in the ignored `.qoder/design-qa/` workspace. The ignored `design-qa.md` + records `final result: passed` after fixing the initial auto-scroll hierarchy. + In-app Browser inspection also exercised Step Into, Stop Conditions, Raw ACP, + the live AG-UI path, compact side-panel overlays, and reported no errors. +- Risk: debugger labels can overstate execution control. Copy names the + Evidence Cursor and Soft Pause boundary, and does not claim a gate or hard + runtime pause. +- Risk: mock data can be mistaken for product evidence. The default session is + visibly marked `Recorded sample`; live runs receive their own state and ids. +- Risk: dense three-column layouts can become unreadable. Columns use bounded + widths, sticky chrome, local overflow, and explicit responsive collapse. +- Risk: keeping the existing live run path can mix semantic sample data with + live AG-UI data. The two modes stay explicit and never merge evidence. diff --git a/docs/specs/2026-08-18-notebook-session-and-studio.md b/docs/specs/2026-08-18-notebook-session-and-studio.md new file mode 100644 index 0000000..88e1698 --- /dev/null +++ b/docs/specs/2026-08-18-notebook-session-and-studio.md @@ -0,0 +1,177 @@ +# Make session review and harness comparison read like a notebook + +## Traceability + +- Spec ID: notebook-session-and-studio +- Status: In Progress + +## Intent + +Make a retained Session and a live Harness Studio comparison easier to scan by +using the same notebook-shaped mental model: shared context first, then one +understandable work unit with its input, collapsible process, result, and +evidence. The two products keep their existing authority boundaries. Inspector +remains a read-only presentation of retained evidence, while Studio may lock and +run an already supported checkpoint-backed comparison. + +The supplied Jupyter-style reference defines hierarchy, composition, and +rhythm, not a new data contract. The implementation should visibly read as a +notebook at first glance: one application bar, one wide cell stream, a +continuous `In`/`Out` execution rail, and a narrow contextual rail. Labels and +actions must continue to describe facts the product actually owns. + +## Acceptance Scenarios + +- AC-1: Inspector Session Detail renders every retained Turn as a numbered Run + Cell with a visible input prompt, a collapsible Process section, and a result + area. Each Process contains a timeline scoped to that Turn's retained calls, + and the final notebook section contains one overall Session timeline. + Retained responses, commits, tool calls, and unplaced evidence keep their + existing selection descriptors and evidence limitations. +- AC-2: Inspector does not label a Turn as a checkpoint, resumable state, code + rollback, or successful artifact unless that fact already exists in the + report. Trace/Replay, activity zoom, Jump, filters, call expansion, evidence + selection, deep links, and the Continuation packet remain available. +- AC-3: Harness Studio Workbench presents one shared Context block, one Run + Comparison cell, and one Compare Result cell. The Run cell owns the existing + Run/Cancel action and Reference/Baseline/Candidate outputs; the Compare cell + owns comparability plus Summary, Trace, and Evidence. Switching views or run + roles keeps the existing data and selection state. +- AC-4: Studio continues to state one shared starting checkpoint and one + derived treatment boundary without inventing duration, token, cost, + authorship, correctness, or causality. Inspector and Studio both keep + uncertainty and privacy-filtered content explicit. +- AC-5: At 1024 by 576, the Studio context and Run cell lead-in are visible, + the focused call rows remain at least 11 px, and the document does not scroll + horizontally. At 390 px, overflow stays inside the comparison surface and + the context rail remains collapsible. Inspector Session Detail keeps one page + scroller and stacks its index below the cells at narrow width. +- AC-6: Focused tests assert the rendered notebook structure and preserved + interactions through DOM roles and behavior. Browser verification uses real + report/experiment fixtures, exercises primary controls, checks console and + page errors, and compares screenshots against the supplied reference at the + same desktop viewport. +- AC-7: At desktop width, Studio uses a top Notebook bar, a wide left cell + stream, and a right Checkpoints rail rather than a permanent left setup rail. + Inspector uses the same main-stream/right-context composition but names the + right rail `Session outline` and does not expose Continue, Fork, or checkpoint + mutations. Generic card shadows, all-caps microcopy, and console-like gray + framing do not dominate the above-the-fold notebook surface. +- AC-8: Inspector does not repeat a Session-level Context card above the Cell + stream. Stable Session metadata stays in the notebook bar and outline; Turn + activity stays inside its Process, and overall activity appears once after + the Cell stream. +- AC-9: Inspector preserves the observed order of intermediate assistant + messages and tool calls through session parsing, report projection, Trace, + and Replay. Presentation may collapse only adjacent tool-call runs. Counts + distinguish intermediate responses, tool calls, and retained process events. +- AC-10: A terminal assistant response is retained as `Out` only when it is the + final observed event in its Turn. A later tool call makes the retained Turn + incomplete. The Outcome labels observed edit paths, verification calls, and + correlated commits as evidence; it shows a code diff only from a retained, + session-scoped patch artifact and never from the current worktree. +- AC-11: Intermediate and terminal assistant prose renders as sanitized + Markdown without allowing raw HTML or executable links. At narrow widths, + Trace/Replay, Continuation packet, Jump, filters, and Process controls remain + reachable without horizontal document overflow. + +## Non-goals + +- Adding a new checkpoint store, checkpoint mutation, native-session resume, + replay execution, artifact adoption, or Git rollback. +- Merging Inspector and Harness Studio data models or moving Studio execution + controls into the read-only Inspector. +- Replacing the existing Evidence Drawer, Studio comparison models, Builder, + or server endpoints. +- Reproducing the reference image's branch picker, sharing controls, model + names, test counts, file counts, or other illustrative facts when local + evidence does not provide them. + +## Plan and Tasks + +1. Restructure Inspector's existing Session Detail markup into Run Cell + regions while preserving element ids, selection attributes, filters, tool + disclosures, and Replay ownership. Keep Session-wide metadata in the title + bar and outline rather than repeating a Context card. +2. Add notebook-specific Inspector styles for cell numbering, input/process/ + result hierarchy, compact metadata, and responsive stacking. +3. Restructure Studio Workbench markup into a top Notebook bar, shared Context, + Run Comparison and Compare Result cells, plus a right Checkpoints rail, + without changing run, selection, or comparison models. +4. Extend Studio styles and browser coverage for the notebook hierarchy, + desktop density, narrow containment, role switching, filtering, view tabs, + and Run/Cancel behavior. +5. Restructure Inspector Session Detail into the same main-stream/right-outline + composition while keeping its outline and evidence controls strictly + read-only. +6. Render both products, capture desktop and narrow evidence, compare the + implementation with the reference, fix actionable visual gaps, and run the + focused and repository-level gates proportional to the changed surface. +7. Preserve one ordered Turn event stream in the session projection, expose + response availability and honest event counts, and render the same order in + Trace and Replay. +8. Replace the undifferentiated result prose with an evidence-bounded Outcome, + add safe Markdown rendering, and keep notebook navigation available on + narrow screens as specified by + [ADR-0006](../adrs/session-notebook-evidence-projection.md). + +## Test and Review Evidence + +- AC-1/AC-2/AC-8: `npx vitest run + test/reporting/harness-inspector.test.mjs` passed 28 tests. A real five-Turn, + 230-call report rendered five scoped Process timelines and one overall + Session timeline. The in-app browser exercised Process expansion, Trace, + evidence selection/closure, and the read-only Session outline with no page + or console errors. The rendered Session contains no Notebook Context card. +- AC-3/AC-4: `npm run harness-studio:test` passed 59 tests after rebuilding the + package. The built Studio fixture exercised Builder -> Workbench, Process, + Run, Summary/Trace/Evidence, call filtering, and synchronized selection in + the in-app browser with no console or page errors. +- AC-5/AC-7: browser measurements covered 1229 by 819 and 1024 by 576 desktop + states plus two 390 by 844 narrow iframes. Each iframe's one-pixel border + leaves a 388 px inner viewport: Studio document and workspace widths stayed + 388 px, the Checkpoints rail was hidden by default and reopened as a 335 px + overlay without document overflow. Inspector document, Session View, and + layout widths stayed 388 px; the first Cell started at 70 px and the stacked + Session outline began after the Cell stream. Five Process disclosures and one + overall activity section were present. +- AC-6: the prior same-scale reference/implementation boards and + desktop/narrow captures were recorded in the local ignored `design-qa.md`; + they are not used as review evidence for AC-9 through AC-11. The Studio + browser test covers the notebook region, Context, two Cell regions, + Process disclosure, desktop dimensions, collapsed narrow rail, and the 335 + px Checkpoints overlay; `node --check` passed for that test file and the same + interactions were exercised in the in-app browser. + `git diff --check`, `node --check` for the updated Playwright test, + documentation link graph (6 tests), full root suite (95 files / 1327 tests), + package verification (541 npm / 563 runtime-zip entries), and preview + `/health` plus `/canvas-module.js` smokes all passed. +- AC-9/AC-10: `npx vitest run + test/sessions/commit-session-link.test.mjs + test/reporting/harness-inspector.test.mjs` passed 70 tests. The parser test + asserts `tool -> intermediate -> tool`, an incomplete terminal status, and + separate observed/retained counts; the report-model test asserts that the + same order and response status cross the Inspector projection unchanged. + The real 96-event Turn rendered alternating Intermediate/tool-run regions, + reported `80 of 96 process events retained`, aligned `Out` with the Outcome, + and labeled its edit path while explicitly declining to derive a patch from + the current worktree. +- AC-11: browser verification at 1280 by 720 and 390 by 844 kept Trace, Replay, + Continuation packet, Jump, filters, and Process controls visible with document + widths equal to viewport widths. Rendered assistant Markdown contained real + heading and list elements, no raw `script` or `iframe` nodes, and Process + expansion preserved the observed event order. Replay opened at event 1 of + 139; expand/collapse worked for all six Turns; browser warnings and errors + were empty. `npm run harness-studio:test` passed 59 tests, the documentation + link graph passed 6 tests, the full root suite passed 95 files / 1327 tests, + `node --check`, `git diff --check`, and preview `/health` plus + `/canvas-module.js` smokes passed. +- Risk: notebook terminology can overstate state continuity. UI copy uses + `Turn`, `Run`, `result`, and `evidence`, and reserves `checkpoint` for the one + Studio checkpoint source that the server already verifies. +- Risk: added hierarchy can consume too much vertical space. Context stays + compact, Process stays collapsed by default, and repeated metadata is owned + once per notebook or cell. +- Remaining activation decision: the ADR is still `Proposed`, so this spec + remains `In Progress` until maintainers accept the ordered-event and + session-scoped patch boundary or request a different report contract. diff --git a/package-lock.json b/package-lock.json index a1f8715..9098c26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,11 @@ "name": "@qoder-ai/better-harness", "version": "0.6.3", "license": "MIT", + "workspaces": [ + "packages/harness", + "packages/harness-ui", + "packages/harness-studio" + ], "dependencies": { "@vscode/tree-sitter-wasm": "0.3.1", "esbuild-wasm": "0.28.1" @@ -23,901 +28,4918 @@ "npm": ">=10.9.3 <12.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/@chevrotain/cst-dts-gen": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-12.0.0.tgz", + "integrity": "sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "12.0.0", + "@chevrotain/types": "12.0.0" + } }, - "node_modules/@oxc-project/types": { - "version": "0.144.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.144.0.tgz", - "integrity": "sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" + "node_modules/@chevrotain/gast": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-12.0.0.tgz", + "integrity": "sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "12.0.0" } }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.4.tgz", - "integrity": "sha512-jHC2cnyKz5xU2fhECtFl8OZ83cYNt13GZQD+0uMJ/X3o+ijmd56okHhTUwxVSHPx1IRVIJEZ1/1pPzeLCU6XKA==", - "cpu": [ - "arm64" - ], + "node_modules/@chevrotain/regexp-to-ast": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-12.0.0.tgz", + "integrity": "sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-12.0.0.tgz", + "integrity": "sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-12.0.0.tgz", + "integrity": "sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==", + "license": "Apache-2.0" + }, + "node_modules/@earendil-works/pi-coding-agent": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.84.2.tgz", + "integrity": "sha512-l4E+B7hgXKWddRo8bC/eSue2aWZjEgJ9xIpf5p0Og+lq8a2TArCwJ0HCoCPCgaBP/tN4zbYH/wOwvx9pJpeLCA==", "dev": true, + "hasShrinkwrap": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@earendil-works/pi-agent-core": "^0.84.2", + "@earendil-works/pi-ai": "^0.84.2", + "@earendil-works/pi-client": "^0.84.2", + "@earendil-works/pi-protocol": "^0.84.2", + "@earendil-works/pi-tui": "^0.84.2", + "@silvia-odwyer/photon-node": "0.3.4", + "chalk": "5.6.2", + "cross-spawn": "7.0.6", + "diff": "8.0.4", + "glob": "13.0.6", + "grok-mermaid": "0.2.2", + "highlight.js": "10.7.3", + "hosted-git-info": "9.0.3", + "ignore": "7.0.5", + "jiti": "2.7.0", + "minimatch": "10.2.5", + "proper-lockfile": "4.1.2", + "semver": "7.8.0", + "typebox": "1.3.7", + "undici": "8.9.0", + "yaml": "2.9.0" + }, + "bin": { + "pi": "dist/cli.js" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=22.19.0" + }, + "optionalDependencies": { + "@mariozechner/clipboard": "0.3.9" } }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-Dc5mPD8F5F/FS8i01syd7FTF6yB2fVthH/TRkjwJkzUK6EpoxHtqvZQP5Zwq80/5z19TWYHIg1KOHboCgVx/aQ==", - "cpu": [ - "arm64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } } }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.4.tgz", - "integrity": "sha512-fpDm4oBo6SqLvWUYCmFhdde3U9KH2fRNNMeAnAPAIwxRL345xutL0EtEUcuoxsoazdJGv/MuDBQHlCDrtbvqOg==", - "cpu": [ - "x64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=16.0.0" } }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.4.tgz", - "integrity": "sha512-rSJoreDE/HoIzoaib6MTp5jQtCTdMHKIvItAKT/ImS6Y6Ww76oUaeMyp4Vc/fAgd/ehji068IxetHXAnqUwN9A==", - "cpu": [ - "x64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=16.0.0" } }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.4.tgz", - "integrity": "sha512-/jm8OGHgn7oGaJu3i/qZI9spUGcJ+y/lk43ttQ/iO1tOd9NissG6o97bighBCiL+BKRngmcDuR6ikfwYdJmVuQ==", - "cpu": [ - "arm" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", + "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-node": "^3.972.42", + "@aws-sdk/eventstream-handler-node": "^3.972.16", + "@aws-sdk/middleware-eventstream": "^3.972.12", + "@aws-sdk/middleware-websocket": "^3.972.19", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.4.tgz", - "integrity": "sha512-tIP06BeD9EqvECBrPZ+sqdPlYrT+aYaAiu1wYziVx5elRK/ftm33JxVDy2bXGbr6J0CrtirCkR87/X5a2euEng==", - "cpu": [ - "arm64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/core": { + "version": "3.974.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.11.tgz", + "integrity": "sha512-QpnINq5FZH6EOaDEkmHdT7eUunbvD27pDNQypaWjFyYz7Zl1q3UCMQErBZxpmfGfI7MvI2TlK8KTkgNpv8b1ug==", "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/xml-builder": "^3.972.24", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/core": "^3.24.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.4.tgz", - "integrity": "sha512-Ql1Q0EQqVThvn9VAVlwNzsUvbSFtCMGjLpRRi4pk5i7NZZ4n5ISiLMjHYtus4VQ2PvkSw24zyaCVsiS+sXPj1w==", - "cpu": [ - "arm64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.37.tgz", + "integrity": "sha512-/jpPvEh6f7ntmIzf7dNxoNX6Q8vt8UpesCjbW6mFfk4V1NW6bIy9qxcQ6WbA8As5yQhsZOe+xeNd4xHX8kdY2Q==", "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.4.tgz", - "integrity": "sha512-GjbjXD4XXfN19D0LZNbmiCBUoDiRACsYHr0yaIbbn8aFsXjHZifcYqu/W5Er5X2X990WjHXFrxarn5chzItorQ==", - "cpu": [ - "ppc64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.39", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.39.tgz", + "integrity": "sha512-pIgTpisWyWg7X1bUbzSjuUYosYTD0Ghz2M0hkSTmb3a6i3qV3uU+NYJPI/E2XSC0HcsZh5rsLPzeXrkb2DS0Cg==", "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.4.tgz", - "integrity": "sha512-p5WR0NOwaRmJ/B1b6IjEFLLivwEsf3PrdBIhRbhTCQisbo2SvHHpG4ELB/+FgQNnB88LTOF86upmJmbvZdQ2lw==", - "cpu": [ - "s390x" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.41.tgz", + "integrity": "sha512-u2tyjaxJJzW8UtW4SM1ZcPMDwO6y+kV+llvou+Adts0FAKyzes5jG4izQN+KX3yE8ZROpS5y1LJ//xL2iSf76w==", "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-env": "^3.972.37", + "@aws-sdk/credential-provider-http": "^3.972.39", + "@aws-sdk/credential-provider-login": "^3.972.41", + "@aws-sdk/credential-provider-process": "^3.972.37", + "@aws-sdk/credential-provider-sso": "^3.972.41", + "@aws-sdk/credential-provider-web-identity": "^3.972.41", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.4.tgz", - "integrity": "sha512-4/GyVjmhR+Tc6HLJvwc1sOhPqAZtySiSMesOZyX6JQ5XBxoTDEMKQzvo07NIK6nTon/SivlZqvhzvuVBNQhObQ==", - "cpu": [ - "x64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.41.tgz", + "integrity": "sha512-0LBitxXiAiaE5nlFPfpNIww/8FRY/I7WIndWsc9GmNFOM7cE1wNpVNQEGEk9Outg5l8xl+3vybxFyUy4l9q/LQ==", "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.4.tgz", - "integrity": "sha512-l9eeLsCNvPpmSXUej0etw/J1eqV0Jj1D5G/xG6YTijmE6dkv6E2QezgWbTfQk63v952DPqrjOCoiqxq7Bw0YUQ==", - "cpu": [ - "x64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.42", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.42.tgz", + "integrity": "sha512-D4oon2zbqqsWOJUM99Gm3/ZyJ0IJvTXVN3PyloGb3kQEyI36fjCZheZj422lAgTWWd6TSHgiImLt3RIaLdv3dQ==", "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.37", + "@aws-sdk/credential-provider-http": "^3.972.39", + "@aws-sdk/credential-provider-ini": "^3.972.41", + "@aws-sdk/credential-provider-process": "^3.972.37", + "@aws-sdk/credential-provider-sso": "^3.972.41", + "@aws-sdk/credential-provider-web-identity": "^3.972.41", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.4.tgz", - "integrity": "sha512-e0F355MSTMm3+UOqtV3L24gFUp2N5m1f8L/7d56deik6va+AXdrt9F8LbzGpeWGWRbZEDq4m8NVnJDeBtf9DZg==", - "cpu": [ - "arm64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.37.tgz", + "integrity": "sha512-7nVaHBUaWIddASYfVaA9O4D5ZVjewU3sCol9WqZPGfW0nR+0WqE0xHZnD/U2L33PlOB8KNXGKZ6wOES/QijKzg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.4.tgz", - "integrity": "sha512-AWLi0uBRYh6QlE7OKhiz+phZC0qwtij2QZmhmOdsLdFn64m7oMpooE9ICE3lhm9xMb4SpDo2WbHcxX1iFLFtqw==", - "cpu": [ - "arm64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.41.tgz", + "integrity": "sha512-IOWAWEHe5LkjSKkkUUX9ciV6Y1scHTsnfEkdt5yyC4Slrc7AGbkLPrpntjqh18ksJAMOaVhoBsO8p2WyTcY2wQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.4.tgz", - "integrity": "sha512-UwSDJOg3dqCAejWdxclJjCsh3Qq4vLYMDxmyHqo1btz3stK2VqgwNd3mm5tuIwzSlGIQ/1H9Hr+Zn09mrezNqQ==", - "cpu": [ - "x64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.41.tgz", + "integrity": "sha512-mbACk9Yypa8nm4iGZLs0PofOXEcTDOUw6wDnsPXNDNSd2WNXs1tSo+6nc/fh0jLYdfVZThhBL98PHW4aXFsG5A==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.0.0" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "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==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.16", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.16.tgz", + "integrity": "sha512-yedpPgKftqjU5SlPFHfqWpOw6xSCRieWRG1euWOlXn4WJxt2VX92VprCa2PpSOXjVCAeK6dTjW9eJRXVig9yGA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" } }, - "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==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.12", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.12.tgz", + "integrity": "sha512-tHTHHCHNrq6XklQvlzHBDJG4Iuhh7NVPRdtmvP+nHFA+5sxPlIDzlAHHgfoYHGvT3NXP1yVP/L5c3opUn6T3Qg==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } }, - "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.19", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.19.tgz", + "integrity": "sha512-mkEhOGYozqKQkbFaVrjwr0faiwwZza1v5/jSY6Tucm3bD+uKTazIUH/4Yo6aMnQD2ua2W9cMP6s8mvwTcjtqHw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/nested-clients": { + "version": "3.997.9", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.9.tgz", + "integrity": "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@vitest/spy": "4.1.10", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/signature-v4-multi-region": "^3.996.27", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.27", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.27.tgz", + "integrity": "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "tinyrainbow": "^3.1.0" + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/token-providers": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", + "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@vitest/utils": "4.1.10", - "pathe": "^2.0.3" + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/types": { + "version": "3.973.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", + "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", + "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/xml-builder": { + "version": "3.972.24", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.24.tgz", + "integrity": "sha512-V8z5YcDPfsvzrBlj0xR1vhRtocblhYbqdreCJB/voGd4Sr5zjNAeWxexbnqVtskTJe0vFb5KMqbSL++ePl+zRw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@vitest/pretty-format": "4.1.10", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" + "@nodable/entities": "2.1.0", + "@smithy/types": "^4.14.1", + "fast-xml-parser": "5.7.3", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@vscode/tree-sitter-wasm": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.3.1.tgz", - "integrity": "sha512-RJFoomET6FajjG511fmQxeBQfU6M24a0aFZPqpid+ttIxanWf1VGytBG0UmsGjt07qmIPJS8U31D+aecuCucsQ==", - "license": "MIT" - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws/lambda-invoke-store": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", + "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": ">=18.0.0" } }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "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==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-agent-core": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.84.2.tgz", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@earendil-works/pi-ai": "^0.84.2", + "@earendil-works/pi-telemetry": "^0.84.2", + "diff": "8.0.4", + "ignore": "7.0.5", + "typebox": "1.3.7", + "yaml": "2.9.0" + }, + "engines": { + "node": ">=22.19.0" + } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-ai": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.84.2.tgz", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@earendil-works/pi-telemetry": "^0.84.2", + "@google/genai": "1.52.0", + "@opentelemetry/api": "1.9.0", + "@smithy/node-http-handler": "4.7.3", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", + "openai": "6.40.0", + "partial-json": "0.1.7", + "typebox": "1.3.7" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, "engines": { - "node": ">=8" + "node": ">=22.19.0" } }, - "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-client": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-client/-/pi-client-0.84.2.tgz", "dev": true, - "license": "MIT" - }, - "node_modules/esbuild-wasm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.28.1.tgz", - "integrity": "sha512-p/GD4E8oYRjg3kjdKrnMb0s4PzXgJF42e0MF4H0+ACyK/kIlFRp3e0fzOleIG+wBBm6MM3XQrbpe7soEA+vJIA==", "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "@earendil-works/pi-protocol": "^0.84.2" }, "engines": { - "node": ">=18" + "node": ">=22.19.0" } }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-protocol": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-protocol/-/pi-protocol-0.84.2.tgz", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" + "typebox": "1.3.7" + }, + "engines": { + "node": ">=22.19.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==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-telemetry": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.84.2.tgz", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">=22.19.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==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-tui": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.84.2.tgz", "dev": true, "license": "MIT", + "dependencies": { + "get-east-asian-width": "1.6.0", + "marked": "18.0.5" + }, "engines": { - "node": ">=12.0.0" + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@google/genai": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.52.0.tgz", + "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" }, "peerDependencies": { - "picomatch": "^3 || ^4" + "@modelcontextprotocol/sdk": "^1.25.2" }, "peerDependenciesMeta": { - "picomatch": { + "@modelcontextprotocol/sdk": { "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==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard/-/clipboard-0.3.9.tgz", + "integrity": "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA==", "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "@mariozechner/clipboard-darwin-arm64": "0.3.9", + "@mariozechner/clipboard-darwin-universal": "0.3.9", + "@mariozechner/clipboard-darwin-x64": "0.3.9", + "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", + "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-x64-musl": "0.3.9", + "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", + "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" } }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-darwin-arm64": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-arm64/-/clipboard-darwin-arm64-0.3.9.tgz", + "integrity": "sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", - "cpu": [ - "x64" - ], + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-darwin-universal": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-universal/-/clipboard-darwin-universal-0.3.9.tgz", + "integrity": "sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ==", "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-darwin-x64": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-x64/-/clipboard-darwin-x64-0.3.9.tgz", + "integrity": "sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg==", "cpu": [ "x64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ - "freebsd" + "darwin" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-arm64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-gnu/-/clipboard-linux-arm64-gnu-0.3.9.tgz", + "integrity": "sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw==", "cpu": [ - "arm" + "arm64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-arm64-musl": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-musl/-/clipboard-linux-arm64-musl-0.3.9.tgz", + "integrity": "sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ==", "cpu": [ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-riscv64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-riscv64-gnu/-/clipboard-linux-riscv64-gnu-0.3.9.tgz", + "integrity": "sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw==", "cpu": [ - "arm64" + "riscv64" ], "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-x64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-gnu/-/clipboard-linux-x64-gnu-0.3.9.tgz", + "integrity": "sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-x64-musl": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-musl/-/clipboard-linux-x64-musl-0.3.9.tgz", + "integrity": "sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-win32-arm64-msvc": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-arm64-msvc/-/clipboard-win32-arm64-msvc-0.3.9.tgz", + "integrity": "sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 10" } }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-win32-x64-msvc": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-x64-msvc/-/clipboard-win32-x64-msvc-0.3.9.tgz", + "integrity": "sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA==", "cpu": [ "x64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "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": ">= 10" } }, - "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==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", "dev": true, "funding": [ { "type": "github", - "url": "https://github.com/sponsors/ai" + "url": "https://github.com/sponsors/nodable" } ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } + "license": "MIT" }, - "node_modules/obug": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", - "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=12.20.0" + "node": ">=8.0.0" } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "dev": true, - "license": "MIT" + "license": "BSD-3-Clause" }, - "node_modules/picocolors": { + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/eventemitter": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", "dev": true, - "license": "ISC" + "license": "BSD-3-Clause" }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" } }, - "node_modules/postcss": { - "version": "8.5.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", - "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@silvia-odwyer/photon-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@silvia-odwyer/photon-node/-/photon-node-0.3.4.tgz", + "integrity": "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/core": { + "version": "3.24.3", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.3.tgz", + "integrity": "sha512-Ep/7tPamGY8mgESE3LyLKtxJyy6U52WWAqr/3wial47Sj4u3PiIF73AOGI27UyLy9duTkhZbgzodOfLV4TduZg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/credential-provider-imds": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.3.tgz", + "integrity": "sha512-I2Bti0DKFo2IJyN28ijCsx51BAumEYR4/1yZ1FXyBygy9MqbnMqCev4JPth/MbpRfBSRAX35hITSnAdJRo1u5w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/fetch-http-handler": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.3.tgz", + "integrity": "sha512-F+DRf8IJazRJgYog2A/yJK7eYVc0rqTlRzO+5ZxjJd4WkZoKz0IJRncf7G6t1pdVT3kryJcwuTFhN1c5m6N47A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/node-http-handler": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", + "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/signature-v4": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.3.tgz", + "integrity": "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/types": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", + "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@types/node": { + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/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/@earendil-works/pi-coding-agent/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@earendil-works/pi-coding-agent/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/@earendil-works/pi-coding-agent/node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/fast-xml-builder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/fast-xml-parser": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", + "integrity": "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.7", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/grok-mermaid": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/grok-mermaid/-/grok-mermaid-0.2.2.tgz", + "integrity": "sha512-XcJEP5dDC8liHBh52mlLjU18fNvu1ckFsu0QpIG3+APZ270fsj9wxpiA6cOURmbUEuoMVgjbC2+UYgTdCqqgzA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/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/@earendil-works/pi-coding-agent/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/@earendil-works/pi-coding-agent/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/lru-cache": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.4.0.tgz", + "integrity": "sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/marked": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.5.tgz", + "integrity": "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@earendil-works/pi-coding-agent/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/@earendil-works/pi-coding-agent/node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/openai": { + "version": "6.40.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.40.0.tgz", + "integrity": "sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/p-retry/node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/protobufjs": { + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.5.tgz", + "integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/strnum": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/typebox": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.7.tgz", + "integrity": "sha512-meKuifc33Pccx0O6PdIzYMq3Og8zvP4TIi/a+Bw3AEMZMxOD0+RHGQvpglEe6Zdy3wZ8nqn/j95h8LUZLk/6Hg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/undici": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.9.0.tgz", + "integrity": "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "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/@earendil-works/pi-coding-agent/node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/@hono/node-server": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.1.tgz", + "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "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/@modelcontextprotocol/sdk": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", + "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9 || ^2.0.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@oxc-project/types": { + "version": "0.144.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.144.0.tgz", + "integrity": "sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@phosphor-icons/react": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@phosphor-icons/react/-/react-2.1.10.tgz", + "integrity": "sha512-vt8Tvq8GLjheAZZYa+YG/pW7HDbov8El/MANW8pOAz4eGxrwhnbfrQZq0Cp4q8zBEu8NIhHdnr+r8thnfRSNYA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">= 16.8", + "react-dom": ">= 16.8" + } + }, + "node_modules/@pierre/diffs": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@pierre/diffs/-/diffs-1.3.5.tgz", + "integrity": "sha512-BhaLEiUvR+BdIyOYdogA4JLQjluWPubuwySmmIqEkcE0FwIWRbgJgHNC/r884dlxEr89fO4hTk/sBln0a7NSOw==", + "license": "apache-2.0", + "dependencies": { + "@pierre/theme": "2.0.0", + "@pierre/theming": "1.0.1", + "@shikijs/transformers": "^3.0.0 || ^4.0.0", + "diff": "9.0.0", + "hast-util-to-html": "9.0.5", + "lru_map": "0.4.1", + "shiki": "^3.0.0 || ^4.0.0" + }, + "peerDependencies": { + "react": "^18.3.1 || ^19.0.0", + "react-dom": "^18.3.1 || ^19.0.0" + } + }, + "node_modules/@pierre/theme": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@pierre/theme/-/theme-2.0.0.tgz", + "integrity": "sha512-yNDd9GYLQl1mEUJR8AneJ5e4ohLIHQd/wZLWr4fagt78vS2RwwZNW530vVgHqXFAyFVcFlRmGUD5ramXH46OXw==", + "license": "apache-2.0", + "engines": { + "vscode": "^1.0.0" + } + }, + "node_modules/@pierre/theming": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@pierre/theming/-/theming-1.0.1.tgz", + "integrity": "sha512-WCI5Qd7iprDpISL9fBYOLe8RV53+b7mFNA3bPzl60/2CKCSrsKN8zEcep6Y3BAzvARlmca50zGjDodqPGiTUKA==", + "license": "apache-2.0", + "peerDependencies": { + "@pierre/theme": "^1.1.0 || ^2.0.0", + "@shikijs/themes": "^3.0.0 || ^4.0.0", + "react": "^18.3.1 || ^19.0.0", + "react-dom": "^18.3.1 || ^19.0.0", + "shiki": "^3.0.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "@pierre/theme": { + "optional": true + }, + "@shikijs/themes": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "shiki": { + "optional": true + } + } + }, + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@qoder-ai/harness": { + "resolved": "packages/harness", + "link": true + }, + "node_modules/@qoder-ai/harness-studio": { + "resolved": "packages/harness-studio", + "link": true + }, + "node_modules/@qoder-ai/harness-ui": { + "resolved": "packages/harness-ui", + "link": true + }, + "node_modules/@qoder-ai/qoder-agent-sdk": { + "version": "1.0.21", + "resolved": "https://registry.npmjs.org/@qoder-ai/qoder-agent-sdk/-/qoder-agent-sdk-1.0.21.tgz", + "integrity": "sha512-G+pLA5HYZRjbytpDF7nlumbEgLvntA+yL2IGGy7BO6OtRI0c9RfzjwGnVNqr3mHQeiF7mi9b4jmrBNtI8I1wAA==", + "dev": true, + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.27.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.4.tgz", + "integrity": "sha512-jHC2cnyKz5xU2fhECtFl8OZ83cYNt13GZQD+0uMJ/X3o+ijmd56okHhTUwxVSHPx1IRVIJEZ1/1pPzeLCU6XKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-Dc5mPD8F5F/FS8i01syd7FTF6yB2fVthH/TRkjwJkzUK6EpoxHtqvZQP5Zwq80/5z19TWYHIg1KOHboCgVx/aQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.4.tgz", + "integrity": "sha512-fpDm4oBo6SqLvWUYCmFhdde3U9KH2fRNNMeAnAPAIwxRL345xutL0EtEUcuoxsoazdJGv/MuDBQHlCDrtbvqOg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.4.tgz", + "integrity": "sha512-rSJoreDE/HoIzoaib6MTp5jQtCTdMHKIvItAKT/ImS6Y6Ww76oUaeMyp4Vc/fAgd/ehji068IxetHXAnqUwN9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.4.tgz", + "integrity": "sha512-/jm8OGHgn7oGaJu3i/qZI9spUGcJ+y/lk43ttQ/iO1tOd9NissG6o97bighBCiL+BKRngmcDuR6ikfwYdJmVuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.4.tgz", + "integrity": "sha512-tIP06BeD9EqvECBrPZ+sqdPlYrT+aYaAiu1wYziVx5elRK/ftm33JxVDy2bXGbr6J0CrtirCkR87/X5a2euEng==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.4.tgz", + "integrity": "sha512-Ql1Q0EQqVThvn9VAVlwNzsUvbSFtCMGjLpRRi4pk5i7NZZ4n5ISiLMjHYtus4VQ2PvkSw24zyaCVsiS+sXPj1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.4.tgz", + "integrity": "sha512-GjbjXD4XXfN19D0LZNbmiCBUoDiRACsYHr0yaIbbn8aFsXjHZifcYqu/W5Er5X2X990WjHXFrxarn5chzItorQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.4.tgz", + "integrity": "sha512-p5WR0NOwaRmJ/B1b6IjEFLLivwEsf3PrdBIhRbhTCQisbo2SvHHpG4ELB/+FgQNnB88LTOF86upmJmbvZdQ2lw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.4.tgz", + "integrity": "sha512-4/GyVjmhR+Tc6HLJvwc1sOhPqAZtySiSMesOZyX6JQ5XBxoTDEMKQzvo07NIK6nTon/SivlZqvhzvuVBNQhObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.4.tgz", + "integrity": "sha512-l9eeLsCNvPpmSXUej0etw/J1eqV0Jj1D5G/xG6YTijmE6dkv6E2QezgWbTfQk63v952DPqrjOCoiqxq7Bw0YUQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.4.tgz", + "integrity": "sha512-e0F355MSTMm3+UOqtV3L24gFUp2N5m1f8L/7d56deik6va+AXdrt9F8LbzGpeWGWRbZEDq4m8NVnJDeBtf9DZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.4.tgz", + "integrity": "sha512-AWLi0uBRYh6QlE7OKhiz+phZC0qwtij2QZmhmOdsLdFn64m7oMpooE9ICE3lhm9xMb4SpDo2WbHcxX1iFLFtqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.4.tgz", + "integrity": "sha512-UwSDJOg3dqCAejWdxclJjCsh3Qq4vLYMDxmyHqo1btz3stK2VqgwNd3mm5tuIwzSlGIQ/1H9Hr+Zn09mrezNqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@shikijs/core": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.4.3.tgz", + "integrity": "sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg==", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.4.3", + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.4.3.tgz", + "integrity": "sha512-FbOjFJp9VLdo1Wevs10BBtVxiTWwNLqZh5Gkhjgda/ioL15YOgeSl9n+6XMa3qRlPQzfhFNe641SrynFHYG0nQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.4.3.tgz", + "integrity": "sha512-EcOQkxdxGQrc1Row/cC2c96/v1dbZqGnEVu1qTuT/MJmp6+cXCvQussowVmCv5Tqr3KuY3c7IbM6HTW3LJ1k9w==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/langs": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.4.3.tgz", + "integrity": "sha512-ePic0yfAJGOF83D5wBHK/00EjK65oahBYxFk5epgq33WRv7X9UuxLEV8PtR0szC0z8dl7INIpIodB99JRFlR+A==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.4.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/primitive": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.4.3.tgz", + "integrity": "sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/themes": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.4.3.tgz", + "integrity": "sha512-w8UHjeUnIR965KMWJHUPXOc2mNJUnK3vpVLYLvw5IYU2mnTTJ89E24OrJDBNiJDQ0qzb0tc4l7mrIXx5cFeIyw==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.4.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/transformers": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-4.4.3.tgz", + "integrity": "sha512-oJSARV6NaWd+rnNJbtnpAdj3Zg0ZVyzsnMgb3vi3HA+35y8lBWUCpOnWsmyiXZIikY+x1BDqrQUgmxfzWh7Jvw==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.4.3", + "@shikijs/types": "4.4.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/types": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.4.3.tgz", + "integrity": "sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.14.9", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.14.9.tgz", + "integrity": "sha512-qZyr0FZDP8rDC4WBhsryIZmAd9bveJvFGUJJtskWaew6/0dTRS6wZxnR6VQ5bY2KwL3LjerrHqQLk3a0GKcPXQ==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.17.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.17.7", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.7.tgz", + "integrity": "sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "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/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/node": { + "version": "26.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "license": "ISC" + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vscode/tree-sitter-wasm": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.3.1.tgz", + "integrity": "sha512-RJFoomET6FajjG511fmQxeBQfU6M24a0aFZPqpid+ttIxanWf1VGytBG0UmsGjt07qmIPJS8U31D+aecuCucsQ==", + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "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/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chevrotain": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-12.0.0.tgz", + "integrity": "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "12.0.0", + "@chevrotain/gast": "12.0.0", + "@chevrotain/regexp-to-ast": "12.0.0", + "@chevrotain/types": "12.0.0", + "@chevrotain/utils": "12.0.0" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.4.4.tgz", + "integrity": "sha512-HKjrnG6rGOkaxoOx8B4oKRYoD8Gdt6wCL5ItwAtZPgS5kI6rKyezUyWKCFVr6nLYQXT6/BLVVp5b00xBbnjakQ==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.18.1" + }, + "peerDependencies": { + "chevrotain": "^12.0.0" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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/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/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.28.1.tgz", + "integrity": "sha512-p/GD4E8oYRjg3kjdKrnMb0s4PzXgJF42e0MF4H0+ACyK/kIlFRp3e0fzOleIG+wBBm6MM3XQrbpe7soEA+vJIA==", + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "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/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", + "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.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/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.6.2.tgz", + "integrity": "sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "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/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "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/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hono": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.2.tgz", + "integrity": "sha512-JydRilDRkYBQMt9qR9U92mXxmbGqsqSn/IKOrh4e7/gEbn+0zSr8igTu0obwJoNGN4sez28DIql7FBHWydoJpA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", + "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.8.tgz", + "integrity": "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", + "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/langium": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.3.1.tgz", + "integrity": "sha512-4lmkLHytLXD5pvyL0PKUj1LCNpgzv9s8luH+GbWXHG45QLmO6PlFXrCUghDN5BfcFTlaQyXpXiaSl8A28Xep8w==", + "license": "MIT", + "dependencies": { + "@chevrotain/regexp-to-ast": "~12.0.0", + "chevrotain": "~12.0.0", + "chevrotain-allstar": "~0.4.3", + "vscode-languageserver": "~10.0.1", + "vscode-languageserver-protocol": "~3.18.1", + "vscode-languageserver-textdocument": "~1.0.13", + "vscode-languageserver-types": "~3.18.0", + "vscode-uri": "~3.1.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, + "node_modules/langium-cli": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/langium-cli/-/langium-cli-4.3.0.tgz", + "integrity": "sha512-+TtgkhX8Z3exRBJvTFWV1semhWUCnWMhMP+ZKjpKIeyY6GgnQHehf3ZWyCvVL5T95uqgWZb77aoq9rhI2MPNTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "~5.6.2", + "commander": "~15.0.0", + "fs-extra": "~11.3.5", + "jsonschema": "~1.5.0", + "langium": "~4.3.0", + "langium-railroad": "~4.3.0", + "lodash": "~4.18.1" + }, + "bin": { + "langium": "bin/langium.js" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, + "node_modules/langium-railroad": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/langium-railroad/-/langium-railroad-4.3.0.tgz", + "integrity": "sha512-dbuv149MQe8XcgM48FagH22JBaqN0MvN9RRJKBdRQWDeHUYAASliiOtLdMfgOl3kV+nLx7idSc+LLdcBSduvHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "langium": "~4.3.0", + "railroad-diagrams": "~1.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, + "node_modules/lru_map": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.4.1.tgz", + "integrity": "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==", + "license": "MIT" + }, + "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/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/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.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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" }, { @@ -927,45 +4949,392 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.17", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rolldown": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.4.tgz", + "integrity": "sha512-rSr7irW0K7QRWzjdJXqZowkcRdDtjRduh43rBltnVKd0VFq839l1lJoDvGJb6gl7+4rTTCrPWu+YfujUL8Ug7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.144.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.4", + "@rolldown/binding-darwin-arm64": "1.2.4", + "@rolldown/binding-darwin-x64": "1.2.4", + "@rolldown/binding-freebsd-x64": "1.2.4", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.4", + "@rolldown/binding-linux-arm64-gnu": "1.2.4", + "@rolldown/binding-linux-arm64-musl": "1.2.4", + "@rolldown/binding-linux-ppc64-gnu": "1.2.4", + "@rolldown/binding-linux-s390x-gnu": "1.2.4", + "@rolldown/binding-linux-x64-gnu": "1.2.4", + "@rolldown/binding-linux-x64-musl": "1.2.4", + "@rolldown/binding-openharmony-arm64": "1.2.4", + "@rolldown/binding-win32-arm64-msvc": "1.2.4", + "@rolldown/binding-win32-x64-msvc": "1.2.4" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "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/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": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.4.3.tgz", + "integrity": "sha512-Mb/GvXPHBAXdgGIcnfU5L3ldpn1XcxrGkPHwqgRx17/I2XRfqlFKk2vGkHWINn1kdXvzJZeuO3is6I9KLPFm0g==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.4.3", + "@shikijs/engine-javascript": "4.4.3", + "@shikijs/engine-oniguruma": "4.4.3", + "@shikijs/langs": "4.4.3", + "@shikijs/themes": "4.4.3", + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rolldown": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.4.tgz", - "integrity": "sha512-rSr7irW0K7QRWzjdJXqZowkcRdDtjRduh43rBltnVKd0VFq839l1lJoDvGJb6gl7+4rTTCrPWu+YfujUL8Ug7w==", + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.144.0", - "@rolldown/pluginutils": "^1.0.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" }, - "bin": { - "rolldown": "bin/cli.mjs" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 0.4" }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.4", - "@rolldown/binding-darwin-arm64": "1.2.4", - "@rolldown/binding-darwin-x64": "1.2.4", - "@rolldown/binding-freebsd-x64": "1.2.4", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.4", - "@rolldown/binding-linux-arm64-gnu": "1.2.4", - "@rolldown/binding-linux-arm64-musl": "1.2.4", - "@rolldown/binding-linux-ppc64-gnu": "1.2.4", - "@rolldown/binding-linux-s390x-gnu": "1.2.4", - "@rolldown/binding-linux-x64-gnu": "1.2.4", - "@rolldown/binding-linux-x64-musl": "1.2.4", - "@rolldown/binding-openharmony-arm64": "1.2.4", - "@rolldown/binding-win32-arm64-msvc": "1.2.4", - "@rolldown/binding-win32-x64-msvc": "1.2.4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/siginfo": { @@ -985,6 +5354,16 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -992,6 +5371,16 @@ "dev": true, "license": "MIT" }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/std-env": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", @@ -999,6 +5388,20 @@ "dev": true, "license": "MIT" }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -1043,6 +5446,227 @@ "node": ">=14.0.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", @@ -1211,6 +5835,90 @@ } } }, + "node_modules/vscode-jsonrpc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.1.tgz", + "integrity": "sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-10.0.1.tgz", + "integrity": "sha512-hfERoZvpaHWzQa7t5mMIrHkEOhF7aTs1dpktem0TW/Xs4QZD7NtcHjIq/aE1CZJEj6Rb8LSGUkBhvTRDdpyGig==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.18.1" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.2.tgz", + "integrity": "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "9.0.1", + "vscode-languageserver-types": "3.18.0" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.13.tgz", + "integrity": "sha512-nx0ZHwMGIsVkzFG3/VLeJYBLTaFBRuNdGDvevvjuoayU5EOS2fEYazOhtCM3PI9ClMMg5igc0uwXtAq4tJj+Dw==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.0.tgz", + "integrity": "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==", + "license": "MIT" + }, + "node_modules/vscode-languageserver/node_modules/vscode-jsonrpc": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.0.tgz", + "integrity": "sha512-+VvMmQPJhtvJ+8O+zu2JKIRiLxXF8NW7krWgyMGeOHrp4Cn23T5hc0v2LknNeopDOB70wghHAds7mKtcZ0I4Sg==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-protocol": { + "version": "3.18.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.1.tgz", + "integrity": "sha512-RTiiVHdpxpYcJVI5sq6S5TLjQ4WDR/rBrIWru+kPXe6sGQ9PFQ3GamrTKLvPqbR4ylr1SoodhmcqbFII0WXVuw==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "9.0.0", + "vscode-languageserver-types": "3.18.0" + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "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", @@ -1227,6 +5935,134 @@ "engines": { "node": ">=8" } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "packages/harness": { + "name": "@qoder-ai/harness", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "0.34.52", + "langium": "4.3.1", + "semver": "7.8.5", + "shiki": "4.4.3" + }, + "bin": { + "harness-compare": "dist/compare/cli.js" + }, + "devDependencies": { + "@earendil-works/pi-coding-agent": "0.84.2", + "@qoder-ai/qoder-agent-sdk": "1.0.21", + "@types/node": "26.2.0", + "@types/semver": "7.8.0", + "es-module-lexer": "2.3.1", + "langium-cli": "4.3.0", + "typescript": "7.0.2", + "vitest": "4.1.10" + }, + "engines": { + "node": ">=22.20.0 <25.0.0" + }, + "peerDependencies": { + "@earendil-works/pi-coding-agent": "^0.84.2", + "@qoder-ai/qoder-agent-sdk": "^1.0.21" + }, + "peerDependenciesMeta": { + "@earendil-works/pi-coding-agent": { + "optional": true + }, + "@qoder-ai/qoder-agent-sdk": { + "optional": true + } + } + }, + "packages/harness-studio": { + "name": "@qoder-ai/harness-studio", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@phosphor-icons/react": "^2.1.10", + "@pierre/diffs": "^1.3.5", + "@qoder-ai/harness": "0.1.0", + "@qoder-ai/harness-ui": "0.1.0", + "@shikijs/core": "^4.4.3", + "@shikijs/engine-javascript": "^4.4.3", + "@shikijs/langs": "^4.4.3", + "@tanstack/react-virtual": "^3.14.9", + "react": "19.2.8", + "react-dom": "19.2.8" + }, + "bin": { + "harness-studio": "dist/server/cli.js" + }, + "devDependencies": { + "@playwright/test": "^1.62.1", + "@types/node": "26.2.0", + "@types/react": "19.2.18", + "@types/react-dom": "19.2.4", + "esbuild-wasm": "0.28.1", + "typescript": "7.0.2", + "vitest": "4.1.10" + }, + "engines": { + "node": ">=22.20.0 <25.0.0" + } + }, + "packages/harness-ui": { + "name": "@qoder-ai/harness-ui", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@qoder-ai/harness": "0.1.0" + }, + "bin": { + "harness-ui": "dist/cli.js" + }, + "devDependencies": { + "@types/node": "26.2.0", + "es-module-lexer": "2.3.1", + "typescript": "7.0.2", + "vitest": "4.1.10" + }, + "engines": { + "node": ">=22.20.0 <25.0.0" + } } } } diff --git a/package.json b/package.json index 93e2426..91d8725 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,11 @@ "pi-package" ], "type": "module", + "workspaces": [ + "packages/harness", + "packages/harness-ui", + "packages/harness-studio" + ], "pi": { "skills": [ "./skills" @@ -55,6 +60,7 @@ "!docs/scripts/", "!docs/build/", "!docs/.docusaurus/", + "!docs/node_modules/", "!docs/docusaurus.config.js", "!docs/sidebars.js", "!docs/package.json", @@ -74,7 +80,15 @@ }, "scripts": { "bundle:zip": "node scripts/npm-package/create-bundle.mjs", - "check": "npm test && npm run pack:verify", + "check": "npm test && npm run harness:generated && npm run harness:test && npm run harness-ui:test && npm run harness-studio:test && npm run pack:verify", + "harness:build": "npm run build -w @qoder-ai/harness", + "harness:generated": "npm run check:generated -w @qoder-ai/harness", + "harness:test": "npm test -w @qoder-ai/harness", + "harness-ui:build": "npm run build -w @qoder-ai/harness-ui", + "harness-ui:test": "npm test -w @qoder-ai/harness-ui", + "harness-studio:build": "npm run build -w @qoder-ai/harness-studio", + "harness-studio:test": "npm test -w @qoder-ai/harness-studio", + "harness-studio:test:browser": "npm run test:browser -w @qoder-ai/harness-studio", "inspector": "node scripts/harness-inspector/cli.mjs render", "inspector:open": "node scripts/harness-inspector/cli.mjs render --open", "pack:verify": "node scripts/npm-package/verify-pack.mjs", diff --git a/packages/harness-studio/LICENSE b/packages/harness-studio/LICENSE new file mode 100644 index 0000000..e5b5c28 --- /dev/null +++ b/packages/harness-studio/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Qoder + +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/harness-studio/README.md b/packages/harness-studio/README.md new file mode 100644 index 0000000..426e952 --- /dev/null +++ b/packages/harness-studio/README.md @@ -0,0 +1,106 @@ +# @qoder-ai/harness-studio + +A local React control plane for [`@qoder-ai/harness`](../harness/README.md): +durable Harness objects organize the evidence, inspection, live-run, and +experiment surfaces the Harness toolchain produces. + +- **Harness control plane** — organizes work as `Overview`, `Inspector`, + `Harnesses`, `Task Suites`, `Experiments`, and `Registry`. Unimplemented + source, suite, and promotion capabilities stay visibly marked as foundations + instead of appearing as working controls. + +- **Inspector workspace** — embeds an explicitly supplied, self-contained + Harness Inspector report behind a sandboxed, read-only document boundary. + +- **Run view** — drives a live harness run over the AG-UI protocol served by + [`@qoder-ai/harness-ui`](../harness-ui/README.md) (embedded under `/agui`), + rendering streamed assistant messages, warnings, and workbench-style + expandable tool cards with arguments, retained results, execution state, + failed/result-unavailable states, bounded-result truncation evidence, and the + final run result. +- **Compare view** — loads a `harness-compare.v1` evidence directory and + renders the frozen `verdict.json`: per-variant pass rate, mean score, cost, + and per-trial outcomes. + +The existing static outputs (the zero-dependency harness inspector HTML and +the compare `verdict.html`) stay authoritative and offline-friendly; the +studio reads the same evidence and adds interactivity on top. + +## Usage + +```sh +# Inspector evidence only +npx @qoder-ai/harness-studio --inspector ./harness-inspector.html + +# Compare evidence only +npx @qoder-ai/harness-studio --evidence ./harness-readme-compare-evidence + +# Live runs only +npx @qoder-ai/harness-studio --harness my-agent.harness + +# Combined control plane on one port +npx @qoder-ai/harness-studio \ + --inspector ./harness-inspector.html \ + --harness my-agent.harness \ + --evidence ./evidence + +# Discover project history, resolve a checkpoint, and lock it before Run +npx @qoder-ai/harness-studio \ + --experiment ./experiment.json \ + --history-catalog ./checkpoint-history.json \ + --experiment-locks ./.harness-studio-locks +``` + +Then open the printed URL (default `http://127.0.0.1:3311`). The server binds +to loopback; live runs execute through the same v0.2 executors and redaction +rules as the core package. The embedded run endpoint accepts same-origin JSON +browser requests only; use the standalone `@qoder-ai/harness-ui` server with +an explicit `--allow-origin` when the frontend is hosted on another origin. + +A `source`-backed skill is locked and read from `--source-root`, which +defaults to the directory containing `--harness`. Pass it explicitly when the +harness's skills live somewhere else. + +The optional `checkpoint-history.v1` catalog is the first file-backed history +adapter. Studio exposes only opaque item ids and display projections to the +browser. Resolving an item verifies its checkpoint, prompt, and trajectory but +does not create a worktree or sandbox. `Lock selected history` writes a +content-addressed experiment definition and makes it active only after the +existing experiment loader accepts it; isolated lane copies are still created +only by Run. Other providers, including versioned document or presentation +systems, can inject the same server adapter interface without adopting the +catalog's storage format. + +## Architecture + +```text +dist/app/ esbuild-bundled React app (index.html + assets/app.js) +src/app/ components plus pure state modules: + agui-store.ts AG-UI event → run view state reducer + compare-model.ts verdict.json → table model + sse-client.ts incremental SSE frame parser + studio-shell-model.ts + config → IA/readiness projection +src/server/ static host + /api/config + /api/evidence + embedded /agui + read-only /inspector + checkpoint history list/resolve + + durable experiment lock +``` + +The pure modules are the tested seam; the React components are direct renders +of their outputs. + +## Development + +```sh +npm run harness-studio:build # tsc + esbuild-wasm bundle +npm run harness-studio:test +npm run harness-studio:test:browser # built-app Playwright interaction +``` + +Publication is repository-owned: select `harness-studio` in the protected +GitHub Actions `Publish npm` workflow. Local commands only build, test, pack, +or dry-run; do not publish this workspace from a developer machine. + +See the spec: +[Harness UI and Studio](https://github.com/QoderAI/better-harness/blob/main/docs/specs/2026-08-15-harness-ui-studio.md) +and [Harness Studio information architecture](../../docs/specs/2026-08-18-harness-studio-information-architecture.md). diff --git a/packages/harness-studio/package.json b/packages/harness-studio/package.json new file mode 100644 index 0000000..8126f6b --- /dev/null +++ b/packages/harness-studio/package.json @@ -0,0 +1,65 @@ +{ + "name": "@qoder-ai/harness-studio", + "version": "0.1.0", + "description": "React studio for @qoder-ai/harness: live AG-UI run view plus harness-compare evidence explorer.", + "license": "MIT", + "type": "module", + "engines": { + "node": ">=22.20.0 <25.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/QoderAI/better-harness.git", + "directory": "packages/harness-studio" + }, + "homepage": "https://github.com/QoderAI/better-harness/tree/main/packages/harness-studio#readme", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "bin": { + "harness-studio": "./dist/server/cli.js" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "files": [ + "dist/", + "README.md", + "LICENSE" + ], + "scripts": { + "build": "npm run clean && tsc && node scripts/build-app.mjs", + "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"", + "prepack": "npm test", + "pretest": "npm run build", + "test": "vitest run", + "test:browser": "playwright test", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@phosphor-icons/react": "^2.1.10", + "@pierre/diffs": "^1.3.5", + "@qoder-ai/harness": "0.1.0", + "@qoder-ai/harness-ui": "0.1.0", + "@shikijs/core": "^4.4.3", + "@shikijs/engine-javascript": "^4.4.3", + "@shikijs/langs": "^4.4.3", + "@tanstack/react-virtual": "^3.14.9", + "react": "19.2.8", + "react-dom": "19.2.8" + }, + "devDependencies": { + "@playwright/test": "^1.62.1", + "@types/node": "26.2.0", + "@types/react": "19.2.18", + "@types/react-dom": "19.2.4", + "esbuild-wasm": "0.28.1", + "typescript": "7.0.2", + "vitest": "4.1.10" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/harness-studio/playwright.config.mjs b/packages/harness-studio/playwright.config.mjs new file mode 100644 index 0000000..f546f22 --- /dev/null +++ b/packages/harness-studio/playwright.config.mjs @@ -0,0 +1,15 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: "./test/browser", + timeout: 30_000, + fullyParallel: false, + workers: 1, + reporter: "list", + use: { + browserName: "chromium", + headless: true, + viewport: { width: 390, height: 844 }, + screenshot: "only-on-failure", + }, +}); diff --git a/packages/harness-studio/scripts/build-app.mjs b/packages/harness-studio/scripts/build-app.mjs new file mode 100644 index 0000000..e6b296e --- /dev/null +++ b/packages/harness-studio/scripts/build-app.mjs @@ -0,0 +1,29 @@ +// Bundle the React app with the repo-conventional esbuild-wasm toolchain. +import { copyFile, mkdir } from "node:fs/promises"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { build } from "esbuild-wasm"; + +const packageRoot = join(dirname(fileURLToPath(import.meta.url)), ".."); +const appDir = join(packageRoot, "dist", "app"); + +await mkdir(join(appDir, "assets"), { recursive: true }); +await build({ + entryPoints: { app: join(packageRoot, "src", "app", "main.tsx") }, + outdir: join(appDir, "assets"), + entryNames: "[name]", + chunkNames: "chunks/[name]-[hash]", + bundle: true, + splitting: true, + format: "esm", + platform: "browser", + target: "es2022", + jsx: "automatic", + minify: true, + sourcemap: true, + define: { "process.env.NODE_ENV": '"production"' }, + logLevel: "warning", +}); +await copyFile(join(packageRoot, "src", "app", "index.html"), join(appDir, "index.html")); +process.stdout.write(`Built studio app into ${appDir}\n`); +process.exit(0); diff --git a/packages/harness-studio/src/app/App.tsx b/packages/harness-studio/src/app/App.tsx new file mode 100644 index 0000000..1e8dd36 --- /dev/null +++ b/packages/harness-studio/src/app/App.tsx @@ -0,0 +1,320 @@ +import { useEffect, useRef, useState, type ReactNode } from "react"; +import type { Icon } from "@phosphor-icons/react"; +import { ArrowRight } from "@phosphor-icons/react/ArrowRight"; +import { Binoculars } from "@phosphor-icons/react/Binoculars"; +import { Database } from "@phosphor-icons/react/Database"; +import { Flask } from "@phosphor-icons/react/Flask"; +import { GitBranch } from "@phosphor-icons/react/GitBranch"; +import { ListChecks } from "@phosphor-icons/react/ListChecks"; +import { SidebarSimple } from "@phosphor-icons/react/SidebarSimple"; +import { SquaresFour } from "@phosphor-icons/react/SquaresFour"; +import { TreeStructure } from "@phosphor-icons/react/TreeStructure"; +import { CompareView } from "./CompareView.js"; +import { ExperimentView } from "./ExperimentView.js"; +import { RunView } from "./RunView.js"; +import { + capabilitySummary, + experimentSurfaces, + inspectorSurfaces, + studioDestinations, + type StudioArea, + type StudioConfig, + type StudioDestination, + type StudioExperimentSurface, +} from "./studio-shell-model.js"; + +const NAV_ICONS: Record = { + overview: SquaresFour, + inspector: Binoculars, + harnesses: TreeStructure, + "task-suites": ListChecks, + experiments: Flask, + registry: Database, +}; + +const AREA_COPY: Record = { + overview: { eyebrow: "Control", title: "Harness Control Center" }, + inspector: { eyebrow: "Observe", title: "Inspector" }, + harnesses: { eyebrow: "Compose", title: "Harnesses" }, + "task-suites": { eyebrow: "Compose", title: "Task Suites" }, + experiments: { eyebrow: "Validate", title: "Experiments · Harness Bench" }, + registry: { eyebrow: "Govern", title: "Registry" }, +}; + +const EMPTY_CONFIG: StudioConfig = { + aguiEnabled: false, + evidenceEnabled: false, + experimentEnabled: false, + historyEnabled: false, + inspectorEnabled: false, +}; + +export function App(): React.JSX.Element { + const [config, setConfig] = useState(undefined); + const [configFailure, setConfigFailure] = useState(null); + const [area, setArea] = useState(areaFromHash); + const [experimentSurface, setExperimentSurface] = useState("experiment"); + const [navigationOpen, setNavigationOpen] = useState(false); + const navigationToggleRef = useRef(null); + + useEffect(() => { + let cancelled = false; + void (async () => { + try { + const response = await fetch("api/config"); + if (!response.ok) throw new Error(`Studio config failed (${response.status}).`); + const loaded = { ...EMPTY_CONFIG, ...(await response.json() as Partial) }; + if (!cancelled) { + setConfigFailure(null); + setConfig(loaded); + setExperimentSurface(experimentSurfaces(loaded)[0] ?? "experiment"); + } + } catch (error) { + if (!cancelled) { + setConfigFailure(error instanceof Error ? error.message : "Studio configuration is unavailable."); + setConfig(EMPTY_CONFIG); + } + } + })(); + return () => { + cancelled = true; + }; + }, []); + + useEffect(() => { + const onHashChange = (): void => setArea(areaFromHash()); + globalThis.addEventListener("hashchange", onHashChange); + globalThis.addEventListener("popstate", onHashChange); + return () => { + globalThis.removeEventListener("hashchange", onHashChange); + globalThis.removeEventListener("popstate", onHashChange); + }; + }, []); + + useEffect(() => { + if (!navigationOpen) return undefined; + const focusFrame = globalThis.requestAnimationFrame(() => { + document.querySelector(".studio-primary-nav nav button")?.focus(); + }); + const onKeyDown = (event: KeyboardEvent): void => { + if (event.key !== "Escape") return; + setNavigationOpen(false); + navigationToggleRef.current?.focus(); + }; + globalThis.addEventListener("keydown", onKeyDown); + return () => { + globalThis.cancelAnimationFrame(focusFrame); + globalThis.removeEventListener("keydown", onKeyDown); + }; + }, [navigationOpen]); + + function openArea(next: StudioArea): void { + setArea(next); + setNavigationOpen(false); + if (area !== next) globalThis.history.pushState(null, "", `#/${next}`); + } + + if (config === undefined) { + return

Loading Harness control plane…

; + } + if (configFailure !== null) { + return
Cannot load Studio configuration.

{configFailure}

; + } + + const destinations = studioDestinations(config); + const current = destinations.find((destination) => destination.id === area) ?? destinations[0]!; + const experimentNavigation = ( + ({ + id, + label: id === "experiment" ? "Bench" : id === "live-run" ? "Live trial" : "Evidence results", + }))} + active={experimentSurface} + onSelect={setExperimentSurface} + /> + ); + const contextNavigation = area === "experiments" && experimentSurfaces(config).length > 1 + ? experimentNavigation + : null; + + return
+ + +
{AREA_COPY[area].eyebrow}

{AREA_COPY[area].title}

+ {contextNavigation &&
{contextNavigation}
} +
{current.status}Local control plane
+ +
+ {area === "overview" && } + {area === "inspector" && } + {area === "harnesses" && } + {area === "task-suites" && } + {area === "experiments" && } + {area === "registry" && } +
+ +
; +} + +function PrimaryNavigation(props: { + destinations: readonly StudioDestination[]; + current: StudioArea; + onSelect: (area: StudioArea) => void; +}): React.JSX.Element { + const groups = [...new Set(props.destinations.map((destination) => destination.group))]; + return ; +} + +function Overview(props: { config: StudioConfig; onOpen: (area: StudioArea) => void }): React.JSX.Element { + const summary = capabilitySummary(props.config); + const nextArea: StudioArea = props.config.experimentEnabled + ? "experiments" + : props.config.inspectorEnabled + ? "inspector" + : props.config.aguiEnabled || props.config.evidenceEnabled + ? "experiments" + : "harnesses"; + const inputs = [ + ["Inspector report", props.config.inspectorEnabled], + ["Harness runtime", props.config.aguiEnabled], + ["Experiment manifest", props.config.experimentEnabled], + ["Compare evidence", props.config.evidenceEnabled], + ["History adapter", props.config.historyEnabled], + ] as const; + const loop = [ + { step: "01", label: "Observe", detail: "Inspect retained delivery evidence", ready: props.config.inspectorEnabled }, + { step: "02", label: "Compose", detail: "Name the Harness change", ready: props.config.aguiEnabled || props.config.experimentEnabled }, + { step: "03", label: "Experiment", detail: "Hold task and runtime constant", ready: props.config.experimentEnabled }, + { step: "04", label: "Explain", detail: "Compare outcome and trace evidence", ready: props.config.experimentEnabled || props.config.evidenceEnabled }, + { step: "05", label: "Promote", detail: "Bind evidence to a team default", ready: false }, + ]; + return
+
+
Repository-native Harness Engineering

Change one Harness variable.
Prove it holds.

Observe real delivery, lock the Harness and runtime envelope, run a controlled comparison, then decide with evidence.

+ +
+ +
Operating model

Observe → Compose → Experiment → Explain → Promote

{summary.ready} ready · {summary.partial} partial · {summary.foundation} foundations
    {loop.map((item) =>
  1. {item.step}{item.label}

    {item.detail}

    {item.ready ? "Available" : "Contract first"}
  2. )}
+ +
+
Loaded inputs

Current workspace boundary

Server facts
    {inputs.map(([label, enabled]) =>
  • {label}{enabled ? "Connected" : "Not supplied"}
  • )}
+
Information architecture

Objects before pages

No invented state
Harnesses

Source, components, revisions, compatibility, materialization.

Task Suites

Tasks, checkpoints, graders, splits, replayability.

Experiments

Design, lock, run, analyze, evidence bundle.

Registry

Candidates, policies, revalidation, rollback.

+
+
; +} + +function InspectorWorkspace(props: { config: StudioConfig }): React.JSX.Element { + const available = inspectorSurfaces(props.config); + if (available.length === 0) { + return ; + } + if (props.config.inspectorEnabled) { + return
+
Inspector WorkbenchCross-delivery evidence · read-only

Capability / Date → Session → Commit / File

+