From ced43fbb11213c9b51a0be3b31cf2757ca39f830 Mon Sep 17 00:00:00 2001 From: StanPonomarev Date: Sat, 10 Oct 2026 15:00:15 +0200 Subject: [PATCH 1/2] chore: reorg files --- .oxfmtrc.json | 2 +- package.json | 12 ++++++------ scripts/build.ts | 13 ++++++++----- scripts/test-multi-work-host.ts | 4 ++-- src/{ => agents}/agents-rpc.ts | 0 src/{ => agents}/agents.ts | 4 ++-- src/{ => agents}/config.ts | 0 src/{ => agents}/model.ts | 0 src/{ => agents}/provider.ts | 0 src/{ => agents}/routing.ts | 0 src/{ => multi-work}/herdr.ts | 0 src/{ => multi-work}/multi-work.ts | 4 ++-- src/{ => quota}/claude-quota.ts | 0 src/{ => quota}/quota-plugin.ts | 0 src/{ => quota}/quota-rpc.ts | 0 src/{ => quota}/quota.ts | 0 src/{ => quota}/tui.tsx | 0 src/{ => skills}/anti-overengineering.md | 0 src/{ => skills}/task-planning.md | 0 tests/claude-quota.test.ts | 2 +- tests/fixtures/native-agents-plugin.ts | 2 +- tests/fixtures/native-host-plugin.ts | 2 +- tests/herdr.test.ts | 2 +- tests/multi-work.test.ts | 4 ++-- tests/plugin.test.ts | 6 +++--- tests/plugins.test.ts | 4 ++-- tests/quota.test.ts | 2 +- tests/tui.test.ts | 4 ++-- 28 files changed, 35 insertions(+), 32 deletions(-) rename src/{ => agents}/agents-rpc.ts (100%) rename src/{ => agents}/agents.ts (98%) rename src/{ => agents}/config.ts (100%) rename src/{ => agents}/model.ts (100%) rename src/{ => agents}/provider.ts (100%) rename src/{ => agents}/routing.ts (100%) rename src/{ => multi-work}/herdr.ts (100%) rename src/{ => multi-work}/multi-work.ts (99%) rename src/{ => quota}/claude-quota.ts (100%) rename src/{ => quota}/quota-plugin.ts (100%) rename src/{ => quota}/quota-rpc.ts (100%) rename src/{ => quota}/quota.ts (100%) rename src/{ => quota}/tui.tsx (100%) rename src/{ => skills}/anti-overengineering.md (100%) rename src/{ => skills}/task-planning.md (100%) diff --git a/.oxfmtrc.json b/.oxfmtrc.json index 1bda0df..48a61da 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -16,7 +16,7 @@ ".roo/**", ".windsurf/**", "tools/oxlint/anti-slop/**", - "src/anti-overengineering.md", + "src/skills/anti-overengineering.md", "node_modules/**", "dist/**", "coverage/**", diff --git a/package.json b/package.json index 6dc0fe5..533f9c4 100644 --- a/package.json +++ b/package.json @@ -5,27 +5,27 @@ "type": "module", "exports": { "./agents": { - "types": "./dist/agents.d.ts", + "types": "./dist/agents/agents.d.ts", "import": "./dist/agents.js" }, "./multi-work": { - "types": "./dist/multi-work.d.ts", + "types": "./dist/multi-work/multi-work.d.ts", "import": "./dist/multi-work.js" }, "./quota": { - "types": "./dist/quota-plugin.d.ts", + "types": "./dist/quota/quota-plugin.d.ts", "import": "./dist/quota-plugin.js" }, "./tui": { - "types": "./dist/tui.d.ts", + "types": "./dist/quota/tui.d.ts", "import": "./dist/tui.js" }, "./quota/tui": { - "types": "./dist/tui.d.ts", + "types": "./dist/quota/tui.d.ts", "import": "./dist/tui.js" }, "./quota-rpc": { - "types": "./dist/quota-rpc.d.ts", + "types": "./dist/quota/quota-rpc.d.ts", "import": "./dist/quota-rpc.js" } }, diff --git a/scripts/build.ts b/scripts/build.ts index 0ee3381..f1001f5 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -7,24 +7,27 @@ export async function build() { const results = await Promise.all([ Bun.build({ entrypoints: [ - "src/agents.ts", - "src/multi-work.ts", - "src/quota-plugin.ts", - "src/quota-rpc.ts", + "src/agents/agents.ts", + "src/multi-work/multi-work.ts", + "src/quota/quota-plugin.ts", + "src/quota/quota-rpc.ts", ], outdir: "dist", + naming: "[name].[ext]", target: "bun", format: "esm", }), Bun.build({ entrypoints: ["scripts/install.ts"], outdir: "dist", + naming: "[name].[ext]", target: "bun", format: "esm", }), Bun.build({ - entrypoints: ["src/tui.tsx"], + entrypoints: ["src/quota/tui.tsx"], outdir: "dist", + naming: "[name].[ext]", target: "bun", format: "esm", external: ["@opencode/plugin/tui", "@opentui/solid", "solid-js"], diff --git a/scripts/test-multi-work-host.ts b/scripts/test-multi-work-host.ts index 514b109..5b907e3 100644 --- a/scripts/test-multi-work-host.ts +++ b/scripts/test-multi-work-host.ts @@ -5,7 +5,7 @@ import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { createServer } from "node:net"; import { OpenCode } from "@opencode/client"; -import { command } from "../src/herdr.js"; +import { command } from "../src/multi-work/herdr.js"; import { z } from "zod"; const binary = process.env.OPENCODE_2022; @@ -358,7 +358,7 @@ try { server.kill(); await server.exited; const quotaBuild = await Bun.build({ - entrypoints: [resolve("src/quota-plugin.ts")], + entrypoints: [resolve("src/quota/quota-plugin.ts")], outdir: join(temp, "plugin", "quota"), naming: "index.js", target: "bun", diff --git a/src/agents-rpc.ts b/src/agents/agents-rpc.ts similarity index 100% rename from src/agents-rpc.ts rename to src/agents/agents-rpc.ts diff --git a/src/agents.ts b/src/agents/agents.ts similarity index 98% rename from src/agents.ts rename to src/agents/agents.ts index 597f6ba..59ff9e3 100644 --- a/src/agents.ts +++ b/src/agents/agents.ts @@ -8,8 +8,8 @@ import { descriptions, routingGuide } from "./routing.js"; import { Skill } from "@opencode/schema/skill"; import { AbsolutePath } from "@opencode/schema/schema"; import { fileURLToPath } from "node:url"; -import antiOverengineering from "./anti-overengineering.md" with { type: "text" }; -import taskPlanning from "./task-planning.md" with { type: "text" }; +import antiOverengineering from "../skills/anti-overengineering.md" with { type: "text" }; +import taskPlanning from "../skills/task-planning.md" with { type: "text" }; import { AgentsRpc } from "./agents-rpc.js"; // Permission actions use wildcards, not filesystem globs. diff --git a/src/config.ts b/src/agents/config.ts similarity index 100% rename from src/config.ts rename to src/agents/config.ts diff --git a/src/model.ts b/src/agents/model.ts similarity index 100% rename from src/model.ts rename to src/agents/model.ts diff --git a/src/provider.ts b/src/agents/provider.ts similarity index 100% rename from src/provider.ts rename to src/agents/provider.ts diff --git a/src/routing.ts b/src/agents/routing.ts similarity index 100% rename from src/routing.ts rename to src/agents/routing.ts diff --git a/src/herdr.ts b/src/multi-work/herdr.ts similarity index 100% rename from src/herdr.ts rename to src/multi-work/herdr.ts diff --git a/src/multi-work.ts b/src/multi-work/multi-work.ts similarity index 99% rename from src/multi-work.ts rename to src/multi-work/multi-work.ts index 3d9810d..c9c3ec7 100644 --- a/src/multi-work.ts +++ b/src/multi-work/multi-work.ts @@ -4,12 +4,12 @@ import { Session } from "@opencode/schema/session"; import { AbsolutePath } from "@opencode/schema/schema"; import type { Context } from "@opencode/plugin/effect/plugin"; import { Plugin } from "@opencode/plugin/effect"; -import { AgentsRpc } from "./agents-rpc.js"; +import { AgentsRpc } from "../agents/agents-rpc.js"; import { Cause, Effect, Schedule, Stream } from "effect"; import { z } from "zod"; import { randomUUID } from "node:crypto"; import { Herdr, rootSchema } from "./herdr.js"; -import { multiWorkGuide } from "./routing.js"; +import { multiWorkGuide } from "../agents/routing.js"; export const bindingSchema = z .object({ diff --git a/src/claude-quota.ts b/src/quota/claude-quota.ts similarity index 100% rename from src/claude-quota.ts rename to src/quota/claude-quota.ts diff --git a/src/quota-plugin.ts b/src/quota/quota-plugin.ts similarity index 100% rename from src/quota-plugin.ts rename to src/quota/quota-plugin.ts diff --git a/src/quota-rpc.ts b/src/quota/quota-rpc.ts similarity index 100% rename from src/quota-rpc.ts rename to src/quota/quota-rpc.ts diff --git a/src/quota.ts b/src/quota/quota.ts similarity index 100% rename from src/quota.ts rename to src/quota/quota.ts diff --git a/src/tui.tsx b/src/quota/tui.tsx similarity index 100% rename from src/tui.tsx rename to src/quota/tui.tsx diff --git a/src/anti-overengineering.md b/src/skills/anti-overengineering.md similarity index 100% rename from src/anti-overengineering.md rename to src/skills/anti-overengineering.md diff --git a/src/task-planning.md b/src/skills/task-planning.md similarity index 100% rename from src/task-planning.md rename to src/skills/task-planning.md diff --git a/tests/claude-quota.test.ts b/tests/claude-quota.test.ts index f4ecd4c..784b81d 100644 --- a/tests/claude-quota.test.ts +++ b/tests/claude-quota.test.ts @@ -2,7 +2,7 @@ import { afterEach, beforeEach, expect, test } from "bun:test"; import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { ClaudeQuotaTracker, normalizeClaudeQuota } from "../src/claude-quota.js"; +import { ClaudeQuotaTracker, normalizeClaudeQuota } from "../src/quota/claude-quota.js"; const payload = { five_hour: { utilization: 12.5, resets_at: "2026-10-07T12:00:00+00:00" }, diff --git a/tests/fixtures/native-agents-plugin.ts b/tests/fixtures/native-agents-plugin.ts index 16093e2..4d54d33 100644 --- a/tests/fixtures/native-agents-plugin.ts +++ b/tests/fixtures/native-agents-plugin.ts @@ -1,7 +1,7 @@ import { Plugin, Model, Provider } from "@opencode/plugin/effect"; import { fromPromise } from "@opencode/plugin/promise/adapter"; import { Effect } from "effect"; -import agents from "../../src/agents.js"; +import agents from "../../src/agents/agents.js"; export default Plugin.define({ id: agents.id, diff --git a/tests/fixtures/native-host-plugin.ts b/tests/fixtures/native-host-plugin.ts index 5ff8877..85f0f7e 100644 --- a/tests/fixtures/native-host-plugin.ts +++ b/tests/fixtures/native-host-plugin.ts @@ -6,7 +6,7 @@ import { Tool } from "@opencode/schema/tool"; import { Cause, Effect } from "effect"; import { z } from "zod"; import { appendFile } from "node:fs/promises"; -import multiWork from "../../src/multi-work.js"; +import multiWork from "../../src/multi-work/multi-work.js"; const probe = Rpc.define({ id: "multi-work-test", diff --git a/tests/herdr.test.ts b/tests/herdr.test.ts index 60769b6..724e527 100644 --- a/tests/herdr.test.ts +++ b/tests/herdr.test.ts @@ -2,7 +2,7 @@ import { afterEach, expect, test } from "bun:test"; import { mkdir, mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { command, Herdr } from "../src/herdr.js"; +import { command, Herdr } from "../src/multi-work/herdr.js"; const directories: string[] = []; afterEach(async () => { diff --git a/tests/multi-work.test.ts b/tests/multi-work.test.ts index bbd22aa..9e93905 100644 --- a/tests/multi-work.test.ts +++ b/tests/multi-work.test.ts @@ -9,8 +9,8 @@ import type { ToolEditor, ToolHooks } from "@opencode/plugin/effect/tool"; import type { AgentEditor } from "@opencode/plugin/effect/agent"; import type { SessionContext } from "@opencode/plugin/effect/session"; import { z } from "zod"; -import { Herdr, type HerdrRoot } from "../src/herdr.js"; -import { bindingKey, bindingSchema, installMultiWork } from "../src/multi-work.js"; +import { Herdr, type HerdrRoot } from "../src/multi-work/herdr.js"; +import { bindingKey, bindingSchema, installMultiWork } from "../src/multi-work/multi-work.js"; class FixtureHerdr extends Herdr { eligible = true; diff --git a/tests/plugin.test.ts b/tests/plugin.test.ts index 14c1ba7..f08d721 100644 --- a/tests/plugin.test.ts +++ b/tests/plugin.test.ts @@ -7,10 +7,10 @@ import type { SkillEditor } from "@opencode/plugin/promise/skill"; import type { DeepMutable } from "@opencode/plugin/promise/types"; import type { Skill } from "@opencode/schema/skill"; import type { ModelInfo } from "@opencode/client"; -import plugin from "../src/agents.js"; -import { model } from "../src/model.js"; +import plugin from "../src/agents/agents.js"; +import { model } from "../src/agents/model.js"; import { z } from "zod"; -import { AgentsRpc } from "../src/agents-rpc.js"; +import { AgentsRpc } from "../src/agents/agents-rpc.js"; const cleanups: Plugin.Cleanup[] = []; afterEach(async () => { diff --git a/tests/plugins.test.ts b/tests/plugins.test.ts index e35fe92..b38bd30 100644 --- a/tests/plugins.test.ts +++ b/tests/plugins.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "bun:test"; import type { Plugin } from "@opencode/plugin"; -import quota from "../src/quota-plugin.js"; -import { QuotaRpc } from "../src/quota-rpc.js"; +import quota from "../src/quota/quota-plugin.js"; +import { QuotaRpc } from "../src/quota/quota-rpc.js"; test("Quota loads independently and retains its RPC ID and nullable status", async () => { let controller: ReadableStreamDefaultController; diff --git a/tests/quota.test.ts b/tests/quota.test.ts index 0a05ada..0e9e50f 100644 --- a/tests/quota.test.ts +++ b/tests/quota.test.ts @@ -1,6 +1,6 @@ import { expect, test } from "bun:test"; import type { Schema } from "effect"; -import { normalizeQuota, QuotaTracker } from "../src/quota.js"; +import { normalizeQuota, QuotaTracker } from "../src/quota/quota.js"; const plus = { plan_type: "plus", diff --git a/tests/tui.test.ts b/tests/tui.test.ts index efc796f..a7513b0 100644 --- a/tests/tui.test.ts +++ b/tests/tui.test.ts @@ -4,7 +4,7 @@ import type { Route, SlotMap } from "@opencode/plugin/tui/context"; import { testRender, type JSX } from "@opentui/solid"; import { createSignal } from "solid-js"; import { build } from "../scripts/build.js"; -import type { QuotaStatus } from "../src/quota.js"; +import type { QuotaStatus } from "../src/quota/quota.js"; type SidebarSlotRender = (input: { readonly sessionID: string }) => JSX.Element; type HomeSlotRender = (input: SlotMap["prompt.footer"]) => JSX.Element; @@ -27,7 +27,7 @@ const status = (plan: string, remaining: number): QuotaStatus => ({ test("built quota slot stays reactive across pending, empty, failure, update, and session states", async () => { await build(); // Resolve the built bundle at runtime; tsc runs before build creates dist/tui.js. - const tui: typeof import("../src/tui.js") = await import( + const tui: typeof import("../src/quota/tui.js") = await import( new URL("../dist/tui.js", import.meta.url).href ); const { default: plugin } = tui; -- 2.54.0 From 513d51f702aafc579a95a9c2b4a92d63f614f084 Mon Sep 17 00:00:00 2001 From: StanPonomarev Date: Sat, 10 Oct 2026 15:16:53 +0200 Subject: [PATCH 2/2] stricter checks --- .dependency-cruiser.cjs | 62 ++++++ .gitea/workflows/ci.yml | 5 +- .gitea/workflows/release.yml | 5 +- .jscpd.json | 8 + .oxlintrc.json | 79 ++++++- bun.lock | 273 ++++++++++++++++++++++--- knip.json | 15 ++ package.json | 13 +- scripts/install.ts | 223 ++++++++++---------- scripts/test-multi-work-host.ts | 85 ++++---- src/agents/agents.ts | 124 +++++------ src/agents/model.ts | 4 +- src/agents/wildcard.ts | 8 + src/multi-work/herdr.ts | 8 +- src/multi-work/multi-work.ts | 64 +++--- src/quota/claude-quota.ts | 63 +++--- src/quota/quota-plugin.ts | 2 +- src/quota/quota.ts | 114 +++++++---- src/quota/tui.tsx | 51 ++--- tests/claude-quota.test.ts | 15 +- tests/fixtures/native-agents-plugin.ts | 10 +- tests/fixtures/native-host-plugin.ts | 4 +- tests/herdr.test.ts | 15 +- tests/install.test.ts | 78 ++++--- tests/multi-work.test.ts | 49 +++-- tests/package.test.ts | 17 +- tests/plugin.test.ts | 46 +++-- tests/plugins.test.ts | 6 +- tests/quota.test.ts | 4 +- tsconfig.json | 4 + 30 files changed, 984 insertions(+), 470 deletions(-) create mode 100644 .dependency-cruiser.cjs create mode 100644 .jscpd.json create mode 100644 knip.json create mode 100644 src/agents/wildcard.ts diff --git a/.dependency-cruiser.cjs b/.dependency-cruiser.cjs new file mode 100644 index 0000000..d5d63df --- /dev/null +++ b/.dependency-cruiser.cjs @@ -0,0 +1,62 @@ +/** @type {import('dependency-cruiser').IConfiguration} */ +module.exports = { + forbidden: [ + { + name: "no-circular", + severity: "error", + from: {}, + to: { circular: true }, + }, + { + name: "no-orphans", + severity: "error", + from: { orphan: true, pathNot: ["\\.d\\.ts$"] }, + to: {}, + }, + { + name: "not-to-unresolvable", + severity: "error", + from: {}, + to: { couldNotResolve: true, pathNot: ["^bun:"] }, + }, + { + name: "quota-is-standalone", + comment: "Quota ships independently of Agents and Multi-work.", + severity: "error", + from: { path: "^src/quota/" }, + to: { path: "^src/(agents|multi-work)/" }, + }, + { + name: "agents-is-standalone", + comment: "Agents must load without Quota or Multi-work.", + severity: "error", + from: { path: "^src/agents/" }, + to: { path: "^src/(quota|multi-work)/" }, + }, + { + name: "multi-work-not-to-quota", + comment: "Multi-work may build on Agents but not on Quota.", + severity: "error", + from: { path: "^src/multi-work/" }, + to: { path: "^src/quota/" }, + }, + { + name: "src-not-to-scripts-or-tests", + severity: "error", + from: { path: "^src/" }, + to: { path: "^(scripts|tests)/" }, + }, + ], + options: { + doNotFollow: { path: "node_modules" }, + tsConfig: { fileName: "tsconfig.json" }, + tsPreCompilationDeps: true, + // TypeScript 7 has no compiler API yet; swc parses TS/TSX for the cruise. + parser: "swc", + enhancedResolveOptions: { + exportsFields: ["exports"], + conditionNames: ["import", "types", "bun", "default"], + extensions: [".ts", ".tsx", ".js", ".d.ts"], + }, + }, +}; diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index ab3708e..2f13d15 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -22,8 +22,5 @@ jobs: - name: Verify and build run: | bun install --frozen-lockfile - bun run check - bun run lint - bun run format:check - bun run test + bun run verify bun run build diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 75c89cf..fd644fd 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -28,10 +28,7 @@ jobs: - name: Verify and build run: | bun install --frozen-lockfile - bun run check - bun run lint - bun run format:check - bun run test + bun run verify bun run build - name: Pack distributable run: | diff --git a/.jscpd.json b/.jscpd.json new file mode 100644 index 0000000..95dc85b --- /dev/null +++ b/.jscpd.json @@ -0,0 +1,8 @@ +{ + "path": ["src", "scripts", "tests"], + "format": ["typescript", "tsx"], + "threshold": 1, + "minTokens": 50, + "reporters": ["console"], + "gitignore": true +} diff --git a/.oxlintrc.json b/.oxlintrc.json index c782fd1..59f8adc 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -24,6 +24,34 @@ } ], "rules": { + "typescript/no-explicit-any": "error", + "typescript/ban-ts-comment": "error", + "typescript/no-non-null-assertion": "error", + "max-lines": [ + "error", + { + "max": 600, + "skipBlankLines": true, + "skipComments": true + } + ], + "max-lines-per-function": "off", + "complexity": ["error", 20], + "max-depth": ["error", 4], + "max-params": ["error", 5], + "typescript/no-floating-promises": "error", + "typescript/no-misused-promises": "error", + "typescript/no-unsafe-argument": "error", + "typescript/no-unsafe-assignment": "error", + "typescript/no-unsafe-call": "error", + "typescript/no-unsafe-member-access": "error", + "typescript/no-unsafe-return": "error", + "typescript/no-unsafe-enum-comparison": "error", + "typescript/no-unsafe-unary-minus": "error", + "typescript/no-unsafe-type-assertion": "error", + "typescript/no-unnecessary-condition": "error", + "typescript/strict-boolean-expressions": "error", + "typescript/switch-exhaustiveness-check": "error", "anti-slop/no-chained-type-assertions": "error", "anti-slop/no-conditional-empty-object-spread": "error", "anti-slop/no-known-value-widening": "error", @@ -38,6 +66,53 @@ "anti-slop/no-unknown-type-aliases": "error", "anti-slop/no-unsafe-dictionary-type": "error", "anti-slop/no-widen-then-assert": "error", - "anti-slop/require-safety-comment-for-type-assertion": "error" - } + "anti-slop/require-safety-comment-for-type-assertion": "error", + "typescript/prefer-readonly-parameter-types": "off", + "eslint/require-await": "off", + "eslint/no-await-in-loop": "off", + "import/max-dependencies": [ + "error", + { + "max": 15 + } + ], + "typescript/require-await": "off", + "typescript/consistent-return": "off", + "eslint/no-underscore-dangle": "off", + "unicorn/prefer-top-level-await": "off", + "unicorn/no-useless-undefined": [ + "error", + { + "checkArguments": false, + "checkArrowFunctionBody": false + } + ], + "oxc/no-map-spread": "off", + "eslint/no-useless-return": "off" + }, + "plugins": ["typescript", "unicorn", "oxc", "import", "promise"], + "categories": { + "correctness": "error", + "suspicious": "error", + "pedantic": "error", + "perf": "error" + }, + "overrides": [ + { + "files": ["tests/**"], + "rules": { + "typescript/no-unsafe-type-assertion": "off", + "typescript/await-thenable": "off", + "typescript/no-confusing-void-expression": "off" + } + }, + { + "files": ["**/*.tsx", "tests/tui.test.ts"], + "rules": { + "typescript/no-unsafe-return": "off", + "typescript/no-unsafe-assignment": "off", + "typescript/no-unsafe-member-access": "off" + } + } + ] } diff --git a/bun.lock b/bun.lock index 9f7d01c..c802aba 100644 --- a/bun.lock +++ b/bun.lock @@ -15,9 +15,14 @@ "@opentui/core": "0.5.14", "@opentui/solid": "0.5.14", "@oxlint/plugins": "1.86.0", + "@swc/core": "1.16.13", "@types/bun": "1.4.2", + "dependency-cruiser": "18.5.0", + "jscpd": "5.4.1", + "knip": "6.41.0", "oxfmt": "0.71.0", "oxlint": "1.86.0", + "oxlint-tsgolint": "7.0.2004", "solid-js": "1.9.15", "typescript": "7.0.2", }, @@ -144,6 +149,12 @@ "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="], + "@emnapi/core": ["@emnapi/core@1.11.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], + "@gar/promise-retry": ["@gar/promise-retry@1.0.3", "", {}, "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA=="], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], @@ -172,6 +183,8 @@ "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA=="], + "@npmcli/agent": ["@npmcli/agent@4.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg=="], "@npmcli/arborist": ["@npmcli/arborist@9.4.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-4Bm8hNixJG/sii1PMnag0V9i/sGOX9VRzFrUiZMSBJpGlLR38f+Btl85d07G9GL56xO0l0OZjvrGNYsDYp0xKA=="], @@ -260,6 +273,84 @@ "@opentui/solid": ["@opentui/solid@0.5.14", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.14", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-bBRl34mZ0wFGhjHX6y1VNiZmJ3DSm2DVPm0PNSVDpvq9qxRHuywEPTCn/Lgte0C9450tgf11cDqcE3pR9cZwVA=="], + "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.153.0", "", { "os": "android", "cpu": "arm" }, "sha512-BcWu25dMwMjHpaDCEidmpAi7rGg1qZoihJeUUH9bD55pVZ0z4Wa5CQgqSTo0R41H81oozisQKW3WqvAN2m77IQ=="], + + "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.153.0", "", { "os": "android", "cpu": "arm64" }, "sha512-9l5rdp2DhRqVriBHsNpu5cEf+hizZ4B58rt93HzyQEBUgZiC6qe2oFpaAAnXGCxHGnQExI1s7S2G0QhFacUZ6w=="], + + "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.153.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EcpsyRXHhENDpekpG4QNaSZj2F/BAz4Gh4o89zZwNss86R8KyRSQ6sXbAj74Xyeb4z3j/yBZZ6joQZhraIWyfw=="], + + "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.153.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-hlj80HUQy07/2lYp6rmxH+3u+H2ik3rjLR52CUdPApxmZCNxASDUf/+ykTzAHS/fehftmVMATKvPaWmuLHuasg=="], + + "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.153.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fWRcv2pMSh1qtez46MOu8vuUJ5fiaQZPHSphbWulbL7SHBMKfRgZl2PzjXZYQJbq7NEXyXbgIuIuUm+/Rmkv8w=="], + + "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.153.0", "", { "os": "linux", "cpu": "arm" }, "sha512-paZeUK1GXShl/bOJQET1/8AQxayFeuN4SIWAkgTRxE7ZQwv9uYSB2n0648smygP22N7jcI3zxAm0Z+ALNiIKxg=="], + + "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.153.0", "", { "os": "linux", "cpu": "arm" }, "sha512-qFPp5NwMf4K1C0O+DCVGmcbOaYyYAq98Rvv9p4VSfb777iUwlJCqMUxf6QG9N5f5ls4TEX6LitOZHi+6GL6rYQ=="], + + "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.153.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-oufEhZCX7saeo27Logra8cvBR1jQ/yw2zUI2hHmWw3qA/XYqEW31FOvLQBv7DWN32NjVdlcaP11WBBZTJo4k9g=="], + + "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.153.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-zXYzuAqng85h6+LI3iRm0zeMLX1/K2z41ZAMWxVRgt0D10VvZUaV5q+TEB46KDhoKBpdexoTLC6QoB/EiP2oqQ=="], + + "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.153.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-J7+NLwLEzdkKM9cKyPHH/AjXXstWOs98KYgLrPPnO4N9MO8EZRBfPNnBcS3S67uMOBkRpUmCl2FhRnWdQ5CbBA=="], + + "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.153.0", "", { "os": "linux", "cpu": "none" }, "sha512-sD0K11GQTLWylln54nPMMTtgmBbQrR5It/vMpZpy/fogiw8O2AvIE+9LuWUXddrWk9zvFIHGRcSgFn4IHOfoYg=="], + + "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.153.0", "", { "os": "linux", "cpu": "none" }, "sha512-7L66uql2BhvSz51LwfExjOdn6et/ydTiQxl23VApdKzJhTc3TczA1Qt6VR/UcvlQrL2ZbytIJb447vh7p5wmUw=="], + + "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.153.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hXV3T7mNyrPR19rbPYkglkQJtoM/UNo/xwbZeeqdAxEg8PXgb4LXXuxPpGgI4bzRRCWwLUxdDSS58xIyC2u1TA=="], + + "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.153.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Da8Vqs1xdtoDYtEjmozD7wGgJeLBQkMbR0WUBECOSxodyX5DXy8ySlvJWbukyO2Q0+TM9EK+4LT6tbq0jCg4hQ=="], + + "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.153.0", "", { "os": "linux", "cpu": "x64" }, "sha512-zGAPxNTIIw6X5WyTRscIFE/oDjpdNtrrl32ing6NOXdGjzRucadnxBilexLdeYQ9YxixF93GujpXyQ0jw7ddSg=="], + + "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.153.0", "", { "os": "none", "cpu": "arm64" }, "sha512-GoHzpqP5XyPIp9DHokoEdCp+K4UPl/h1neFj1uXnUB3pJYyOQ7NOhFVOttNUgCGcj2eywAvu5cRivTOSq4S10g=="], + + "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.153.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-xGcy12tO9k7zFbeyQzEuilfWfQpyRq23/fLPfN3wjSWuWv58k46fQT1hsO1KFNykZuVGW9xSJE/z592TmAoSDA=="], + + "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.153.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-o1ykUjWncvXX6N5a4KebgLjtD8zRui+f1llMhSGoSC9oP2KOqapRpdwmZ3NcNG0axFouwVKmhGBjd+IhA8BksA=="], + + "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.153.0", "", { "os": "win32", "cpu": "x64" }, "sha512-gxQz7G96Up136fd+2zWrP+o6FYGs9NO4Dyv55IoeJFJUDwLFHcLYY11hhA5wQKs0HoM57Q8esQ3nEVhnCdsjAQ=="], + + "@oxc-project/types": ["@oxc-project/types@0.153.0", "", {}, "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw=="], + + "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA=="], + + "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg=="], + + "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w=="], + + "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q=="], + + "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw=="], + + "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg=="], + + "@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA=="], + + "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA=="], + + "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw=="], + + "@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA=="], + + "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw=="], + + "@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w=="], + + "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ=="], + + "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg=="], + + "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw=="], + + "@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg=="], + + "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.24.2", "", { "dependencies": { "@emnapi/core": "1.11.2", "@emnapi/runtime": "1.11.2", "@napi-rs/wasm-runtime": "^1.1.6" }, "cpu": "none" }, "sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q=="], + + "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg=="], + + "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw=="], + "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.71.0", "", { "os": "android", "cpu": "arm" }, "sha512-l31EyBfB4egJeFua11aQFEUE9nnDtfpWCadqQovm0WL30t/yUHtdFl/5HyFXvd5xT8Ewh3U4TI9f30GowrQ1fw=="], "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.71.0", "", { "os": "android", "cpu": "arm64" }, "sha512-E8q39SUZzSXQ08oZoFoTkxRADkdBNgL6De4qgZYr2O4JCunwqrZwAyCebxIF3yVHBafHM30WUkhTkDi+jNYZOw=="], @@ -298,6 +389,18 @@ "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.71.0", "", { "os": "win32", "cpu": "x64" }, "sha512-L06SVp7Hu1EQTkh3+PHnKK26dxVbEpOG2InMwCooTE4MA437b5FgfTleCCiGn4ykISHnHU6UHaIg7SiMO7rBHA=="], + "@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@7.0.2004", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJk3ttju7Lz+Nv8WG4CsLyewoL1qf/Ny8S8OksJ7Bm/F14Tc9gMfW6arM1PCc57IzH/X/I79YsCWTgxX1FKibQ=="], + + "@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@7.0.2004", "", { "os": "darwin", "cpu": "x64" }, "sha512-0BFfHTzDxNDFPcu0UZAXT6CyCJHAXM0dZveyDb4KEHa2qF/DSnOKOrmvK/wFuFol9kvijbGM9JfuOsor+zWXRw=="], + + "@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@7.0.2004", "", { "os": "linux", "cpu": "arm64" }, "sha512-TAehQc+qdRXyDN3nl/r/3/oPrBVrbtrDeGMkFyG6mf+XphpoJ2lAMVFLclyvrVZCw02RbKROjyw8h72XwQQHcw=="], + + "@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@7.0.2004", "", { "os": "linux", "cpu": "x64" }, "sha512-LPunZvm6ZbWPfHMAyfZf9ci3HHvNEzLejO8zdqO3GoVGoSEHqqufHUD7+OgeatVSaJP7uXDJ2HaNOHIoH7go4Q=="], + + "@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@7.0.2004", "", { "os": "win32", "cpu": "arm64" }, "sha512-FVWplzDImWhiuawnIZVETaQecv4GWom6Jv4Fx2xj7hhXXDZ5okEgiw1gTCImHTIQsi2ycC5oSxVwrn69bMh7iw=="], + + "@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@7.0.2004", "", { "os": "win32", "cpu": "x64" }, "sha512-7PsxuUx11Ry9DYTWcljTzRbmZY9B6O9fFFfZV+aodQEMy6pfRT3fhoQRv9PtGN/89z1pPz3nFKrsFm6WqNtX7w=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.86.0", "", { "os": "android", "cpu": "arm" }, "sha512-63Ozq6yQn79B2UxjSZ9huJmI+3/ZPI7hxAe6TyFh9oQL447KnIMoffOdtog+h4KILbQr61ZRvFPW5gYbAUgpgQ=="], "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.86.0", "", { "os": "android", "cpu": "arm64" }, "sha512-JdLGp44phbf/0Du236Dt06yfK6Qw8xhTFeDvHJdjk167r59OfP5+BL31mgMYVnswS8e+j6tFuccSY0QDC/lgCw=="], @@ -386,10 +489,42 @@ "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@swc/core": ["@swc/core@1.16.13", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.28" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.16.13", "@swc/core-darwin-x64": "1.16.13", "@swc/core-linux-arm-gnueabihf": "1.16.13", "@swc/core-linux-arm64-gnu": "1.16.13", "@swc/core-linux-arm64-musl": "1.16.13", "@swc/core-linux-ppc64-gnu": "1.16.13", "@swc/core-linux-s390x-gnu": "1.16.13", "@swc/core-linux-x64-gnu": "1.16.13", "@swc/core-linux-x64-musl": "1.16.13", "@swc/core-win32-arm64-msvc": "1.16.13", "@swc/core-win32-ia32-msvc": "1.16.13", "@swc/core-win32-x64-msvc": "1.16.13" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-k4uUsIMS0IwOKVsrQs48IZK75O4roV3FnuJEdL7ES+DFESftdgvz73QBqN3VUAbUmUr78We4tzG0kgYj36M22Q=="], + + "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.16.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JrMH2h7ohd4mOIneNRx/diqTmCDSdWfp9uOdQ8VJ2V2CA7jOJ1jWb+qp8RoZLqgiVmwDDC7eySKB1kbvZ+jVXQ=="], + + "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.16.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-HauZMRxpOImRxgY6GXjw5gbD8ts2NcPZuLMM8htY8Mic7j1Izt/lxkXrKYUwqyU56YLwQZ4dHRT+6jFHkztcag=="], + + "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.16.13", "", { "os": "linux", "cpu": "arm" }, "sha512-tUSojGIythnHJKrElDM9OvuhBnK+FF39eM9iIBgj9kdfbAm6PhAM7dKbaSDcnX2gOLG2slkasjD0Z8m/YUlzOA=="], + + "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.16.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-qS3bk/ezRrLXGn1b764S/EG3/oKj6uRhnTNRAALpnuu8d9I0YwSiUkQghnX7lOH9X/yRr+qrFI3R0wAruO47Tg=="], + + "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.16.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-aeoYoG6fQsOS3mFOuTKvnJo1aaaxYNI0aRRlhdHaGP4q1YQx4XOc5Hkd35IFduWCBG3eZl3fPTjRuYvxpl7eTA=="], + + "@swc/core-linux-ppc64-gnu": ["@swc/core-linux-ppc64-gnu@1.16.13", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eEFoueZXWZ2S1lsqL8Ve2C8RjhzH9+Ktj8U4IGTUQL6CNG04+VhQiYQWJOf5xfVBU6I+PbH80yvsYegqZOOSZQ=="], + + "@swc/core-linux-s390x-gnu": ["@swc/core-linux-s390x-gnu@1.16.13", "", { "os": "linux", "cpu": "s390x" }, "sha512-K0q1ReVXL3d5bzBgZxS+yJq5q2xRjg4k2XXGj9yiCEpE5ZqJGQ4Gtk1sRrk8W2lo3KY0DCJD3Myt6x2SMvGArQ=="], + + "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.16.13", "", { "os": "linux", "cpu": "x64" }, "sha512-Qvpihw30irhIjy2f91BR1pamcJBCgf8hmr9XWenztAX1YLkneRkkTB/PFGWQubhaBqQhY2uZKViMj/xV61uMBQ=="], + + "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.16.13", "", { "os": "linux", "cpu": "x64" }, "sha512-iCGxHbh3Cq5vqRvCPlw3XkkDz4RlkPSyQwfFKbOKTMj5tiEuojY/rLmf4BMfI9Z8yPJTf9VB07t3NbKInoC97g=="], + + "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.16.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-iOabn6cd+hg3cnoKlAC8j3Yufv8nQHBVU5OIDX8dCPA95PjAZ0B0TlDn9sWivk8ezo/cLJux7p9n0B9vRej+1Q=="], + + "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.16.13", "", { "os": "win32", "cpu": "ia32" }, "sha512-+1b/3xBNuVbpnJIZUCAaSdscOPYRWq85eohKx44y/3qbPp56UMiCJWBiWtyr7K5F1nf1JENXm2IBSEJaLgWq6Q=="], + + "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.16.13", "", { "os": "win32", "cpu": "x64" }, "sha512-6kEJhYshk7OVoVIWryiHqjCNuwZeOlPTS6et+bKV/WhtHs8fLA01wyTLrQGi+4ultgRe/o0M4b25K/KKdvl0dQ=="], + + "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], + + "@swc/types": ["@swc/types@0.1.28", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw=="], + "@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="], "@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.4", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A=="], + "@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="], "@types/node": ["@types/node@26.5.0", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-dVSGpriSoCgz8WnDNTuSSuSv1PC/ALXihO4ulRZt7Md8k9mlbdin3lGOcDE8SnWOgf513ByWlXd7BK4azmyg/A=="], @@ -438,11 +573,21 @@ "abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], + "acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "acorn-jsx-walk": ["acorn-jsx-walk@2.0.0", "", {}, "sha512-uuo6iJj4D4ygkdzd6jPtcxs8vZgDX9YFIkqczGImoypX2fQ4dVImmu3UzA4ynixCIMTrEOWW+95M2HuBaCEOVA=="], + + "acorn-loose": ["acorn-loose@8.5.2", "", { "dependencies": { "acorn": "^8.15.0" } }, "sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A=="], + + "acorn-walk": ["acorn-walk@8.3.5", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], - "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], @@ -480,6 +625,8 @@ "caniuse-lite": ["caniuse-lite@1.0.30001810", "", {}, "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], @@ -492,6 +639,8 @@ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "commander": ["commander@15.0.0", "", {}, "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg=="], + "common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], "content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], @@ -514,6 +663,8 @@ "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + "dependency-cruiser": ["dependency-cruiser@18.5.0", "", { "dependencies": { "acorn": "8.18.0", "acorn-jsx": "5.3.2", "acorn-jsx-walk": "2.0.0", "acorn-loose": "8.5.2", "acorn-walk": "8.3.5", "commander": "15.0.0", "enhanced-resolve": "5.26.0", "ignore": "7.0.11", "interpret": "3.1.1", "is-installed-globally": "1.0.1", "json5": "2.2.3", "picomatch": "4.0.7", "prompts": "2.4.2", "rechoir": "0.8.0", "safe-regex": "2.1.1", "semver": "7.8.5", "tsconfig-paths-webpack-plugin": "4.2.0", "watskeburt": "6.0.0" }, "bin": { "depcruise": "bin/dependency-cruiser.mjs", "depcruise-fmt": "bin/depcruise-fmt.mjs", "dependency-cruise": "bin/dependency-cruiser.mjs", "depcruise-baseline": "bin/depcruise-baseline.mjs", "dependency-cruiser": "bin/dependency-cruiser.mjs", "depcruise-wrap-stream-in-html": "bin/wrap-stream-in-html.mjs" } }, "sha512-LFvJOvufjQ7XTucSI40NHqse0gcQBevDGkZabLAKcGwO+VWOywTqZ5EyFRYWSokNxvLOO7v6EXyNi+9I72oWUA=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], @@ -528,6 +679,8 @@ "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + "enhanced-resolve": ["enhanced-resolve@5.26.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw=="], + "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], @@ -542,6 +695,8 @@ "fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], + "fd-package-json": ["fd-package-json@2.0.0", "", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], @@ -552,6 +707,8 @@ "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + "formatly": ["formatly@0.11.4", "", { "dependencies": { "fd-package-json": "^2.0.0", "package-manager-detector": "^1.8.0" }, "bin": { "formatly": "bin/index.mjs" } }, "sha512-TeCC10lP8KCgoX+Fe5lryILIT0/Dy+nP0OSVnsuB5CwXoLuOdqxCYlPFF1inR8S/zTy1ec7TjhS2TeRKWzzImA=="], + "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], @@ -568,8 +725,12 @@ "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], + "get-tsconfig": ["get-tsconfig@4.14.3", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA=="], + "glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], + "global-directory": ["global-directory@4.0.1", "", { "dependencies": { "ini": "4.1.1" } }, "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q=="], + "google-auth-library": ["google-auth-library@10.5.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.0.0", "gcp-metadata": "^8.0.0", "google-logging-utils": "^1.0.0", "gtoken": "^8.0.0", "jws": "^4.0.0" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="], "google-logging-utils": ["google-logging-utils@1.2.0", "", {}, "sha512-WE9av4wKDZgRjBwgVUabocx8T6/7o3Ca1Fat46FXDhXVAFibzNadedcOXrdgd1Kzmk8tsk/9ZH89Wyf/SqeZ3A=="], @@ -578,6 +739,8 @@ "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], @@ -592,10 +755,14 @@ "iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="], + "ignore": ["ignore@7.0.11", "", {}, "sha512-YChdK5txDjwGUvgR7oCJcLGkwi3LDh8Zx8tS7ndYciLEg/oOCL26VUBSUEtgS7EjiybcBqFxh5j0rAdDX7/bbg=="], + "ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="], "ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], + "interpret": ["interpret@3.1.1", "", {}, "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ=="], + "ip-address": ["ip-address@10.7.0", "", {}, "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA=="], "is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="], @@ -608,14 +775,38 @@ "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + "is-installed-globally": ["is-installed-globally@1.0.1", "", { "dependencies": { "global-directory": "^4.0.1", "is-path-inside": "^4.0.0" } }, "sha512-li88H4QGRoNMX27jEmY8nR515oJVspAgC/WFMlhHfFV8RJ4QyGpHhXnwAe9gH5RIgKmdYRUmrOhQobcgEjIdSw=="], + + "is-path-inside": ["is-path-inside@4.0.0", "", {}, "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA=="], + "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "jscpd": ["jscpd@5.4.1", "", { "optionalDependencies": { "jscpd-darwin-arm64": "5.4.1", "jscpd-darwin-x64": "5.4.1", "jscpd-linux-arm64-gnu": "5.4.1", "jscpd-linux-arm64-musl": "5.4.1", "jscpd-linux-x64-gnu": "5.4.1", "jscpd-linux-x64-musl": "5.4.1", "jscpd-windows-arm64-msvc": "5.4.1", "jscpd-windows-x64-msvc": "5.4.1" }, "bin": { "jscpd": "run-jscpd.js" } }, "sha512-afUt+LSQMmzSPYrWZlNGTwj8X4tmwVJbMNmr92qxPf4uUF/naLwG7SQyMPEZtrHqGgzGxmAzNjiwlVdjls2MyQ=="], + + "jscpd-darwin-arm64": ["jscpd-darwin-arm64@5.4.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LXHVeH60C9BsozcVIMPmXWvj97KqFKbCJYmYG4hDwfwIwS1kz+uF7yiObckP6h2xo12pD88nI4XjWTB5frjZUw=="], + + "jscpd-darwin-x64": ["jscpd-darwin-x64@5.4.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Gqck4tcMZjv4IvYHU2Vcikb885zTADo5T/YfEqeu1i5W5tfFpLdViiTYrh5wbrW+uxBqC33gHpG1hy0xbGYknQ=="], + + "jscpd-linux-arm64-gnu": ["jscpd-linux-arm64-gnu@5.4.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-XUYZJZVxSY7JIBEoyOOMTgvJwmymkns4wG55tu6I/vRKXnS5QtaTESQfRLt6xj1+62aflAvr01FAhPAy+du6tA=="], + + "jscpd-linux-arm64-musl": ["jscpd-linux-arm64-musl@5.4.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-h2sH8Bk++yBxWqq2QAy4fvPzXkw1vecDSyOmzLwPfnRQoQ2Q/EWxCNOrgJSb+SNMLWoHLLzfqx8m9wt2GG6a8w=="], + + "jscpd-linux-x64-gnu": ["jscpd-linux-x64-gnu@5.4.1", "", { "os": "linux", "cpu": "x64" }, "sha512-UiC4YoGAVVLy6hPVz8A6cndo7W5br4FAO2hADnFeinhBPnXPu0QFh1q/s/8B3ldeQHQkpYd/l5cjqNBMrbm78w=="], + + "jscpd-linux-x64-musl": ["jscpd-linux-x64-musl@5.4.1", "", { "os": "linux", "cpu": "x64" }, "sha512-toAafl5roqfFotPrDJNMY9noNVZ9dReBqcO/nT5pJ8+7aq+opbscaLUcV4+8jxTq5btUD6CiO72+Fu+TyUZv3Q=="], + + "jscpd-windows-arm64-msvc": ["jscpd-windows-arm64-msvc@5.4.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-JLMga/NIwv/OPurPsXA2/d5OdWfdwrsBk2D4NhyKnrV/uNjo1BIi2zXztzDyTQVKMK/TEK6GPgLD143GG1fZ0A=="], + + "jscpd-windows-x64-msvc": ["jscpd-windows-x64-msvc@5.4.1", "", { "os": "win32", "cpu": "x64" }, "sha512-sN57Y9YP3ijrqc1IsWDceOFHUwbukg9/mU2NSDHTryKKc5CUvWz+o9GId8uKTiJIhkKfR/Ce5GKkCepTwB6kaw=="], + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], @@ -638,6 +829,10 @@ "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], + "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], + + "knip": ["knip@6.41.0", "", { "dependencies": { "formatly": "^0.11.4", "get-tsconfig": "4.14.3", "jiti": "^2.7.0", "oxc-parser": "^0.153.0", "oxc-resolver": "11.24.2", "picomatch": "^4.0.7", "smol-toml": "^1.9.0", "strip-json-comments": "5.0.3", "tinyglobby": "^0.2.17", "unbash": "^5.0.0", "yaml": "^2.9.1", "zod": "^4.6.5" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-DrhQlIuV6xScd5Q+WTF1znd1w41QzxFGCtAHXCajsH/ndGMotHoNYbdXbuFtzW3mIOmniHtZ7zCtvnQkUmJtQQ=="], + "locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], "lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], @@ -654,6 +849,8 @@ "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], @@ -704,10 +901,16 @@ "open": ["open@11.0.4", "", { "dependencies": { "default-browser": "^5.5.1", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.2.1", "wsl-utils": "^1.0.0" } }, "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg=="], + "oxc-parser": ["oxc-parser@0.153.0", "", { "dependencies": { "@oxc-project/types": "^0.153.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.153.0", "@oxc-parser/binding-android-arm64": "0.153.0", "@oxc-parser/binding-darwin-arm64": "0.153.0", "@oxc-parser/binding-darwin-x64": "0.153.0", "@oxc-parser/binding-freebsd-x64": "0.153.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.153.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.153.0", "@oxc-parser/binding-linux-arm64-gnu": "0.153.0", "@oxc-parser/binding-linux-arm64-musl": "0.153.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.153.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.153.0", "@oxc-parser/binding-linux-riscv64-musl": "0.153.0", "@oxc-parser/binding-linux-s390x-gnu": "0.153.0", "@oxc-parser/binding-linux-x64-gnu": "0.153.0", "@oxc-parser/binding-linux-x64-musl": "0.153.0", "@oxc-parser/binding-openharmony-arm64": "0.153.0", "@oxc-parser/binding-win32-arm64-msvc": "0.153.0", "@oxc-parser/binding-win32-ia32-msvc": "0.153.0", "@oxc-parser/binding-win32-x64-msvc": "0.153.0" } }, "sha512-cEnpyyV1OJRXv++SFNw0z8i+2o/cr88rVLaOYJafELDoHM5yHvCAbwGRLvxuany6SNLcbblSMUyZaGzH+quSYg=="], + + "oxc-resolver": ["oxc-resolver@11.24.2", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.24.2", "@oxc-resolver/binding-android-arm64": "11.24.2", "@oxc-resolver/binding-darwin-arm64": "11.24.2", "@oxc-resolver/binding-darwin-x64": "11.24.2", "@oxc-resolver/binding-freebsd-x64": "11.24.2", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.24.2", "@oxc-resolver/binding-linux-arm-musleabihf": "11.24.2", "@oxc-resolver/binding-linux-arm64-gnu": "11.24.2", "@oxc-resolver/binding-linux-arm64-musl": "11.24.2", "@oxc-resolver/binding-linux-ppc64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-musl": "11.24.2", "@oxc-resolver/binding-linux-s390x-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-musl": "11.24.2", "@oxc-resolver/binding-openharmony-arm64": "11.24.2", "@oxc-resolver/binding-wasm32-wasi": "11.24.2", "@oxc-resolver/binding-win32-arm64-msvc": "11.24.2", "@oxc-resolver/binding-win32-x64-msvc": "11.24.2" } }, "sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw=="], + "oxfmt": ["oxfmt@0.71.0", "", { "dependencies": { "tinypool": "2.2.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.71.0", "@oxfmt/binding-android-arm64": "0.71.0", "@oxfmt/binding-darwin-arm64": "0.71.0", "@oxfmt/binding-darwin-x64": "0.71.0", "@oxfmt/binding-freebsd-x64": "0.71.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.71.0", "@oxfmt/binding-linux-arm-musleabihf": "0.71.0", "@oxfmt/binding-linux-arm64-gnu": "0.71.0", "@oxfmt/binding-linux-arm64-musl": "0.71.0", "@oxfmt/binding-linux-ppc64-gnu": "0.71.0", "@oxfmt/binding-linux-riscv64-gnu": "0.71.0", "@oxfmt/binding-linux-riscv64-musl": "0.71.0", "@oxfmt/binding-linux-s390x-gnu": "0.71.0", "@oxfmt/binding-linux-x64-gnu": "0.71.0", "@oxfmt/binding-linux-x64-musl": "0.71.0", "@oxfmt/binding-openharmony-arm64": "0.71.0", "@oxfmt/binding-win32-arm64-msvc": "0.71.0", "@oxfmt/binding-win32-ia32-msvc": "0.71.0", "@oxfmt/binding-win32-x64-msvc": "0.71.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-lUPUl0d/+Io5pDrsPXWs6rB4N/bpB78oj9CTDpnbulfDz+0r3XXcHPlQ7kRPJ2GjIT4nX+/mcqunOeP9BvsEtg=="], "oxlint": ["oxlint@1.86.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.86.0", "@oxlint/binding-android-arm64": "1.86.0", "@oxlint/binding-darwin-arm64": "1.86.0", "@oxlint/binding-darwin-x64": "1.86.0", "@oxlint/binding-freebsd-x64": "1.86.0", "@oxlint/binding-linux-arm-gnueabihf": "1.86.0", "@oxlint/binding-linux-arm-musleabihf": "1.86.0", "@oxlint/binding-linux-arm64-gnu": "1.86.0", "@oxlint/binding-linux-arm64-musl": "1.86.0", "@oxlint/binding-linux-ppc64-gnu": "1.86.0", "@oxlint/binding-linux-riscv64-gnu": "1.86.0", "@oxlint/binding-linux-riscv64-musl": "1.86.0", "@oxlint/binding-linux-s390x-gnu": "1.86.0", "@oxlint/binding-linux-x64-gnu": "1.86.0", "@oxlint/binding-linux-x64-musl": "1.86.0", "@oxlint/binding-openharmony-arm64": "1.86.0", "@oxlint/binding-win32-arm64-msvc": "1.86.0", "@oxlint/binding-win32-ia32-msvc": "1.86.0", "@oxlint/binding-win32-x64-msvc": "1.86.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2003", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-og0lhgvZfgGF//gOOmZXvtr+GmBbAGEnbEhv/QUg7UW2Wi4wHMnJbnMD+zuHgPdJxdklfgpPupdlAaAySyxrZg=="], + "oxlint-tsgolint": ["oxlint-tsgolint@7.0.2004", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "7.0.2004", "@oxlint-tsgolint/darwin-x64": "7.0.2004", "@oxlint-tsgolint/linux-arm64": "7.0.2004", "@oxlint-tsgolint/linux-x64": "7.0.2004", "@oxlint-tsgolint/win32-arm64": "7.0.2004", "@oxlint-tsgolint/win32-x64": "7.0.2004" }, "bin": { "tsgolint": "./bin/tsgolint.js" } }, "sha512-vQ9WDF3fiZJvRdSDosNOflerOCOpwol6vWzVDxW76RcU19cjTh7engvkHLvmv+tzedR8fAiJUVUGr6IVZdkzXQ=="], + "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], @@ -718,6 +921,8 @@ "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + "package-manager-detector": ["package-manager-detector@1.9.0", "", {}, "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA=="], + "pacote": ["pacote@21.5.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": { "pacote": "bin/index.js" } }, "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg=="], "parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="], @@ -750,16 +955,24 @@ "promise-call-limit": ["promise-call-limit@3.0.2", "", {}, "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw=="], + "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], + "pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="], "read-cmd-shim": ["read-cmd-shim@6.0.0", "", {}, "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A=="], + "rechoir": ["rechoir@0.8.0", "", { "dependencies": { "resolve": "^1.20.0" } }, "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ=="], + "redis": ["redis@6.2.1", "", { "dependencies": { "@redis/bloom": "6.2.1", "@redis/client": "6.2.1", "@redis/json": "6.2.1", "@redis/search": "6.2.1", "@redis/time-series": "6.2.1" } }, "sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg=="], + "regexp-tree": ["regexp-tree@0.1.27", "", { "bin": { "regexp-tree": "bin/regexp-tree" } }, "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA=="], + "reselect": ["reselect@4.1.8", "", {}, "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="], "resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="], + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="], "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], @@ -768,9 +981,11 @@ "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "safe-regex": ["safe-regex@2.1.1", "", { "dependencies": { "regexp-tree": "~0.1.1" } }, "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A=="], + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], "seroval": ["seroval@1.5.6", "", {}, "sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA=="], @@ -784,8 +999,12 @@ "sigstore": ["sigstore@4.1.1", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0", "@sigstore/sign": "^4.1.1", "@sigstore/tuf": "^4.0.2", "@sigstore/verify": "^3.1.1" } }, "sha512-endqECJkfhozrXMK5ngu/UAA0xVcVEFdnHJCElGaExypjW+HK5i6zu3NteLoaX/iFbRUbC3+DjttQs0GARr+5w=="], + "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], + "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + "smol-toml": ["smol-toml@1.9.1", "", {}, "sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ=="], + "socks": ["socks@2.8.10", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ=="], "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], @@ -808,8 +1027,16 @@ "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + + "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + "tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="], "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], @@ -818,12 +1045,18 @@ "treeverse": ["treeverse@3.0.0", "", {}, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], + "tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="], + + "tsconfig-paths-webpack-plugin": ["tsconfig-paths-webpack-plugin@4.2.0", "", { "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.7.0", "tapable": "^2.2.1", "tsconfig-paths": "^4.1.2" } }, "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "tuf-js": ["tuf-js@4.1.0", "", { "dependencies": { "@tufjs/models": "4.1.0", "debug": "^4.4.3", "make-fetch-happen": "^15.0.1" } }, "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ=="], "typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], + "unbash": ["unbash@5.0.0", "", {}, "sha512-RYNm/ISFtflWpIcXTPHHLJZ0mqzInav+L9ke9PcL+hHsSf9+Fd/syPb614Mlqs/O3AYgjnvxDOFl0a+zVqi1/w=="], + "undici": ["undici@8.10.2", "", {}, "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ=="], "undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="], @@ -836,6 +1069,8 @@ "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], + "watskeburt": ["watskeburt@6.0.0", "", { "bin": { "watskeburt": "dist/run-cli.js" } }, "sha512-jfiuDABaxSkC71T6oZ3vCS99roYkSHm/+As+G0Dz8taAHQb+SJBvLEm5RlsgG71XdfAj3rv7eudUBTgwcQUPlQ=="], + "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], "web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="], @@ -854,32 +1089,28 @@ "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="], + "zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="], "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "@isaacs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - "@npmcli/arborist/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - - "@npmcli/config/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - - "@npmcli/fs/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - - "@npmcli/git/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - "@npmcli/git/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], - "@npmcli/metavuln-calculator/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - - "@npmcli/package-json/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - "@npmcli/promise-spawn/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], "@opencode/plugin/zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], @@ -892,22 +1123,16 @@ "gcp-metadata/google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], + "global-directory/ini": ["ini@4.1.1", "", {}, "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g=="], + "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "node-gyp/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - "node-gyp/undici": ["undici@6.28.1", "", {}, "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA=="], "node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], - "npm-install-checks/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - - "npm-package-arg/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - - "npm-pick-manifest/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], "rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], @@ -920,12 +1145,12 @@ "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "wrap-ansi/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], diff --git a/knip.json b/knip.json new file mode 100644 index 0000000..082dbc7 --- /dev/null +++ b/knip.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://unpkg.com/knip@6/schema.json", + "entry": [ + "src/agents/agents.ts", + "src/multi-work/multi-work.ts", + "src/quota/quota-plugin.ts", + "src/quota/quota-rpc.ts", + "src/quota/tui.tsx", + "scripts/*.ts", + "tests/**/*.test.ts", + "tests/fixtures/*.ts" + ], + "project": ["src/**/*.{ts,tsx}", "scripts/**/*.ts", "tests/**/*.ts"], + "ignoreDependencies": ["@swc/core"] +} diff --git a/package.json b/package.json index 533f9c4..061968d 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,15 @@ }, "scripts": { "check": "tsc --noEmit", - "lint": "oxlint --deny-warnings .", + "lint": "oxlint --type-aware --deny-warnings .", "format": "oxfmt --write .", "format:check": "oxfmt --check .", "test": "bun test --conditions=browser", - "build": "bun scripts/build.ts && tsc --project tsconfig.build.json --emitDeclarationOnly" + "build": "bun scripts/build.ts && tsc --project tsconfig.build.json --emitDeclarationOnly", + "knip": "knip", + "duplicates": "jscpd", + "deps": "depcruise src scripts tests", + "verify": "bun run lint && bun run check && bun run knip && bun run duplicates && bun run deps && bun run format:check && bun run test" }, "devDependencies": { "@opencode/client": "2.0.22", @@ -52,9 +56,14 @@ "@opentui/core": "0.5.14", "@opentui/solid": "0.5.14", "@oxlint/plugins": "1.86.0", + "@swc/core": "1.16.13", "@types/bun": "1.4.2", + "dependency-cruiser": "18.5.0", + "jscpd": "5.4.1", + "knip": "6.41.0", "oxfmt": "0.71.0", "oxlint": "1.86.0", + "oxlint-tsgolint": "7.0.2004", "solid-js": "1.9.15", "typescript": "7.0.2" }, diff --git a/scripts/install.ts b/scripts/install.ts index c7f1a1e..a14603c 100644 --- a/scripts/install.ts +++ b/scripts/install.ts @@ -50,11 +50,118 @@ const nativePlugin = z.union([ z.object({ id: z.string(), effect: z.function() }), ]); type DirectoryExports = { ".": string; "./tui"?: string }; +type Name = (typeof names)[number]; + +async function prompt(retained: Name[]) { + const input = createInterface({ input: process.stdin, output: process.stdout }); + try { + const defaults = retained.length > 0 ? retained : names; + const chosen = ( + ( + await input.question(`Plugins (agents,multi-work,quota) [${defaults.join(",")}]: `) + ).trim() || defaults.join(",") + ).split(","); + if ( + chosen.includes("multi-work") && + !chosen.includes("agents") && + /^(y|yes)?$/iu.test( + (await input.question("Multi-work requires Agents. Add Agents? [Y/n]: ")).trim(), + ) + ) + chosen.push("agents"); + return chosen; + } finally { + input.close(); + } +} + +async function choose(retained: Name[], selection?: string) { + if (selection !== undefined) return selection.split(","); + if (process.stdin.isTTY) return prompt(retained); + if (retained.length === 0) + throw new Error( + "Noninteractive installation requires --plugins agents,multi-work,quota (or a valid subset)", + ); + return [...retained]; +} + +async function stage(source: string, staged: string, name: Name) { + const file = name === "quota" ? "quota-plugin" : name; + const entrypoint = join(source, "dist", `${file}.js`); + const { default: plugin } = z.object({ default: nativePlugin }).parse(await import(entrypoint)); + if (plugin.id !== `stanp-opencode.${name}`) + throw new Error(`Invalid native OpenCode plugin: ${name}`); + const directory = join(staged, name); + await mkdir(directory); + await copyFile(entrypoint, join(directory, "index.js")); + const exports: DirectoryExports = { ".": "./index.js" }; + if (name === "quota") { + const tui = join(source, "dist", "tui.js"); + if ( + !new Bun.Transpiler({ loader: "js" }) + .scan(await Bun.file(tui).text()) + .exports.includes("default") + ) + throw new Error("Quota lacks its TUI entrypoint"); + await copyFile(tui, join(directory, "tui.js")); + exports["./tui"] = "./tui.js"; + } + await Bun.write( + join(directory, "package.json"), + JSON.stringify({ + name: `stanp-opencode-${name}`, + type: "module", + main: "./index.js", + exports, + }), + ); +} + +async function activate( + source: string, + config: string, + selected: Name[], + updated: z.infer, +) { + const configFile = join(config, "opencode.json"); + const parent = join(config, "plugins"); + await mkdir(parent, { recursive: true }); + const staged = join(parent, `.stanp-opencode.new.${process.pid}`); + const backup = join(parent, `.stanp-opencode.old.${process.pid}`); + const target = join(parent, "stanp-opencode"); + const configStage = join(config, `.stanp-opencode.config.${process.pid}`); + let saved = false; + let activated = false; + try { + await mkdir(staged); + for (const name of selected) await stage(source, staged, name); + await Bun.write(configStage, JSON.stringify(updated, null, 4) + "\n"); + try { + await rename(target, backup); + saved = true; + } catch (error) { + if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) + throw error; + } + await rename(staged, target); + activated = true; + await rename(configStage, configFile); + } catch (error) { + if (activated) await rm(target, { recursive: true, force: true }); + if (saved) await rename(backup, target); + throw error; + } finally { + await rm(staged, { recursive: true, force: true }); + await rm(configStage, { force: true }); + } + if (saved) await rm(backup, { recursive: true, force: true }); + await rm(join(parent, "stanp-opencode.js"), { force: true }); +} export async function install(source: string, config: string, selection?: string) { const absoluteBase = join(config, "plugins", "stanp-opencode"); const monolith = (target: string) => - target === base || target === absoluteBase || /^stanp-opencode(?:@[^/]+)?$/.test(target); + target === base || target === absoluteBase || /^stanp-opencode(?:@[^/]+)?$/u.test(target); const owned = new Set( names.flatMap((name) => [ `${base}/${name}`, @@ -82,39 +189,7 @@ export async function install(source: string, config: string, selection?: string entry.package === `stanp-opencode/${name}`, ), ); - let chosen: string[]; - if (selection !== undefined) chosen = selection.split(","); - else if (process.stdin.isTTY) { - const input = createInterface({ input: process.stdin, output: process.stdout }); - try { - const defaults = retained.length ? retained : names; - chosen = ( - ( - await input.question( - `Plugins (agents,multi-work,quota) [${defaults.join(",")}]: `, - ) - ).trim() || defaults.join(",") - ).split(","); - if (chosen.includes("multi-work") && !chosen.includes("agents")) { - if ( - /^(y|yes)?$/i.test( - ( - await input.question("Multi-work requires Agents. Add Agents? [Y/n]: ") - ).trim(), - ) - ) - chosen.push("agents"); - } - } finally { - input.close(); - } - } else { - if (!retained.length) - throw new Error( - "Noninteractive installation requires --plugins agents,multi-work,quota (or a valid subset)", - ); - chosen = [...retained]; - } + const chosen = await choose(retained, selection); if ( !z.array(z.enum(names)).min(1).safeParse(chosen).success || new Set(chosen).size !== chosen.length @@ -131,17 +206,16 @@ export async function install(source: string, config: string, selection?: string entry.package === `stanp-opencode/${name}` || (name === "agents" && monolith(entry.package)), ); - const options: NonNullable = {}; - Object.assign(options, prior?.options); - delete options.playwright; + const options: NonNullable = { ...prior?.options }; + delete options["playwright"]; fill(options, skeleton(name)); const entry = entrySchema.parse({ ...prior, package: `${base}/${name}` }); delete entry.options; - if (Object.keys(options).length) entry.options = options; + if (Object.keys(options).length > 0) entry.options = options; return entry; }); const first = configured.findIndex((entry) => isOwned(entry.package)); - const next = entries.filter((_entry, index) => !isOwned(configured[index]!.package)); + const next = entries.filter((_entry, index) => !isOwned(configured[index]?.package ?? "")); next.splice(first < 0 ? next.length : first, 0, ...registrations); const updated: z.infer = { ...current, @@ -149,75 +223,13 @@ export async function install(source: string, config: string, selection?: string plugins: next, }; // Coordinate delegates to workers from Multi-work children, so routing needs depth >= 2. - const experimental = experimentalSchema.safeParse(current.experimental ?? {}); + const experimental = experimentalSchema.safeParse(current["experimental"] ?? {}); if (selected.includes("agents") && experimental.success) - updated.experimental = { + updated["experimental"] = { ...experimental.data, subagent_depth: Math.max(experimental.data.subagent_depth ?? 0, 2), }; - const parent = join(config, "plugins"); - await mkdir(parent, { recursive: true }); - const staged = join(parent, `.stanp-opencode.new.${process.pid}`); - const backup = join(parent, `.stanp-opencode.old.${process.pid}`); - const target = join(parent, "stanp-opencode"); - const configStage = join(config, `.stanp-opencode.config.${process.pid}`); - let saved = false; - let activated = false; - try { - await mkdir(staged); - for (const name of selected) { - const file = name === "quota" ? "quota-plugin" : name; - const entrypoint = join(source, "dist", `${file}.js`); - const { default: definition } = await import(entrypoint); - const plugin = nativePlugin.parse(definition); - if (plugin.id !== `stanp-opencode.${name}`) - throw new Error(`Invalid native OpenCode plugin: ${name}`); - const directory = join(staged, name); - await mkdir(directory); - await copyFile(entrypoint, join(directory, "index.js")); - const exports: DirectoryExports = { ".": "./index.js" }; - if (name === "quota") { - const tui = join(source, "dist", "tui.js"); - if ( - !new Bun.Transpiler({ loader: "js" }) - .scan(await Bun.file(tui).text()) - .exports.includes("default") - ) - throw new Error("Quota lacks its TUI entrypoint"); - await copyFile(tui, join(directory, "tui.js")); - exports["./tui"] = "./tui.js"; - } - await Bun.write( - join(directory, "package.json"), - JSON.stringify({ - name: `stanp-opencode-${name}`, - type: "module", - main: "./index.js", - exports, - }), - ); - } - await Bun.write(configStage, JSON.stringify(updated, null, 4) + "\n"); - try { - await rename(target, backup); - saved = true; - } catch (error) { - if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) - throw error; - } - await rename(staged, target); - activated = true; - await rename(configStage, configFile); - } catch (error) { - if (activated) await rm(target, { recursive: true, force: true }); - if (saved) await rename(backup, target); - throw error; - } finally { - await rm(staged, { recursive: true, force: true }); - await rm(configStage, { force: true }); - } - if (saved) await rm(backup, { recursive: true, force: true }); - await rm(join(parent, "stanp-opencode.js"), { force: true }); + await activate(source, config, selected, updated); console.log(`Installed ${selected.join(", ")}. Restart OpenCode.`); if (oldMonolith) console.log( @@ -227,6 +239,7 @@ export async function install(source: string, config: string, selection?: string if (import.meta.main) { const [source, config, selection] = process.argv.slice(2); - if (!source || !config) throw new Error("Expected package directory and config directory"); + if (source === undefined || source === "" || config === undefined || config === "") + throw new Error("Expected package directory and config directory"); await install(source, config, selection); } diff --git a/scripts/test-multi-work-host.ts b/scripts/test-multi-work-host.ts index 5b907e3..c330241 100644 --- a/scripts/test-multi-work-host.ts +++ b/scripts/test-multi-work-host.ts @@ -8,14 +8,15 @@ import { OpenCode } from "@opencode/client"; import { command } from "../src/multi-work/herdr.js"; import { z } from "zod"; -const binary = process.env.OPENCODE_2022; -if (!binary) throw new Error("Set OPENCODE_2022 to an isolated OpenCode 2.0.22 binary"); +const binary = process.env["OPENCODE_2022"]; +if (binary === undefined || binary === "") + throw new Error("Set OPENCODE_2022 to an isolated OpenCode 2.0.22 binary"); const temp = await mkdtemp(join(tmpdir(), "native-multi-work-")); try { - const root = join(temp, "root"), - destination = join(temp, "child"), - bin = join(temp, "bin"), - config = join(temp, "config"); + const root = join(temp, "root"); + const destination = join(temp, "child"); + const bin = join(temp, "bin"); + const config = join(temp, "config"); const herdrCreation = join(temp, "herdr-creation.txt"); for (const path of [root, bin, config, join(temp, "plugin")]) await mkdir(path); const signal = AbortSignal.timeout(120_000); @@ -82,7 +83,7 @@ try { target: "bun", format: "esm", }); - if (!built.success) throw new Error(String(built.logs)); + if (!built.success) throw new Error(built.logs.map((log) => log.message).join(",")); } await writeFile( join(config, "opencode.json"), @@ -134,12 +135,18 @@ try { }, }); const socket = createServer(); - await new Promise((done) => socket.listen(0, "127.0.0.1", done)); + await new Promise((done) => { + socket.listen(0, "127.0.0.1", done); + }); const { port } = z.object({ port: z.number() }).parse(socket.address()); - await new Promise((done) => socket.close(() => done())); + await new Promise((done) => { + socket.close(() => { + done(); + }); + }); // Do not inherit user credentials, discovery URLs, Herdr identity, or config overrides. const env = { - PATH: `${bin}:${process.env.PATH}`, + PATH: `${bin}:${process.env["PATH"]}`, HOME: join(temp, "home"), XDG_CONFIG_HOME: config, XDG_DATA_HOME: join(temp, "data"), @@ -160,13 +167,13 @@ try { let server = start(); const headers = { authorization: "" }; const client = OpenCode.make({ baseUrl: `http://127.0.0.1:${port}`, headers }); - async function ready() { + const ready = async () => { for (let attempt = 0; attempt < 200; attempt++) { try { const password = (await readFile(join(temp, "server.log"), "utf8")).match( - /server password (\S+)/, + /server password (\S+)/u, )?.[1]; - if (password) + if (password !== undefined) headers.authorization = `Basic ${Buffer.from(`opencode:${password}`).toString("base64")}`; await client.server.info(); return; @@ -177,7 +184,7 @@ try { throw new Error( `Host did not start: ${await readFile(join(temp, "server-errors.log"), "utf8")}`, ); - } + }; try { await ready(); const location = { directory: root }; @@ -228,7 +235,7 @@ try { (await readFile(env.FIXTURE_TRACE, "utf8")) .trim() .split("\n") - .map((line) => JSON.parse(line)), + .map((line) => z.json().parse(JSON.parse(line))), ); if ( !admission.some((entry) => entry.id === child.id && entry.directory === destination) || @@ -305,21 +312,21 @@ try { pending.then(() => { throw new Error("Foreground unexpectedly finished before cancellation"); }), - new Promise((_resolve, reject) => + new Promise((_resolve, reject) => { deadline.addEventListener( "abort", - () => reject(new Error("Model was not reached")), - { - once: true, + () => { + reject(new Error("Model was not reached")); }, - ), - ), + { once: true }, + ); + }), ]); cancel.abort(); - let rejected = false; - await pending.catch(() => { - rejected = true; - }); + const rejected = await pending.then( + () => false, + () => true, + ); if (!rejected) throw new Error("Cancelled RPC did not reject"); for (let attempt = 0; attempt < 100; attempt++) { if ((await client.session.get({ sessionID: child.id })).outcome === "interrupted") @@ -329,6 +336,18 @@ try { } releaseModel.resolve(); holdModel = false; + const multiWorkFailed = async () => { + for (let attempt = 0; attempt < 100; attempt++) { + const { data } = await client.plugin.list({ location }); + const multi = data.find((plugin) => plugin.id === "stanp-opencode.multi-work"); + if (multi?.state.status === "failed") return; + if (attempt === 99 || multi?.state.status === "active") + throw new Error( + `Missing or late Agents did not fail Multi-work activation: ${JSON.stringify(data)}`, + ); + await Bun.sleep(100); + } + }; for (const plugins of [ [{ package: join(temp, "plugin", "multi-work") }], [ @@ -344,16 +363,7 @@ try { ); server = start(); await ready(); - for (let attempt = 0; attempt < 100; attempt++) { - const { data } = await client.plugin.list({ location }); - const multi = data.find((plugin) => plugin.id === "stanp-opencode.multi-work"); - if (multi?.state.status === "failed") break; - if (attempt === 99 || multi?.state.status === "active") - throw new Error( - `Missing or late Agents did not fail Multi-work activation: ${JSON.stringify(data)}`, - ); - await Bun.sleep(100); - } + await multiWorkFailed(); } server.kill(); await server.exited; @@ -364,7 +374,8 @@ try { target: "bun", format: "esm", }); - if (!quotaBuild.success) throw new Error(String(quotaBuild.logs)); + if (!quotaBuild.success) + throw new Error(quotaBuild.logs.map((log) => log.message).join(",")); await writeFile( join(config, "opencode.json"), JSON.stringify({ @@ -409,7 +420,7 @@ try { releaseModel.resolve(); server.kill(); await server.exited; - model.stop(true); + void model.stop(true); } } finally { await rm(temp, { recursive: true, force: true }); diff --git a/src/agents/agents.ts b/src/agents/agents.ts index 59ff9e3..bf8a8cb 100644 --- a/src/agents/agents.ts +++ b/src/agents/agents.ts @@ -1,4 +1,5 @@ import { Agent, Model, Plugin, Provider } from "@opencode/plugin"; +import type { DeepMutable } from "@opencode/plugin/promise/types"; import type { ModelInfo } from "@opencode/client"; import { z } from "zod"; import { settings, workerNames } from "./config.js"; @@ -7,18 +8,38 @@ import { discover, modelKey } from "./provider.js"; import { descriptions, routingGuide } from "./routing.js"; import { Skill } from "@opencode/schema/skill"; import { AbsolutePath } from "@opencode/schema/schema"; -import { fileURLToPath } from "node:url"; import antiOverengineering from "../skills/anti-overengineering.md" with { type: "text" }; import taskPlanning from "../skills/task-planning.md" with { type: "text" }; import { AgentsRpc } from "./agents-rpc.js"; +import { matches } from "./wildcard.js"; -// Permission actions use wildcards, not filesystem globs. -function matches(value: string, pattern: string) { - const escaped = pattern - .replace(/[.+^${}()|[\]\\]/g, "\\$&") - .replace(/\*/g, ".*") - .replace(/\?/g, "."); - return new RegExp(`^${escaped}$`, "s").test(value); +// Assignments use "" as unset. +function assigned(value: string | undefined): value is string { + return value !== undefined && value !== ""; +} + +/** Points the agent at the available model, using the variant or a reasoning-effort fallback. */ +function useModel( + agent: DeepMutable, + assignment: ReturnType, + available: ModelInfo, +) { + const hasVariant = + assignment.variant !== undefined && + available.variants.some(({ id }) => id === assignment.variant); + agent.model = { + providerID: Provider.ID.make(available.providerID), + id: Model.ID.make(available.id), + }; + if (hasVariant) agent.model.variant = Model.VariantID.make(assignment.variant); + agent.request = { + settings: + hasVariant || assignment.variant === undefined + ? {} + : { reasoningEffort: assignment.variant }, + headers: {}, + body: {}, + }; } const reading = [ @@ -40,12 +61,12 @@ export default Plugin.define({ id: "stanp-opencode.agents", async setup(context) { const { agents } = settings.parse(context.options); - if (!workerNames.some((name) => agents?.[name])) return; + if (!workerNames.some((name) => assigned(agents?.[name]))) return; const assignments: Partial>> = {}; for (const name of workerNames) { const reference = agents?.[name]; - if (reference) assignments[name] = model(reference, `agents ${name}`); + if (assigned(reference)) assignments[name] = model(reference, `agents ${name}`); else if (!name.startsWith("deep-")) throw new Error(`agents ${name} is required`); } let models = new Map(); @@ -106,13 +127,14 @@ export default Plugin.define({ ["task-planning", taskPlanning], ] as const) { if (editor.get(name)) continue; - const description = content.match(/^description: "?(.+?)"?$/m)?.[1]; - if (!description) throw new Error(`${name} skill has no description`); + const description = content.match(/^description: "?(.+?)"?$/mu)?.[1]; + if (description === undefined || description === "") + throw new Error(`${name} skill has no description`); editor.add({ id: Skill.ID.make(name), name: Skill.Name.make(name), description, - path: AbsolutePath.make(fileURLToPath(import.meta.url)), + path: AbsolutePath.make(import.meta.filename), content, }); } @@ -123,22 +145,20 @@ export default Plugin.define({ .list() .map((tool) => tool.id) .filter((id) => id.startsWith("codegraph_")) - .sort(); + .toSorted(); if (JSON.stringify(next) === JSON.stringify(codegraphTools)) return; codegraphTools = next; if (agentTransformReady) queueMicrotask(() => { - void context.agent - .reload() - .catch((error) => - console.error("stanp-opencode agent reload failed", error), - ); + void context.agent.reload().catch((error) => { + console.error("stanp-opencode agent reload failed", error); + }); }); }); + const availableFor = (assignment: { providerID: string; id: string }) => + models.get(modelKey(assignment.providerID, assignment.id)); await context.agent.transform((editor) => { - const availableFor = (assignment: { providerID: string; id: string }) => - models.get(modelKey(assignment.providerID, assignment.id)); const deepLo = assignments["deep-lo"]; const deep = deepLo !== undefined && @@ -154,59 +174,37 @@ export default Plugin.define({ active.clear(); for (const name of workers) active.add(name); if (workers.length === 0 || coordinate === undefined) return; - for (const name of workers) { - const assignment = assignments[name]!; - const available = availableFor(assignment)!; + const configureWorker = ( + name: (typeof workerNames)[number], + assignment: ReturnType, + available: ModelInfo, + ) => { editor.update(name, (agent) => { - const hasVariant = - assignment.variant !== undefined && - available.variants.some(({ id }) => id === assignment.variant); agent.name = Agent.Name.make(name); agent.mode = "subagent"; agent.hidden = false; agent.description = descriptions[name]; - agent.model = { - providerID: Provider.ID.make(available.providerID), - id: Model.ID.make(available.id), - }; - if (hasVariant) agent.model.variant = Model.VariantID.make(assignment.variant!); - agent.request = { - settings: - hasVariant || assignment.variant === undefined - ? {} - : { reasoningEffort: assignment.variant }, - headers: {}, - body: {}, - }; + useModel(agent, assignment, available); agent.permissions = [ ...structuredClone(inherited), { action: "subagent", resource: "*", effect: "deny" }, ]; }); + }; + for (const name of workers) { + const assignment = assignments[name]; + const available = assignment && availableFor(assignment); + if (assignment && available) configureWorker(name, assignment, available); } + const available = availableFor(coordinate); + if (!available) return; editor.update("coordinate", (agent) => { - const available = availableFor(coordinate)!; - const hasVariant = - coordinate.variant !== undefined && - available.variants.some(({ id }) => id === coordinate.variant); agent.name = Agent.Name.make("coordinate"); agent.mode = "primary"; agent.hidden = false; agent.description = "Read, plan, and coordinate specialist workers; never implement directly."; - agent.model = { - providerID: Provider.ID.make(available.providerID), - id: Model.ID.make(available.id), - }; - if (hasVariant) agent.model.variant = Model.VariantID.make(coordinate.variant!); - agent.request = { - settings: - hasVariant || coordinate.variant === undefined - ? {} - : { reasoningEffort: coordinate.variant }, - headers: {}, - body: {}, - }; + useModel(agent, coordinate, available); agent.system = routingGuide(deep); agent.permissions = [ { action: "*", resource: "*", effect: "deny" }, @@ -242,18 +240,20 @@ export default Plugin.define({ } await context.session.hook("context", (event) => { if (workerNames.some((name) => name === event.agent)) { - delete event.tools.subagent; + delete event.tools["subagent"]; return; } - const tool = event.tools.subagent; + const tool = event.tools["subagent"]; if (event.agent === "coordinate" && workers.length === 0) { - delete event.tools.subagent; + delete event.tools["subagent"]; return; } if (event.agent !== "coordinate" || !tool) return; tool.description = `Delegate a self-contained assignment to one of these workers:\n${workers.map((name) => `- ${name}: ${descriptions[name]}`).join("\n")}`; // The executable definition remains native; constrain only this request's schema. - const properties = z.record(z.string(), z.unknown()).parse(tool.input.properties ?? {}); + const properties = z + .record(z.string(), z.unknown()) + .parse(tool.input["properties"] ?? {}); tool.input = { ...tool.input, properties: { ...properties, agent: { type: "string", enum: workers } }, @@ -273,7 +273,7 @@ export default Plugin.define({ // Commands can create child sessions without going through the subagent tool. await context.session.hook("prompt", async (event) => { const child = await context.session.get({ sessionID: event.sessionID }); - if (!child.parentID) return; + if (child.parentID === undefined || child.parentID === "") return; const parent = await context.session.get({ sessionID: child.parentID }); if (child.agent === "coordinate" && parent.agent !== "multi-work") throw new Error("coordinate cannot run as a subagent without Multi-work"); diff --git a/src/agents/model.ts b/src/agents/model.ts index 7436f94..f8f9136 100644 --- a/src/agents/model.ts +++ b/src/agents/model.ts @@ -5,5 +5,7 @@ export function model(reference: string, name: string) { if (slash <= 0) throw new Error(`${name} must be provider/model[#variant]: ${reference}`); const providerID = path.slice(0, slash); const id = path.slice(slash + 1); - return variant ? { providerID, id, variant } : { providerID, id }; + return variant !== undefined && variant !== "" + ? { providerID, id, variant } + : { providerID, id }; } diff --git a/src/agents/wildcard.ts b/src/agents/wildcard.ts new file mode 100644 index 0000000..1782826 --- /dev/null +++ b/src/agents/wildcard.ts @@ -0,0 +1,8 @@ +// Permission actions use wildcards, not filesystem globs. +export function matches(value: string, pattern: string) { + const escaped = pattern + .replaceAll(/[.+^${}()|[\]\\]/gu, "\\$&") + .replaceAll("*", ".*") + .replaceAll("?", "."); + return new RegExp(`^${escaped}$`, "su").test(value); +} diff --git a/src/multi-work/herdr.ts b/src/multi-work/herdr.ts index 2ed22b0..553a403 100644 --- a/src/multi-work/herdr.ts +++ b/src/multi-work/herdr.ts @@ -3,13 +3,15 @@ import { realpath } from "node:fs/promises"; import { z } from "zod"; export async function command(args: string[], cwd: string, signal: AbortSignal) { + const [file, ...rest] = args; + if (file === undefined) throw new Error("Missing command"); return new Promise((resolve, reject) => { execFile( - args[0]!, - args.slice(1), + file, + rest, { cwd, signal, timeout: 30_000, maxBuffer: 2_000_000 }, (error, stdout, stderr) => { - if (error) reject(new Error(`${args[0]} failed: ${stderr || error.message}`)); + if (error) reject(new Error(`${file} failed: ${stderr || error.message}`)); else resolve(stdout.trim()); }, ); diff --git a/src/multi-work/multi-work.ts b/src/multi-work/multi-work.ts index c9c3ec7..c9a8989 100644 --- a/src/multi-work/multi-work.ts +++ b/src/multi-work/multi-work.ts @@ -10,6 +10,7 @@ import { z } from "zod"; import { randomUUID } from "node:crypto"; import { Herdr, rootSchema } from "./herdr.js"; import { multiWorkGuide } from "../agents/routing.js"; +import { matches } from "../agents/wildcard.js"; export const bindingSchema = z .object({ @@ -62,14 +63,8 @@ const readTools = new Set([ export const childProtocol = "Bound child sessions use stanp-opencode multi-work protocol 1 and must remain in their assigned worktree."; -function matches(value: string, pattern: string) { - return new RegExp( - `^${pattern - .replace(/[.+^${}()|[\]\\]/g, "\\$&") - .replace(/\*/g, ".*") - .replace(/\?/g, ".")}$`, - "s", - ).test(value); +function present(value: string | undefined): value is string { + return value !== undefined && value !== ""; } export const installMultiWork = ( @@ -158,6 +153,20 @@ export const installMultiWork = ( return binding; }); + const verifyLocalChild = ( + sessionID: Session.ID, + parent: { id: string; location: { directory: string } }, + ) => + Effect.gen(function* () { + const child = yield* context.session.get({ sessionID }); + if ( + child.parentID !== parent.id || + child.agent !== "fast-lo" || + child.location.directory !== parent.location.directory + ) + throw new Error("Local fast-lo child binding changed"); + }); + // Commands can create children without going through the subagent tool. yield* context.session.hook("prompt", (event) => Effect.gen(function* () { @@ -192,12 +201,12 @@ export const installMultiWork = ( if (event.agent === "coordinate" && session.parentID) yield* validate(event.sessionID); if (event.agent !== "multi-work") { - const tool = event.tools.subagent; + const tool = event.tools["subagent"]; if (tool) { const properties = z .record(z.string(), z.unknown()) - .parse(tool.input.properties ?? {}); - delete properties.worktree; + .parse(tool.input["properties"] ?? {}); + delete properties["worktree"]; tool.input = { ...tool.input, properties }; } return; @@ -211,13 +220,13 @@ export const installMultiWork = ( ); if (!root) throw new Error("multi-work requires a live, unambiguous Herdr root checkout"); - const tool = event.tools.subagent; + const tool = event.tools["subagent"]; if (tool) { tool.input = z.toJSONSchema(inputSchema); const properties = z .record(z.string(), z.unknown()) - .parse(tool.input.properties); - tool.input.properties = { + .parse(tool.input["properties"]); + tool.input["properties"] = { ...properties, agent: { type: "string", enum: ["fast-lo", "coordinate"] }, }; @@ -238,7 +247,7 @@ export const installMultiWork = ( if (input.agent === "multi-work") throw new Error("multi-work is primary only"); if ( - input.sessionID && + present(input.sessionID) && (yield* context.storage.get(bindingKey(input.sessionID))) !== undefined && (call.agent !== "multi-work" || input.agent !== "coordinate") @@ -261,22 +270,13 @@ export const installMultiWork = ( ); if (input.agent === "fast-lo") { if (input.worktree) throw new Error("fast-lo is local retrieval only"); - if (input.sessionID) { - const child = yield* context.session.get({ - sessionID: Session.ID.make(input.sessionID), - }); - if ( - child.parentID !== parent.id || - child.agent !== "fast-lo" || - child.location.directory !== parent.location.directory - ) - throw new Error("Local fast-lo child binding changed"); - } + if (present(input.sessionID)) + yield* verifyLocalChild(Session.ID.make(input.sessionID), parent); return yield* native.execute(input, call); } if (input.agent !== "coordinate") throw new Error("multi-work delegates only to fast-lo or coordinate"); - if (input.sessionID && input.worktree !== undefined) + if (present(input.sessionID) && input.worktree !== undefined) throw new Error( "Coordinate resumes require only sessionID; worktree is create-only", ); @@ -287,7 +287,7 @@ export const installMultiWork = ( return yield* Effect.gen(function* () { let initialized = false; let placement: z.infer | undefined; - if (input.sessionID) { + if (present(input.sessionID)) { const binding = yield* validate(Session.ID.make(input.sessionID)); if (binding.owner !== call.sessionID) throw new Error("Cannot resume another parent's binding"); @@ -336,7 +336,7 @@ export const installMultiWork = ( } const { worktree, ...args } = input; const callKey = `multi-work-call:${call.sessionID}:${call.id}`; - if (!input.sessionID) { + if (!present(input.sessionID)) { const previous = yield* context.storage.get(callKey); if (previous !== undefined) throw new Error( @@ -350,7 +350,7 @@ export const installMultiWork = ( // Native 2.0.22 awaits this update after creation and before prompt admission. yield* call.progress(metadata); if (initialized) return; - const id = z.string().parse(metadata.sessionID); + const id = z.string().parse(metadata["sessionID"]); if (busy.has(id)) throw new Error( "This child is already being delegated", @@ -433,7 +433,7 @@ export const installMultiWork = ( coordinator?.mode === "all" && coordinator.system?.includes( childProtocol, - ) && + ) === true && [ "coordinate", "fast-lo", @@ -503,7 +503,7 @@ export const installMultiWork = ( Effect.ensuring( Effect.sync(() => { busy.delete(lock); - if (childLock) busy.delete(childLock); + if (present(childLock)) busy.delete(childLock); }), ), ); diff --git a/src/quota/claude-quota.ts b/src/quota/claude-quota.ts index 1b74808..c52355a 100644 --- a/src/quota/claude-quota.ts +++ b/src/quota/claude-quota.ts @@ -11,11 +11,15 @@ const TIMEOUT_MS = 5_000; const RETRY_MS = 2_000; const RETRIES = 4; const WEEK = 604_800; +const jsonValue = z.json(); type QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise; -export function claudeCredentialsPath() { - return join(process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), ".claude"), ".credentials.json"); +function claudeCredentialsPath() { + return join( + process.env["CLAUDE_CONFIG_DIR"] ?? join(homedir(), ".claude"), + ".credentials.json", + ); } const credentials = z.object({ @@ -27,7 +31,7 @@ const credentials = z.object({ }); const usageWindow = z - .object({ utilization: z.number().finite(), resets_at: z.string().nullish() }) + .object({ utilization: z.number(), resets_at: z.string().nullish() }) .nullish(); const usagePayload = z.object({ five_hour: usageWindow, @@ -38,7 +42,7 @@ const usagePayload = z.object({ .array( z.object({ kind: z.string(), - percent: z.number().finite(), + percent: z.number(), resets_at: z.string().nullish(), scope: z .object({ @@ -63,7 +67,7 @@ function window( label, seconds, used: Math.max(0, Math.min(100, used)), - resetsAt: resetsAt ? Date.parse(resetsAt) : Number.NaN, + resetsAt: resetsAt === null || resetsAt === undefined ? Number.NaN : Date.parse(resetsAt), }; } @@ -173,31 +177,14 @@ export class ClaudeQuotaTracker { const credential = parsed.data.claudeAiOauth; if (this.disposed) return true; if (credential.expiresAt <= Date.now()) return false; - const controller = new AbortController(); - this.controller = controller; - const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS); - let response: Response; - try { - response = await this.fetcher(USAGE_URL, { - headers: { - Authorization: `Bearer ${credential.accessToken}`, - "anthropic-beta": "oauth-2025-04-20", - Accept: "application/json", - }, - signal: controller.signal, - }); - } finally { - clearTimeout(timeout); - if (this.controller === controller) this.controller = undefined; - } + const response = await this.fetchUsage(credential.accessToken); if (!response.ok) return false; - // SAFETY: Response.json yields JSON values; usagePayload validates fields used. - const payload = (await response.json()) as Schema.Json; + const payload = jsonValue.parse(await response.json()); const snapshot = normalizeClaudeQuota( payload, credential.subscriptionType ?? "unknown", ); - if (this.disposed) return true; + if (this.isDisposed()) return true; if (!snapshot) return false; this.latest = snapshot; } catch { @@ -207,6 +194,32 @@ export class ClaudeQuotaTracker { return true; } + private async fetchUsage(accessToken: string) { + const controller = new AbortController(); + this.controller = controller; + const timeout = setTimeout(() => { + controller.abort(); + }, TIMEOUT_MS); + try { + return await this.fetcher(USAGE_URL, { + headers: { + Authorization: `Bearer ${accessToken}`, + "anthropic-beta": "oauth-2025-04-20", + Accept: "application/json", + }, + signal: controller.signal, + }); + } finally { + clearTimeout(timeout); + if (this.controller === controller) this.controller = undefined; + } + } + + /** Reads the flag through a call so checks after `await` are not narrowed away. */ + private isDisposed() { + return this.disposed; + } + status(): QuotaStatus | undefined { if (!this.latest) return; return { diff --git a/src/quota/quota-plugin.ts b/src/quota/quota-plugin.ts index 9641eff..f48dace 100644 --- a/src/quota/quota-plugin.ts +++ b/src/quota/quota-plugin.ts @@ -40,7 +40,7 @@ export default Plugin.define({ await quota.authChanged(); } else if ( event.type === "credential.switched" && - String(event.data.integrationID) === "openai" + event.data.integrationID === "openai" ) { await quota.authChanged(true); } diff --git a/src/quota/quota.ts b/src/quota/quota.ts index a7c1491..7cc1d7c 100644 --- a/src/quota/quota.ts +++ b/src/quota/quota.ts @@ -8,24 +8,30 @@ const USAGE_URL = "https://chatgpt.com/backend-api/wham/usage"; const POLL_MS = 60_000; const TIMEOUT_MS = 5_000; const STORAGE_KEY = "chatgpt-quota"; +const jsonValue = z.json(); function compactLimitIdentity(value: string) { - return value.toLowerCase().replace(/[^a-z0-9]+/g, ""); + return value.toLowerCase().replaceAll(/[^a-z0-9]+/gu, ""); } function isSparkLimit(meteredFeature?: string, limitName?: string | null) { return ( (meteredFeature !== undefined && compactLimitIdentity(meteredFeature) === "codexbengalfox") || - (limitName != null && compactLimitIdentity(limitName) === "gpt53codexspark") + (limitName !== null && + limitName !== undefined && + compactLimitIdentity(limitName) === "gpt53codexspark") ); } +function hasReserveToken(value: string) { + return /(^|[^a-z0-9])reserve($|[^a-z0-9])/iu.test(value); +} + function isReserveLimit(meteredFeature?: string, limitName?: string | null) { - const hasReserveToken = (value: string) => /(^|[^a-z0-9])reserve($|[^a-z0-9])/i.test(value); return ( (meteredFeature !== undefined && hasReserveToken(meteredFeature)) || - (limitName != null && hasReserveToken(limitName)) + (limitName !== null && limitName !== undefined && hasReserveToken(limitName)) ); } @@ -81,7 +87,10 @@ function withoutExcludedState(state: StoredState): StoredState { const windows = state.latest?.windows.filter((window) => !isExcludedWindow(window)); return { ...state, - latest: state.latest && windows?.length ? { ...state.latest, windows } : undefined, + latest: + state.latest && windows !== undefined && windows.length > 0 + ? { ...state.latest, windows } + : undefined, }; } @@ -89,9 +98,9 @@ type QuotaContext = Pick; type QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise; const quotaWindow = z.object({ - limit_window_seconds: z.number().finite().positive(), - used_percent: z.number().finite(), - reset_at: z.number().finite(), + limit_window_seconds: z.number().positive(), + used_percent: z.number(), + reset_at: z.number(), }); const additionalRateLimitIdentity = z.object({ limit_name: z.string().optional(), @@ -187,7 +196,7 @@ export function normalizeQuota( function accountID(credential: Credential.OAuth) { const metadataID = z .string() - .safeParse(credential.metadata?.accountID ?? credential.metadata?.accountId); + .safeParse(credential.metadata?.["accountID"] ?? credential.metadata?.["accountId"]); if (metadataID.success) return metadataID.data; const parts = credential.access.split("."); if (parts.length !== 3) return; @@ -200,7 +209,7 @@ function accountID(credential: Credential.OAuth) { .optional(), organizations: z.array(z.object({ id: z.string() })).optional(), }) - .safeParse(JSON.parse(Buffer.from(parts[1]!, "base64url").toString())); + .safeParse(JSON.parse(Buffer.from(parts[1] ?? "", "base64url").toString())); if (!claims.success) return; return ( claims.data.chatgpt_account_id ?? @@ -250,23 +259,30 @@ export class QuotaTracker { return; } const id = accountID(credential); - const account = id - ? await fingerprint(`account:${id}`) - : (this.state?.account ?? (await fingerprint(`credential:${credential.refresh}`))); + const account = + id !== undefined && id !== "" + ? await fingerprint(`account:${id}`) + : (this.state?.account ?? (await fingerprint(`credential:${credential.refresh}`))); if (generation !== this.generation) return; - if (this.state?.account !== account) { - const value = await this.context.storage.get(STORAGE_KEY); - const parsed = storedState.safeParse(value); - if (generation !== this.generation) return; - const stored = parsed.success ? parsed.data : undefined; - if (generation !== this.generation) return; - this.state = stored?.account === account ? withoutExcludedState(stored) : { account }; - } + if (this.state?.account !== account) await this.load(account, generation); if (generation !== this.generation) return; - if (!this.timer) this.timer = setInterval(() => void this.refresh(), this.pollMs); + this.timer ??= setInterval(() => void this.refresh(), this.pollMs); return credential; } + private async load(account: string, generation: number) { + const value = await this.context.storage.get(STORAGE_KEY); + const parsed = storedState.safeParse(value); + if (generation !== this.generation) return; + const stored = parsed.success ? parsed.data : undefined; + this.state = stored?.account === account ? withoutExcludedState(stored) : { account }; + } + + /** Reads state through a call so checks after `await` are not narrowed away. */ + private current(): StoredState | undefined { + return this.state; + } + private async clear() { this.state = undefined; if (this.timer) clearInterval(this.timer); @@ -297,32 +313,20 @@ export class QuotaTracker { try { const credential = await this.resolveCredential(generation); if (!credential || !this.state || generation !== this.generation) return; - const controller = new AbortController(); - this.controller = controller; - const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS); - let response: Response; - try { - const headers = new Headers({ - Authorization: `Bearer ${credential.access}`, - Accept: "application/json", - }); - const id = accountID(credential); - if (id) headers.set("ChatGPT-Account-Id", id); - response = await this.fetcher(USAGE_URL, { headers, signal: controller.signal }); - } finally { - clearTimeout(timeout); - if (this.controller === controller) this.controller = undefined; - } + const response = await this.fetchUsage(credential); if (!response.ok || generation !== this.generation) return; - // SAFETY: JSON.parse semantics from Response.json produce only JSON values; - // quotaPayload validates all fields used below. - const payload = (await response.json()) as Schema.Json; - if (generation !== this.generation || !this.state) return; + const payload = jsonValue.parse(await response.json()); + if (generation !== this.generation || !this.current()) return; const parsed = quotaPayload.safeParse(payload); - if (parsed.success && parsed.data.account_id) { + if ( + parsed.success && + parsed.data.account_id !== undefined && + parsed.data.account_id !== "" + ) { const account = await fingerprint(`account:${parsed.data.account_id}`); - if (generation !== this.generation || !this.state) return; - if (account !== this.state.account) this.state = { account }; + const state = this.current(); + if (generation !== this.generation || !state) return; + if (account !== state.account) this.state = { account }; } const snapshot = normalizeQuota(payload); if (!snapshot) return; @@ -335,6 +339,26 @@ export class QuotaTracker { } } + private async fetchUsage(credential: Credential.OAuth) { + const controller = new AbortController(); + this.controller = controller; + const timeout = setTimeout(() => { + controller.abort(); + }, TIMEOUT_MS); + try { + const headers = new Headers({ + Authorization: `Bearer ${credential.access}`, + Accept: "application/json", + }); + const id = accountID(credential); + if (id !== undefined && id !== "") headers.set("ChatGPT-Account-Id", id); + return await this.fetcher(USAGE_URL, { headers, signal: controller.signal }); + } finally { + clearTimeout(timeout); + if (this.controller === controller) this.controller = undefined; + } + } + private apply(snapshot: QuotaSnapshot) { if (!this.state) return; this.state.latest = snapshot; diff --git a/src/quota/tui.tsx b/src/quota/tui.tsx index 4272845..28baf6e 100644 --- a/src/quota/tui.tsx +++ b/src/quota/tui.tsx @@ -34,9 +34,10 @@ function resetTiming(resetsAt: number, now: number) { } export function formatQuotaWindow(window: QuotaWindow & { remaining: number }, now = Date.now()) { - const label = window.label - ? `${window.label} ${duration(window.seconds)}` - : duration(window.seconds); + const label = + window.label !== null && window.label !== "" + ? `${window.label} ${duration(window.seconds)}` + : duration(window.seconds); return `${label}: ${percent(window.remaining)}% ยท ${resetTiming(window.resetsAt, now)}`; } @@ -60,6 +61,26 @@ export default Plugin.define({ setRevision((value) => value + 1); }); + const Section = (section: { title: string; status: QuotaStatus | null }) => ( + + {(status: () => QuotaStatus) => ( + <> + + + {section.title} quota ({status().plan}) + + + + {(window) => ( + + {formatQuotaWindow(window)} + + )} + + + )} + + ); const Slot = (props: { instance: string; centered?: boolean; visible?: () => boolean }) => { const [statuses] = createResource( () => (props.visible?.() === false ? false : `${props.instance}:${revision()}`), @@ -71,30 +92,10 @@ export default Plugin.define({ return chatgpt || claude ? { chatgpt, claude } : null; }, ); - const Section = (section: { title: string; status: QuotaStatus | null }) => ( - - {(status: () => QuotaStatus) => ( - <> - - - {section.title} quota ({status().plan}) - - - - {(window) => ( - - {formatQuotaWindow(window)} - - )} - - - )} - - ); const Content = () => ( -
-
+
+
); return ( diff --git a/tests/claude-quota.test.ts b/tests/claude-quota.test.ts index 784b81d..aedc874 100644 --- a/tests/claude-quota.test.ts +++ b/tests/claude-quota.test.ts @@ -97,7 +97,10 @@ test("reads credentials file and sends OAuth usage request", async () => { changed++; }, async (input, init) => { - calls.push({ url: String(input), headers: new Headers(init?.headers) }); + calls.push({ + url: input instanceof Request ? input.url : String(input), + headers: new Headers(init?.headers), + }); return Response.json(payload); }, 60_000, @@ -105,10 +108,12 @@ test("reads credentials file and sends OAuth usage request", async () => { ); await tracker.init(); expect(calls).toHaveLength(1); - expect(calls[0]!.url).toBe("https://api.anthropic.com/api/oauth/usage"); - expect(calls[0]!.headers.get("authorization")).toBe("Bearer token-123"); - expect(calls[0]!.headers.get("anthropic-beta")).toBe("oauth-2025-04-20"); - expect(calls[0]!.headers.get("accept")).toBe("application/json"); + const [call] = calls; + if (!call) throw new Error("Missing usage request"); + expect(call.url).toBe("https://api.anthropic.com/api/oauth/usage"); + expect(call.headers.get("authorization")).toBe("Bearer token-123"); + expect(call.headers.get("anthropic-beta")).toBe("oauth-2025-04-20"); + expect(call.headers.get("accept")).toBe("application/json"); expect(tracker.status()?.plan).toBe("max"); expect(tracker.status()?.windows[0]?.remaining).toBe(87.5); expect(changed).toBe(1); diff --git a/tests/fixtures/native-agents-plugin.ts b/tests/fixtures/native-agents-plugin.ts index 4d54d33..7d4db70 100644 --- a/tests/fixtures/native-agents-plugin.ts +++ b/tests/fixtures/native-agents-plugin.ts @@ -10,13 +10,13 @@ export default Plugin.define({ const providerID = Provider.ID.make("fixture"); yield* context.provider.transform((editor) => editor.add({ - info: { - ...Provider.Info.empty(providerID), + // Copy own fields like the former spread; the editor accepts plain info. + info: Object.assign({}, Provider.Info.empty(providerID), { name: "Isolated fixture", - activation: "enabled", + activation: "enabled" as const, package: "@opencode/ai/providers/openai-compatible", - settings: { baseURL: process.env.FIXTURE_MODEL_URL! }, - }, + settings: { baseURL: process.env["FIXTURE_MODEL_URL"] ?? "" }, + }), models: ["gpt-6-luna", "gpt-6.1-sol", "gpt-6-astra"].map((id) => Model.Info.default(providerID, Model.ID.make(id)), ), diff --git a/tests/fixtures/native-host-plugin.ts b/tests/fixtures/native-host-plugin.ts index 85f0f7e..4231dcc 100644 --- a/tests/fixtures/native-host-plugin.ts +++ b/tests/fixtures/native-host-plugin.ts @@ -37,7 +37,7 @@ export default Plugin.define({ const child = yield* context.session.get({ sessionID: event.sessionID }); yield* Effect.promise(() => appendFile( - process.env.FIXTURE_TRACE!, + process.env["FIXTURE_TRACE"] ?? "", JSON.stringify({ id: child.id, parent: child.parentID, @@ -59,7 +59,7 @@ export default Plugin.define({ description: "native host proof", prompt: "Reply with FIXTURE_COMPLETE", background: input.background, - ...(input.child + ...(input.child !== undefined && input.child !== "" ? { sessionID: input.child } : { worktree: { diff --git a/tests/herdr.test.ts b/tests/herdr.test.ts index 724e527..b5752a3 100644 --- a/tests/herdr.test.ts +++ b/tests/herdr.test.ts @@ -45,9 +45,9 @@ async function fixture() { let childWorkspaceIDOverride: string | undefined; let childPathOverride: string | undefined; let repoOverride: string | undefined; - const run = async (args: string[], cwd: string, signal: AbortSignal) => { + const run = async (args: string[], cwd: string, abort: AbortSignal) => { calls.push(args); - if (args[0] !== "herdr") return command(args, cwd, signal); + if (args[0] !== "herdr") return command(args, cwd, abort); if (args[1] === "workspace") return JSON.stringify({ result: { @@ -57,7 +57,7 @@ async function fixture() { }, }); if (args[2] === "list") { - const id = args[4]!; + const id = args[4] ?? ""; const path = id === "w2" ? destination : root; const sourceWorkspaceID = sourceWorkspaceIDOverride ?? (id === "w2" ? "w1" : id); const sourcePath = sourcePathOverride ?? root; @@ -93,10 +93,10 @@ async function fixture() { expect(args[2]).toBe("create"); expect(args.slice(3, 5)).toEqual(["--cwd", root]); expect(args.at(-1)).toBe("--no-focus"); - branch = args[args.indexOf("--branch") + 1]!; + branch = args[args.indexOf("--branch") + 1] ?? ""; const labelIndex = args.indexOf("--label"); label = labelIndex === -1 ? undefined : args[labelIndex + 1]; - const base = args[args.indexOf("--base") + 1]!; + const base = args[args.indexOf("--base") + 1] ?? ""; // Real Git worktree behavior, but only in an isolated temporary repository. await command(["git", "worktree", "add", "-b", branch, destination, base], root, signal); return JSON.stringify({ @@ -144,14 +144,15 @@ test("create verifies a linked workspace whose inventory source remains the pare const f = await fixture(); const root = await f.herdr.root(f.root, f.signal); expect(root?.workspaceID).toBe("w1"); - const destination = await f.herdr.create(root!, "other", "multi-work/fixture", f.signal); + if (!root) throw new Error("Missing Herdr root"); + const destination = await f.herdr.create(root, "other", "multi-work/fixture", f.signal); expect(destination.directory).toBe(f.destination); expect(destination.branch).toStartWith("multi-work/"); expect(await command(["git", "branch", "--show-current"], f.root, f.signal)).toBe("main"); await f.herdr.verify( destination.directory, destination.workspaceID, - root!, + root, destination.branch, f.signal, ); diff --git a/tests/install.test.ts b/tests/install.test.ts index 9b35f26..46e1778 100644 --- a/tests/install.test.ts +++ b/tests/install.test.ts @@ -3,6 +3,7 @@ import { chmod, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { createHash } from "node:crypto"; +import { z } from "zod"; import { install } from "../scripts/install.js"; const directories: string[] = []; @@ -34,6 +35,15 @@ const empty = { "deep-hi": "", }, }; +const pluginEntry = z + .object({ package: z.string(), options: z.record(z.string(), z.json()).optional() }) + .loose(); +const configFile = z + .object({ plugins: z.array(z.json()), experimental: z.json().optional() }) + .loose(); +const manifestFile = z.object({ exports: z.record(z.string(), z.json()) }).loose(); +const entries = (plugins: z.infer["plugins"]) => + z.array(pluginEntry).parse(plugins); const helper = new URL("../scripts/install.ts", import.meta.url); async function run( command: string[], @@ -50,8 +60,8 @@ async function run( timeout: 30_000, }); if (input !== undefined && process.stdin) { - process.stdin.write(input); - process.stdin.end(); + void process.stdin.write(input); + void process.stdin.end(); } const [exitCode, stdout, stderr] = await Promise.all([ process.exited, @@ -83,7 +93,9 @@ async function fixture() { format: "esm", }); expect(built.success).toBe(true); - await Bun.write(join(source, "dist", "install.js"), built.outputs[0]!); + const [output] = built.outputs; + if (output === undefined) throw new Error("Missing installer build output"); + await Bun.write(join(source, "dist", "install.js"), output); await writeFile(join(source, "package.json"), '{"type":"module"}'); await writeFile( join(config, "opencode.json"), @@ -96,7 +108,7 @@ async function fixture() { return { directory, source, config }; } async function contents(config: string) { - return JSON.parse(await readFile(join(config, "opencode.json"), "utf8")); + return configFile.parse(JSON.parse(await readFile(join(config, "opencode.json"), "utf8"))); } for (const selection of ["quota", "agents,multi-work,quota"]) { @@ -106,14 +118,16 @@ for (const selection of ["quota", "agents,multi-work,quota"]) { const result = await contents(f.config); expect(result).toMatchObject(unrelated); expect(result.experimental === undefined).toBe(selection === "quota"); - expect(result.plugins.map((entry: { package: string }) => entry.package)).toEqual([ + expect(entries(result.plugins).map((entry) => entry.package)).toEqual([ "before", ...selection.split(",").map((name) => `./plugins/stanp-opencode/${name}`), ]); const target = join(f.config, "plugins", "stanp-opencode"); - expect((await readdir(target)).sort()).toEqual(selection.split(",").sort()); + expect((await readdir(target)).toSorted()).toEqual(selection.split(",").toSorted()); for (const name of selection.split(",")) { - const manifest = await Bun.file(join(target, name, "package.json")).json(); + const manifest = manifestFile.parse( + await Bun.file(join(target, name, "package.json")).json(), + ); expect(manifest.exports["./tui"] !== undefined).toBe(name === "quota"); expect(await Bun.file(join(target, name, "tui.js")).exists()).toBe(name === "quota"); } @@ -127,18 +141,23 @@ test("upgrades retain selection and options; explicit selection replaces only ow const f = await fixture(); await install(f.source, f.config, "agents,quota"); const current = await contents(f.config); - current.plugins[1].options = { - agents: { ...empty.agents, "fast-lo": "openai/gpt-6-luna#low" }, - }; - current.plugins.push({ package: "after", options: { untouched: 1 } }); - await writeFile(join(f.config, "opencode.json"), JSON.stringify(current)); + const [before, agents, quota] = entries(current.plugins); + if (!before || !agents || !quota) throw new Error("Missing installed plugins"); + const after = { package: "after", options: { untouched: 1 } }; + const plugins = [ + before, + { ...agents, options: { agents: { ...empty.agents, "fast-lo": "openai/gpt-6-luna#low" } } }, + quota, + after, + ]; + await writeFile(join(f.config, "opencode.json"), JSON.stringify({ ...current, plugins })); await install(f.source, f.config); - expect((await contents(f.config)).plugins).toEqual(current.plugins); + expect(entries((await contents(f.config)).plugins)).toEqual(plugins); await install(f.source, f.config, "quota"); - expect((await contents(f.config)).plugins).toEqual([ - current.plugins[0], + expect(entries((await contents(f.config)).plugins)).toEqual([ + before, { package: "./plugins/stanp-opencode/quota" }, - current.plugins[3], + after, ]); }); @@ -152,14 +171,17 @@ test("installer writes empty option skeletons and subagent_depth, fills only mis { package: "./plugins/stanp-opencode/quota" }, ]); expect(fresh.experimental).toEqual({ subagent_depth: 2 }); - fresh.plugins[1].options = { - agents: { "fast-lo": "openai/gpt-6-luna#low" }, - extra: 1, - }; - await writeFile(join(f.config, "opencode.json"), JSON.stringify(fresh)); + const [before, agents, ...rest] = entries(fresh.plugins); + if (!before || !agents) throw new Error("Missing installed plugins"); + const plugins = [ + before, + { ...agents, options: { agents: { "fast-lo": "openai/gpt-6-luna#low" }, extra: 1 } }, + ...rest, + ]; + await writeFile(join(f.config, "opencode.json"), JSON.stringify({ ...fresh, plugins })); await install(f.source, f.config); const filled = await contents(f.config); - expect(filled.plugins[1].options).toEqual({ + expect(entries(filled.plugins)[1]?.options).toEqual({ agents: { ...empty.agents, "fast-lo": "openai/gpt-6-luna#low" }, extra: 1, }); @@ -169,7 +191,7 @@ test("installer writes empty option skeletons and subagent_depth, fills only mis for (const [depth, expected] of [ [1, 2], [3, 3], - ]) { + ] as const) { await writeFile( join(f.config, "opencode.json"), JSON.stringify({ @@ -214,12 +236,14 @@ test("replaces the legacy monolith without duplicates and retains Agents options await writeFile(join(f.config, "plugins", "stanp-opencode.js"), "legacy"); await install(f.source, f.config); const result = await contents(f.config); - expect(result.plugins.map((entry: { package: string }) => entry.package)).toEqual([ + expect(entries(result.plugins).map((entry) => entry.package)).toEqual([ "before", ...names.map((name) => `./plugins/stanp-opencode/${name}`), "after", ]); - expect(result.plugins[1].options.agents["fast-lo"]).toBe("openai/gpt-6-luna#low"); + expect(result.plugins[1]).toMatchObject({ + options: { agents: { "fast-lo": "openai/gpt-6-luna#low" } }, + }); expect(await Bun.file(join(f.config, "plugins", "stanp-opencode.js")).exists()).toBe(false); expect(result).toMatchObject(unrelated); }); @@ -283,7 +307,7 @@ test("local shell installer builds its checkout and upgrades mixed entries witho await chmod(join(bin, "bun"), 0o755); const env = { ...Bun.env, - PATH: `${bin}:${dirname(process.execPath)}:${Bun.env.PATH}`, + PATH: `${bin}:${dirname(process.execPath)}:${Bun.env["PATH"]}`, REAL_BUN: process.execPath, CALLS: join(f.directory, "calls"), OPENCODE_CONFIG_DIR: f.config, @@ -357,7 +381,7 @@ for (const validChecksum of [true, false]) f.directory, { ...Bun.env, - PATH: `${bin}:${dirname(process.execPath)}:${Bun.env.PATH}`, + PATH: `${bin}:${dirname(process.execPath)}:${Bun.env["PATH"]}`, ARCHIVE: archive, CHECKSUM: checksum, RELEASE: release, diff --git a/tests/multi-work.test.ts b/tests/multi-work.test.ts index 9e93905..9227584 100644 --- a/tests/multi-work.test.ts +++ b/tests/multi-work.test.ts @@ -70,6 +70,19 @@ interface FixtureSession { permissions: Agent.Info["permissions"]; } +const defaultInput = { + agent: "coordinate", + description: "test", + prompt: "work", + worktree: { base: "main" }, +}; + +function required(map: Map, key: string) { + const value = map.get(key); + if (value === undefined) throw new Error(`Missing fixture entry ${key}`); + return value; +} + function fixture() { const herdr = new FixtureHerdr(); const storage = new Map[1]>(); @@ -112,7 +125,7 @@ function fixture() { }) .parse(raw); const id = Session.ID.make(input.sessionID ?? `ses_child${++serial}`); - if (!input.sessionID) + if (input.sessionID === undefined || input.sessionID === "") sessions.set(id, { ...parent, id, @@ -122,7 +135,7 @@ function fixture() { }); order.push("create"); yield* call.progress({ sessionID: id, status: "running" }); - order.push(`prompt:${sessions.get(id)!.location.directory}`); + order.push(`prompt:${required(sessions, id).location.directory}`); prompts++; entered.resolve(); if (hold) @@ -135,7 +148,10 @@ function fixture() { ); return { content: "native result", - metadata: { sessionID: id, status: input.background ? "running" : "completed" }, + metadata: { + sessionID: id, + status: input.background === true ? "running" : "completed", + }, }; }), }; @@ -144,7 +160,7 @@ function fixture() { []; const hooks: ((event: SessionContext) => Effect.Effect)[] = []; let prompt!: (event: Pick) => Effect.Effect; - let transform!: (editor: AgentEditor) => void; + let transform: ((editor: AgentEditor) => void) | undefined; const registration = Effect.succeed({ dispose: Effect.void }); const editAgents = (): AgentEditor => ({ get: (id) => agents.get(id), @@ -185,16 +201,16 @@ function fixture() { }), }, agent: { - transform: (callback: typeof transform) => + transform: (callback: (editor: AgentEditor) => void) => Effect.sync(() => { transform = callback; callback(editAgents()); }).pipe(Effect.andThen(registration)), reload: () => Effect.sync(() => { - if (transform) transform(editAgents()); + transform?.(editAgents()); }), - get: () => Effect.succeed({ data: agents.get("multi-work")! }), + get: () => Effect.succeed({ data: required(agents, "multi-work") }), list: () => Effect.sync(() => { agentReads++; @@ -204,14 +220,15 @@ function fixture() { }, session: { get: ({ sessionID }: { sessionID: string }) => - Effect.sync(() => sessions.get(sessionID)!), + Effect.sync(() => required(sessions, sessionID)), move: ({ sessionID, directory }: { sessionID: string; directory: string }) => Effect.sync(() => { order.push("move-request"); if (!delayMove) { - sessions.get(sessionID)!.location.directory = directory; + required(sessions, sessionID).location.directory = directory; order.push("moved"); - if (crossProject) sessions.get(sessionID)!.projectID = "another-project"; + if (crossProject) + required(sessions, sessionID).projectID = "another-project"; } entered.resolve(); }), @@ -272,15 +289,7 @@ function fixture() { Agent.Info.default(Agent.ID.make("build")).permissions, herdr, ), - invoke: ( - input = { - agent: "coordinate", - description: "test", - prompt: "work", - worktree: { base: "main" }, - }, - caller = call, - ) => tool.execute(input, caller), + invoke: (input = defaultInput, caller = call) => tool.execute(input, caller), execute: (input: z.infer, caller = call) => tool.execute(input, caller), hold() { hold = true; @@ -381,7 +390,7 @@ test("root-local resume rejects location, binding, and live-root changes", async prompt: "work", }); if (tamper === "session") - f.sessions.get("ses_child1")!.location.directory = "/other"; + required(f.sessions, "ses_child1").location.directory = "/other"; else if (tamper === "live-root") f.herdr.rootWorkspaceID = "foreign"; else { const binding = bindingSchema.parse( diff --git a/tests/package.test.ts b/tests/package.test.ts index 9318d30..bdacbcc 100644 --- a/tests/package.test.ts +++ b/tests/package.test.ts @@ -3,6 +3,7 @@ import { mkdir, mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Host } from "@opencode/plugin/host"; +import { z } from "zod"; import { build } from "../scripts/build.js"; import { install } from "../scripts/install.js"; @@ -23,13 +24,19 @@ test("packed package has independent native plugins and quota-only TUI discovery }); expect(await unpack.exited).toBe(0); const source = join(directory, "package"); - const manifest = await Bun.file(join(source, "package.json")).json(); + const manifest = z + .object({ exports: z.record(z.string(), z.object({ import: z.string() }).loose()) }) + .loose() + .parse(await Bun.file(join(source, "package.json")).json()); + const entrypoint = (name: string) => + join(source, z.string().parse(manifest.exports[name]?.import)); expect(manifest.exports["."]).toBeUndefined(); expect(await Bun.file(join(source, "index.js")).exists()).toBe(false); expect(await Bun.file(join(source, "dist", "index.js")).exists()).toBe(false); for (const name of ["agents", "multi-work", "quota"]) { - const entrypoint = join(source, manifest.exports[`./${name}`].import); - const { default: plugin } = await import(entrypoint); + const { default: plugin } = z + .object({ default: z.object({ id: z.string() }).loose() }) + .parse(await import(entrypoint(`./${name}`))); expect(plugin.id).toBe(`stanp-opencode.${name}`); } const config = join(directory, "config"); @@ -42,7 +49,9 @@ test("packed package has independent native plugins and quota-only TUI discovery expect(entries.server).toBeDefined(); expect(entries.tui !== undefined).toBe(name === "quota"); } - const { QuotaRpc } = await import(join(source, manifest.exports["./quota-rpc"].import)); + const { QuotaRpc } = z + .object({ QuotaRpc: z.object({ id: z.string() }).loose() }) + .parse(await import(entrypoint("./quota-rpc"))); expect(QuotaRpc.id).toBe("stanp-opencode.quota"); } finally { await rm(directory, { recursive: true, force: true }); diff --git a/tests/plugin.test.ts b/tests/plugin.test.ts index f08d721..a2477e4 100644 --- a/tests/plugin.test.ts +++ b/tests/plugin.test.ts @@ -31,24 +31,29 @@ const agents = { "deep-lo": "test/gpt-6-astra#low", "deep-hi": "test/gpt-6-astra#high", }; +const defaultOptions = { agents }; +const defaultLocation = { directory: "/fixture" }; +async function flush() { + await Bun.sleep(10); +} async function host( catalog: ModelInfo[] = models, - options: Plugin.Context["options"] = { agents }, + options: Plugin.Context["options"] = defaultOptions, existingSkill?: Skill.Info, ) { - const agents = new Map>(); + const registry = new Map>(); let build: DeepMutable = Agent.Info.default(Agent.ID.make("build")); const skills = new Map( existingSkill ? [[existingSkill.id, existingSkill]] : [], ); - let transform: (editor: AgentEditor) => void; + let transform: ((editor: AgentEditor) => void) | undefined; let contextHook: (event: Pick) => Promise | void; let promptHook: (event: { sessionID: string }) => Promise | void; let before: (event: { tool: string; agent: string; input: unknown }) => Promise | void; let parent = "build"; let child = "fast-lo"; let tools: string[] = []; - let toolTransform: (editor: ToolEditor) => void; + let toolTransform: ((editor: ToolEditor) => void) | undefined; let permissions: () => Promise; let controller: ReadableStreamDefaultController; const stream = new ReadableStream({ @@ -58,20 +63,20 @@ async function host( }); const registration = { async dispose() {} }; const replay = () => { - agents.clear(); - agents.set("build", structuredClone(build)); + registry.clear(); + registry.set("build", structuredClone(build)); transform?.({ - get: (id) => agents.get(id), - list: () => [...agents.values()], + get: (id) => registry.get(id), + list: () => [...registry.values()], default() {}, remove: (id) => { - agents.delete(id); + registry.delete(id); }, update(id, update) { const draft = - agents.get(id) ?? structuredClone(Agent.Info.default(Agent.ID.make(id))); + registry.get(id) ?? structuredClone(Agent.Info.default(Agent.ID.make(id))); update(draft); - agents.set(id, draft); + registry.set(id, draft); }, }); }; @@ -110,7 +115,7 @@ async function host( }, agent: { async list() { - return { data: [...agents.values()] }; + return { data: [...registry.values()] }; }, async reload() { replay(); @@ -182,11 +187,8 @@ async function host( replay(); const cleanup = await setup(context); if (cleanup) cleanups.push(cleanup); - const flush = async () => { - await Bun.sleep(10); - }; return { - agents, + agents: registry, skills, permissions: () => permissions(), async configure(rules: Agent.Info["permissions"]) { @@ -195,7 +197,7 @@ async function host( controller.enqueue({ type: "agent.updated" }); await flush(); }, - async models(next: ModelInfo[], location = { directory: "/fixture" }) { + async models(next: ModelInfo[], location = defaultLocation) { catalog = next; controller.enqueue({ type: "model.updated", location }); await flush(); @@ -205,10 +207,10 @@ async function host( replayTools(); await flush(); }, - async delegate(agent: string, target: string) { + delegate: async (agent: string, target: string) => { await before({ tool: "subagent", agent, input: { agent: target } }); }, - async command(owner: string, target: string) { + command: async (owner: string, target: string) => { parent = owner; child = target; await promptHook({ sessionID: "child" }); @@ -231,7 +233,7 @@ async function host( test("worker availability, deep fallback, and model refresh remain provider aware", async () => { const h = await host(); - expect([...h.skills.keys()].sort()).toEqual(["anti-overengineering", "task-planning"]); + expect([...h.skills.keys()].toSorted()).toEqual(["anti-overengineering", "task-planning"]); expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6-astra"); await h.models(models.slice(0, 2)); expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6.1-sol"); @@ -256,7 +258,7 @@ test("assignments are provider-qualified with optional deep pair and variant; pa const shallow = Object.fromEntries( Object.entries(agents).filter(([name]) => !name.startsWith("deep-")), ); - const duplicate = models.map((model) => ({ ...model, providerID: Provider.ID.make("other") })); + const duplicate = models.map((entry) => ({ ...entry, providerID: Provider.ID.make("other") })); const h = await host([...duplicate, ...models], { agents: shallow }); expect(String(h.agents.get("coordinate")?.model?.providerID)).toBe("test"); expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6.1-sol"); @@ -295,6 +297,6 @@ test("native tool and command paths retain core delegation restrictions", async expect( z .object({ agent: z.object({ type: z.string(), enum: z.array(z.string()) }) }) - .parse((await h.request("coordinate")).subagent?.input.properties).agent, + .parse((await h.request("coordinate"))["subagent"]?.input["properties"]).agent, ).toEqual({ type: "string", enum: ["fast-lo", "fast-hi", "good-lo", "good-hi"] }); }); diff --git a/tests/plugins.test.ts b/tests/plugins.test.ts index b38bd30..4da21d1 100644 --- a/tests/plugins.test.ts +++ b/tests/plugins.test.ts @@ -18,9 +18,7 @@ test("Quota loads independently and retains its RPC ID and nullable status", asy location: { directory: "/fixture" }, integration: { connection: { - async active() { - return undefined; - }, + async active() {}, }, }, event: { @@ -56,7 +54,7 @@ test("Quota loads independently and retains its RPC ID and nullable status", asy ) => ReturnType; const cleanup = await setup(context); expect(quota.id).toBe("stanp-opencode.quota"); - expect(await status!()).toBeNull(); + expect(await status?.()).toBeNull(); expect(modelHook).toBe(true); if (cleanup) await cleanup(); expect(disposed).toBe(true); diff --git a/tests/quota.test.ts b/tests/quota.test.ts index 0e9e50f..c82b661 100644 --- a/tests/quota.test.ts +++ b/tests/quota.test.ts @@ -186,8 +186,8 @@ function fixture( changes: () => changes, headers, stored, - switch(credential: typeof current) { - current = credential; + switch(next: typeof current) { + current = next; }, logout: () => { current = undefined; diff --git a/tsconfig.json b/tsconfig.json index d7eba60..46e4afa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,10 @@ "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "allowUnreachableCode": false, "noUnusedLocals": true, "noUnusedParameters": true, "verbatimModuleSyntax": true, -- 2.54.0