diff --git a/.agents/skills/orpc-server b/.agents/skills/orpc-server new file mode 120000 index 0000000..6eb7756 --- /dev/null +++ b/.agents/skills/orpc-server @@ -0,0 +1 @@ +../../.skills/orpc-server \ No newline at end of file diff --git a/.skills/agent-zero-architecture/SKILL.md b/.skills/agent-zero-architecture/SKILL.md index 5a423e2..311693f 100644 --- a/.skills/agent-zero-architecture/SKILL.md +++ b/.skills/agent-zero-architecture/SKILL.md @@ -16,6 +16,7 @@ Keep dependency direction explicit while changing the monorepo. - `runner`: command execution and checkout mutation boundary, plus the policy-to-boundary factory. - `agent`: orchestration, the lifecycle machine, and the validation policy. - `cli`: argument parsing and terminal presentation. +- `apps/server`: oRPC transport, task persistence, scheduling, and the composition root that constructs a runner. See the `orpc-server` skill. - `apps/dashboard`: frontend-only Nuxt operational dashboard with no runtime-package dependencies. ## Workflow diff --git a/.skills/orpc-server/SKILL.md b/.skills/orpc-server/SKILL.md new file mode 100644 index 0000000..2e45cd3 --- /dev/null +++ b/.skills/orpc-server/SKILL.md @@ -0,0 +1,32 @@ +--- +name: orpc-server +description: Use when changing apps/server procedures, oRPC contracts, handlers, middleware, transport setup, or typed clients. +--- + +# oRPC server + +`apps/server` is a transport adapter and composition root built with oRPC. + +## Rules + +- Keep procedure contracts and router composition in `apps/server/src/rpc.ts`, and the runtime + operations they delegate to in `apps/server/src/router.ts`. +- Keep Node HTTP startup in `apps/server/src/index.ts` and request routing in + `apps/server/src/http.ts`. +- Infer client types from the router; do not duplicate request or response interfaces. +- Validate inputs at the procedure boundary and return stable domain-shaped results. +- Procedures call the agent runtime through typed APIs. They do not execute shell commands or + mutate checkouts directly. +- Persist through the `KeyValueStorage` contract so Redis, KV, and Nitro drivers stay + interchangeable; never store review input or checkout paths. +- Keep transport-specific headers, status mapping, and request objects out of runtime packages. +- Do not introduce Hono, Nitro, or a second HTTP framework. + +## Workflow + +1. Read the router, its tests, and the runtime method being exposed. +2. Define or adjust the oRPC procedure contract. +3. Keep the handler thin: validate, authorize, delegate, translate. +4. Add router tests with `createRouterClient`, without opening a real network port. +5. Update the README client example when the public router shape changes. +6. Run `aube run test --filter @agent-zero/server`, typecheck, and build. diff --git a/AGENTS.md b/AGENTS.md index cc3f796..0bf38a1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,6 +28,7 @@ These instructions apply to humans and coding agents working in this repository. - `packages/config`: configuration parsing and policy. - `packages/shared`: stable cross-package contracts. - `packages/cli`: argument parsing and terminal presentation. +- `apps/server`: oRPC control-plane transport and composition root. - `apps/dashboard`: frontend-only Nuxt operational dashboard. The runtime must remain independent from HTTP, GitHub, terminal UI, and specific model providers. Adapters depend on the runtime; the runtime must not depend on adapters. diff --git a/README.md b/README.md index 0c79a62..8476baa 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ GitHub adapter / CLI ▼ Runner boundary ─── repository commands and file operations +oRPC control plane ─── typed task API, persistence, and scheduling Nuxt dashboard ─── frontend-only operational interface ``` @@ -56,6 +57,7 @@ Nuxt dashboard ─── frontend-only operational interface | [`packages/config`](./packages/config) | Configuration parsing and policy | | [`packages/shared`](./packages/shared) | Stable cross-package contracts | | [`packages/cli`](./packages/cli) | Argument parsing and terminal presentation | +| [`apps/server`](./apps/server) | oRPC control-plane transport and composition root | | [`apps/dashboard`](./apps/dashboard) | Frontend-only Nuxt operational dashboard | Adapters depend on the runtime; the runtime never depends on adapters. See [docs/architecture.md](./docs/architecture.md) for the full dependency rules. @@ -96,6 +98,40 @@ The CLI parses arguments with [`@bomb.sh/args`](https://github.com/bomb-sh/args) --- +## Control plane + +`aube --filter @agent-zero/server run dev` starts the control plane on `http://localhost:3001` (override with `PORT`; 3000 belongs to the dashboard). It is the only adapter that composes a runner for hosted work, and it exposes exactly two surfaces: + +| Surface | Purpose | +| -------------------- | ------------------------------------------------------------------------- | +| `/rpc/**` | Typed oRPC router: `health`, `tasks.list/get/create`, `approvals.decide` | +| `GET /api/dashboard` | One aggregate view: task history plus queue, approval, and usage counters | + +Reads are open for the dashboard; mutations (`tasks.create`, `approvals.decide`) fail closed. `AGENT_ZERO_CONTROL_PLANE_TOKENS` holds comma-separated `name:token` bearer credentials, and `AGENT_ZERO_CONTROL_PLANE_REPOSITORIES` allow-lists the repository paths `tasks.create` may target; without them every mutation is rejected. `AGENT_ZERO_CONTROL_PLANE_MODES` holds comma-separated `name:mode|mode` grants for the execution modes each principal may request; without a grant a principal may only request the non-writable `observe` and `suggest` modes, so `fix` and `autonomous` require an explicit operator grant. The approval actor is the authenticated principal's name, never a wire-supplied value. + +Clients infer their types from the router rather than redeclaring request and response shapes: + +```ts +import { createORPCClient } from '@orpc/client'; +import { RPCLink } from '@orpc/client/fetch'; +import type { RouterClient } from '@orpc/server'; +import type { RpcRouter } from '@agent-zero/server'; + +const client: RouterClient = createORPCClient( + new RPCLink({ + url: 'http://localhost:3001/rpc', + headers: { authorization: `Bearer ${process.env.CONTROL_PLANE_TOKEN}` }, + }), +); + +const { tasks } = await client.tasks.list(); +await client.approvals.decide({ taskId: tasks[0]!.id, decision: 'approved' }); +``` + +Task history persists through a `KeyValueStorage` contract — a filesystem store by default, with Redis, KV, or Nitro storage dropping in unchanged. Records are redacted before they are written and never contain review input or checkout paths. `TaskScheduler` bounds work globally and per repository, so a burst queues instead of fanning out unbounded runs. + +--- + ## Dashboard `aube run dev` starts the frontend-only Nuxt dashboard on `http://localhost:3000`. It is an operational interface shell: it does not expose API or RPC routes, persist task data, import runtime packages, or execute repository work. diff --git a/apps/server/package.json b/apps/server/package.json new file mode 100644 index 0000000..ef243fe --- /dev/null +++ b/apps/server/package.json @@ -0,0 +1,32 @@ +{ + "name": "@agent-zero/server", + "version": "0.3.0", + "type": "module", + "scripts": { + "build": "tsdown", + "clean": "tsc -b --clean", + "dev": "node --import tsx src/index.ts", + "lint": "oxlint --config ../../.oxlintrc.json --type-aware --type-check src shared", + "start": "node dist/index.js", + "test": "vitest run src", + "typecheck": "tsc --project tsconfig.json --pretty false --noEmit" + }, + "dependencies": { + "@agent-zero/agent": "workspace:*", + "@agent-zero/config": "workspace:*", + "@agent-zero/github": "workspace:*", + "@agent-zero/models": "workspace:*", + "@agent-zero/runner": "workspace:*", + "@agent-zero/shared": "workspace:*", + "@orpc/server": "2.0.0-beta.26", + "zod": "^4.1.5" + }, + "devDependencies": { + "oxlint": "^1.44.0", + "oxlint-tsgolint": "^7.0.2001", + "tsdown": "^0.22.14", + "tsx": "^4.20.5", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + } +} diff --git a/apps/server/shared/dashboard.ts b/apps/server/shared/dashboard.ts new file mode 100644 index 0000000..ca9a5c1 --- /dev/null +++ b/apps/server/shared/dashboard.ts @@ -0,0 +1,31 @@ +import type { TaskEvent, TaskResult } from '@agent-zero/shared'; + +export type ControlPlaneTaskStatus = 'queued' | 'running' | 'completed' | 'needs-human' | 'failed'; +export type ApprovalDecision = 'approved' | 'rejected'; + +export interface TaskApproval { + decision: ApprovalDecision; + actor: string; + comment: string | null; + decidedAt: string; +} + +export interface DashboardTask { + id: string; + repository: string; + status: ControlPlaneTaskStatus; + createdAt: string; + updatedAt: string; + events: TaskEvent[]; + result?: TaskResult; + approval?: TaskApproval; +} + +export interface DashboardOverview { + tasks: DashboardTask[]; + active: number; + queued: number; + awaitingApproval: number; + totalTokens: number; + costUsd: number; +} diff --git a/apps/server/src/auth.test.ts b/apps/server/src/auth.test.ts new file mode 100644 index 0000000..8577a7e --- /dev/null +++ b/apps/server/src/auth.test.ts @@ -0,0 +1,125 @@ +import { describe, expect, it } from 'vitest'; + +import { + accessFromEnvironment, + authenticate, + mayTargetRepository, + type ControlPlaneAccess, +} from './auth.js'; + +const TOKEN_FORMAT_ERROR = /name:token/; +const MODE_FORMAT_ERROR = /name:mode\|mode/; +const UNKNOWN_MODE_ERROR = /unknown mode/; +const UNKNOWN_PRINCIPAL_ERROR = /unknown principal/; + +function access(overrides: Partial = {}): ControlPlaneAccess { + return { + principals: new Map([ + ['token-value', { name: 'release-manager', modes: ['observe', 'suggest'] as const }], + ]), + repositories: ['/srv/checkout'], + ...overrides, + }; +} + +describe('accessFromEnvironment', () => { + it('fails closed when no tokens are configured', () => { + expect(accessFromEnvironment(undefined, '/srv/checkout')).toBeUndefined(); + expect(accessFromEnvironment('', '/srv/checkout')).toBeUndefined(); + expect(accessFromEnvironment(' , ', '/srv/checkout')).toBeUndefined(); + }); + + it('parses name:token pairs and the repository allow-list', () => { + const parsed = accessFromEnvironment('release-manager:tok1, ci:tok2', '/srv/app, ./checkout'); + expect(parsed?.principals.get('tok1')?.name).toBe('release-manager'); + expect(parsed?.principals.get('tok2')?.name).toBe('ci'); + expect(parsed?.repositories).toEqual(['/srv/app', './checkout']); + }); + + it('keeps tokens containing separators intact after the first colon', () => { + const parsed = accessFromEnvironment('ops:v1:secret'); + expect(parsed?.principals.get('v1:secret')?.name).toBe('ops'); + }); + + it('refuses malformed entries rather than silently dropping them', () => { + expect(() => accessFromEnvironment('missing-separator')).toThrow(TOKEN_FORMAT_ERROR); + expect(() => accessFromEnvironment(':token-only')).toThrow(TOKEN_FORMAT_ERROR); + expect(() => accessFromEnvironment('name-only:')).toThrow(TOKEN_FORMAT_ERROR); + }); + + it('defaults to an empty repository allow-list', () => { + expect(accessFromEnvironment('ops:tok', undefined)?.repositories).toEqual([]); + }); + + it('grants only the non-writable modes without an explicit mode entry', () => { + const parsed = accessFromEnvironment('ops:tok', undefined, undefined); + expect(parsed?.principals.get('tok')?.modes).toEqual(['observe', 'suggest']); + }); + + it('parses per-principal mode grants', () => { + const parsed = accessFromEnvironment( + 'release-manager:tok1, ci:tok2', + undefined, + 'release-manager:observe|fix|autonomous', + ); + expect(parsed?.principals.get('tok1')?.modes).toEqual(['observe', 'fix', 'autonomous']); + expect(parsed?.principals.get('tok2')?.modes).toEqual(['observe', 'suggest']); + }); + + it('refuses unknown modes rather than silently granting or dropping them', () => { + expect(() => accessFromEnvironment('ops:tok', undefined, 'ops:yolo')).toThrow( + UNKNOWN_MODE_ERROR, + ); + }); + + it('refuses mode grants for principals that hold no token', () => { + expect(() => accessFromEnvironment('ops:tok', undefined, 'ghost:fix')).toThrow( + UNKNOWN_PRINCIPAL_ERROR, + ); + }); + + it('refuses malformed mode entries', () => { + expect(() => accessFromEnvironment('ops:tok', undefined, 'ops')).toThrow(MODE_FORMAT_ERROR); + expect(() => accessFromEnvironment('ops:tok', undefined, 'ops:')).toThrow(MODE_FORMAT_ERROR); + expect(() => accessFromEnvironment('ops:tok', undefined, ':fix')).toThrow(MODE_FORMAT_ERROR); + expect(() => accessFromEnvironment('ops:tok', undefined, 'ops:|')).toThrow(MODE_FORMAT_ERROR); + }); +}); + +describe('authenticate', () => { + it('resolves the principal for a valid bearer token', () => { + expect(authenticate('Bearer token-value', access())).toEqual({ + name: 'release-manager', + modes: ['observe', 'suggest'], + }); + }); + + it('rejects missing, malformed, and unknown credentials', () => { + expect(authenticate(undefined, access())).toBeUndefined(); + expect(authenticate('token-value', access())).toBeUndefined(); + expect(authenticate('Basic token-value', access())).toBeUndefined(); + expect(authenticate('Bearer wrong-token', access())).toBeUndefined(); + expect(authenticate('Bearer token-valu', access())).toBeUndefined(); + }); + + it('fails closed when no access policy is configured', () => { + expect(authenticate('Bearer token-value', undefined)).toBeUndefined(); + }); +}); + +describe('mayTargetRepository', () => { + it('authorizes only allow-listed repository paths', () => { + expect(mayTargetRepository('/srv/checkout', access())).toBe(true); + expect(mayTargetRepository('/srv/other', access())).toBe(false); + }); + + it('compares resolved paths so traversal cannot dodge the allow-list', () => { + expect(mayTargetRepository('/srv/checkout/../checkout', access())).toBe(true); + expect(mayTargetRepository('/srv/checkout/../other', access())).toBe(false); + }); + + it('fails closed without a policy or with an empty allow-list', () => { + expect(mayTargetRepository('/srv/checkout', undefined)).toBe(false); + expect(mayTargetRepository('/srv/checkout', access({ repositories: [] }))).toBe(false); + }); +}); diff --git a/apps/server/src/auth.ts b/apps/server/src/auth.ts new file mode 100644 index 0000000..63ef5c4 --- /dev/null +++ b/apps/server/src/auth.ts @@ -0,0 +1,138 @@ +import { timingSafeEqual } from 'node:crypto'; +import { resolve } from 'node:path'; + +import type { RunMode } from '@agent-zero/shared'; + +/** An authenticated control-plane caller. Mutations record this identity, never a wire-supplied one. */ +export interface Principal { + name: string; + /** Execution modes this principal may request from `tasks.create`. */ + modes: readonly RunMode[]; +} + +/** + * Static access policy for the control-plane transport. + * + * Mutating procedures fail closed: without configured principals no mutation is accepted, and task + * creation additionally requires the target repository path to be allow-listed by the operator and + * the requested execution mode to be granted to the authenticated principal. + */ +export interface ControlPlaneAccess { + /** Bearer token to authenticated principal. */ + principals: ReadonlyMap; + /** Repository paths that `tasks.create` may target. */ + repositories: readonly string[]; +} + +const BEARER_PREFIX = 'Bearer '; + +const RUN_MODES: ReadonlySet = new Set([ + 'observe', + 'suggest', + 'fix', + 'autonomous', +] satisfies RunMode[]); + +/** Granted when a principal has no explicit mode entry; neither mode can produce a writable runner. */ +const DEFAULT_MODES: readonly RunMode[] = ['observe', 'suggest']; + +function isRunMode(value: string): value is RunMode { + return RUN_MODES.has(value); +} + +/** + * Parse the access policy from the environment. + * + * `AGENT_ZERO_CONTROL_PLANE_TOKENS` holds comma-separated `name:token` pairs, + * `AGENT_ZERO_CONTROL_PLANE_REPOSITORIES` holds comma-separated repository paths, and + * `AGENT_ZERO_CONTROL_PLANE_MODES` holds comma-separated `name:mode|mode` grants. Principals + * without a grant may only request the non-writable `observe` and `suggest` modes. Returns + * `undefined` when no tokens are configured, which keeps every mutation rejected. + */ +export function accessFromEnvironment( + tokens = process.env.AGENT_ZERO_CONTROL_PLANE_TOKENS, + repositories = process.env.AGENT_ZERO_CONTROL_PLANE_REPOSITORIES, + modes = process.env.AGENT_ZERO_CONTROL_PLANE_MODES, +): ControlPlaneAccess | undefined { + if (tokens === undefined || tokens.trim() === '') return undefined; + const grants = parseModeGrants(modes); + const principals = new Map(); + const names = new Set(); + for (const entry of tokens.split(',')) { + const trimmed = entry.trim(); + if (trimmed === '') continue; + const separator = trimmed.indexOf(':'); + const name = separator > 0 ? trimmed.slice(0, separator).trim() : ''; + const token = separator > 0 ? trimmed.slice(separator + 1).trim() : ''; + if (name === '' || token === '') + throw new Error('AGENT_ZERO_CONTROL_PLANE_TOKENS entries must be name:token pairs'); + names.add(name); + principals.set(token, { name, modes: grants.get(name) ?? DEFAULT_MODES }); + } + if (principals.size === 0) return undefined; + for (const name of grants.keys()) + if (!names.has(name)) + throw new Error( + `AGENT_ZERO_CONTROL_PLANE_MODES grants modes to an unknown principal: ${name}`, + ); + return { + principals, + repositories: (repositories ?? '') + .split(',') + .map((path) => path.trim()) + .filter((path) => path !== ''), + }; +} + +/** Parse `name:mode|mode` grants, refusing unknown modes rather than silently widening or narrowing. */ +function parseModeGrants(modes: string | undefined): Map { + const grants = new Map(); + if (modes === undefined || modes.trim() === '') return grants; + for (const entry of modes.split(',')) { + const trimmed = entry.trim(); + if (trimmed === '') continue; + const separator = trimmed.indexOf(':'); + const name = separator > 0 ? trimmed.slice(0, separator).trim() : ''; + const granted = separator > 0 ? trimmed.slice(separator + 1).trim() : ''; + if (name === '' || granted === '') + throw new Error('AGENT_ZERO_CONTROL_PLANE_MODES entries must be name:mode|mode pairs'); + const parsed: RunMode[] = []; + for (const candidate of granted.split('|')) { + const mode = candidate.trim(); + if (mode === '') continue; + if (!isRunMode(mode)) + throw new Error(`AGENT_ZERO_CONTROL_PLANE_MODES grants an unknown mode: ${mode}`); + parsed.push(mode); + } + if (parsed.length === 0) + throw new Error('AGENT_ZERO_CONTROL_PLANE_MODES entries must be name:mode|mode pairs'); + grants.set(name, parsed); + } + return grants; +} + +/** Resolve the principal for an `Authorization` header using constant-time token comparison. */ +export function authenticate( + authorization: string | undefined, + access: ControlPlaneAccess | undefined, +): Principal | undefined { + if (!access || authorization === undefined || !authorization.startsWith(BEARER_PREFIX)) + return undefined; + const presented = Buffer.from(authorization.slice(BEARER_PREFIX.length)); + for (const [token, principal] of access.principals) { + const expected = Buffer.from(token); + if (presented.length === expected.length && timingSafeEqual(presented, expected)) + return principal; + } + return undefined; +} + +/** Whether task creation may target this repository path. Fails closed without a policy. */ +export function mayTargetRepository( + repository: string, + access: ControlPlaneAccess | undefined, +): boolean { + if (!access) return false; + const target = resolve(repository); + return access.repositories.some((allowed) => resolve(allowed) === target); +} diff --git a/apps/server/src/control-plane.test.ts b/apps/server/src/control-plane.test.ts new file mode 100644 index 0000000..97d04ee --- /dev/null +++ b/apps/server/src/control-plane.test.ts @@ -0,0 +1,133 @@ +import { describe, expect, it } from 'vitest'; + +import { + MemoryTaskStore, + PersistentTaskStore, + TaskQueueQuotaError, + TaskScheduler, + type KeyValueStorage, + type StoredTask, +} from './control-plane.js'; + +function record(id: string, summary = 'safe'): StoredTask { + return { + id, + repository: 'acme/app', + status: 'queued', + createdAt: '2026-08-09T10:00:00.000Z', + updatedAt: '2026-08-09T10:00:00.000Z', + events: [], + ...(summary === 'safe' + ? {} + : { + approval: { + decision: 'approved' as const, + actor: 'operator', + comment: summary, + decidedAt: '2026-08-09T10:00:00.000Z', + }, + }), + }; +} + +class RecordingStorage implements KeyValueStorage { + readonly values = new Map(); + async getItem(key: string): Promise { + return this.values.get(key) ?? null; + } + async setItem(key: string, value: unknown): Promise { + this.values.set(key, value); + } + async getKeys(base = ''): Promise { + return [...this.values.keys()].filter((key) => key.startsWith(base)); + } +} + +describe('task persistence', () => { + it('round-trips structured history through a provider-neutral store', async () => { + const storage = new RecordingStorage(); + const store = new PersistentTaskStore(storage); + await store.save(record('az_1')); + await expect(store.get('az_1')).resolves.toMatchObject({ id: 'az_1', status: 'queued' }); + await expect(store.list()).resolves.toHaveLength(1); + }); + + it('redacts credentials before persistence', async () => { + const storage = new RecordingStorage(); + const store = new PersistentTaskStore(storage, ['provider-secret-value']); + await store.save(record('az_1', 'token=provider-secret-value')); + expect(JSON.stringify(storage.values.get('tasks:az_1'))).not.toContain('provider-secret-value'); + await expect(store.get('az_1')).resolves.toMatchObject({ + approval: { comment: 'token=[redacted]' }, + }); + }); + + it('keeps in-memory records isolated from caller mutation', async () => { + const store = new MemoryTaskStore(); + const task = record('az_1'); + await store.save(task); + task.status = 'failed'; + await expect(store.get('az_1')).resolves.toMatchObject({ status: 'queued' }); + }); +}); + +describe('TaskScheduler', () => { + it('enforces global and repository concurrency while draining FIFO work', async () => { + const scheduler = new TaskScheduler({ + maxConcurrent: 2, + maxQueued: 3, + maxConcurrentPerRepository: 1, + }); + const releases: Array<() => void> = []; + const work = (value: number) => + scheduler.schedule( + 'acme/app', + () => new Promise((resolve) => releases.push(() => resolve(value))), + ); + const first = work(1); + const second = work(2); + expect(scheduler.snapshot()).toEqual({ active: 1, queued: 1, capacity: 2 }); + releases.shift()?.(); + await expect(first).resolves.toBe(1); + await Promise.resolve(); + expect(scheduler.snapshot()).toMatchObject({ active: 1, queued: 0 }); + releases.shift()?.(); + await expect(second).resolves.toBe(2); + }); + + it('rejects work after the bounded queue is full', () => { + const scheduler = new TaskScheduler({ + maxConcurrent: 1, + maxQueued: 1, + maxConcurrentPerRepository: 1, + }); + void scheduler.schedule('one', () => new Promise(() => undefined)); + void scheduler.schedule('two', () => new Promise(() => undefined)); + expect(() => scheduler.schedule('three', async () => 3)).toThrow(TaskQueueQuotaError); + }); + + it('enforces the queue limit for repository-blocked work even with free global capacity', () => { + const scheduler = new TaskScheduler({ + maxConcurrent: 4, + maxQueued: 1, + maxConcurrentPerRepository: 1, + }); + void scheduler.schedule('acme/app', () => new Promise(() => undefined)); + void scheduler.schedule('acme/app', () => new Promise(() => undefined)); + expect(scheduler.snapshot()).toMatchObject({ active: 1, queued: 1 }); + expect(() => scheduler.schedule('acme/app', async () => 3)).toThrow(TaskQueueQuotaError); + expect(scheduler.snapshot()).toMatchObject({ active: 1, queued: 1 }); + }); + + it('still starts immediately runnable work while the queue holds only blocked jobs', async () => { + const scheduler = new TaskScheduler({ + maxConcurrent: 4, + maxQueued: 1, + maxConcurrentPerRepository: 1, + }); + void scheduler.schedule('acme/app', () => new Promise(() => undefined)); + void scheduler.schedule('acme/app', () => new Promise(() => undefined)); + await expect(scheduler.schedule('acme/site', async () => 'ran')).resolves.toBe('ran'); + expect(scheduler.snapshot()).toMatchObject({ queued: 1 }); + }); +}); diff --git a/apps/server/src/control-plane.ts b/apps/server/src/control-plane.ts new file mode 100644 index 0000000..2dd963b --- /dev/null +++ b/apps/server/src/control-plane.ts @@ -0,0 +1,216 @@ +import { + redactSecrets, + secretValuesFromEnvironment, + type EvidenceBundle, +} from '@agent-zero/shared'; + +import type { DashboardTask } from '../shared/dashboard.js'; + +export type { + ApprovalDecision, + ControlPlaneTaskStatus, + TaskApproval, +} from '../shared/dashboard.js'; + +/** Durable, deliberately narrow task history. Review input and checkout paths are never stored. */ +export interface StoredTask extends DashboardTask { + evidence?: EvidenceBundle; +} + +export interface TaskStore { + get(id: string): Promise; + list(): Promise; + save(task: StoredTask): Promise; + clear?(): Promise; +} + +/** Minimal surface shared by Nitro storage, Redis/KV drivers, and deterministic test stores. */ +export interface KeyValueStorage { + getItem(key: string): Promise; + setItem(key: string, value: unknown): Promise; + getKeys(base?: string): Promise; + removeItem?(key: string): Promise; +} + +const TASK_PREFIX = 'tasks:'; + +/** Persists redacted records through Nitro's provider-neutral storage layer. */ +export class PersistentTaskStore implements TaskStore { + constructor( + private readonly storage: KeyValueStorage, + private readonly secrets: readonly string[] = secretValuesFromEnvironment(), + ) {} + + async get(id: string): Promise { + const value = await this.storage.getItem(`${TASK_PREFIX}${id}`); + return isStoredTask(value) ? value : undefined; + } + + async list(): Promise { + const keys = await this.storage.getKeys(TASK_PREFIX); + const records = await Promise.all(keys.map((key) => this.storage.getItem(key))); + return records + .filter(isStoredTask) + .toSorted((left, right) => right.createdAt.localeCompare(left.createdAt)); + } + + async save(task: StoredTask): Promise { + await this.storage.setItem(`${TASK_PREFIX}${task.id}`, sanitizeTask(task, this.secrets)); + } +} + +/** In-memory adapter used by embedded callers and tests; production Nitro routes use storage. */ +export class MemoryTaskStore implements TaskStore { + readonly records = new Map(); + + async get(id: string): Promise { + const value = this.records.get(id); + return value ? structuredClone(value) : undefined; + } + + async list(): Promise { + return Array.from(this.records.values(), (task) => structuredClone(task)).toSorted( + (left, right) => right.createdAt.localeCompare(left.createdAt), + ); + } + + async save(task: StoredTask): Promise { + this.records.set(task.id, sanitizeTask(task, secretValuesFromEnvironment())); + } + + async clear(): Promise { + this.records.clear(); + } +} + +export interface SchedulerOptions { + maxConcurrent: number; + maxQueued: number; + maxConcurrentPerRepository: number; +} + +export interface SchedulerSnapshot { + active: number; + queued: number; + capacity: number; +} + +export class TaskQueueQuotaError extends Error { + constructor(message: string) { + super(message); + this.name = 'TaskQueueQuotaError'; + } +} + +interface QueuedJob { + repository: string; + start: () => Promise; +} + +/** Bounded FIFO scheduler with a separate per-repository fairness quota. */ +export class TaskScheduler { + private active = 0; + private readonly activeByRepository = new Map(); + private readonly queue: QueuedJob[] = []; + + constructor(private readonly options: SchedulerOptions) { + assertPositiveInteger(options.maxConcurrent, 'maxConcurrent'); + assertPositiveInteger(options.maxQueued, 'maxQueued'); + assertPositiveInteger(options.maxConcurrentPerRepository, 'maxConcurrentPerRepository'); + } + + schedule(repository: string, run: () => Promise): Promise { + if (this.queue.length >= this.options.maxQueued && !this.hasImmediateCapacity(repository)) + throw new TaskQueueQuotaError('Task queue capacity is exhausted'); + return new Promise((resolve, reject) => { + this.queue.push({ + repository, + start: async () => { + try { + resolve(await run()); + } catch (error) { + reject(error); + } + }, + }); + this.drain(); + }); + } + + snapshot(): SchedulerSnapshot { + return { + active: this.active, + queued: this.queue.length, + capacity: this.options.maxConcurrent, + }; + } + + /** + * Whether a new job for this repository would start synchronously in {@link drain}. + * + * Only jobs without immediate capacity occupy the queue, so `maxQueued` must bound exactly those: + * a job blocked by its repository quota counts against the queue even while global capacity is + * free, otherwise per-repository-blocked submissions could grow the queue without limit. + */ + private hasImmediateCapacity(repository: string): boolean { + return ( + this.active < this.options.maxConcurrent && + (this.activeByRepository.get(repository) ?? 0) < this.options.maxConcurrentPerRepository + ); + } + + private drain(): void { + while (this.active < this.options.maxConcurrent) { + const index = this.queue.findIndex( + (job) => + (this.activeByRepository.get(job.repository) ?? 0) < + this.options.maxConcurrentPerRepository, + ); + if (index < 0) return; + const [job] = this.queue.splice(index, 1); + if (!job) return; + this.active += 1; + this.activeByRepository.set( + job.repository, + (this.activeByRepository.get(job.repository) ?? 0) + 1, + ); + void job.start().finally(() => { + this.active -= 1; + const repositoryActive = (this.activeByRepository.get(job.repository) ?? 1) - 1; + if (repositoryActive === 0) this.activeByRepository.delete(job.repository); + else this.activeByRepository.set(job.repository, repositoryActive); + this.drain(); + }); + } + } +} + +function sanitizeTask(task: StoredTask, secrets: readonly string[]): StoredTask { + const serialized = JSON.stringify(task, (_key, value: unknown) => + typeof value === 'string' ? redactSecrets(value, secrets) : value, + ); + const value: unknown = JSON.parse(serialized); + if (!isStoredTask(value)) throw new Error('Refusing to persist an invalid task record'); + return value; +} + +function isStoredTask(value: unknown): value is StoredTask { + if (!isRecord(value)) return false; + const task = value; + return ( + typeof task.id === 'string' && + typeof task.repository === 'string' && + typeof task.status === 'string' && + typeof task.createdAt === 'string' && + typeof task.updatedAt === 'string' && + Array.isArray(task.events) + ); +} + +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +function assertPositiveInteger(value: number, name: string): void { + if (!Number.isInteger(value) || value < 1) throw new Error(`${name} must be a positive integer`); +} diff --git a/apps/server/src/dashboard.test.ts b/apps/server/src/dashboard.test.ts new file mode 100644 index 0000000..71f1faf --- /dev/null +++ b/apps/server/src/dashboard.test.ts @@ -0,0 +1,90 @@ +import type { TaskResult } from '@agent-zero/shared'; +import { describe, expect, it } from 'vitest'; + +import type { StoredTask } from './control-plane.js'; +import { dashboardOverview } from './dashboard.js'; + +const TIMESTAMP = '2026-08-09T10:00:00.000Z'; + +function task(id: string, overrides: Partial = {}): StoredTask { + return { + id, + repository: 'acme/app', + status: 'queued', + createdAt: TIMESTAMP, + updatedAt: TIMESTAMP, + events: [], + ...overrides, + }; +} + +function finished(totalTokens: number, costUsd: number): TaskResult { + return { + id: 'az_run', + state: 'completed', + verdict: 'accepted', + verified: true, + finding: null, + plan: [], + checks: [], + changedFiles: [], + attempts: 1, + events: [], + usage: { + modelCalls: 1, + inputTokens: 0, + outputTokens: 0, + totalTokens, + latencyMs: 0, + costUsd, + models: {}, + }, + runner: { kind: 'local', isolated: false, writable: false, network: 'none' }, + summary: 'done', + }; +} + +describe('dashboardOverview', () => { + it('reports an empty control plane without inventing counters', () => { + expect(dashboardOverview([])).toEqual({ + tasks: [], + active: 0, + queued: 0, + awaitingApproval: 0, + totalTokens: 0, + costUsd: 0, + }); + }); + + it('counts queued and running work separately', () => { + const overview = dashboardOverview([ + task('az_1'), + task('az_2', { status: 'running' }), + task('az_3', { status: 'completed' }), + ]); + expect(overview).toMatchObject({ queued: 1, active: 1 }); + }); + + it('counts only undecided human reviews as awaiting approval', () => { + const decided = task('az_2', { + status: 'needs-human', + approval: { + decision: 'approved', + actor: 'operator', + comment: null, + decidedAt: TIMESTAMP, + }, + }); + const overview = dashboardOverview([task('az_1', { status: 'needs-human' }), decided]); + expect(overview.awaitingApproval).toBe(1); + }); + + it('totals usage across finished runs and ignores runs that never reported any', () => { + const overview = dashboardOverview([ + task('az_1', { status: 'completed', result: finished(100, 0.25) }), + task('az_2', { status: 'completed', result: finished(50, 0.5) }), + task('az_3'), + ]); + expect(overview).toMatchObject({ totalTokens: 150, costUsd: 0.75 }); + }); +}); diff --git a/apps/server/src/dashboard.ts b/apps/server/src/dashboard.ts new file mode 100644 index 0000000..d3e5484 --- /dev/null +++ b/apps/server/src/dashboard.ts @@ -0,0 +1,17 @@ +import type { DashboardOverview } from '../shared/dashboard.js'; +import type { StoredTask } from './control-plane.js'; + +export type { DashboardOverview } from '../shared/dashboard.js'; + +export function dashboardOverview(tasks: StoredTask[]): DashboardOverview { + return { + tasks, + active: tasks.filter((task) => task.status === 'running').length, + queued: tasks.filter((task) => task.status === 'queued').length, + awaitingApproval: tasks.filter( + (task) => task.status === 'needs-human' && task.approval === undefined, + ).length, + totalTokens: tasks.reduce((total, task) => total + (task.result?.usage.totalTokens ?? 0), 0), + costUsd: tasks.reduce((total, task) => total + (task.result?.usage.costUsd ?? 0), 0), + }; +} diff --git a/apps/server/src/http.ts b/apps/server/src/http.ts new file mode 100644 index 0000000..234fd4d --- /dev/null +++ b/apps/server/src/http.ts @@ -0,0 +1,97 @@ +import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'; + +import { redactSecrets } from '@agent-zero/shared'; +import { RPCHandler } from '@orpc/server/node'; + +import { + accessFromEnvironment, + authenticate, + mayTargetRepository, + type ControlPlaneAccess, +} from './auth.js'; +import { PersistentTaskStore, type TaskStore } from './control-plane.js'; +import { dashboardOverview } from './dashboard.js'; +import { rpcRouter, type RpcContext } from './rpc.js'; +import { FileKeyValueStorage } from './storage.js'; + +const RPC_PREFIX = '/rpc'; +const DASHBOARD_PATH = '/api/dashboard'; +const DEFAULT_DATA_DIRECTORY = './.data/agent-zero'; + +export interface ControlPlaneOptions { + /** Defaults to a filesystem store; Redis, KV, or Nitro storage drop in unchanged. */ + store?: TaskStore; + dataDirectory?: string; + /** Access policy for mutating procedures; defaults to the environment and fails closed when unset. */ + access?: ControlPlaneAccess; +} + +/** + * Build the control-plane HTTP surface. + * + * The transport only validates, delegates, and serialises. It holds no runner and no checkout, so + * an HTTP client cannot reach a repository except through the procedures in {@link rpcRouter}, + * which run behind the runner boundary. + */ +export function createControlPlane(options: ControlPlaneOptions = {}): Server { + const store = + options.store ?? + new PersistentTaskStore( + new FileKeyValueStorage(options.dataDirectory ?? DEFAULT_DATA_DIRECTORY), + ); + const access = options.access ?? accessFromEnvironment(); + const handler = new RPCHandler(rpcRouter); + + return createServer((request, response) => { + void route(request, response, handler, store, access).catch((error: unknown) => { + respond(response, 500, { error: redactSecrets(messageOf(error)) }); + }); + }); +} + +/** Start the control plane and resolve once it is accepting connections. */ +export async function startControlPlane( + port: number, + options: ControlPlaneOptions = {}, +): Promise { + const server = createControlPlane(options); + await new Promise((resolve) => server.listen(port, resolve)); + return server; +} + +async function route( + request: IncomingMessage, + response: ServerResponse, + handler: RPCHandler, + store: TaskStore, + access: ControlPlaneAccess | undefined, +): Promise { + const principal = authenticate(request.headers.authorization, access); + const context: RpcContext = { + store, + ...(principal ? { principal } : {}), + mayTargetRepository: (repository) => mayTargetRepository(repository, access), + }; + const { matched } = await handler.handle(request, response, { + prefix: RPC_PREFIX, + context, + }); + if (matched) return; + + const path = (request.url ?? '/').split('?')[0]; + if (path === DASHBOARD_PATH && request.method === 'GET') { + respond(response, 200, dashboardOverview(await store.list())); + return; + } + respond(response, 404, { error: 'Not found' }); +} + +function respond(response: ServerResponse, status: number, body: unknown): void { + if (response.writableEnded) return; + response.writeHead(status, { 'content-type': 'application/json' }); + response.end(JSON.stringify(body)); +} + +function messageOf(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} diff --git a/apps/server/src/index.test.ts b/apps/server/src/index.test.ts new file mode 100644 index 0000000..a1ffeca --- /dev/null +++ b/apps/server/src/index.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest'; + +import { portFromEnvironment } from './index.js'; + +const PORT_ERROR = /PORT must be an integer/; + +describe('portFromEnvironment', () => { + it('falls back to the dashboard-free default when PORT is unset', () => { + expect(portFromEnvironment(undefined)).toBe(3001); + expect(portFromEnvironment('')).toBe(3001); + }); + + it('accepts an explicit port, including the ephemeral 0', () => { + expect(portFromEnvironment('8080')).toBe(8080); + expect(portFromEnvironment('0')).toBe(0); + }); + + it('refuses a malformed port rather than silently listening on the default', () => { + expect(() => portFromEnvironment('http')).toThrow(PORT_ERROR); + expect(() => portFromEnvironment('8080.5')).toThrow(PORT_ERROR); + expect(() => portFromEnvironment('-1')).toThrow(PORT_ERROR); + expect(() => portFromEnvironment('70000')).toThrow(PORT_ERROR); + }); +}); diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts new file mode 100644 index 0000000..db7dee7 --- /dev/null +++ b/apps/server/src/index.ts @@ -0,0 +1,66 @@ +export { + createTask, + decideApproval, + getStoredTask, + getTask, + getTaskEvidence, + githubTokenFromEnvironment, + health, + ingestWebhook, + listTasks, + publishEvidence, + runTask, + taskInput, + tasks, + type PublishOptions, + type RunTaskOptions, + type WebhookOptions, + type WebhookOutcome, + type WebhookRequest, +} from './router.js'; +export { + accessFromEnvironment, + authenticate, + mayTargetRepository, + type ControlPlaneAccess, + type Principal, +} from './auth.js'; +export { + MemoryTaskStore, + PersistentTaskStore, + TaskQueueQuotaError, + TaskScheduler, + type ApprovalDecision, + type ControlPlaneTaskStatus, + type KeyValueStorage, + type SchedulerOptions, + type SchedulerSnapshot, + type StoredTask, + type TaskApproval, + type TaskStore, +} from './control-plane.js'; +export { dashboardOverview, type DashboardOverview } from './dashboard.js'; +export { createControlPlane, startControlPlane, type ControlPlaneOptions } from './http.js'; +export { rpcRouter, type RpcContext, type RpcRouter } from './rpc.js'; +export { FileKeyValueStorage } from './storage.js'; + +import { startControlPlane } from './http.js'; + +// 3000 belongs to the Nuxt dashboard, so `aube run dev` can start both without a port collision. +const DEFAULT_PORT = 3001; + +/** Resolve the listen port, refusing a malformed value rather than silently picking a default. */ +export function portFromEnvironment(value = process.env.PORT): number { + if (value === undefined || value === '') return DEFAULT_PORT; + const port = Number(value); + if (!Number.isInteger(port) || port < 0 || port > 65_535) + throw new Error('PORT must be an integer between 0 and 65535'); + return port; +} + +// Importing the package must stay side-effect free; only direct execution starts a listener. +if (import.meta.main) { + const port = portFromEnvironment(); + await startControlPlane(port); + process.stdout.write(`Agent Zero control plane listening on port ${String(port)}\n`); +} diff --git a/apps/server/src/router.test.ts b/apps/server/src/router.test.ts new file mode 100644 index 0000000..9b775d3 --- /dev/null +++ b/apps/server/src/router.test.ts @@ -0,0 +1,314 @@ +import { createHmac } from 'node:crypto'; +import { mkdtemp, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { beforeEach, describe, expect, it } from 'vitest'; + +import { + decideApproval, + getStoredTask, + getTask, + getTaskEvidence, + health, + ingestWebhook, + listTasks, + publishEvidence, + runTask, + taskInput, + tasks, +} from './router.js'; + +const secret = 'webhook-secret-value'; +const MODE_ERROR = /mode/i; + +function sign(body: string): string { + return `sha256=${createHmac('sha256', secret).update(body).digest('hex')}`; +} + +function reviewPayload(overrides: Record = {}): string { + return JSON.stringify({ + action: 'submitted', + repository: { name: 'app', owner: { login: 'acme' } }, + pull_request: { + number: 7, + base: { sha: 'b'.repeat(40) }, + head: { sha: 'a'.repeat(40) }, + }, + review: { + id: 1, + body: 'load() can return null', + state: 'changes_requested', + user: { login: 'alice', type: 'User' }, + ...overrides, + }, + }); +} + +let checkout: string; + +beforeEach(async () => { + tasks.clear(); + checkout = await mkdtemp(join(tmpdir(), 'agent-zero-server-')); + await writeFile(join(checkout, 'package.json'), JSON.stringify({ scripts: {} }), 'utf8'); +}); + +describe('server task API', () => { + it('exposes health metadata for Nitro handlers', () => { + expect(health()).toMatchObject({ status: 'ok', service: 'agent-zero' }); + }); + + it('starts with an empty task collection', async () => { + await expect(listTasks()).resolves.toEqual({ tasks: [] }); + }); + + it('keeps task input validation independent from HTTP transport', () => { + expect( + taskInput.parse({ repository: '.', feedback: 'Check error handling', mode: 'observe' }), + ).toMatchObject({ repository: '.', mode: 'observe' }); + }); + + it('rejects an unknown mode at the transport edge', () => { + expect(() => taskInput.parse({ repository: '.', feedback: 'x', mode: 'yolo' })).toThrow( + MODE_ERROR, + ); + }); + + it('records a human approval only for a task awaiting review', async () => { + const timestamp = new Date(0).toISOString(); + tasks.set('az_approval', { + id: 'az_approval', + repository: 'acme/app', + status: 'needs-human', + createdAt: timestamp, + updatedAt: timestamp, + events: [], + }); + + await expect( + decideApproval('az_approval', 'approved', 'release-manager', 'Reviewed evidence'), + ).resolves.toMatchObject({ + status: 'needs-human', + approval: { + decision: 'approved', + actor: 'release-manager', + comment: 'Reviewed evidence', + }, + }); + await expect(getStoredTask('az_approval')).resolves.toMatchObject({ + approval: { decision: 'approved' }, + }); + }); +}); + +describe('runTask', () => { + it('stores the result and its evidence together', async () => { + const result = await runTask({ + repository: checkout, + feedback: 'load() is wrong', + mode: 'observe', + }); + await expect(getTask(result.id)).resolves.toEqual(result); + await expect(getTaskEvidence(result.id)).resolves.toContain('## Agent Zero'); + await expect(listTasks()).resolves.toMatchObject({ tasks: [expect.any(Object)] }); + }); + + it('produces a read-only boundary for an observe run', async () => { + const result = await runTask({ + repository: checkout, + feedback: 'load() is wrong', + mode: 'observe', + }); + expect(result.runner.writable).toBe(false); + expect(result.changedFiles).toEqual([]); + }); + + it('keeps the boundary read-only in fix mode while policy disables autofix', async () => { + const result = await runTask({ + repository: checkout, + feedback: 'load() is wrong', + mode: 'fix', + }); + expect(result.runner.writable).toBe(false); + }); + + it('reports an unverified conclusion when no model is configured', async () => { + const result = await runTask({ + repository: checkout, + feedback: 'load() is wrong', + mode: 'observe', + }); + expect(result.verified).toBe(false); + expect(result.verdict).toBe('rejected'); + }); +}); + +describe('ingestWebhook', () => { + const options = () => ({ secret, checkoutPath: checkout }); + + it('rejects a forged signature before parsing the payload', async () => { + const body = reviewPayload(); + await expect( + ingestWebhook( + { event: 'pull_request_review', body, signature: 'sha256=deadbeef' }, + options(), + ), + ).resolves.toEqual({ status: 'rejected', reason: 'Invalid webhook signature' }); + expect(tasks.size).toBe(0); + }); + + it('rejects a body that is not JSON', async () => { + const body = 'not json'; + const outcome = await ingestWebhook( + { event: 'pull_request_review', body, signature: sign(body) }, + options(), + ); + expect(outcome).toEqual({ status: 'rejected', reason: 'Webhook body is not valid JSON' }); + }); + + it('ignores an event that carries no claim to validate', async () => { + const body = reviewPayload({ state: 'approved' }); + const outcome = await ingestWebhook( + { event: 'pull_request_review', body, signature: sign(body) }, + options(), + ); + expect(outcome.status).toBe('ignored'); + expect(tasks.size).toBe(0); + }); + + it('ignores its own account so a run cannot answer itself', async () => { + const body = reviewPayload({ user: { login: 'agent-zero[bot]' } }); + const outcome = await ingestWebhook( + { event: 'pull_request_review', body, signature: sign(body) }, + { ...options(), ignoreAuthors: ['agent-zero[bot]'] }, + ); + expect(outcome.status).toBe('ignored'); + }); + + it('runs an authenticated review in observe mode and never writes', async () => { + const body = reviewPayload(); + const outcome = await ingestWebhook( + { event: 'pull_request_review', body, signature: sign(body) }, + options(), + ); + expect(outcome.status).toBe('accepted'); + if (outcome.status !== 'accepted') return; + expect(outcome.pullRequest).toEqual({ + owner: 'acme', + repo: 'app', + number: 7, + baseSha: 'b'.repeat(40), + headSha: 'a'.repeat(40), + }); + expect(outcome.result.runner.writable).toBe(false); + expect(outcome.result.changedFiles).toEqual([]); + expect(outcome.result.summary).toContain('github:acme/app#7'); + }); + + it('ignores proactive pull-request events until repository policy enables them', async () => { + const body = JSON.stringify({ + action: 'synchronize', + repository: { name: 'app', owner: { login: 'acme' } }, + pull_request: { + number: 7, + base: { sha: 'b'.repeat(40) }, + head: { sha: 'a'.repeat(40) }, + }, + }); + await expect( + ingestWebhook({ event: 'pull_request', body, signature: sign(body) }, options()), + ).resolves.toEqual({ + status: 'ignored', + reason: 'Proactive review is disabled by repository policy', + }); + }); + + it('runs an enabled proactive pull-request review in repository mode', async () => { + await writeFile( + join(checkout, '.agent-zero.yml'), + 'version: 1\nproactive:\n enabled: true\nmode: observe\n', + 'utf8', + ); + const body = JSON.stringify({ + action: 'opened', + repository: { name: 'app', owner: { login: 'acme' } }, + pull_request: { + number: 7, + base: { sha: 'b'.repeat(40) }, + head: { sha: 'a'.repeat(40) }, + }, + }); + const outcome = await ingestWebhook( + { event: 'pull_request', body, signature: sign(body) }, + options(), + ); + expect(outcome.status).toBe('accepted'); + if (outcome.status !== 'accepted') return; + expect(outcome.result.runner.writable).toBe(false); + await expect(getTaskEvidence(outcome.result.id)).resolves.toContain('proactive finding'); + }); +}); + +type FetchArguments = Parameters; + +function readBody(body: NonNullable['body']): Record { + if (typeof body !== 'string') return {}; + const parsed: unknown = JSON.parse(body); + return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) + ? { ...parsed } + : {}; +} + +/** Records what would have been sent to GitHub, so no test needs the network. */ +function recordingFetch(): { + fetch: typeof globalThis.fetch; + bodies: Record[]; +} { + const bodies: Record[] = []; + const fetch: typeof globalThis.fetch = async (_url, init) => { + bodies.push(readBody(init?.body)); + return new Response(JSON.stringify({ id: 99 }), { + status: 201, + headers: { 'content-type': 'application/json' }, + }); + }; + return { fetch, bodies }; +} + +describe('publishEvidence', () => { + const target = { + owner: 'acme', + repo: 'app', + number: 7, + baseSha: 'b'.repeat(40), + headSha: 'a'.repeat(40), + }; + + it('skips publishing rather than faking a check without a token', async () => { + const result = await runTask({ repository: checkout, feedback: 'x', mode: 'observe' }); + const { fetch, bodies } = recordingFetch(); + await expect(publishEvidence(target, result.id, { token: undefined, fetch })).resolves.toEqual({ + published: false, + reason: 'GITHUB_TOKEN is not configured', + }); + expect(bodies).toEqual([]); + }); + + it('reports an unknown task instead of publishing an empty report', async () => { + const { fetch, bodies } = recordingFetch(); + await expect( + publishEvidence(target, 'az_missing', { token: 'ghs_token_value', fetch }), + ).resolves.toMatchObject({ published: false }); + expect(bodies).toEqual([]); + }); + + it('publishes the stored evidence without claiming an unverified run passed', async () => { + const result = await runTask({ repository: checkout, feedback: 'x', mode: 'observe' }); + const { fetch, bodies } = recordingFetch(); + await expect( + publishEvidence(target, result.id, { token: 'ghs_token_value', fetch }), + ).resolves.toEqual({ published: true }); + expect(bodies[0]).toMatchObject({ head_sha: target.headSha, status: 'completed' }); + expect(bodies[0]?.conclusion).not.toBe('success'); + }); +}); diff --git a/apps/server/src/router.ts b/apps/server/src/router.ts new file mode 100644 index 0000000..2bd9b26 --- /dev/null +++ b/apps/server/src/router.ts @@ -0,0 +1,315 @@ +import { AgentZero } from '@agent-zero/agent'; +import { loadConfig, mayModifyRepository } from '@agent-zero/config'; +import { + GitHubChecks, + parseReviewEvent, + reviewInputFromEvent, + verifyWebhook, +} from '@agent-zero/github'; +import { modelFromEnvironment } from '@agent-zero/models'; +import { createRunner, runnerOptionsFromPolicy, type RunnerPool } from '@agent-zero/runner'; +import { + evidenceFromResult, + now, + redactSecrets, + renderEvidenceMarkdown, + secretValuesFromEnvironment, + taskId, + type PullRequestRef, + type ReviewInput, + type TaskResult, +} from '@agent-zero/shared'; +import { z } from 'zod'; + +import { + MemoryTaskStore, + TaskScheduler, + type ApprovalDecision, + type StoredTask, + type TaskStore, +} from './control-plane.js'; + +const TRAILING_SLASH = /\/$/u; + +const defaultStore = new MemoryTaskStore(); +const defaultScheduler = new TaskScheduler({ + maxConcurrent: 4, + maxQueued: 100, + maxConcurrentPerRepository: 1, +}); + +/** Backwards-compatible inspection hook for embedded callers and tests. */ +export const tasks = defaultStore.records; + +export const taskInput = z + .object({ + repository: z.string().min(1), + feedback: z.string().min(1).optional(), + trigger: z.enum(['feedback', 'proactive']).default('feedback'), + mode: z.enum(['observe', 'suggest', 'fix', 'autonomous']), + source: z.string().optional(), + files: z.array(z.string()).optional(), + }) + .superRefine((input, context) => { + if (input.trigger !== 'proactive' && input.feedback === undefined) + context.addIssue({ code: 'custom', path: ['feedback'], message: 'Feedback is required' }); + }); + +/** The actor is never accepted from the wire; the transport derives it from the authenticated principal. */ +export const approvalInput = z.object({ + taskId: z.string().min(1), + decision: z.enum(['approved', 'rejected']), + comment: z.string().max(2_000).optional(), +}); + +export function health() { + return { status: 'ok' as const, service: 'agent-zero', version: '0.3.0' }; +} + +export async function listTasks(store: TaskStore = defaultStore) { + return { tasks: await store.list() }; +} + +export async function getStoredTask( + id: string, + store: TaskStore = defaultStore, +): Promise { + return store.get(id); +} + +export async function getTask( + id: string, + store: TaskStore = defaultStore, +): Promise { + return (await store.get(id))?.result; +} + +/** The rendered evidence report for a finished run. */ +export async function getTaskEvidence( + id: string, + store: TaskStore = defaultStore, +): Promise { + const task = await store.get(id); + return task?.evidence ? renderEvidenceMarkdown(task.evidence) : undefined; +} + +export async function createTask( + input: z.infer, + store: TaskStore = defaultStore, + scheduler: TaskScheduler = defaultScheduler, +): Promise { + return runTask( + { + repository: input.repository, + mode: input.mode, + trigger: input.trigger, + ...(input.feedback ? { feedback: input.feedback } : {}), + ...(input.source ? { source: input.source } : {}), + ...(input.files ? { files: input.files } : {}), + }, + { store, scheduler }, + ); +} + +export interface RunTaskOptions { + store?: TaskStore; + scheduler?: TaskScheduler; + /** Optional hosted execution pool; its leases still expose only the Runner boundary. */ + runnerPool?: RunnerPool; +} + +/** + * Queue and run one unit of work, persisting its structured lifecycle and evidence. + * + * This composition root resolves policy and constructs the only execution boundary. Neither the + * transport, persistence adapter, scheduler, nor dashboard can execute repository commands. + */ +export async function runTask( + input: ReviewInput, + options: RunTaskOptions = {}, +): Promise { + const store = options.store ?? defaultStore; + const scheduler = options.scheduler ?? defaultScheduler; + const identifier = taskId(); + const timestamp = now(); + const record: StoredTask = { + id: identifier, + repository: repositoryLabel(input), + status: 'queued', + createdAt: timestamp, + updatedAt: timestamp, + events: [], + }; + await store.save(record); + + try { + return await scheduler.schedule(input.repository, async () => { + record.status = 'running'; + record.updatedAt = now(); + await store.save(record); + + const config = await loadConfig(input.repository); + let eventWrites = Promise.resolve(); + const writable = mayModifyRepository(config, input.mode); + const lease = options.runnerPool + ? await options.runnerPool.acquire({ + taskId: identifier, + repository: input.repository, + mode: input.mode, + writable, + network: config.permissions.network, + leaseMs: config.agent.timeoutMs, + }) + : undefined; + const runner = + lease?.runner ?? createRunner(input.repository, runnerOptionsFromPolicy(config, writable)); + const agent = new AgentZero({ + model: modelFromEnvironment(config.model), + runner, + config, + taskIdentifier: identifier, + onEvent: (event) => { + record.events.push(event); + record.updatedAt = event.timestamp; + eventWrites = eventWrites.then(() => store.save(record)); + }, + }); + let result: TaskResult; + try { + result = await agent.run(input); + } finally { + if (lease) await options.runnerPool?.release(lease.id); + } + await eventWrites; + record.status = result.state; + record.updatedAt = now(); + record.result = result; + record.evidence = evidenceFromResult(result, input); + await store.save(record); + return result; + }); + } catch (error) { + record.status = 'failed'; + record.updatedAt = now(); + record.events.push({ + state: 'failed', + message: redactSecrets(error instanceof Error ? error.message : String(error)), + timestamp: record.updatedAt, + }); + await store.save(record); + throw error; + } +} + +export async function decideApproval( + taskIdentifier: string, + decision: ApprovalDecision, + actor: string, + comment: string | undefined, + store: TaskStore = defaultStore, +): Promise { + const record = await store.get(taskIdentifier); + if (!record) throw new Error(`Unknown task: ${taskIdentifier}`); + if (record.status !== 'needs-human') + throw new Error('Only tasks awaiting human review can receive an approval decision'); + const timestamp = now(); + record.approval = { + decision, + actor: redactSecrets(actor, secretValuesFromEnvironment()), + comment: comment ? redactSecrets(comment, secretValuesFromEnvironment()) : null, + decidedAt: timestamp, + }; + record.updatedAt = timestamp; + await store.save(record); + return record; +} + +export interface WebhookRequest { + event: string; + body: string; + signature: string | undefined; +} + +export interface WebhookOptions { + secret: string; + checkoutPath: string; + ignoreAuthors?: readonly string[]; + store?: TaskStore; + scheduler?: TaskScheduler; +} + +export type WebhookOutcome = + | { status: 'rejected'; reason: string } + | { status: 'ignored'; reason: string } + | { status: 'accepted'; result: TaskResult; pullRequest: PullRequestRef }; + +export async function ingestWebhook( + request: WebhookRequest, + options: WebhookOptions, +): Promise { + if (!verifyWebhook(request.body, request.signature, options.secret)) + return { status: 'rejected', reason: 'Invalid webhook signature' }; + + let payload: unknown; + try { + payload = JSON.parse(request.body); + } catch { + return { status: 'rejected', reason: 'Webhook body is not valid JSON' }; + } + + const event = parseReviewEvent( + request.event, + payload, + options.ignoreAuthors ? { ignoreAuthors: options.ignoreAuthors } : {}, + ); + if (!event) return { status: 'ignored', reason: 'No actionable review feedback in this event' }; + + let mode: ReviewInput['mode'] = 'observe'; + if (event.trigger === 'proactive') { + const config = await loadConfig(options.checkoutPath); + if (!config.proactive.enabled) + return { status: 'ignored', reason: 'Proactive review is disabled by repository policy' }; + mode = config.mode; + } + + const runOptions: RunTaskOptions = { + ...(options.store ? { store: options.store } : {}), + ...(options.scheduler ? { scheduler: options.scheduler } : {}), + }; + const result = await runTask( + reviewInputFromEvent(event, { checkoutPath: options.checkoutPath, mode }), + runOptions, + ); + return { status: 'accepted', result, pullRequest: event.pullRequest }; +} + +export interface PublishOptions { + token: string | undefined; + fetch?: typeof globalThis.fetch; + store?: TaskStore; +} + +export function githubTokenFromEnvironment(): string | undefined { + return process.env.GITHUB_TOKEN; +} + +export async function publishEvidence( + target: PullRequestRef, + taskIdentifier: string, + options: PublishOptions, +): Promise<{ published: boolean; reason?: string }> { + if (!options.token) return { published: false, reason: 'GITHUB_TOKEN is not configured' }; + const task = await (options.store ?? defaultStore).get(taskIdentifier); + if (!task?.evidence) return { published: false, reason: `Unknown task: ${taskIdentifier}` }; + await new GitHubChecks({ + token: options.token, + ...(options.fetch ? { fetch: options.fetch } : {}), + }).publish(target, task.evidence); + return { published: true }; +} + +function repositoryLabel(input: ReviewInput): string { + if (input.pullRequest) return `${input.pullRequest.owner}/${input.pullRequest.repo}`; + const normalized = input.repository.replaceAll('\\', '/').replace(TRAILING_SLASH, ''); + return redactSecrets(normalized.split('/').at(-1) || 'repository'); +} diff --git a/apps/server/src/rpc.test.ts b/apps/server/src/rpc.test.ts new file mode 100644 index 0000000..82fa746 --- /dev/null +++ b/apps/server/src/rpc.test.ts @@ -0,0 +1,147 @@ +import { createRouterClient } from '@orpc/server'; +import { beforeEach, describe, expect, it } from 'vitest'; + +import type { Principal } from './auth.js'; +import { MemoryTaskStore, type StoredTask } from './control-plane.js'; +import { rpcRouter } from './rpc.js'; + +const TIMESTAMP = '2026-08-09T10:00:00.000Z'; +const VALIDATION_ERROR = /validation/i; +const APPROVAL_ERROR = /awaiting human review/i; +const UNAUTHORIZED_ERROR = /authentication required/i; +const FORBIDDEN_ERROR = /not allow-listed/i; +const MODE_ERROR = /not granted/i; + +let store: MemoryTaskStore; + +interface ClientOptions { + principal?: Principal; + allowRepository?: boolean; +} + +/** A server-side client exercises every procedure without opening a network port. */ +function client(options: ClientOptions = {}) { + return createRouterClient(rpcRouter, { + context: { + store, + ...(options.principal ? { principal: options.principal } : {}), + mayTargetRepository: () => options.allowRepository ?? false, + }, + }); +} + +function operator() { + return client({ + principal: { name: 'release-manager', modes: ['observe', 'suggest', 'fix', 'autonomous'] }, + allowRepository: true, + }); +} + +function awaiting(id: string): StoredTask { + return { + id, + repository: 'acme/app', + status: 'needs-human', + createdAt: TIMESTAMP, + updatedAt: TIMESTAMP, + events: [], + }; +} + +beforeEach(() => { + store = new MemoryTaskStore(); +}); + +describe('rpc router', () => { + it('reports health without touching the store', async () => { + await expect(client().health()).resolves.toMatchObject({ + status: 'ok', + service: 'agent-zero', + }); + }); + + it('reads task history through the injected store', async () => { + await store.save(awaiting('az_1')); + await expect(client().tasks.list()).resolves.toMatchObject({ + tasks: [{ id: 'az_1', status: 'needs-human' }], + }); + await expect(client().tasks.get({ id: 'az_1' })).resolves.toMatchObject({ id: 'az_1' }); + }); + + it('resolves an unknown task as absent rather than fabricating one', async () => { + await expect(client().tasks.get({ id: 'az_missing' })).resolves.toBeUndefined(); + }); + + it('rejects an unknown mode at the procedure boundary', async () => { + await expect( + // @ts-expect-error the schema is the contract under test + operator().tasks.create({ repository: '.', feedback: 'x', mode: 'yolo' }), + ).rejects.toThrow(VALIDATION_ERROR); + }); + + it('rejects an unauthenticated task submission before any work is created', async () => { + await expect( + client().tasks.create({ repository: '.', feedback: 'x', mode: 'autonomous' }), + ).rejects.toThrow(UNAUTHORIZED_ERROR); + await expect(store.list()).resolves.toEqual([]); + }); + + it('refuses task creation for a repository outside the allow-list', async () => { + await expect( + client({ principal: { name: 'release-manager', modes: ['autonomous'] } }).tasks.create({ + repository: '/etc', + feedback: 'x', + mode: 'autonomous', + }), + ).rejects.toThrow(FORBIDDEN_ERROR); + await expect(store.list()).resolves.toEqual([]); + }); + + it('refuses an execution mode outside the principal grant', async () => { + const readOnly = client({ + principal: { name: 'ci', modes: ['observe', 'suggest'] }, + allowRepository: true, + }); + await expect( + readOnly.tasks.create({ repository: '.', feedback: 'x', mode: 'fix' }), + ).rejects.toThrow(MODE_ERROR); + await expect( + readOnly.tasks.create({ repository: '.', feedback: 'x', mode: 'autonomous' }), + ).rejects.toThrow(MODE_ERROR); + await expect(store.list()).resolves.toEqual([]); + }); + + it('rejects an unauthenticated approval decision', async () => { + await store.save(awaiting('az_1')); + await expect( + client().approvals.decide({ taskId: 'az_1', decision: 'approved' }), + ).rejects.toThrow(UNAUTHORIZED_ERROR); + await expect(store.get('az_1')).resolves.toMatchObject({ status: 'needs-human' }); + }); + + it('records an approval attributed to the authenticated principal', async () => { + await store.save(awaiting('az_1')); + await expect( + operator().approvals.decide({ taskId: 'az_1', decision: 'approved' }), + ).resolves.toMatchObject({ approval: { decision: 'approved', actor: 'release-manager' } }); + }); + + it('ignores a wire-supplied actor in favour of the principal identity', async () => { + await store.save(awaiting('az_1')); + await expect( + operator().approvals.decide({ + taskId: 'az_1', + decision: 'approved', + // @ts-expect-error the schema no longer accepts an actor from the wire + actor: 'impostor', + }), + ).resolves.toMatchObject({ approval: { actor: 'release-manager' } }); + }); + + it('refuses an approval for a task that is not awaiting review', async () => { + await store.save({ ...awaiting('az_1'), status: 'completed' }); + await expect( + operator().approvals.decide({ taskId: 'az_1', decision: 'approved' }), + ).rejects.toThrow(APPROVAL_ERROR); + }); +}); diff --git a/apps/server/src/rpc.ts b/apps/server/src/rpc.ts new file mode 100644 index 0000000..77e5c8e --- /dev/null +++ b/apps/server/src/rpc.ts @@ -0,0 +1,67 @@ +import { ORPCError, os } from '@orpc/server'; +import { z } from 'zod'; + +import type { Principal } from './auth.js'; +import type { TaskStore } from './control-plane.js'; +import { + approvalInput, + createTask, + decideApproval, + getStoredTask, + health, + listTasks, + taskInput, +} from './router.js'; + +export interface RpcContext { + store: TaskStore; + /** Authenticated caller resolved by the transport; absent for anonymous requests. */ + principal?: Principal; + /** Whether `tasks.create` may target this repository. Fails closed when absent. */ + mayTargetRepository?: (repository: string) => boolean; +} + +const procedure = os.$context(); + +/** Mutations require an authenticated principal; reads stay open for the dashboard. */ +const authenticated = procedure.use(({ context, next }) => { + const principal = context.principal; + if (!principal) throw new ORPCError('UNAUTHORIZED', { message: 'Authentication required' }); + return next({ context: { principal } }); +}); + +export const rpcRouter = { + health: procedure.handler(() => health()), + tasks: { + list: procedure.handler(({ context }) => listTasks(context.store)), + get: procedure + .input(z.object({ id: z.string().min(1) })) + .handler(({ input, context }) => getStoredTask(input.id, context.store)), + create: authenticated.input(taskInput).handler(({ input, context }) => { + if (!context.mayTargetRepository?.(input.repository)) + throw new ORPCError('FORBIDDEN', { + message: 'Repository is not allow-listed for task creation', + }); + if (!context.principal.modes.includes(input.mode)) + throw new ORPCError('FORBIDDEN', { + message: `Execution mode '${input.mode}' is not granted to this principal`, + }); + return createTask(input, context.store); + }), + }, + approvals: { + decide: authenticated + .input(approvalInput) + .handler(({ input, context }) => + decideApproval( + input.taskId, + input.decision, + context.principal.name, + input.comment, + context.store, + ), + ), + }, +}; + +export type RpcRouter = typeof rpcRouter; diff --git a/apps/server/src/storage.test.ts b/apps/server/src/storage.test.ts new file mode 100644 index 0000000..f8b9cd3 --- /dev/null +++ b/apps/server/src/storage.test.ts @@ -0,0 +1,51 @@ +import { mkdtemp } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { beforeEach, describe, expect, it } from 'vitest'; + +import { FileKeyValueStorage } from './storage.js'; + +const UNSAFE_KEY = /unsafe key/i; + +let directory: string; + +beforeEach(async () => { + directory = await mkdtemp(join(tmpdir(), 'agent-zero-storage-')); +}); + +describe('FileKeyValueStorage', () => { + it('round-trips a namespaced record', async () => { + const storage = new FileKeyValueStorage(directory); + await storage.setItem('tasks:az_1', { id: 'az_1' }); + await expect(storage.getItem('tasks:az_1')).resolves.toEqual({ id: 'az_1' }); + await expect(storage.getKeys('tasks:')).resolves.toEqual(['tasks:az_1']); + }); + + it('reports a missing record as absent instead of throwing', async () => { + await expect( + new FileKeyValueStorage(directory).getItem('tasks:az_missing'), + ).resolves.toBeNull(); + }); + + it('lists no keys when the directory has never been written', async () => { + await expect( + new FileKeyValueStorage(join(directory, 'absent')).getKeys('tasks:'), + ).resolves.toEqual([]); + }); + + it('refuses a key that could address a path outside the store', async () => { + const storage = new FileKeyValueStorage(directory); + await expect(storage.setItem('../escape', {})).rejects.toThrow(UNSAFE_KEY); + await expect(storage.getItem('tasks:../../etc/passwd')).rejects.toThrow(UNSAFE_KEY); + await expect(storage.getKeys('tasks:')).resolves.toEqual([]); + }); + + it('removes a record without disturbing its siblings', async () => { + const storage = new FileKeyValueStorage(directory); + await storage.setItem('tasks:az_1', { id: 'az_1' }); + await storage.setItem('tasks:az_2', { id: 'az_2' }); + await storage.removeItem('tasks:az_1'); + await expect(storage.getKeys('tasks:')).resolves.toEqual(['tasks:az_2']); + }); +}); diff --git a/apps/server/src/storage.ts b/apps/server/src/storage.ts new file mode 100644 index 0000000..2c362a8 --- /dev/null +++ b/apps/server/src/storage.ts @@ -0,0 +1,65 @@ +import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; + +import type { KeyValueStorage } from './control-plane.js'; + +/** Keys are namespaced with `:`; anything outside this set cannot address a file. */ +const SAFE_KEY = /^[A-Za-z0-9:_-]+$/u; +const SUFFIX = '.json'; + +/** + * Filesystem-backed storage for the default single-node deployment. + * + * Keys are validated rather than escaped: a rejected key is a bug in the caller, and silently + * rewriting one would let two distinct records collide on a single file. Redis, KV, and Nitro + * storage drivers satisfy the same {@link KeyValueStorage} contract without touching this class. + */ +export class FileKeyValueStorage implements KeyValueStorage { + constructor(private readonly directory: string) {} + + async getItem(key: string): Promise { + const path = this.pathFor(key); + try { + return JSON.parse(await readFile(path, 'utf8')); + } catch { + // A missing or unreadable record is absence, not a transport failure. + return null; + } + } + + async setItem(key: string, value: unknown): Promise { + await mkdir(this.directory, { recursive: true }); + await writeFile(this.pathFor(key), JSON.stringify(value), 'utf8'); + } + + async getKeys(base = ''): Promise { + let entries: string[]; + try { + entries = await readdir(this.directory); + } catch { + return []; + } + return entries + .filter((entry) => entry.endsWith(SUFFIX)) + .map((entry) => decodeKey(entry.slice(0, -SUFFIX.length))) + .filter((key) => key.startsWith(base)); + } + + async removeItem(key: string): Promise { + await rm(this.pathFor(key), { force: true }); + } + + private pathFor(key: string): string { + if (!SAFE_KEY.test(key)) throw new Error(`Refusing to address storage with an unsafe key`); + return join(this.directory, `${encodeKey(key)}${SUFFIX}`); + } +} + +// `:` is not a portable filename character on Windows, so it is the one byte we transliterate. +function encodeKey(key: string): string { + return key.replaceAll(':', '__'); +} + +function decodeKey(name: string): string { + return name.replaceAll('__', ':'); +} diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json new file mode 100644 index 0000000..7aa810a --- /dev/null +++ b/apps/server/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { "rootDir": ".", "outDir": "dist" }, + "include": ["src/**/*.ts", "shared/**/*.ts"], + "references": [ + { "path": "../../packages/agent" }, + { "path": "../../packages/config" }, + { "path": "../../packages/github" }, + { "path": "../../packages/models" }, + { "path": "../../packages/runner" }, + { "path": "../../packages/shared" } + ] +} diff --git a/apps/server/tsdown.config.ts b/apps/server/tsdown.config.ts new file mode 100644 index 0000000..42d4623 --- /dev/null +++ b/apps/server/tsdown.config.ts @@ -0,0 +1,3 @@ +import { defineAppConfig } from '../../scripts/tsdown.config.ts'; + +export default defineAppConfig(); diff --git a/docs/architecture.md b/docs/architecture.md index 3cd3171..898e47d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -4,8 +4,8 @@ Agent Zero is organized as a dependency-directed monorepo. The core decides what ```text GitHub adapter ─┐ -CLI adapter ────┴──> agent runtime ──> runner boundary ──> isolated checkout - │ +CLI adapter ────┼──> agent runtime ──> runner boundary ──> isolated checkout +oRPC server ────┘ │ ├──> model abstraction ──> provider └──> shared contracts @@ -18,6 +18,7 @@ Nuxt dashboard ───> frontend-only operational interface - `config`, `models`, `github`, and `runner` implement focused capabilities around shared contracts. - `agent` composes policies and state transitions without knowing HTTP or terminal details. - `cli` is an entry-point adapter. It may depend on the runtime, but the runtime must not depend on it. +- `apps/server` is an entry-point adapter and composition root. Like `cli`, it may depend on the runtime; the runtime must not depend on it. - `apps/dashboard` is a frontend-only Nuxt interface and does not import runtime packages. If a change creates a reverse dependency, move the shared contract inward instead of importing an adapter into the runtime. @@ -42,6 +43,18 @@ Model transports follow the same adapter rule. `packages/models` owns the AI SDK `apps/dashboard` owns presentation only. It has no custom Nitro server routes, RPC contracts, persistence adapters, scheduler, runtime-package dependencies, shell capability, or target-filesystem capability. Any future live data source must be implemented as a separate adapter with an explicit contract rather than composed into the dashboard. +## Control-plane boundary + +`apps/server` is that separate adapter: the transport and composition root the dashboard reads from, kept in its own package so presentation never gains runtime capability. + +It exposes one typed oRPC router (`health`, `tasks.list`, `tasks.get`, `tasks.create`, `approvals.decide`) over a plain Node HTTP listener, plus a single aggregate `GET /api/dashboard` for the operational view. Procedures validate at the boundary with Zod and then delegate; they never invoke a shell or touch a checkout, because `runTask` is the only place that resolves policy and constructs a runner. A hosted `RunnerPool` lease is optional and still yields nothing but a `Runner`. + +Mutations fail closed behind operator-issued bearer credentials (`AGENT_ZERO_CONTROL_PLANE_TOKENS`, comma-separated `name:token` pairs). `tasks.create` additionally requires the target repository path to appear in `AGENT_ZERO_CONTROL_PLANE_REPOSITORIES`, so an HTTP caller cannot point a run at an arbitrary server-local path, and the requested execution mode to be granted to the principal via `AGENT_ZERO_CONTROL_PLANE_MODES` (comma-separated `name:mode|mode` grants; without one a principal is limited to the non-writable `observe` and `suggest` modes). Approval decisions record the authenticated principal's name rather than a wire-supplied actor. Reads stay open for the dashboard. + +Persistence is a narrow `KeyValueStorage` contract so a filesystem store, Redis, KV, or Nitro storage driver stays interchangeable. Records are redacted on the way in and hold no review input and no checkout path, so task history cannot become a credential or filesystem leak. `TaskScheduler` bounds concurrency globally and per repository, and rejects work once the queue is exhausted rather than growing without limit. + +Transport concerns stop here: headers, status mapping, and request objects never reach a runtime package. + ## State transitions The lifecycle is: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58f23d5..f9bae32 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,13 +22,13 @@ importers: version: 3.21.11 esbuild: specifier: '*' - version: 0.28.1 + version: 0.28.2 rollup: specifier: ^3 version: 4.62.4 vite: specifier: '>=3' - version: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + version: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) webpack: specifier: ^4 || ^5 version: 5.109.2 @@ -38,7 +38,7 @@ importers: version: 0.18.5 '@commitlint/cli': specifier: ^21.2.1 - version: 21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.1.2)(typescript@6.0.3-bridge.12.tsgo.7.0.2) + version: 21.2.1(@types/node@24.13.3)(typescript@6.0.3-bridge.12.tsgo.7.0.2) '@commitlint/config-conventional': specifier: ^21.2.0 version: 21.2.0 @@ -47,7 +47,7 @@ importers: version: 0.8.0(oxlint@1.77.0(oxlint-tsgolint@7.0.2001)) '@redstardev/unplugin-version-injector': specifier: 0.0.2 - version: 0.0.2(@nuxt/kit@3.21.11)(@nuxt/schema@3.21.11)(esbuild@0.28.1)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + version: 0.0.2(@nuxt/kit@3.21.11)(@nuxt/schema@3.21.11)(esbuild@0.28.2)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(webpack@5.109.2) '@types/node': specifier: ^24.3.0 version: 24.13.3 @@ -74,7 +74,7 @@ importers: version: 0.3.23 skilld: specifier: ^2.1.0 - version: 2.1.0(ws@8.21.3)(zod@4.4.3) + version: 2.1.0 tsdown: specifier: ^0.22.14 version: 0.22.14(@arethetypeswrong/core@0.18.5)(publint@0.3.23)(tsx@4.23.11) @@ -114,13 +114,13 @@ importers: version: 4.1.0(@playwright/test@1.62.1)(playwright-core@1.62.1) '@nuxtjs/color-mode': specifier: 4.0.1 - version: 4.0.1(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + version: 4.0.1(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) '@playwright/test': specifier: ^1.62.0 version: 1.62.1 '@unocss/nuxt': specifier: ^66.7.5 - version: 66.7.5(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2))(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + version: 66.7.5(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2))(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))(webpack@5.109.2) '@unocss/preset-wind4': specifier: ^66.7.5 version: 66.7.5 @@ -143,6 +143,64 @@ importers: specifier: ^3.1.2 version: 3.3.9(typescript@6.0.3-bridge.12.tsgo.7.0.2) + apps/server: + dependencies: + '@agent-zero/agent': + specifier: workspace:* + version: 0.3.0 + '@agent-zero/config': + specifier: workspace:* + version: 0.3.0 + '@agent-zero/github': + specifier: workspace:* + version: 0.3.0 + '@agent-zero/models': + specifier: workspace:* + version: 0.3.0 + '@agent-zero/runner': + specifier: workspace:* + version: 0.3.0 + '@agent-zero/shared': + specifier: workspace:* + version: 0.3.0 + '@arethetypeswrong/core': + specifier: ^0.18.1 + version: 0.18.5 + '@orpc/server': + specifier: 2.0.0-beta.26 + version: 2.0.0-beta.26(crossws@0.4.10) + '@types/node': + specifier: ^18.0.0 || ^20.0.0 || >=22.0.0 + version: 24.13.3 + crossws: + specifier: '>=0.3.4' + version: 0.4.10 + publint: + specifier: ^0.3.8 + version: 0.3.23 + zod: + specifier: ^4.1.5 + version: 4.4.3 + devDependencies: + oxlint: + specifier: ^1.44.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) + oxlint-tsgolint: + specifier: ^7.0.2001 + version: 7.0.2001 + tsdown: + specifier: ^0.22.14 + version: 0.22.14(@arethetypeswrong/core@0.18.5)(publint@0.3.23)(tsx@4.23.11) + tsx: + specifier: ^4.20.5 + version: 4.23.11 + typescript: + specifier: ^5.9.2 + version: typescript-native-bridge@6.0.3-bridge.12.tsgo.7.0.2 + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/node@24.13.3) + packages/agent: dependencies: '@agent-zero/config': @@ -254,7 +312,7 @@ importers: version: 2.0.5 magic-regexp: specifier: ^0.11.0 - version: 0.11.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + version: 0.11.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) publint: specifier: ^0.3.8 version: 0.3.23 @@ -383,7 +441,7 @@ importers: version: 0.0.3 magic-regexp: specifier: ^0.11.0 - version: 0.11.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + version: 0.11.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) publint: specifier: ^0.3.8 version: 0.3.23 @@ -905,167 +963,164 @@ packages: '@emnapi/runtime@1.11.2': resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} - '@emnapi/runtime@1.11.3': - resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} - '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@esbuild/aix-ppc64@0.28.1': - resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.28.1': - resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.28.1': - resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.28.1': - resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.28.1': - resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.28.1': - resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.28.1': - resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.28.1': - resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.28.1': - resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.28.1': - resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.28.1': - resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.28.1': - resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.28.1': - resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.28.1': - resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.28.1': - resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.28.1': - resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.28.1': - resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.28.1': - resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.28.1': - resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.28.1': - resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.28.1': - resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.28.1': - resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.28.1': - resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.28.1': - resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.28.1': - resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.28.1': - resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1125,89 +1180,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -1348,24 +1419,28 @@ packages: engines: {node: '>= 22.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@mdream/rust-linux-arm64-musl@1.5.12': resolution: {integrity: sha512-NneU7n/OGfOQu95oBILZpFB56o9nBxOP/pTo+vZGTgDG2E5QUycKl/zflJycTwcCXjssS58kTiB9CTgwC1YcWg==} engines: {node: '>= 22.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@mdream/rust-linux-x64-gnu@1.5.12': resolution: {integrity: sha512-CI1b9b/bFUDDVNUb1NK3uc8grJeM8qD4bRoo0qCY0dpUWRYwErmTs7Sze9O7wwkpGEaGl9bv12kHSW5/9C2AWg==} engines: {node: '>= 22.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@mdream/rust-linux-x64-musl@1.5.12': resolution: {integrity: sha512-sAoSJKsSdtP9kjTDbMnNyAnTj+yh2lUGFrHBrqN8zWcHYl6L09rRz7Sgoguo/4kmMkzLxg24y9EDk/5660ZwVA==} engines: {node: '>= 22.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@mdream/rust-wasm32-wasi@1.5.12': resolution: {integrity: sha512-OGriLOVHwOlXG067QKLqnGwfz+CaPKW816cG1IFrmHSAEgIA6UJzQ6zMfr0DK7yu2PGh0pkAmiurIDMt8l6/QA==} @@ -1428,30 +1503,35 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@napi-rs/keyring-linux-arm64-musl@1.3.0': resolution: {integrity: sha512-iIK6JWHXAJqDrEyLY3TmswwloVyt2vj+04TZnew+uSJ9gnDO8EwRbp3/iw3LpWaXiDO7VomGO6y8I0Id8uBZSw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@napi-rs/keyring-linux-riscv64-gnu@1.3.0': resolution: {integrity: sha512-/PGqrwn6EwgtK6vccASSXJRfOSP4vN1F4ASsIQ+7MdrK6hNvAJ1FZPrIuD5gGGdxezo3F++To2Wq7DbuGIeuNQ==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] + libc: [glibc] '@napi-rs/keyring-linux-x64-gnu@1.3.0': resolution: {integrity: sha512-2PDK1WKWTu9lBGq9VvNEkSlQD3O7YwVpmnyN2M3cy4v7NJ/8gDMd9GXv3G+FVXN13uhp4gnnPBS+ScefmEeD2A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@napi-rs/keyring-linux-x64-musl@1.3.0': resolution: {integrity: sha512-oJ2HkX8YUo46QBkn0pG+HuIKQNqr523q6vBobCn+P95s4C4K6/kLBqHY/1bg5J4ap31DzsznhnFKcfBNBsjCnw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@napi-rs/keyring-win32-arm64-msvc@1.3.0': resolution: {integrity: sha512-tOd3c/uAaeoE4ycVlmAdSvygz0Zt3zdca6Y7gokBeIbaRDWpjDIUOpU3MvML59XAaqyuKGsVVu0F/DZb1lHPmw==} @@ -1480,6 +1560,7 @@ packages: engines: {node: ^22.20 || ^24.12 || >=25} cpu: [x64] os: [linux] + libc: [glibc] '@napi-rs/wasm-runtime@1.2.2': resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} @@ -1649,6 +1730,31 @@ packages: resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} + '@orpc/client@2.0.0-beta.26': + resolution: {integrity: sha512-TT2+S4TP/EzU19mXqzqnd938tuaOss7prtXqlowY1MZh1wxsEW6t5b+RI310yHtgLM5u/ovku26BvOpl5Fb49Q==} + + '@orpc/contract@2.0.0-beta.26': + resolution: {integrity: sha512-tTeJBN0s+weE67t6Xyjt7pCnSaytWrUase4VdyajjjtWba2wxqIwMHITyvSKohmLVwym6LYAoGLqXF4ORgwHYQ==} + + '@orpc/server@2.0.0-beta.26': + resolution: {integrity: sha512-IBvwkJkCkPMxOLd2A2Js2baTXc4FE//W+wnXrMXkdNXarwjId9AJ+NJngxHitjepQKqc2fnqvWlMDvypS3WdQg==} + peerDependencies: + crossws: '>=0.3.4' + fastify: '>=5.6.1' + peerDependenciesMeta: + crossws: + optional: true + fastify: + optional: true + + '@orpc/shared@2.0.0-beta.26': + resolution: {integrity: sha512-rbzPz6fSE+5WWn1uesSnekBIy4aJFx0ocGI3EcWVAu8l0ILLjdufof6A2E9RwvRSZeEefIE9D7iadW044YCBSw==} + peerDependencies: + '@opentelemetry/api': '>=1.9.0' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@oxc-parser/binding-android-arm-eabi@0.131.0': resolution: {integrity: sha512-t2xicr9pfzkSRYx5aPqZqlLaayIwJTqgQ81Jor31Xep2nGyL2Aq3d0K5wOfeR7VevaSdxaS9dzSQP9xDwn8fDg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1794,6 +1900,7 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-arm64-musl@0.131.0': resolution: {integrity: sha512-vtPiwmfVTAXzaxDKsOXG+LwgRAA7WEnaeHzhS5z0GE89gAK18KSXnly7Z6saXXq6L3dVMyK44uoTI03zKxrpmw==} @@ -1814,6 +1921,7 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-ppc64-gnu@0.131.0': resolution: {integrity: sha512-8AW8L7w5cGHSdZPcyZX2yR0+GUODsT15rbRjfdD54rv6DMbtuEB19ysLOpKJlRGfH6UNYNpCHaU1uJWgTWf1/w==} @@ -1834,6 +1942,7 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-gnu@0.131.0': resolution: {integrity: sha512-vvpjkjEOUsPcsYf8evE4MO3aGx9+3wodXEBOicGNnOwTuAik8eBONNkgSdhkGsAblQmfVHJyanRnpxglddTXIA==} @@ -1854,6 +1963,7 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-musl@0.131.0': resolution: {integrity: sha512-AqmcNC3fClXX+fxQ6VGEN1667xVFiRBkY0CZmDMSiaeFUsv1+UkBPYYi48IUKcA9/ivvoKNRzQl2I4//kT9F/w==} @@ -1874,6 +1984,7 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-s390x-gnu@0.131.0': resolution: {integrity: sha512-7d3jOMKy7RSQCcDLIci+ySll2FgsOMl/GiRux4q2JNv0zg4EdhFISa9idvrdN/HEUIQQJNg6dmveUeJl2YErGA==} @@ -1894,6 +2005,7 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-gnu@0.131.0': resolution: {integrity: sha512-JHK/h95qVqVQ+ITER837kcTdwBDFpFaNnOTYGCP0zdUSX/mLKC7tXOoyrTb6vG7iRPwGlcgBil3v2IjYw1FqJA==} @@ -1914,6 +2026,7 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-musl@0.131.0': resolution: {integrity: sha512-b2BO82O8azXAyf7EUgOPKu145nWypbNyk07HbU09fkzhm9lEA5oPvaN/M8Nlo7tOErVTa2WOgS4QbOnxAPXdDQ==} @@ -1934,6 +2047,7 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-parser/binding-openharmony-arm64@0.131.0': resolution: {integrity: sha512-GHO9glZaX7LkX/OGfluEPf1yjg+ehiFbUdowbX6uNWOQhmwKWU4m4+nZ9FJkrHNKuxyI1KKertMdGjVKCApKWA==} @@ -2176,48 +2290,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-arm64-musl@0.62.0': resolution: {integrity: sha512-lk25fAl7KWaLWVJcW0CHEXB7QlQZtx5eDkjpaGMK0hzXTjUe0Wmlu8IKuFHoviSOcEJedRTs4VE/506VqGxGew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxfmt/binding-linux-ppc64-gnu@0.62.0': resolution: {integrity: sha512-SFyNqHQLwySceWNLhiSldx7wPXRAzP0L0WcW9GegP3uWrpZGJiZlQO85NbHAFPEfxR9PhZ9qSnZryEh7+v+4Gw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-riscv64-gnu@0.62.0': resolution: {integrity: sha512-KYj55C1ywJfHo6+aKDuEmUtVEdJALsC5GwayDGsI6FGz2GxFqNr/mA8nxVsNbJzm7sE5MRqTQ9ziImSzhYXysA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-riscv64-musl@0.62.0': resolution: {integrity: sha512-BhZDNo5GOU5nC378RhD0/XpvaEBHsH3HLgJp8YZX3A0InC7oivzA63HsRmiXFLtLSHAstEVrDf6fbC7Rs8Jh/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxfmt/binding-linux-s390x-gnu@0.62.0': resolution: {integrity: sha512-UyAFmyHkgSgUJ/wOM4p3U8AC2yAFvRH5PNBs7TnK0fObTT/XSWcdr/lAzPSWaekHaZFaMeFZyk9n93Joq3J93A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-x64-gnu@0.62.0': resolution: {integrity: sha512-1iYMP0leytWazFubD/WnINJuIrzRPuoL1aWEJdlGezEzDbTxcd29R4r8IUzP2oWeKst5V02uMJgR2NILlPlG6w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-x64-musl@0.62.0': resolution: {integrity: sha512-4rA/URtJSTVNVAQz6Q8wf7SaRvOXVy+TizriT9hs/Y1XhLR/R+92uWKRQG8yFWRAIEBbFHJ6WevQcl/G9SXEfw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxfmt/binding-openharmony-arm64@0.62.0': resolution: {integrity: sha512-mSZuFHU2ar1KLUjXpI2QBQcJ1VsOB3mOCgQXuXCpKs19dgh4u+OaovNfrWDfiJb+ihJ2+f7YFcaO9bS2dlTCXA==} @@ -2320,48 +2442,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxlint/binding-linux-arm64-musl@1.77.0': resolution: {integrity: sha512-LSbwuRKiNCenPDcbARqAZ5RfBy7gmj7vOvfJRLeCDU3gFtSxWbhv/+VTlaUqzUhNj1gFLHB8h7ALnxa/Az6z6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxlint/binding-linux-ppc64-gnu@1.77.0': resolution: {integrity: sha512-QWdcH31mXEUe5Nq1s0CfCpceaKjIo9uZtwDjAuL681g1axf+5x8xrg/eXWaw//4NCxYZ4V4e5Hu5tvdR+pTBlg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxlint/binding-linux-riscv64-gnu@1.77.0': resolution: {integrity: sha512-GnOfYgJxbcElOiPZaDFDl406ONddwvOWk2jvAAAEjwAl4GofNoHF+/HHUIBYa6bFCArlcGPi0XjC4cU1pkgF/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxlint/binding-linux-riscv64-musl@1.77.0': resolution: {integrity: sha512-AyEMTUCf0xY+hHF+IxqXFQIX0yQOIR8ykpY0lJNOw9xYqOzUX8dyZfRvlG0RfXwuQn2eonf/8NrMmDSZJjdqsA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxlint/binding-linux-s390x-gnu@1.77.0': resolution: {integrity: sha512-sPLzEcNvxd/oyVQ5oZo92CiHkFkpBeRop13E/P3TPY+hZfXHKCOWKI70TE2RYwMKFJDc20EMjH16L7NZICtKTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxlint/binding-linux-x64-gnu@1.77.0': resolution: {integrity: sha512-1Oh2ssH2L7lwyvkdSqaMUfsGfwU2Wfvew+obBUYjRVqhpBcUpwnsPSEr1IzVi9XqkuY10geiLsNKecqaZC34Dw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxlint/binding-linux-x64-musl@1.77.0': resolution: {integrity: sha512-0j/2wRgNGO+Qj/M1uu/p57h/hFTTWWcfie0ufkbabeus2s5+/QqkCflnMOwLLN5m2GsNeWp4xdl4cPa4n7QCOQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxlint/binding-openharmony-arm64@1.77.0': resolution: {integrity: sha512-BJ/j54qS0usEnyDkLYURMj2iiD9h5Cyy+ppzeMSXBGRXaGRNWnj1Mw14NqWMR5E/PzdgB30OOCCzLzbRoduafw==} @@ -2504,36 +2634,42 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.2.3': resolution: {integrity: sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@rolldown/binding-linux-ppc64-gnu@1.2.3': resolution: {integrity: sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-s390x-gnu@1.2.3': resolution: {integrity: sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-gnu@1.2.3': resolution: {integrity: sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-musl@1.2.3': resolution: {integrity: sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@rolldown/binding-openharmony-arm64@1.2.3': resolution: {integrity: sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug==} @@ -2662,66 +2798,79 @@ packages: resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.62.4': resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.62.4': resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.62.4': resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.62.4': resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.62.4': resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.62.4': resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.62.4': resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.62.4': resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.62.4': resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.62.4': resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.62.4': resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.62.4': resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.62.4': resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==} @@ -2823,12 +2972,38 @@ packages: resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} engines: {node: '>=14.0.0'} - '@speed-highlight/core@1.2.23': - resolution: {integrity: sha512-iRoq6i6JDJP6Mt2A5JaPvzw0pgYHH6k92ij+yXiTrB7T2y9N789aWE3EHWj/5ztlJBokcCBja3iYLVdu5wgnkg==} + '@speed-highlight/core@1.2.24': + resolution: {integrity: sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==} '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@standardserver/aws-lambda@0.7.1': + resolution: {integrity: sha512-fuwAx2M2O5Bnjk2JdFrtEQALmBwVtnn4jKApzFVmlIivWA7EGMj5kOzCNaJizxCQXlhPmC+doDHqf/H7FKMaNA==} + + '@standardserver/core@0.7.1': + resolution: {integrity: sha512-ZMoFDR92p9HnaI6vXK1iNFKXyLK8/6r3D4EJUM+SqeyReUH3OEJO4CZKU8BfXyzAV1A6Nsa7y2dGqDOYqH5LlQ==} + + '@standardserver/fastify@0.7.1': + resolution: {integrity: sha512-Oa+ttR0CyNkFjNczs2dO/WFFeZ4sAszVBKIOhKb1FFcDtD9VdqDgMBhbQ4sFR885fwpYckoYjFU6xXWWTueBlw==} + peerDependencies: + fastify: '>=5.6.1' + peerDependenciesMeta: + fastify: + optional: true + + '@standardserver/fetch@0.7.1': + resolution: {integrity: sha512-BeiAWESedv0woYpoBHCnq2Y3xLZZ3voFahdzpFd+HqLyenXIL4XX3z7/WgWNQnf+WsSQrK6HzBkDWCicCXVoKQ==} + + '@standardserver/node@0.7.1': + resolution: {integrity: sha512-Ikc07cGBTJ8tJgPd1OanNKVNpijcbixB1iKk0GdL/b1vkYbriGgNW3oHvbApM7+XqeCeNHj5XawHk6q90mwEEA==} + + '@standardserver/peer@0.7.1': + resolution: {integrity: sha512-ggqPbwz4X4GIziQgoyCTDHFw9nM9YuEvlSpO21pfoXLYF80ijtpN/iq4P0zKpb4kcXnBoSVDRUSnBJSZi0SJDg==} + + '@standardserver/shared@0.7.1': + resolution: {integrity: sha512-tBDheI3Me1gQEKPU+XhcCZ6/njmkKgJhA5rhi1/m6GauGhHq87UuVslDNc8qB+T/xsxVch/qETFhssEWO9c6BA==} + '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} @@ -3259,31 +3434,37 @@ packages: resolution: {integrity: sha512-g6LnHrR0Rfqq5cXs7olwR2+LlVDc876pw7Hh7YXbukVSiBxQkaxqsEO/trO25z2g99zWzgXwoYvQZ1TnwA2wEw==} cpu: [arm] os: [linux] + libc: [glibc] '@yuku-codegen/binding-linux-arm-musl@0.8.4': resolution: {integrity: sha512-7XAPHrROPEFuJWXEGZeLZQN4xR8ENQ65+HSCtCHjSzCwGgnX53GUjM9ExVcHopV0a5g4vu57v2wwtyWIM5iNOQ==} cpu: [arm] os: [linux] + libc: [musl] '@yuku-codegen/binding-linux-arm64-gnu@0.8.4': resolution: {integrity: sha512-fnBm7NLuuwFXy7F1vRIuyOc+RW9ADUjuCKVGY87Dj8jtr9XgESNrwb+B9VLSFY7nZ0rCdK/Sm1fBqJpI7eLdKQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@yuku-codegen/binding-linux-arm64-musl@0.8.4': resolution: {integrity: sha512-6vTw4ZHO9nm4SUkw36uG+UE6/qifZ0E8HIef7Mx/U/c2Zxu3JLBfXtU7U/NN2GMkDmcJkgwjXfpQoYw4Ch5Y1w==} cpu: [arm64] os: [linux] + libc: [musl] '@yuku-codegen/binding-linux-x64-gnu@0.8.4': resolution: {integrity: sha512-+vuC3V3Lw+DB4oJgHV9pVDfQZlsZJnxmbdods7HzxgEALU3P5+czwdAcw3wfh7Ebabt0Ny8eLUb1k9RV5OB/+w==} cpu: [x64] os: [linux] + libc: [glibc] '@yuku-codegen/binding-linux-x64-musl@0.8.4': resolution: {integrity: sha512-QH60PE4eZecmgNGa1/T1cKPhrfxt6ANtu4lrQ1FZ50F9b0GS9WjGmIjrfdSUeQa+f2Iqk3oEFSJdgVHBg1KPNg==} cpu: [x64] os: [linux] + libc: [musl] '@yuku-codegen/binding-win32-arm64@0.8.4': resolution: {integrity: sha512-6r68c0nKZPIBRXZIBiD7zjlEukBR+xRxpTOVj4n1Fsjcdh4YbbJfjFfmIzdbo9jXR1xL+dPueDVdsRGOUH5MoQ==} @@ -3319,31 +3500,37 @@ packages: resolution: {integrity: sha512-Fo3r5fYhGDcFnl+KN+L9PgtiQPS4AIE1n1mG1o5jZ11p7g5yZ/1EjLFmSHAUsoXreun8KjTsFjEL7P1Sb93PZQ==} cpu: [arm] os: [linux] + libc: [glibc] '@yuku-parser/binding-linux-arm-musl@0.8.4': resolution: {integrity: sha512-BEB31vUEgXPWf7WkoMPSzzJhpC/wWCBXyysRCCPsw47BJ/OtbQsvJbxX9fFDuSRLy3kbyIV/WbdUTgbQ9COxiw==} cpu: [arm] os: [linux] + libc: [musl] '@yuku-parser/binding-linux-arm64-gnu@0.8.4': resolution: {integrity: sha512-xGLCRcHn9xVz7JVNyyKtiNJSf503qtUmih9XVSsghgzOmiKUMnHObs69OMMwXN3788tg1jsl11fNjjQlB8idMA==} cpu: [arm64] os: [linux] + libc: [glibc] '@yuku-parser/binding-linux-arm64-musl@0.8.4': resolution: {integrity: sha512-3kNRi8NJT2q6FQRVCUFHIQ99+kXdi8cVJEEUi6+xtFqpMgNrZNnbgAj28ILsDC7zmclaU+v47eUCeJoKLSCbww==} cpu: [arm64] os: [linux] + libc: [musl] '@yuku-parser/binding-linux-x64-gnu@0.8.4': resolution: {integrity: sha512-isi62oMy94Z3OXwGs2l2rkqRiRyqLmfHeTRHpA/uWZbsNhnm7IdVvkF7e7wHNKAtd5jwGzOqYSroxKv2fOm7Cw==} cpu: [x64] os: [linux] + libc: [glibc] '@yuku-parser/binding-linux-x64-musl@0.8.4': resolution: {integrity: sha512-9RsEw2xYHqU/pjSRBTOupWN3sF8uz9stjJdARfz6o0llvF+yfrj5QHmTiocGGBeAI80fvKmDtr2RIQClUzAPcA==} cpu: [x64] os: [linux] + libc: [musl] '@yuku-parser/binding-win32-arm64@0.8.4': resolution: {integrity: sha512-VEZHo9rEGOBKR20sA3vCO00aQvwWND5aLu7YxeX+YupMZJh9hd1f17AbClJN37Q2iL1PCHht+wDTOKX6tZYqXg==} @@ -3768,6 +3955,10 @@ packages: cookie-es@3.1.1: resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + cookie@2.0.1: + resolution: {integrity: sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==} + engines: {node: '>=22'} + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -4007,8 +4198,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.402: - resolution: {integrity: sha512-/oOpMaPT6Yg+6/1XQhyIPlzgj7Ye9zf+nNM2Uh6OcE2G2oNptWazFa+qB2Pdqqbsc9KnIDzgAntoYN0dbwOXwA==} + electron-to-chromium@1.5.403: + resolution: {integrity: sha512-MQsYmdaLzvaCX5j+ZZBr5Fm6uCCnPQcRtlvmvRlWqrXy+BH2O4ffXIAScF+JQznQWB9brWp4lSD9Z4yNmaf2BA==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -4085,8 +4276,8 @@ packages: es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - esbuild@0.28.1: - resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} hasBin: true @@ -5552,6 +5743,10 @@ packages: resolution: {integrity: sha512-So0Sqw869y/S2oE3Nuc0uT3Dhqgvsj8FSrwBdsuTosVsG8ME5/OcudU1GxsrIFdFABgy17GHnTVO9TYV/bLQcA==} engines: {node: '>=16.0.0'} + radash@12.1.1: + resolution: {integrity: sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==} + engines: {node: '>=14.18.0'} + radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} @@ -6308,8 +6503,8 @@ packages: weaviate-client: optional: true - unbash@4.0.9: - resolution: {integrity: sha512-J8HTKzXbwi6oQKiKEbTKMsc30jKaU5vEzDejemz4bK8OqfENSPWWV8lW+Dl7rvcTTwBmAx/It4PUd1H9RjESIw==} + unbash@4.0.10: + resolution: {integrity: sha512-b7zoBQvpWp0vuN5q2vK2RRBR2SvuruQAs50DApdDveBSn3eSYd84IaHodFqQIMlvY9K2VnyBUEXgwOBuGU9GBg==} engines: {node: '>=14'} unconfig-core@7.5.0: @@ -6968,11 +7163,9 @@ snapshots: package-manager-detector: 1.8.0 tinyexec: 1.3.0 - '@anthropic-ai/sdk@0.91.1(zod@4.4.3)': + '@anthropic-ai/sdk@0.91.1': dependencies: json-schema-to-ts: 3.1.1 - optionalDependencies: - zod: 4.4.3 '@arethetypeswrong/cli@0.18.5': dependencies: @@ -7429,18 +7622,20 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@commitlint/cli@21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.1.2)(typescript@6.0.3-bridge.12.tsgo.7.0.2)': + '@commitlint/cli@21.2.1(@types/node@24.13.3)(typescript@6.0.3-bridge.12.tsgo.7.0.2)': dependencies: '@commitlint/config-conventional': 21.2.0 '@commitlint/format': 21.2.0 '@commitlint/lint': 21.2.0 '@commitlint/load': 21.2.0(@types/node@24.13.3)(typescript@6.0.3-bridge.12.tsgo.7.0.2) - '@commitlint/read': 21.2.1(conventional-commits-parser@7.1.2) + '@commitlint/read': 21.2.1 '@commitlint/types': 21.2.0 tinyexec: 1.3.0 yargs: 18.1.0 transitivePeerDependencies: - conventional-commits-filter + - conventional-commits-parser + - typescript '@commitlint/config-conventional@21.2.0': dependencies: @@ -7487,6 +7682,8 @@ snapshots: es-toolkit: 1.50.0 is-plain-obj: 4.1.0 picocolors: 1.1.1 + transitivePeerDependencies: + - typescript '@commitlint/message@21.2.0': {} @@ -7496,14 +7693,15 @@ snapshots: conventional-changelog-angular: 9.2.1 conventional-commits-parser: 7.1.2 - '@commitlint/read@21.2.1(conventional-commits-parser@7.1.2)': + '@commitlint/read@21.2.1': dependencies: '@commitlint/top-level': 21.2.0 '@commitlint/types': 21.2.0 - '@conventional-changelog/git-client': 3.1.1(conventional-commits-parser@7.1.2) + '@conventional-changelog/git-client': 3.1.1 tinyexec: 1.3.0 transitivePeerDependencies: - conventional-commits-filter + - conventional-commits-parser '@commitlint/resolve-extends@21.2.0': dependencies: @@ -7531,27 +7729,25 @@ snapshots: conventional-commits-parser: 7.1.2 picocolors: 1.1.1 - '@conventional-changelog/git-client@3.1.1(conventional-commits-parser@7.1.2)': + '@conventional-changelog/git-client@3.1.1': dependencies: '@simple-libs/child-process-utils': 2.0.0 '@simple-libs/stream-utils': 2.0.0 semver: 7.8.5 - optionalDependencies: - conventional-commits-parser: 7.1.2 '@conventional-changelog/template@1.2.1': {} - '@dxup/nuxt@0.5.6(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)': + '@dxup/nuxt@0.5.6(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)': dependencies: '@dxup/unimport': 0.1.2 - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) '@vue/compiler-dom': 3.5.41 chokidar: 5.0.0 knitwork: 1.3.0 magic-string: 1.1.0 pathe: 2.0.3 tinyglobby: 0.2.17 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -7566,13 +7762,12 @@ snapshots: dependencies: empathic: 2.0.1 module-replacements: 3.1.0 - semver: 7.8.5 - optionalDependencies: oxlint: 1.77.0(oxlint-tsgolint@7.0.2001) + semver: 7.8.5 - '@earendil-works/pi-ai@0.83.0(ws@8.21.3)(zod@4.4.3)': + '@earendil-works/pi-ai@0.83.0': dependencies: - '@anthropic-ai/sdk': 0.91.1(zod@4.4.3) + '@anthropic-ai/sdk': 0.91.1 '@aws-sdk/client-bedrock-runtime': 3.1048.0 '@google/genai': 1.52.0 '@mistralai/mistralai': 2.2.6(@opentelemetry/api@1.9.0) @@ -7580,7 +7775,7 @@ snapshots: '@smithy/node-http-handler': 4.7.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 - openai: 6.26.0(ws@8.21.3)(zod@4.4.3) + openai: 6.26.0 partial-json: 0.1.7 typebox: 1.3.7 transitivePeerDependencies: @@ -7588,6 +7783,8 @@ snapshots: - bufferutil - supports-color - utf-8-validate + - ws + - zod '@emnapi/core@1.10.0': dependencies: @@ -7611,11 +7808,6 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.11.3': - dependencies: - tslib: 2.8.1 - optional: true - '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 @@ -7626,82 +7818,82 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.28.1': + '@esbuild/aix-ppc64@0.28.2': optional: true - '@esbuild/android-arm64@0.28.1': + '@esbuild/android-arm64@0.28.2': optional: true - '@esbuild/android-arm@0.28.1': + '@esbuild/android-arm@0.28.2': optional: true - '@esbuild/android-x64@0.28.1': + '@esbuild/android-x64@0.28.2': optional: true - '@esbuild/darwin-arm64@0.28.1': + '@esbuild/darwin-arm64@0.28.2': optional: true - '@esbuild/darwin-x64@0.28.1': + '@esbuild/darwin-x64@0.28.2': optional: true - '@esbuild/freebsd-arm64@0.28.1': + '@esbuild/freebsd-arm64@0.28.2': optional: true - '@esbuild/freebsd-x64@0.28.1': + '@esbuild/freebsd-x64@0.28.2': optional: true - '@esbuild/linux-arm64@0.28.1': + '@esbuild/linux-arm64@0.28.2': optional: true - '@esbuild/linux-arm@0.28.1': + '@esbuild/linux-arm@0.28.2': optional: true - '@esbuild/linux-ia32@0.28.1': + '@esbuild/linux-ia32@0.28.2': optional: true - '@esbuild/linux-loong64@0.28.1': + '@esbuild/linux-loong64@0.28.2': optional: true - '@esbuild/linux-mips64el@0.28.1': + '@esbuild/linux-mips64el@0.28.2': optional: true - '@esbuild/linux-ppc64@0.28.1': + '@esbuild/linux-ppc64@0.28.2': optional: true - '@esbuild/linux-riscv64@0.28.1': + '@esbuild/linux-riscv64@0.28.2': optional: true - '@esbuild/linux-s390x@0.28.1': + '@esbuild/linux-s390x@0.28.2': optional: true - '@esbuild/linux-x64@0.28.1': + '@esbuild/linux-x64@0.28.2': optional: true - '@esbuild/netbsd-arm64@0.28.1': + '@esbuild/netbsd-arm64@0.28.2': optional: true - '@esbuild/netbsd-x64@0.28.1': + '@esbuild/netbsd-x64@0.28.2': optional: true - '@esbuild/openbsd-arm64@0.28.1': + '@esbuild/openbsd-arm64@0.28.2': optional: true - '@esbuild/openbsd-x64@0.28.1': + '@esbuild/openbsd-x64@0.28.2': optional: true - '@esbuild/openharmony-arm64@0.28.1': + '@esbuild/openharmony-arm64@0.28.2': optional: true - '@esbuild/sunos-x64@0.28.1': + '@esbuild/sunos-x64@0.28.2': optional: true - '@esbuild/win32-arm64@0.28.1': + '@esbuild/win32-arm64@0.28.2': optional: true - '@esbuild/win32-ia32@0.28.1': + '@esbuild/win32-ia32@0.28.2': optional: true - '@esbuild/win32-x64@0.28.1': + '@esbuild/win32-x64@0.28.2': optional: true '@google/genai@1.52.0': @@ -7819,7 +8011,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.11.3 + '@emnapi/runtime': 1.11.2 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -7966,6 +8158,13 @@ snapshots: '@mdream/rust-wasm32-wasi@1.5.12': optional: true + bundledDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - '@emnapi/wasi-threads' + - '@napi-rs/wasm-runtime' + - '@tybys/wasm-util' + - tslib '@mdream/rust-win32-arm64-msvc@1.5.12': optional: true @@ -7975,12 +8174,11 @@ snapshots: '@mistralai/mistralai@2.2.6(@opentelemetry/api@1.9.0)': dependencies: + '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.43.0 ws: 8.21.3 zod: 4.4.3 zod-to-json-schema: 3.25.2(zod@4.4.3) - optionalDependencies: - '@opentelemetry/api': 1.9.0 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -8116,19 +8314,19 @@ snapshots: '@nuxt/devalue@2.0.2': {} - '@nuxt/devtools-kit@2.7.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))': + '@nuxt/devtools-kit@2.7.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))': dependencies: '@nuxt/kit': 3.21.11 execa: 8.0.1 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) transitivePeerDependencies: - magicast - '@nuxt/devtools-kit@3.4.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))': + '@nuxt/devtools-kit@3.4.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))': dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) execa: 8.0.1 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) transitivePeerDependencies: - magicast - oxc-parser @@ -8144,11 +8342,11 @@ snapshots: pkg-types: 2.3.1 semver: 7.8.5 - '@nuxt/devtools@3.4.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))': + '@nuxt/devtools@3.4.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))': dependencies: - '@nuxt/devtools-kit': 3.4.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) + '@nuxt/devtools-kit': 3.4.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) '@nuxt/devtools-wizard': 3.4.1 - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) '@vue/devtools-core': 8.2.1(vue@3.5.41) '@vue/devtools-kit': 8.2.1 birpc: 4.0.0 @@ -8175,9 +8373,9 @@ snapshots: structured-clone-es: 2.0.1 tinyglobby: 0.2.17 unstorage: 1.17.5 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) - vite-plugin-inspect: 11.4.1(@nuxt/kit@4.5.2)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) - vite-plugin-vue-tracer: 1.4.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) + vite-plugin-inspect: 11.4.1(@nuxt/kit@4.5.2)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) + vite-plugin-vue-tracer: 1.4.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41) which: 6.0.1 ws: 8.21.3 transitivePeerDependencies: @@ -8232,7 +8430,7 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/kit@4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2))': + '@nuxt/kit@4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2))': dependencies: c12: 3.3.4 consola: 3.4.2 @@ -8252,7 +8450,7 @@ snapshots: scule: 1.3.0 tinyglobby: 0.2.17 ufo: 1.6.4 - unctx: 3.0.0(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + unctx: 3.0.0(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) untyped: 2.0.0 verkit: 0.3.2 transitivePeerDependencies: @@ -8262,8 +8460,8 @@ snapshots: '@nuxt/nitro-server@4.5.2(nuxt@4.5.2(@types/node@24.13.3)(rolldown@1.2.3))': dependencies: '@nuxt/devalue': 2.0.2 - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) - '@unhead/vue': 3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41)(webpack@5.109.2) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@unhead/vue': 3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41)(webpack@5.109.2) '@vue/shared': 3.5.41 consola: 3.4.2 defu: 6.1.7 @@ -8273,7 +8471,7 @@ snapshots: escape-string-regexp: 5.0.0 exsolve: 1.1.1 h3: 1.15.11 - impound: 1.1.6(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + impound: 1.1.6(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) klona: 2.0.6 mocked-exports: 0.1.1 nitropack: 2.13.4 @@ -8285,7 +8483,7 @@ snapshots: rou3: 0.9.1 std-env: 4.2.0 ufo: 1.6.4 - unctx: 3.0.0(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + unctx: 3.0.0(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) unstorage: 1.17.5 vue: 3.5.41 vue-bundle-renderer: 2.3.2 @@ -8354,7 +8552,7 @@ snapshots: '@nuxt/telemetry@2.8.0(@nuxt/kit@4.5.2)': dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) citty: 0.2.2 consola: 3.4.2 ofetch: 2.0.0-alpha.3 @@ -8364,7 +8562,7 @@ snapshots: '@nuxt/test-utils@4.1.0(@playwright/test@1.62.1)(playwright-core@1.62.1)': dependencies: '@clack/prompts': 1.7.0 - '@nuxt/devtools-kit': 2.7.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) + '@nuxt/devtools-kit': 2.7.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) '@nuxt/kit': 3.21.11 '@playwright/test': 1.62.1 c12: 3.3.4 @@ -8390,7 +8588,7 @@ snapshots: std-env: 4.2.0 tinyexec: 1.3.0 ufo: 1.6.4 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) vitest-environment-nuxt: 2.0.0(@playwright/test@1.62.1)(playwright-core@1.62.1) vue: 3.5.41 transitivePeerDependencies: @@ -8403,9 +8601,9 @@ snapshots: '@nuxt/vite-builder@4.5.2(nuxt@4.5.2(@types/node@24.13.3)(rolldown@1.2.3))(rolldown@1.2.3)(vue@3.5.41)': dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) - '@vitejs/plugin-vue': 6.0.8(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41) - '@vitejs/plugin-vue-jsx': 5.1.6(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@vitejs/plugin-vue': 6.0.8(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41) + '@vitejs/plugin-vue-jsx': 5.1.6(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41) autoprefixer: 10.5.4(postcss@8.5.26) consola: 3.4.2 cssnano: 8.0.4(postcss@8.5.26) @@ -8430,9 +8628,9 @@ snapshots: std-env: 4.2.0 ufo: 1.6.4 unenv: 2.0.0-rc.24 - vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11) - vite-node: 6.0.0(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11) - vite-plugin-checker: 0.14.5(oxlint@1.77.0(oxlint-tsgolint@7.0.2001))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11))(vue-tsc@3.3.9(typescript@6.0.3-bridge.12.tsgo.7.0.2)) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) + vite-node: 6.0.0(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) + vite-plugin-checker: 0.14.5(oxlint@1.77.0(oxlint-tsgolint@7.0.2001))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue-tsc@3.3.9(typescript@6.0.3-bridge.12.tsgo.7.0.2)) vue: 3.5.41 vue-bundle-renderer: 2.3.2 transitivePeerDependencies: @@ -8454,9 +8652,9 @@ snapshots: - typescript - yaml - '@nuxtjs/color-mode@4.0.1(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2))': + '@nuxtjs/color-mode@4.0.1(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2))': dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) exsolve: 1.1.1 pathe: 2.0.3 pkg-types: 2.3.1 @@ -8469,6 +8667,46 @@ snapshots: '@opentelemetry/semantic-conventions@1.43.0': {} + '@orpc/client@2.0.0-beta.26': + dependencies: + '@orpc/shared': 2.0.0-beta.26 + '@standardserver/core': 0.7.1 + '@standardserver/fetch': 0.7.1 + '@standardserver/peer': 0.7.1 + transitivePeerDependencies: + - '@opentelemetry/api' + + '@orpc/contract@2.0.0-beta.26': + dependencies: + '@orpc/client': 2.0.0-beta.26 + '@orpc/shared': 2.0.0-beta.26 + '@standard-schema/spec': 1.1.0 + transitivePeerDependencies: + - '@opentelemetry/api' + + '@orpc/server@2.0.0-beta.26(crossws@0.4.10)': + dependencies: + '@orpc/client': 2.0.0-beta.26 + '@orpc/contract': 2.0.0-beta.26 + '@orpc/shared': 2.0.0-beta.26 + '@standardserver/aws-lambda': 0.7.1 + '@standardserver/core': 0.7.1 + '@standardserver/fastify': 0.7.1 + '@standardserver/fetch': 0.7.1 + '@standardserver/node': 0.7.1 + '@standardserver/peer': 0.7.1 + cookie: 2.0.1 + crossws: 0.4.10 + transitivePeerDependencies: + - '@opentelemetry/api' + - fastify + + '@orpc/shared@2.0.0-beta.26': + dependencies: + '@standardserver/shared': 0.7.1 + radash: 12.1.1 + type-fest: 5.8.0 + '@oxc-parser/binding-android-arm-eabi@0.131.0': optional: true @@ -8909,16 +9147,15 @@ snapshots: dependencies: quansync: 1.0.0 - '@redstardev/unplugin-version-injector@0.0.2(@nuxt/kit@3.21.11)(@nuxt/schema@3.21.11)(esbuild@0.28.1)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)': + '@redstardev/unplugin-version-injector@0.0.2(@nuxt/kit@3.21.11)(@nuxt/schema@3.21.11)(esbuild@0.28.2)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(webpack@5.109.2)': dependencies: '@nuxt/kit': 3.21.11 '@nuxt/schema': 3.21.11 '@sapphire/result': 2.8.0 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + esbuild: 0.28.2 + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) webpack: 5.109.2 - optionalDependencies: - esbuild: 0.28.1 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -9173,10 +9410,44 @@ snapshots: '@smithy/util-buffer-from': 2.2.0 tslib: 2.8.1 - '@speed-highlight/core@1.2.23': {} + '@speed-highlight/core@1.2.24': {} '@standard-schema/spec@1.1.0': {} + '@standardserver/aws-lambda@0.7.1': + dependencies: + '@standardserver/core': 0.7.1 + '@standardserver/fetch': 0.7.1 + '@standardserver/node': 0.7.1 + '@standardserver/shared': 0.7.1 + + '@standardserver/core@0.7.1': + dependencies: + '@standardserver/shared': 0.7.1 + + '@standardserver/fastify@0.7.1': + dependencies: + '@standardserver/core': 0.7.1 + '@standardserver/node': 0.7.1 + + '@standardserver/fetch@0.7.1': + dependencies: + '@standardserver/core': 0.7.1 + '@standardserver/shared': 0.7.1 + + '@standardserver/node@0.7.1': + dependencies: + '@standardserver/core': 0.7.1 + '@standardserver/fetch': 0.7.1 + '@standardserver/shared': 0.7.1 + + '@standardserver/peer@0.7.1': + dependencies: + '@standardserver/core': 0.7.1 + '@standardserver/shared': 0.7.1 + + '@standardserver/shared@0.7.1': {} + '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3 @@ -9251,15 +9522,15 @@ snapshots: '@typescript-native-bridge/win32-x64@6.0.3-bridge.12.tsgo.7.0.2': optional: true - '@unhead/bundler@3.3.1(esbuild@0.28.1)(rolldown@1.2.3)(unhead@3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)))(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)': + '@unhead/bundler@3.3.1(esbuild@0.28.2)(rolldown@1.2.3)(unhead@3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(webpack@5.109.2)': dependencies: - esbuild: 0.28.1 + esbuild: 0.28.2 magic-string: 1.1.0 oxc-walker: 1.1.1(rolldown@1.2.3) rolldown: 1.2.3 - unhead: 3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + unhead: 3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) webpack: 5.109.2 transitivePeerDependencies: - '@farmfe/core' @@ -9269,13 +9540,13 @@ snapshots: - oxc-parser - unloader - '@unhead/vue@3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41)(webpack@5.109.2)': + '@unhead/vue@3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41)(webpack@5.109.2)': dependencies: - '@unhead/bundler': 3.3.1(esbuild@0.28.1)(rolldown@1.2.3)(unhead@3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)))(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + '@unhead/bundler': 3.3.1(esbuild@0.28.2)(rolldown@1.2.3)(unhead@3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(webpack@5.109.2) hookable: 6.1.1 - unhead: 3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + unhead: 3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) vue: 3.5.41 webpack: 5.109.2 transitivePeerDependencies: @@ -9328,9 +9599,9 @@ snapshots: gzip-size: 6.0.0 sirv: 3.0.2 - '@unocss/nuxt@66.7.5(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2))(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)': + '@unocss/nuxt@66.7.5(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2))(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))(webpack@5.109.2)': dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) '@unocss/config': 66.7.5 '@unocss/core': 66.7.5 '@unocss/preset-attributify': 66.7.5 @@ -9341,7 +9612,7 @@ snapshots: '@unocss/preset-wind3': 66.7.5 '@unocss/preset-wind4': 66.7.5 '@unocss/reset': 66.7.5 - '@unocss/vite': 66.7.5(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) + '@unocss/vite': 66.7.5(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) '@unocss/webpack': 66.7.5(webpack@5.109.2) unocss: 66.7.5(@unocss/webpack@66.7.5(webpack@5.109.2)) transitivePeerDependencies: @@ -9433,7 +9704,7 @@ snapshots: dependencies: '@unocss/core': 66.7.5 - '@unocss/vite@66.7.5(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))': + '@unocss/vite@66.7.5(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))': dependencies: '@jridgewell/remapping': 2.3.5 '@unocss/config': 66.7.5 @@ -9444,7 +9715,7 @@ snapshots: pathe: 2.0.3 tinyglobby: 0.2.17 unplugin-utils: 0.3.2 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) '@unocss/webpack@66.7.5(webpack@5.109.2)': dependencies: @@ -9455,7 +9726,7 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 tinyglobby: 0.2.17 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) unplugin-utils: 0.3.2 webpack: 5.109.2 webpack-sources: 3.5.1 @@ -9492,22 +9763,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue-jsx@5.1.6(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41)': + '@vitejs/plugin-vue-jsx@5.1.6(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41)': dependencies: '@babel/core': 7.29.7 '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) '@rolldown/pluginutils': 1.0.1 '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.7) - vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) vue: 3.5.41 transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.8(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41)': + '@vitejs/plugin-vue@6.0.8(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41)': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) vue: 3.5.41 '@vitest/expect@3.2.7': @@ -9518,13 +9789,12 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.7(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))': + '@vitest/mocker@3.2.7(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))': dependencies: '@vitest/spy': 3.2.7 estree-walker: 3.0.3 magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) '@vitest/pretty-format@3.2.7': dependencies: @@ -10039,7 +10309,7 @@ snapshots: dependencies: baseline-browser-mapping: 2.11.13 caniuse-lite: 1.0.30001809 - electron-to-chromium: 1.5.402 + electron-to-chromium: 1.5.403 node-releases: 2.0.53 update-browserslist-db: 1.3.0(browserslist@4.28.8) @@ -10234,6 +10504,8 @@ snapshots: cookie-es@3.1.1: {} + cookie@2.0.1: {} + core-util-is@1.0.3: {} cosmiconfig-typescript-loader@6.3.0(@types/node@24.13.3)(cosmiconfig@9.0.2)(typescript@6.0.3-bridge.12.tsgo.7.0.2): @@ -10249,8 +10521,6 @@ snapshots: import-fresh: 3.3.1 js-yaml: 4.3.1 parse-json: 5.2.0 - optionalDependencies: - typescript: typescript-native-bridge@6.0.3-bridge.12.tsgo.7.0.2 crc-32@1.2.2: {} @@ -10273,8 +10543,10 @@ snapshots: dependencies: uncrypto: 0.1.3 + crossws@0.4.10: {} + crossws@0.4.10(srvx@0.11.22): - optionalDependencies: + dependencies: srvx: 0.11.22 css-select@5.2.2: @@ -10441,7 +10713,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.402: {} + electron-to-chromium@1.5.403: {} emoji-regex@10.6.0: {} @@ -10495,34 +10767,34 @@ snapshots: es6-error@4.1.1: {} - esbuild@0.28.1: + esbuild@0.28.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.28.1 - '@esbuild/android-arm': 0.28.1 - '@esbuild/android-arm64': 0.28.1 - '@esbuild/android-x64': 0.28.1 - '@esbuild/darwin-arm64': 0.28.1 - '@esbuild/darwin-x64': 0.28.1 - '@esbuild/freebsd-arm64': 0.28.1 - '@esbuild/freebsd-x64': 0.28.1 - '@esbuild/linux-arm': 0.28.1 - '@esbuild/linux-arm64': 0.28.1 - '@esbuild/linux-ia32': 0.28.1 - '@esbuild/linux-loong64': 0.28.1 - '@esbuild/linux-mips64el': 0.28.1 - '@esbuild/linux-ppc64': 0.28.1 - '@esbuild/linux-riscv64': 0.28.1 - '@esbuild/linux-s390x': 0.28.1 - '@esbuild/linux-x64': 0.28.1 - '@esbuild/netbsd-arm64': 0.28.1 - '@esbuild/netbsd-x64': 0.28.1 - '@esbuild/openbsd-arm64': 0.28.1 - '@esbuild/openbsd-x64': 0.28.1 - '@esbuild/openharmony-arm64': 0.28.1 - '@esbuild/sunos-x64': 0.28.1 - '@esbuild/win32-arm64': 0.28.1 - '@esbuild/win32-ia32': 0.28.1 - '@esbuild/win32-x64': 0.28.1 + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 escalade@3.2.0: {} @@ -10639,7 +10911,7 @@ snapshots: walk-up-path: 4.0.0 fdir@6.5.0(picomatch@4.0.5): - optionalDependencies: + dependencies: picomatch: 4.0.5 fetch-blob@3.2.0: @@ -10893,12 +11165,12 @@ snapshots: import-without-cache@0.4.0: {} - impound@1.1.6(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2): + impound@1.1.6(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2): dependencies: '@jridgewell/trace-mapping': 0.3.31 es-module-lexer: 2.3.1 pathe: 2.0.3 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) unplugin-utils: 0.3.2 transitivePeerDependencies: - '@farmfe/core' @@ -11088,7 +11360,7 @@ snapshots: smol-toml: 1.7.1 strip-json-comments: 5.0.3 tinyglobby: 0.2.17 - unbash: 4.0.9 + unbash: 4.0.10 yaml: 2.9.0 zod: 4.4.3 @@ -11216,12 +11488,12 @@ snapshots: ufo: 1.6.4 unplugin: 2.3.11 - magic-regexp@0.11.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2): + magic-regexp@0.11.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2): dependencies: magic-string: 0.30.21 regexp-tree: 0.1.27 type-level-regexp: 0.1.17 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -11322,10 +11594,10 @@ snapshots: minimist@1.2.8: optional: true - minimizer-webpack-plugin@5.6.1(esbuild@0.28.1)(webpack@5.109.2): + minimizer-webpack-plugin@5.6.1(esbuild@0.28.2)(webpack@5.109.2): dependencies: '@jridgewell/trace-mapping': 0.3.31 - esbuild: 0.28.1 + esbuild: 0.28.2 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.49.2 @@ -11403,7 +11675,7 @@ snapshots: defu: 6.1.7 destr: 2.0.5 dot-prop: 10.2.0 - esbuild: 0.28.1 + esbuild: 0.28.2 escape-string-regexp: 5.0.0 etag: 1.8.1 exsolve: 1.1.1 @@ -11552,16 +11824,16 @@ snapshots: nuxt@4.5.2(@types/node@24.13.3)(rolldown@1.2.3): dependencies: - '@dxup/nuxt': 0.5.6(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + '@dxup/nuxt': 0.5.6(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) '@nuxt/cli': 3.37.0(@nuxt/schema@4.5.2) - '@nuxt/devtools': 3.4.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@nuxt/devtools': 3.4.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) '@nuxt/nitro-server': 4.5.2(nuxt@4.5.2(@types/node@24.13.3)(rolldown@1.2.3)) '@nuxt/schema': 4.5.2 '@nuxt/telemetry': 2.8.0(@nuxt/kit@4.5.2) '@nuxt/vite-builder': 4.5.2(nuxt@4.5.2(@types/node@24.13.3)(rolldown@1.2.3))(rolldown@1.2.3)(vue@3.5.41) '@types/node': 24.13.3 - '@unhead/vue': 3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41)(webpack@5.109.2) + '@unhead/vue': 3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41)(webpack@5.109.2) '@vue/shared': 3.5.41 chokidar: 5.0.0 compatx: 0.2.0 @@ -11575,7 +11847,7 @@ snapshots: fnv1a-64: 0.1.2 hookable: 6.1.1 ignore: 7.0.6 - impound: 1.1.6(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + impound: 1.1.6(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) jiti: 2.7.0 klona: 2.0.6 knitwork: 1.3.0 @@ -11602,17 +11874,17 @@ snapshots: ufo: 1.6.4 ultrahtml: 1.7.0 uncrypto: 0.1.3 - unctx: 3.0.0(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + unctx: 3.0.0(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) undici: 8.10.0 - unhead: 3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) + unhead: 3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)) unimport: 6.4.0(rolldown@1.2.3) - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) unrouting: 0.2.2 untyped: 2.0.0 verkit: 0.3.2 vue: 3.5.41 vue-component-type-helpers: 3.3.9 - vue-router: 5.2.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41) + vue-router: 5.2.0(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11754,10 +12026,7 @@ snapshots: powershell-utils: 0.1.0 wsl-utils: 0.3.1 - openai@6.26.0(ws@8.21.3)(zod@4.4.3): - optionalDependencies: - ws: 8.21.3 - zod: 4.4.3 + openai@6.26.0: {} oxc-parser@0.131.0: dependencies: @@ -11898,6 +12167,8 @@ snapshots: '@oxlint-tsgolint/win32-x64': 7.0.2001 oxlint@1.77.0(oxlint-tsgolint@7.0.2001): + dependencies: + oxlint-tsgolint: 7.0.2001 optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.77.0 '@oxlint/binding-android-arm64': 1.77.0 @@ -11918,7 +12189,6 @@ snapshots: '@oxlint/binding-win32-arm64-msvc': 1.77.0 '@oxlint/binding-win32-ia32-msvc': 1.77.0 '@oxlint/binding-win32-x64-msvc': 1.77.0 - oxlint-tsgolint: 7.0.2001 p-limit@7.3.1: dependencies: @@ -12251,6 +12521,8 @@ snapshots: '@jitl/quickjs-wasmfile-release-sync': 0.32.0 quickjs-emscripten-core: 0.32.0 + radash@12.1.1: {} + radix3@1.1.2: {} range-parser@1.3.0: {} @@ -12332,10 +12604,8 @@ snapshots: signal-exit: 4.1.0 retriv@0.14.7(sqlite-vec@0.1.9): - optionalDependencies: - '@huggingface/transformers': 4.2.0 + dependencies: sqlite-vec: 0.1.9 - typescript: typescript-native-bridge@6.0.3-bridge.12.tsgo.7.0.2 retry@0.12.0: {} @@ -12361,8 +12631,6 @@ snapshots: yuku-ast: 0.8.4 yuku-codegen: 0.8.4 yuku-parser: 0.8.4 - optionalDependencies: - typescript: typescript-native-bridge@6.0.3-bridge.12.tsgo.7.0.2 transitivePeerDependencies: - oxc-resolver @@ -12587,10 +12855,10 @@ snapshots: dependencies: zod: 4.4.3 - skilld@2.1.0(ws@8.21.3)(zod@4.4.3): + skilld@2.1.0: dependencies: '@clack/prompts': 1.7.0 - '@earendil-works/pi-ai': 0.83.0(ws@8.21.3)(zod@4.4.3) + '@earendil-works/pi-ai': 0.83.0 '@huggingface/transformers': 4.2.0 '@mdream/crawl': 1.5.12 citty: 0.2.2 @@ -12621,6 +12889,7 @@ snapshots: - '@ai-sdk/openai' - '@cloudflare/sandbox' - '@deno/sandbox' + - '@huggingface/transformers' - '@libsql/client' - '@modelcontextprotocol/sdk' - '@pinecone-database/pinecone' @@ -12638,9 +12907,12 @@ snapshots: - pg - playwright - supports-color + - typescript - unstorage - utf-8-validate - weaviate-client + - ws + - zod skin-tone@2.0.0: dependencies: @@ -12932,6 +13204,7 @@ snapshots: tsdown@0.22.14(@arethetypeswrong/core@0.18.5)(publint@0.3.23)(tsx@4.23.11): dependencies: + '@arethetypeswrong/core': 0.18.5 ansis: 4.3.1 cac: 7.0.0 defu: 6.1.7 @@ -12940,29 +13213,27 @@ snapshots: import-without-cache: 0.4.0 obug: 2.1.4 picomatch: 4.0.5 + publint: 0.3.23 rolldown: 1.2.3 rolldown-plugin-dts: 0.27.14(rolldown@1.2.3) tinyexec: 1.3.0 tinyglobby: 0.2.17 tree-kill: 1.2.2 + tsx: 4.23.11 unconfig-core: 7.5.0 verkit: 0.3.2 - optionalDependencies: - '@arethetypeswrong/core': 0.18.5 - publint: 0.3.23 - tsx: 4.23.11 - typescript: typescript-native-bridge@6.0.3-bridge.12.tsgo.7.0.2 transitivePeerDependencies: - '@typescript/native-preview' - '@volar/typescript' - oxc-resolver + - typescript - vue-tsc tslib@2.8.1: {} tsx@4.23.11: dependencies: - esbuild: 0.28.1 + esbuild: 0.28.2 optionalDependencies: fsevents: 2.3.3 @@ -13014,16 +13285,15 @@ snapshots: unagent@0.0.8(@huggingface/transformers@4.2.0)(sqlite-vec@0.1.9): dependencies: + '@huggingface/transformers': 4.2.0 croner: 9.1.0 hookable: 6.1.1 pathe: 2.0.3 + sqlite-vec: 0.1.9 std-env: 3.10.0 yaml: 2.9.0 - optionalDependencies: - '@huggingface/transformers': 4.2.0 - sqlite-vec: 0.1.9 - unbash@4.0.9: {} + unbash@4.0.10: {} unconfig-core@7.5.0: dependencies: @@ -13047,11 +13317,11 @@ snapshots: magic-string: 0.30.21 unplugin: 2.3.11 - unctx@3.0.0(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)): + unctx@3.0.0(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)): dependencies: magic-string: 1.1.0 rolldown: 1.2.3 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) undici-types@7.18.2: {} @@ -13063,11 +13333,11 @@ snapshots: dependencies: pathe: 2.0.3 - unhead@3.3.1(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)): + unhead@3.3.1(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)): dependencies: hookable: 6.1.1 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -13095,7 +13365,7 @@ snapshots: scule: 1.3.0 strip-literal: 4.0.0 tinyglobby: 0.2.17 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) unplugin-utils: 0.3.2 transitivePeerDependencies: - '@farmfe/core' @@ -13121,7 +13391,7 @@ snapshots: '@unocss/transformer-compile-class': 66.7.5 '@unocss/transformer-directives': 66.7.5 '@unocss/transformer-variant-group': 66.7.5 - '@unocss/vite': 66.7.5(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) + '@unocss/vite': 66.7.5(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) '@unocss/webpack': 66.7.5(webpack@5.109.2) unplugin-utils@0.3.2: @@ -13136,17 +13406,16 @@ snapshots: picomatch: 4.0.5 webpack-virtual-modules: 0.6.2 - unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2): + unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2): dependencies: '@jridgewell/remapping': 2.3.5 + esbuild: 0.28.2 picomatch: 4.0.5 + rolldown: 1.2.3 rollup: 4.62.4 + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) webpack: 5.109.2 webpack-virtual-modules: 0.6.2 - optionalDependencies: - esbuild: 0.28.1 - rolldown: 1.2.3 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) unrouting@0.2.2: dependencies: @@ -13210,23 +13479,23 @@ snapshots: verkit@0.3.2: {} - vite-dev-rpc@2.0.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)): + vite-dev-rpc@2.0.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)): dependencies: birpc: 4.0.0 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) - vite-hot-client: 2.2.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) + vite-hot-client: 2.2.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) - vite-hot-client@2.2.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)): + vite-hot-client@2.2.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)): dependencies: - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) - vite-node@3.2.4(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0): + vite-node@3.2.4(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) transitivePeerDependencies: - less - lightningcss @@ -13236,14 +13505,15 @@ snapshots: - sugarss - supports-color - terser + - yaml - vite-node@6.0.0(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11): + vite-node@6.0.0(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11): dependencies: cac: 7.0.0 es-module-lexer: 2.3.1 obug: 2.1.4 pathe: 2.0.3 - vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) transitivePeerDependencies: - '@vitejs/devtools' - less @@ -13254,7 +13524,7 @@ snapshots: - terser - yaml - vite-plugin-checker@0.14.5(oxlint@1.77.0(oxlint-tsgolint@7.0.2001))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11))(vue-tsc@3.3.9(typescript@6.0.3-bridge.12.tsgo.7.0.2)): + vite-plugin-checker@0.14.5(oxlint@1.77.0(oxlint-tsgolint@7.0.2001))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11))(vue-tsc@3.3.9(typescript@6.0.3-bridge.12.tsgo.7.0.2)): dependencies: '@babel/code-frame': 7.29.7 chokidar: 5.0.0 @@ -13264,12 +13534,12 @@ snapshots: picomatch: 4.0.5 proper-lockfile: 4.1.2 tiny-invariant: 1.3.3 - vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11) vue-tsc: 3.3.9(typescript@6.0.3-bridge.12.tsgo.7.0.2) - vite-plugin-inspect@11.4.1(@nuxt/kit@4.5.2)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)): + vite-plugin-inspect@11.4.1(@nuxt/kit@4.5.2)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)): dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) + '@nuxt/kit': 4.5.2(magic-string@1.1.0)(rolldown@1.2.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2)) ansis: 4.3.1 error-stack-parser-es: 1.0.5 obug: 2.1.4 @@ -13278,38 +13548,51 @@ snapshots: perfect-debounce: 2.1.0 sirv: 3.0.2 unplugin-utils: 0.3.2 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) - vite-dev-rpc: 2.0.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) + vite-dev-rpc: 2.0.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) - vite-plugin-vue-tracer@1.4.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41): + vite-plugin-vue-tracer@1.4.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11))(vue@3.5.41): dependencies: estree-walker: 3.0.3 exsolve: 1.1.1 magic-string: 0.30.21 pathe: 2.0.3 source-map-js: 1.2.1 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) vue: 3.5.41 - vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0): + vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11): dependencies: - esbuild: 0.28.1 + '@types/node': 24.13.3 + esbuild: 0.28.2 fdir: 6.5.0(picomatch@4.0.5) + jiti: 2.7.0 picomatch: 4.0.5 postcss: 8.5.26 rollup: 4.62.4 tinyglobby: 0.2.17 + tsx: 4.23.11 optionalDependencies: - '@types/node': 24.13.3 fsevents: 2.3.3 + + vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11): + dependencies: + '@types/node': 24.13.3 + esbuild: 0.28.2 jiti: 2.7.0 + lightningcss: 1.33.0 + picomatch: 4.0.5 + postcss: 8.5.26 + rolldown: 1.2.3 + tinyglobby: 0.2.17 tsx: 4.23.11 - yaml: 2.9.0 + optionalDependencies: + fsevents: 2.3.3 - vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.11): + vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0): dependencies: '@types/node': 24.13.3 - esbuild: 0.28.1 + esbuild: 0.28.2 jiti: 2.7.0 lightningcss: 1.33.0 picomatch: 4.0.5 @@ -13317,6 +13600,7 @@ snapshots: rolldown: 1.2.3 tinyglobby: 0.2.17 tsx: 4.23.11 + yaml: 2.9.0 optionalDependencies: fsevents: 2.3.3 @@ -13343,8 +13627,9 @@ snapshots: vitest@3.2.7(@types/node@24.13.3): dependencies: '@types/chai': 5.2.3 + '@types/node': 24.13.3 '@vitest/expect': 3.2.7 - '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0)) + '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)) '@vitest/pretty-format': 3.2.7 '@vitest/runner': 3.2.7 '@vitest/snapshot': 3.2.7 @@ -13362,11 +13647,9 @@ snapshots: tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) - vite-node: 3.2.4(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) + vite-node: 3.2.4(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11) why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 24.13.3 transitivePeerDependencies: - less - lightningcss @@ -13377,6 +13660,7 @@ snapshots: - sugarss - supports-color - terser + - yaml vscode-uri@3.1.0: {} @@ -13388,7 +13672,7 @@ snapshots: vue-devtools-stub@0.1.0: {} - vue-router@5.2.0(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41): + vue-router@5.2.0(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(vue@3.5.41): dependencies: '@babel/generator': 8.0.0 '@vue-macros/common': 3.1.4(vue@3.5.41) @@ -13405,9 +13689,9 @@ snapshots: picomatch: 4.0.5 scule: 1.3.0 tinyglobby: 0.2.17 - unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.62.4)(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) + unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.3)(rollup@4.62.4)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0))(webpack@5.109.2) unplugin-utils: 0.3.2 - vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) + vite: 8.2.1(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.11)(yaml@2.9.0) vue: 3.5.41 yaml: 2.9.0 transitivePeerDependencies: @@ -13460,7 +13744,7 @@ snapshots: events: 3.3.0 graceful-fs: 4.2.11 mime-db: 1.54.0 - minimizer-webpack-plugin: 5.6.1(esbuild@0.28.1)(webpack@5.109.2) + minimizer-webpack-plugin: 5.6.1(esbuild@0.28.2)(webpack@5.109.2) neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.3 @@ -13575,7 +13859,7 @@ snapshots: dependencies: '@poppinss/colors': 4.1.6 '@poppinss/dumper': 0.7.0 - '@speed-highlight/core': 1.2.23 + '@speed-highlight/core': 1.2.24 cookie-es: 3.1.1 youch-core: 0.3.3 diff --git a/tsconfig.json b/tsconfig.json index b811c9b..047ac08 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ { "path": "packages/github" }, { "path": "packages/agent" }, { "path": "packages/cli" }, - { "path": "apps/dashboard" } + { "path": "apps/dashboard" }, + { "path": "apps/server" } ] }