History

Extract reacord from legacy, delete legacy directory and unused adapter package

- Move @openassistant/reacord to assistant/packages/reacord/ (only actively used legacy package) - Delete entire assistant/legacy/openassistant/ directory (~515MB of superseded code) - Delete unused assistant/packages/agent-executor-adapter/ (9-line wrapper never imported) - Update workspace entries in root and assistant package.json

Rhys Sullivan committed 9 months ago

Commit e2dd09a1 parent d7c112897 files · +65 −9966Browse files

Unified · Split

97 files
  1. assistant/README.md +0 −1
  2. assistant/legacy/openassistant/NEW_PLAN.md +0 −344
  3. assistant/legacy/openassistant/README.md +0 −35
  4. assistant/legacy/openassistant/apps/bot/package.json +0 −25
  5. assistant/legacy/openassistant/apps/bot/src/commands/ask.tsx +0 −64
  6. assistant/legacy/openassistant/apps/bot/src/index.ts +0 −122
  7. assistant/legacy/openassistant/apps/bot/src/views/task-message.tsx +0 −522
  8. assistant/legacy/openassistant/apps/bot/tsconfig.json +0 −13
  9. assistant/legacy/openassistant/apps/executor/package.json +0 −18
  10. assistant/legacy/openassistant/apps/executor/src/index.ts +0 −150
  11. assistant/legacy/openassistant/apps/executor/src/smoke.test.ts +0 −5
  12. assistant/legacy/openassistant/apps/executor/tsconfig.json +0 −14
  13. assistant/legacy/openassistant/apps/server/package.json +0 −27
  14. assistant/legacy/openassistant/apps/server/src/client.test.ts +0 −150
  15. assistant/legacy/openassistant/apps/server/src/client.ts +0 −104
  16. assistant/legacy/openassistant/apps/server/src/index.ts +0 −229
  17. assistant/legacy/openassistant/apps/server/src/routes.test.ts +0 −408
  18. assistant/legacy/openassistant/apps/server/src/routes.ts +0 −313
  19. assistant/legacy/openassistant/apps/server/src/state.ts +0 −276
  20. assistant/legacy/openassistant/apps/server/src/task-runner.ts +0 −201
  21. assistant/legacy/openassistant/apps/server/tsconfig.json +0 −15
  22. assistant/legacy/openassistant/bun.lock +0 −1127
  23. assistant/legacy/openassistant/index.ts +0 −1
  24. assistant/legacy/openassistant/package.json +0 −52
  25. assistant/legacy/openassistant/packages/core/package.json +0 −25
  26. assistant/legacy/openassistant/packages/core/src/agent.test.ts +0 −218
  27. assistant/legacy/openassistant/packages/core/src/agent.ts +0 −455
  28. assistant/legacy/openassistant/packages/core/src/discovery.ts +0 −237
  29. assistant/legacy/openassistant/packages/core/src/events.ts +0 −60
  30. assistant/legacy/openassistant/packages/core/src/index.ts +0 −85
  31. assistant/legacy/openassistant/packages/core/src/loop.test.ts +0 −219
  32. assistant/legacy/openassistant/packages/core/src/pi-ai-adapter.ts +0 −217
  33. assistant/legacy/openassistant/packages/core/src/remote-runner.test.ts +0 −89
  34. assistant/legacy/openassistant/packages/core/src/remote-runner.ts +0 −124
  35. assistant/legacy/openassistant/packages/core/src/runner.test.ts +0 −453
  36. assistant/legacy/openassistant/packages/core/src/runner.ts +0 −565
  37. assistant/legacy/openassistant/packages/core/src/tools.test.ts +0 −143
  38. assistant/legacy/openassistant/packages/core/src/tools.ts +0 −226
  39. assistant/legacy/openassistant/packages/core/src/typechecker.test.ts +0 −160
  40. assistant/legacy/openassistant/packages/core/src/typechecker.ts +0 −286
  41. assistant/legacy/openassistant/packages/core/tsconfig.json +0 −11
  42. assistant/legacy/openassistant/packages/tool-gen/package.json +0 −24
  43. assistant/legacy/openassistant/packages/tool-gen/src/e2e.test.ts +0 −109
  44. assistant/legacy/openassistant/packages/tool-gen/src/index.ts +0 −18
  45. assistant/legacy/openassistant/packages/tool-gen/src/integration.test.ts +0 −105
  46. assistant/legacy/openassistant/packages/tool-gen/src/json-schema-to-ts.test.ts +0 −126
  47. assistant/legacy/openassistant/packages/tool-gen/src/json-schema-to-ts.ts +0 −164
  48. assistant/legacy/openassistant/packages/tool-gen/src/mcp.test.ts +0 −121
  49. assistant/legacy/openassistant/packages/tool-gen/src/mcp.ts +0 −271
  50. assistant/legacy/openassistant/packages/tool-gen/src/openapi-integration.test.ts +0 −283
  51. assistant/legacy/openassistant/packages/tool-gen/src/openapi.test.ts +0 −143
  52. assistant/legacy/openassistant/packages/tool-gen/src/openapi.ts +0 −514
  53. assistant/legacy/openassistant/packages/tool-gen/tsconfig.json +0 −12
  54. assistant/legacy/openassistant/tsconfig.base.json +0 −22
  55. assistant/legacy/openassistant/tsconfig.json +0 −9
  56. assistant/legacy/openassistant/vitest.config.ts +0 −8
  57. assistant/package.json +1 −1
  58. assistant/packages/agent-executor-adapter/package.json +0 −18
  59. assistant/packages/agent-executor-adapter/src/index.test.ts +0 −87
  60. assistant/packages/agent-executor-adapter/src/index.ts +0 −8
  61. assistant/packages/agent-executor-adapter/tsconfig.json +0 −14
  62. assistant/packages/reacord/package.json +0 −0
  63. assistant/packages/reacord/src/components/action-row.tsx +0 −0
  64. assistant/packages/reacord/src/components/attachment.tsx +0 −0
  65. assistant/packages/reacord/src/components/button.tsx +0 −0
  66. assistant/packages/reacord/src/components/container.tsx +0 −0
  67. assistant/packages/reacord/src/components/file.tsx +0 −0
  68. assistant/packages/reacord/src/components/link.tsx +0 −0
  69. assistant/packages/reacord/src/components/loading-select.tsx +0 −0
  70. assistant/packages/reacord/src/components/loading.tsx +0 −0
  71. assistant/packages/reacord/src/components/media-gallery.tsx +0 −0
  72. assistant/packages/reacord/src/components/modal-button.tsx +0 −0
  73. assistant/packages/reacord/src/components/option.tsx +0 −0
  74. assistant/packages/reacord/src/components/section.tsx +0 −0
  75. assistant/packages/reacord/src/components/select.tsx +0 −0
  76. assistant/packages/reacord/src/components/separator.tsx +0 −0
  77. assistant/packages/reacord/src/components/text-display.tsx +0 −0
  78. assistant/packages/reacord/src/components/thumbnail.tsx +0 −0
  79. assistant/packages/reacord/src/components/user-select.tsx +0 −0
  80. assistant/packages/reacord/src/create-component.tsx +0 −0
  81. assistant/packages/reacord/src/index.ts +0 −0
  82. assistant/packages/reacord/src/instance-context.tsx +0 −0
  83. assistant/packages/reacord/src/instance.ts +0 −0
  84. assistant/packages/reacord/src/internal/container.ts +0 −0
  85. assistant/packages/reacord/src/internal/element.ts +0 −0
  86. assistant/packages/reacord/src/internal/errors.ts +0 −0
  87. assistant/packages/reacord/src/internal/helpers.ts +0 −0
  88. assistant/packages/reacord/src/internal/interaction.ts +0 −0
  89. assistant/packages/reacord/src/internal/message.ts +0 −0
  90. assistant/packages/reacord/src/internal/node.ts +0 −0
  91. assistant/packages/reacord/src/internal/reconciler.ts +0 −0
  92. assistant/packages/reacord/src/internal/renderer.ts +0 −0
  93. assistant/packages/reacord/src/internal/text-node.ts +0 −0
  94. assistant/packages/reacord/src/reacord.tsx +0 −0
  95. assistant/packages/reacord/tsconfig.json +9 −3
  96. bun.lock +54 −116
  97. package.json +1 −1
assistant/README.md+0−1
@@ -2,5 +2,4 @@ · 1 unmodified line
22
33 Assistant-side code lives here.
44
5−- `packages/agent-executor-adapter`: lightweight adapter for talking to the executor API.
65 - `legacy/openassistant`: previous prototype code moved out of the executor-focused workspace.
assistant/legacy/openassistant/NEW_PLAN.md+0−344
@@ -1,344 +0,0 @@
1−# OpenAssistant — Architecture Plan
2−
3−## What This Is
4−
5−An AI assistant that takes natural language prompts and executes them as typed TypeScript code against registered tools. Unlike CLI-based agents (OpenClaw, ClawdBot), the agent generates TypeScript code rather than shell commands, giving precise control over what gets approved, what runs, and what the agent can access.
6−
7−## Example Prompts
8−
9−| Prompt | Task Type | Duration |
10−|---|---|---|
11−| "On AnswerOverflow/AnswerOverflow, close all issues older than 30 days" | One-shot | Seconds/minutes |
12−| "Every day at 9am check if my site has hit 10M visitors with PostHog and if it has let me know" | Recurring + conditional exit | Days/weeks |
13−| "Tell me how many people have subscribed every day at 5pm" | Recurring, no exit | Forever |
14−| "When I get an email, check if it's spam and if it is delete it" | Event-triggered | Forever |
15−
16−## Architecture
17−
18−```
19− Clients (pull events, push decisions)
20− ──────────────────────────────────────
21− Discord bot Web UI CLI Slack
22− │ │ │ │
23− └────────────┴────────┴───────┘
24− │
25− Event stream (SSE / WS)
26− + REST for decisions
27− │
28− Server (gateway)
29− ──────────────────────────────────────
30− Bun.serve()
31− ├── SSE event stream per task
32− ├── REST API (/api/tasks, /api/approvals, /api/hooks)
33− ├── Workflow .well-known routes (durability)
34− ├── Agent loop (Claude + codemode runner)
35− ├── Tool plugins (hand-written + MCP + OpenAPI)
36− └── Persistence (bun:sqlite for MVP)
37−```
38−
39−### Key Principle: Server Emits Events, Clients Subscribe
40−
41−The server never POSTs to clients. Instead:
42−1. Every task produces a stream of `TaskEvent`s (persisted, resumable)
43−2. Clients subscribe via SSE/WebSocket/polling
44−3. When a tool needs approval, the server emits an `approval_request` event
45−4. Any client renders approval UI and POSTs the decision to `POST /api/approvals/:callId`
46−5. The server picks up the decision and continues execution
47−
48−This is client-agnostic. Discord, web, CLI — they all implement the same protocol.
49−
50−## Execution Sandbox
51−
52−LLM-generated code runs in a `node:vm` sandbox with `Object.create(null)` as the context base:
53−
54−- **Allowed:** `tools` (injected), `JSON`, `Math`, `Date`, `console` (no-op)
55−- **Blocked:** `fetch`, `process`, `Bun`, `require`, `import()`, all Node/Bun APIs
56−- **Constructor chain escape:** Safe — returns the sandbox global which has nothing dangerous
57−- **Prototype pollution:** Stays in sandbox, does not leak to host
58−- **Execution timeout:** `vm.runInContext` `timeout` option
59−- **Memory limits:** Not controllable with `node:vm` (would need rquickjs, deferred to post-MVP)
60−
61−Tool functions are wrapped so `toString()` doesn't leak source code.
62−
63−## Durability — Vercel Workflow
64−
65−[Vercel Workflow DevKit](https://github.com/vercel/workflow) handles:
66−- **Durable scheduling:** `sleep("1 day")` suspends the workflow, consumes zero compute, survives restarts
67−- **Durable event waiting:** `createHook()` + `for await` loop for webhook-triggered tasks
68−- **Crash recovery:** Workflow state is persisted; on restart, replays from the event log
69−- **Observability:** Every workflow run, every step, every retry is traced
70−
71−### Three Workflow Templates (compile-time)
72−
73−All workflows are generic. The `prompt` argument (interpreted by Claude at runtime) determines behavior.
74−
75−```ts
76−// workflows/one-shot.ts — "close all stale issues"
77−export async function oneShotWorkflow(prompt, requesterId, channelId, taskId) {
78− "use workflow";
79− const result = await runAgentTurn(prompt, requesterId, channelId, taskId);
80− return result;
81−}
82−
83−// workflows/recurring.ts — "every day at 9am check X"
84−export async function recurringWorkflow(prompt, requesterId, channelId, taskId, intervalMs) {
85− "use workflow";
86− while (true) {
87− await sleep(intervalMs);
88− await runAgentTurn(prompt, requesterId, channelId, taskId);
89− }
90−}
91−
92−// workflows/event-triggered.ts — "when I get an email, do X"
93−export async function eventTriggeredWorkflow(prompt, requesterId, channelId, taskId, hookToken) {
94− "use workflow";
95− const hook = createHook<Record<string, unknown>>({ token: hookToken });
96− for await (const payload of hook) {
97− const enrichedPrompt = `${prompt}\n\nEvent data:\n${JSON.stringify(payload, null, 2)}`;
98− await runAgentTurn(enrichedPrompt, requesterId, channelId, taskId);
99− }
100−}
101−```
102−
103−### The Shared Step
104−
105−```ts
106−async function runAgentTurn(prompt, requesterId, channelId, taskId) {
107− "use step";
108− // Full runtime access here — this is where the agent loop runs
109− // Creates runner, calls Claude, executes code, collects receipts
110− // Emits TaskEvents to the stream (including approval_request)
111− // Polls for approval decisions from clients
112−}
113−```
114−
115−## Tool System
116−
117−### defineTool API
118−
119−```ts
120−import { z } from "zod";
121−
122−defineTool({
123− description: "Close a GitHub issue",
124− approval: "required",
125− args: z.object({
126− owner: z.string(),
127− repo: z.string(),
128− issueNumber: z.number(),
129− }),
130− returns: z.object({
131− number: z.number(),
132− title: z.string(),
133− state: z.string(),
134− }),
135− run: async (input) => { ... },
136− formatApproval: (input) => ({
137− title: `Close ${input.owner}/${input.repo}#${input.issueNumber}`,
138− }),
139−});
140−```
141−
142−- `args` (Zod schema) → validates input at invocation + generates TypeScript declarations for typechecker + generates LLM prompt guidance
143−- `returns` (Zod schema) → generates TypeScript return type
144−- `description` → LLM prompt guidance
145−- `approval: "auto" | "required"` → determines approval flow
146−- `run` → plain `async` function (not Effect in the public API)
147−- `formatApproval` → optional, provides rich approval presentation
148−
149−### Three Tool Sources
150−
151−All produce the same `ToolTree` + TypeScript declarations. The runner doesn't know the difference.
152−
153−**1. Hand-written plugins**
154−```ts
155−export const githubTools = {
156− github: {
157− issues: {
158− close: defineTool({ ... }),
159− }
160− }
161−};
162−```
163−
164−**2. MCP servers** (auto-generated at startup)
165−```ts
166−// Config: { type: "mcp", name: "answeroverflow", url: "https://www.answeroverflow.com/mcp" }
167−// → Introspects tools/list
168−// → Generates: tools.answeroverflow.search_answeroverflow({ query })
169−// → Each tool wraps client.callTool(name, input)
170−```
171−
172−**3. OpenAPI specs** (auto-generated at startup)
173−```ts
174−// Config: { type: "openapi", name: "fastspring", spec: "https://...", auth: { ... } }
175−// → Parses spec, groups by tag
176−// → GET → approval: "auto", POST/PUT/DELETE → approval: "required"
177−// → Generates: tools.fastspring.accounts.get({ account_id })
178−```
179−
180−### Tool Source Config
181−
182−```ts
183−const toolSources = [
184− createGitHubPlugin(),
185− { type: "mcp", name: "answeroverflow", url: "https://www.answeroverflow.com/mcp" },
186− { type: "openapi", name: "fastspring", spec: "https://...", auth: { type: "basic", credentials: "FASTSPRING_CREDENTIALS" } },
187−];
188−```
189−
190−## Approval Flow
191−
192−### One-shot tasks (user is active in conversation)
193−
194−1. Agent generates code that calls `tools.github.issues.close(...)`
195−2. Runner hits the approval gate for `approval: "required"` tools
196−3. Runner emits `{ type: "approval_request", id, toolPath, preview }` to the task event stream
197−4. Runner polls `getApprovalDecision(callId)` in a loop
198−5. Client (Discord/web/CLI) sees the event, renders approval UI
199−6. User clicks Approve → client POSTs to `POST /api/approvals/:callId`
200−7. Decision is written to DB
201−8. Runner's poll picks it up, execution continues
202−
203−### Background tasks (recurring/event-triggered, no active conversation)
204−
205−Same flow, but the client sends a proactive DM/notification with approval buttons. The user approves asynchronously.
206−
207−### Batch approval (future enhancement)
208−
209−For tasks that need many approvals (close 15 issues), a batch approval mode: show all proposed actions upfront, user approves once.
210−
211−## Task Event Stream
212−
213−Every task run produces events. Clients subscribe and render them however they want.
214−
215−```ts
216−type TaskEvent =
217− | { type: "status"; message: string }
218− | { type: "code_generated"; code: string }
219− | { type: "approval_request"; id: string; toolPath: string; input: unknown; preview: ApprovalPresentation }
220− | { type: "approval_resolved"; id: string; decision: "approved" | "denied" }
221− | { type: "tool_result"; id: string; toolPath: string; status: "succeeded" | "failed" | "denied"; preview?: string }
222− | { type: "agent_message"; text: string }
223− | { type: "error"; error: string }
224− | { type: "completed" }
225−```
226−
227−## Task Management
228−
229−The agent has task management tools (so the user speaks natural language):
230−
231−```
232−tools.tasks.list() → active tasks for this user
233−tools.tasks.createRecurring(...) → starts a recurring workflow
234−tools.tasks.createEventTrigger(...) → starts an event-triggered workflow
235−tools.tasks.cancel({ taskId }) → cancels a workflow run
236−tools.tasks.history({ taskId }) → recent events from a task's stream
237−```
238−
239−## Persistence
240−
241−**bun:sqlite** for MVP. Single file, zero ops. Used for:
242−- Workflow world (adapter needed, or use Workflow's local filesystem world)
243−- Approval decisions (polling table)
244−- Task registry (what tasks exist, who owns them)
245−- Auth credentials (env vars for MVP, DB profiles later)
246−
247−## Agent Loop
248−
249−1. Build system prompt from tool descriptions + type declarations + task context
250−2. Call Claude with the prompt and the `run_code` tool
251−3. Claude responds with `run_code({ code: "..." })`
252−4. Typecheck the code against generated TypeScript declarations
253−5. If typecheck fails: feed error back to Claude, retry (up to 3 times)
254−6. Execute code in `node:vm` sandbox
255−7. Collect receipts from all tool calls
256−8. Feed receipts back to Claude
257−9. Claude may call `run_code` again, or produce final text response
258−10. Emit `agent_message` event to the stream
259−
260−## Effect Usage
261−
262−Effect is used throughout the codebase, properly:
263−- **Services + Layers** for dependency injection (database, config, clients)
264−- **Tagged errors** for typed error handling
265−- **Tracing spans** for observability
266−- **Fibers** where concurrency is needed
267−
268−The public `defineTool` API uses plain `async` functions — Effect is an internal implementation detail, not exposed to tool authors or the sandbox.
269−
270−## Server Routes
271−
272−```
273−POST /.well-known/workflow/v1/flow Workflow flow handler
274−POST /.well-known/workflow/v1/step Workflow step handler
275−* /.well-known/workflow/v1/webhook/:token Workflow webhook handler
276−
277−POST /api/tasks Create a new task
278−GET /api/tasks List tasks for a user
279−GET /api/tasks/:id Get task status
280−GET /api/tasks/:id/events SSE stream of TaskEvents
281−POST /api/tasks/:id/cancel Cancel a task
282−
283−POST /api/approvals/:callId Resolve an approval decision
284−
285−POST /api/hooks/:token Webhook ingestion (external services POST here)
286−```
287−
288−## Monorepo Layout
289−
290−```
291−apps/
292− server/ Bun.serve() — the brain
293− index.ts Routes: REST + Workflow + SSE + webhooks
294− workflows/
295− one-shot.ts "use workflow"
296− recurring.ts "use workflow"
297− event-triggered.ts "use workflow"
298− steps.ts "use step" — shared (runAgentTurn, notifyUser)
299−
300− bot/ Discord client
301− index.ts discord.js, subscribes to event streams
302− views/ React components via Reacord
303−
304−packages/
305− core/
306− tools.ts defineTool, ToolTree, ToolCallReceipt types
307− runner.ts node:vm sandbox execution
308− typechecker.ts TypeScript type checking (auto-gen from Zod)
309− agent.ts Agent loop (Claude + run_code + retries)
310− events.ts TaskEvent types
311− approval.ts Approval types + logic
312−
313− tool-gen/
314− mcp.ts MCP server introspection → ToolTree
315− openapi.ts OpenAPI spec parsing → ToolTree
316− type-gen.ts Zod schema → TypeScript declaration strings
317−
318− reacord/ (existing) React reconciler for Discord
319−```
320−
321−## Build Order
322−
323−1. **packages/core** — defineTool, ToolTree, runner (node:vm), typechecker, agent loop, TaskEvent types. Tested with real Claude calls.
324−2. **packages/tool-gen** — MCP + OpenAPI generation. Uses existing parsers (@modelcontextprotocol/sdk, swagger-parser).
325−3. **apps/server** — Bun.serve + Workflow integration + REST API + SSE streams.
326−4. **apps/bot** — Discord client consuming event streams.
327−
328−## Testing
329−
330−Real tests, no mocks. Claude calls use Claude Max credentials.
331−
332−- **Unit tests:** Runner executes code in sandbox, collects receipts. Tool definitions validate with Zod. Typechecker catches bad code.
333−- **Integration tests:** Agent loop generates and executes code for simple tasks. Tool-gen produces correct ToolTree from MCP/OpenAPI specs.
334−- **E2E tests:** Full workflow: create task → subscribe to events → approve → get results.
335−
336−## What's Deferred (post-MVP)
337−
338−- Hard memory limits (rquickjs)
339−- Credential broker / ephemeral tokens
340−- Batch approval UX
341−- Ops web UI
342−- CLI client
343−- Plugin discovery from convention directories
344−- Auto-compaction for long conversation contexts
assistant/legacy/openassistant/README.md+0−35
@@ -1,35 +0,0 @@
1−# OpenAssistant
2−
3−## Install
4−
5−```bash
6−bun install
7−```
8−
9−## Local MVP (remote executor mode)
10−
11−Start the executor (private code runner):
12−
13−```bash
14−bun run --filter '@openassistant/executor' dev
15−```
16−
17−Start the server (agent + approvals + tool broker):
18−
19−```bash
20−OPENASSISTANT_EXECUTOR_URL=http://localhost:3001 \
21−OPENASSISTANT_CALLBACK_BASE_URL=http://localhost:3000 \
22−bun run --filter '@openassistant/server' dev
23−```
24−
25−Or run all services together:
26−
27−```bash
28−bun run dev
29−```
30−
31−## Notes
32−
33−- Untrusted generated code executes in the executor service.
34−- Tool calls are proxied back to the server via `/internal/runs/:runId/invoke`.
35−- Approval flow and secret-backed tool execution stay on the server side.
assistant/legacy/openassistant/apps/bot/package.json+0−25
@@ -1,25 +0,0 @@
1−{
2− "name": "@openassistant/bot",
3− "private": true,
4− "type": "module",
5− "scripts": {
6− "with-env": "bun run --env-file=../../.env --",
7− "dev": "bun run with-env bun --hot src/index.ts",
8− "start": "bun run with-env bun src/index.ts",
9− "typecheck": "tsgo --noEmit",
10− "test": "bun test src/"
11− },
12− "dependencies": {
13− "@openassistant/core": "workspace:*",
14− "@openassistant/server": "workspace:*",
15− "@openassistant/reacord": "workspace:*",
16− "@elysiajs/eden": "latest",
17− "discord.js": "^14.17.3",
18− "effect": "latest",
19− "react": "^19.0.0"
20− },
21− "devDependencies": {
22− "@types/bun": "latest",
23− "@types/react": "^19.0.0"
24− }
25−}
assistant/legacy/openassistant/apps/bot/src/commands/ask.tsx+0−64
@@ -1,64 +0,0 @@
1−/**
2− * /ask command handler
3− *
4− * Defers the interaction, creates a task on the server,
5− * and mounts a self-updating <TaskMessage /> that subscribes
6− * to the server's SSE stream via Eden Treaty.
7− */
8−
9−import type { ChatInputCommandInteraction, CommandInteraction } from "discord.js";
10−import type { Client as ApiClient } from "@openassistant/server/client";
11−import { unwrap } from "@openassistant/server/client";
12−import type { ReacordInstance } from "@openassistant/reacord";
13−import { Effect, Runtime } from "effect";
14−import { TaskMessage } from "../views/task-message";
15−
16−// ---------------------------------------------------------------------------
17−// Types
18−// ---------------------------------------------------------------------------
19−
20−interface AskCommandDeps {
21− readonly api: ApiClient;
22− readonly reacord: {
23− reply: (interaction: CommandInteraction, content: React.ReactNode) => Effect.Effect<ReacordInstance>;
24− };
25−}
26−
27−// ---------------------------------------------------------------------------
28−// Command handler
29−// ---------------------------------------------------------------------------
30−
31−export async function handleAskCommand(
32− interaction: ChatInputCommandInteraction,
33− deps: AskCommandDeps,
34−): Promise<void> {
35− const prompt = interaction.options.getString("prompt", true);
36− const requesterId = interaction.user.id;
37−
38− // Defer immediately — Discord interactions expire after 3 seconds.
39− await interaction.deferReply();
40−
41− // Create task on the server
42− let taskId: string;
43− let executionMode: "local" | "remote" = "local";
44− try {
45− const data = await unwrap(
46− deps.api.api.tasks.post({ prompt, requesterId }),
47− );
48− taskId = data.taskId;
49− executionMode = data.executionMode;
50− } catch (error) {
51− await interaction.editReply({
52− content: `\u274c Failed to create task: ${error instanceof Error ? error.message : String(error)}`,
53− });
54− return;
55− }
56−
57− // Mount the component — it handles its own SSE subscription and state
58− await Runtime.runPromise(Runtime.defaultRuntime)(
59− deps.reacord.reply(
60− interaction,
61− <TaskMessage taskId={taskId} prompt={prompt} api={deps.api} executionMode={executionMode} />,
62− ),
63− );
64−}
assistant/legacy/openassistant/apps/bot/src/index.ts+0−122
@@ -1,122 +0,0 @@
1−/**
2− * OpenAssistant Discord Bot
3− *
4− * Connects to Discord, registers slash commands, and renders
5− * task results using Reacord (React for Discord).
6− *
7− * Communicates with the server via Eden Treaty (type-safe HTTP client).
8− */
9−
10−import {
11− Client,
12− GatewayIntentBits,
13− REST,
14− Routes,
15− SlashCommandBuilder,
16− type ChatInputCommandInteraction,
17−} from "discord.js";
18−import { makeReacord } from "@openassistant/reacord";
19−import { createClient } from "@openassistant/server/client";
20−import { handleAskCommand } from "./commands/ask";
21−
22−// ---------------------------------------------------------------------------
23−// Config
24−// ---------------------------------------------------------------------------
25−
26−const DISCORD_TOKEN = process.env["DISCORD_BOT_TOKEN"];
27−if (!DISCORD_TOKEN) {
28− throw new Error("DISCORD_BOT_TOKEN is required");
29−}
30−
31−const SERVER_URL = process.env["OPENASSISTANT_SERVER_URL"] ?? "http://localhost:3000";
32−
33−// ---------------------------------------------------------------------------
34−// Discord client
35−// ---------------------------------------------------------------------------
36−
37−const client = new Client({
38− intents: [
39− GatewayIntentBits.Guilds,
40− GatewayIntentBits.GuildMessages,
41− ],
42−});
43−
44−// ---------------------------------------------------------------------------
45−// Reacord
46−// ---------------------------------------------------------------------------
47−
48−const reacord = makeReacord(client, { maxInstances: 50 });
49−
50−// ---------------------------------------------------------------------------
51−// Eden Treaty API client
52−// ---------------------------------------------------------------------------
53−
54−const api = createClient(SERVER_URL);
55−
56−// ---------------------------------------------------------------------------
57−// Slash command definitions
58−// ---------------------------------------------------------------------------
59−
60−const commands = [
61− new SlashCommandBuilder()
62− .setName("ask")
63− .setDescription("Ask the AI assistant to do something")
64− .addStringOption((option) =>
65− option
66− .setName("prompt")
67− .setDescription("What do you want the assistant to do?")
68− .setRequired(true),
69− ),
70− new SlashCommandBuilder()
71− .setName("clear")
72− .setDescription("Push chat history out of view"),
73−];
74−
75−// ---------------------------------------------------------------------------
76−// Register commands on startup
77−// ---------------------------------------------------------------------------
78−
79−async function registerCommands() {
80− const rest = new REST().setToken(DISCORD_TOKEN!);
81−
82− try {
83− console.log("Registering slash commands...");
84− await rest.put(Routes.applicationCommands(client.user!.id), {
85− body: commands.map((c) => c.toJSON()),
86− });
87− console.log("Slash commands registered.");
88− } catch (error) {
89− console.error("Failed to register slash commands:", error);
90− }
91−}
92−
93−// ---------------------------------------------------------------------------
94−// Command handler
95−// ---------------------------------------------------------------------------
96−
97−client.on("interactionCreate", async (interaction) => {
98− if (!interaction.isChatInputCommand()) return;
99−
100− switch (interaction.commandName) {
101− case "ask":
102− await handleAskCommand(interaction, { api, reacord });
103− break;
104− case "clear":
105− await interaction.reply({ content: `_${"\n".repeat(50)}_` });
106− break;
107− default:
108− await interaction.reply({ content: `Unknown command: ${interaction.commandName}` });
109− }
110−});
111−
112−// ---------------------------------------------------------------------------
113−// Start
114−// ---------------------------------------------------------------------------
115−
116−client.once("clientReady", async () => {
117− console.log(`Logged in as ${client.user?.tag}`);
118− await registerCommands();
119− console.log(`Connected to server at ${SERVER_URL}`);
120−});
121−
122−client.login(DISCORD_TOKEN);
assistant/legacy/openassistant/apps/bot/src/views/task-message.tsx+0−522
@@ -1,522 +0,0 @@
1−/**
2− * TaskMessage — self-contained live-updating Discord message for a task.
3− *
4− * Subscribes to the server's SSE stream via Eden Treaty on mount,
5− * reduces TaskEvents into local state, and re-renders reactively.
6− *
7− * The command handler just mounts this component and walks away:
8− * <TaskMessage taskId={id} prompt={prompt} api={api} />
9− */
10−
11−import { useState, useEffect } from "react";
12−import {
13− Container,
14− TextDisplay,
15− Separator,
16− ActionRow,
17− Button,
18− ModalButton,
19− Loading,
20− useInstance,
21− type ModalField,
22− type ModalFieldValues,
23−} from "@openassistant/reacord";
24−import type { Client as ApiClient } from "@openassistant/server/client";
25−import { unwrap } from "@openassistant/server/client";
26−import type { TaskEvent } from "@openassistant/core/events";
27−import type { ApprovalPresentation } from "@openassistant/core/tools";
28−
29−// ---------------------------------------------------------------------------
30−// State
31−// ---------------------------------------------------------------------------
32−
33−interface PendingApproval {
34− readonly id: string;
35− readonly toolPath: string;
36− readonly input: unknown;
37− readonly preview: ApprovalPresentation;
38−}
39−
40−interface TaskState {
41− readonly status: "running" | "completed" | "failed" | "cancelled";
42− readonly statusMessage: string;
43− readonly lastCode: string | null;
44− readonly toolResults: string[];
45− readonly pendingApprovals: PendingApproval[];
46− readonly agentMessage: string | null;
47− readonly error: string | null;
48− /** Whether an approval rule has been created for this task. */
49− readonly hasRule: boolean;
50−}
51−
52−const INITIAL_STATE: TaskState = {
53− status: "running",
54− statusMessage: "Thinking...",
55− lastCode: null,
56− toolResults: [],
57− pendingApprovals: [],
58− agentMessage: null,
59− error: null,
60− hasRule: false,
61−};
62−
63−function reduceEvent(state: TaskState, event: TaskEvent): TaskState {
64− switch (event.type) {
65− case "status":
66− return { ...state, statusMessage: event.message };
67−
68− case "code_generated":
69− return { ...state, lastCode: event.code, statusMessage: "Running code..." };
70−
71− case "approval_request":
72− // Deduplicate — if we already have this approval (e.g. from SSE replay), skip it
73− if (state.pendingApprovals.some((a) => a.id === event.id)) return state;
74− return {
75− ...state,
76− pendingApprovals: [
77− ...state.pendingApprovals,
78− { id: event.id, toolPath: event.toolPath, input: event.input, preview: event.preview },
79− ],
80− statusMessage: "Waiting for approval...",
81− };
82−
83− case "approval_resolved":
84− return {
85− ...state,
86− pendingApprovals: state.pendingApprovals.filter((a) => a.id !== event.id),
87− statusMessage: event.decision === "approved" ? "Approved, continuing..." : "Denied.",
88− };
89−
90− case "tool_result": {
91− const r = event.receipt;
92− const icon = r.status === "succeeded" ? "\u2705" : r.status === "denied" ? "\u26d4" : "\u274c";
93− const shortName = formatToolName(r.toolPath);
94− const output = formatToolOutput(r.toolPath, r.outputPreview);
95− const line = `${icon} ${shortName}${output}`;
96− return { ...state, toolResults: [...state.toolResults, line] };
97− }
98−
99− case "agent_message":
100− return { ...state, agentMessage: event.text, statusMessage: "Done" };
101−
102− case "error":
103− return { ...state, status: "failed", error: event.error, statusMessage: "Failed" };
104−
105− case "completed":
106− return { ...state, status: "completed", statusMessage: "Completed" };
107− }
108−}
109−
110−// ---------------------------------------------------------------------------
111−// Component
112−// ---------------------------------------------------------------------------
113−
114−export interface TaskMessageProps {
115− readonly taskId: string;
116− readonly prompt: string;
117− readonly api: ApiClient;
118− readonly executionMode: "local" | "remote";
119−}
120−
121−export function TaskMessage({ taskId, prompt, api, executionMode }: TaskMessageProps) {
122− const instance = useInstance();
123− const [state, setState] = useState<TaskState>(INITIAL_STATE);
124−
125− // Subscribe to SSE stream on mount
126− useEffect(() => {
127− let cancelled = false;
128−
129− const subscribe = async () => {
130− try {
131− const { data: stream, error } = await api.api.tasks({ id: taskId }).events.get();
132−
133− if (error || !stream) {
134− if (!cancelled) {
135− setState((s) => ({ ...s, status: "failed", error: "Failed to connect to event stream", statusMessage: "Failed" }));
136− }
137− return;
138− }
139−
140− for await (const sse of stream as AsyncIterable<{ event: string; data: TaskEvent }>) {
141− if (cancelled) break;
142− setState((s) => reduceEvent(s, sse.data));
143− }
144− } catch (err) {
145− if (!cancelled) {
146− setState((s) => ({
147− ...s,
148− status: "failed",
149− error: err instanceof Error ? err.message : String(err),
150− statusMessage: "Failed",
151− }));
152− }
153− }
154− };
155−
156− subscribe();
157−
158− return () => {
159− cancelled = true;
160− };
161− }, [taskId]);
162−
163− // Deactivate buttons once done
164− useEffect(() => {
165− if (state.status !== "running") {
166− const timer = setTimeout(() => instance.deactivate(), 5000);
167− return () => clearTimeout(timer);
168− }
169− }, [state.status]);
170−
171− const isDone = state.status !== "running";
172− const accentColor = isDone
173− ? state.status === "completed" ? 0x57f287 : 0xed4245
174− : 0x5865f2;
175−
176− return (
177− <Container accentColor={accentColor}>
178− <TextDisplay>{`${statusEmoji(state.status)} **${state.statusMessage}**`}</TextDisplay>
179− <TextDisplay>{`Runner: ${executionMode === "remote" ? "cloud executor" : "in-process local"}`}</TextDisplay>
180− <TextDisplay>{`> ${prompt.length > 200 ? prompt.slice(0, 200) + "..." : prompt}`}</TextDisplay>
181−
182− {state.lastCode && (
183− <>
184− <Separator />
185− <TextDisplay>{`\`\`\`ts\n${state.lastCode.length > 800 ? state.lastCode.slice(0, 800) + "\n// ..." : state.lastCode}\n\`\`\``}</TextDisplay>
186− </>
187− )}
188−
189− {state.toolResults.length > 0 && (
190− <>
191− <Separator />
192− <TextDisplay>{collapseToolResults(state.toolResults, 10).join("\n")}</TextDisplay>
193− </>
194− )}
195−
196− {state.pendingApprovals.map((approval) => (
197− <ApprovalButtons
198− key={approval.id}
199− approval={approval}
200− api={api}
201− taskId={taskId}
202− hasRule={state.hasRule}
203− onRuleCreated={() => setState((s) => ({ ...s, hasRule: true }))}
204− />
205− ))}
206−
207− {state.error && (
208− <>
209− <Separator />
210− <TextDisplay>{`\u274c **Error:** ${state.error.slice(0, 500)}`}</TextDisplay>
211− </>
212− )}
213−
214− {state.agentMessage && (
215− <>
216− <Separator />
217− <TextDisplay>
218− {state.agentMessage.length > 1800
219− ? state.agentMessage.slice(0, 1800) + "..."
220− : state.agentMessage}
221− </TextDisplay>
222− </>
223− )}
224−
225− {state.status === "running" && state.pendingApprovals.length === 0 && (
226− <Loading />
227− )}
228− </Container>
229− );
230−}
231−
232−// ---------------------------------------------------------------------------
233−// Approval buttons
234−// ---------------------------------------------------------------------------
235−
236−function ApprovalButtons({
237− approval,
238− api,
239− taskId,
240− hasRule,
241− onRuleCreated,
242−}: {
243− approval: PendingApproval;
244− api: ApiClient;
245− taskId: string;
246− hasRule: boolean;
247− onRuleCreated: () => void;
248−}) {
249− const [resolved, setResolved] = useState(false);
250−
251− const handle = async (decision: "approved" | "denied") => {
252− setResolved(true);
253− try {
254− await unwrap(api.api.approvals({ callId: approval.id }).post({ decision }));
255− } catch (err) {
256− console.error(`[approval ${approval.id}]`, err);
257− }
258− };
259−
260− // Extract field names from the input for the rule builder
261− const inputFields = extractFieldNames(approval.input);
262−
263− const ruleFields: ModalField[] = [
264− {
265− type: "stringSelect",
266− id: "field",
267− label: "Field",
268− description: "Which input field to check",
269− placeholder: "Select a field...",
270− required: true,
271− options: inputFields.map((f) => ({
272− label: f.name,
273− value: f.path,
274− description: f.preview ? `Current: ${f.preview}` : undefined,
275− })),
276− },
277− {
278− type: "stringSelect",
279− id: "operator",
280− label: "Condition",
281− description: "How to compare the field value",
282− required: true,
283− options: [
284− { label: "equals", value: "equals" },
285− { label: "does not equal", value: "not_equals" },
286− { label: "includes", value: "includes" },
287− { label: "does not include", value: "not_includes" },
288− ],
289− },
290− {
291− type: "textInput",
292− id: "value",
293− label: "Value",
294− description: "Value to compare against",
295− placeholder: "e.g. rhys.dev",
296− style: "short",
297− required: true,
298− },
299− {
300− type: "stringSelect",
301− id: "decision",
302− label: "Action",
303− description: "What to do when the rule matches",
304− required: true,
305− options: [
306− { label: "Approve matching", value: "approved" },
307− { label: "Deny matching", value: "denied" },
308− ],
309− },
310− ];
311−
312− const handleRuleSubmit = async (values: ModalFieldValues) => {
313− const field = values.getStringSelect("field")?.[0];
314− const operator = values.getStringSelect("operator")?.[0];
315− const value = values.getTextInput("value");
316− const decision = values.getStringSelect("decision")?.[0];
317−
318− if (!field || !operator || value === undefined || !decision) return;
319−
320− try {
321− await unwrap(
322− api.api.tasks({ id: taskId })["approval-rules"].post({
323− toolPath: approval.toolPath,
324− field,
325− operator: operator as "equals" | "not_equals" | "includes" | "not_includes",
326− value,
327− decision: decision as "approved" | "denied",
328− }),
329− );
330− onRuleCreated();
331− } catch (err) {
332− console.error(`[rule creation]`, err);
333− }
334− };
335−
336− return (
337− <>
338− <Separator />
339− <TextDisplay>
340− {formatApprovalDisplay(approval)}
341− </TextDisplay>
342− {!resolved && (
343− <ActionRow>
344− <Button label="Approve" style="success" onClick={() => handle("approved")} />
345− <Button label="Deny" style="danger" onClick={() => handle("denied")} />
346− {!hasRule && inputFields.length > 0 && (
347− <ModalButton
348− label="Create Rule"
349− style="secondary"
350− modalTitle="Auto-approve/deny rule"
351− fields={ruleFields}
352− onSubmit={handleRuleSubmit}
353− />
354− )}
355− </ActionRow>
356− )}
357− </>
358− );
359−}
360−
361−// ---------------------------------------------------------------------------
362−// Field extraction for rule builder
363−// ---------------------------------------------------------------------------
364−
365−interface FieldInfo {
366− readonly name: string;
367− readonly path: string;
368− readonly preview?: string;
369−}
370−
371−function extractFieldNames(input: unknown, prefix = ""): FieldInfo[] {
372− if (!input || typeof input !== "object") return [];
373− const fields: FieldInfo[] = [];
374−
375− for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
376− const path = prefix ? `${prefix}.${key}` : key;
377− if (value !== null && typeof value === "object" && !Array.isArray(value)) {
378− // Recurse into nested objects
379− fields.push(...extractFieldNames(value, path));
380− } else {
381− const preview = value === undefined ? undefined : String(value).slice(0, 50);
382− fields.push({ name: path, path, preview });
383− }
384− }
385−
386− return fields.slice(0, 25); // Discord select max 25 options
387−}
388−
389−// ---------------------------------------------------------------------------
390−// Helpers
391−// ---------------------------------------------------------------------------
392−
393−function statusEmoji(status: TaskState["status"]): string {
394− switch (status) {
395− case "running": return "\u23f3";
396− case "completed": return "\u2705";
397− case "failed": return "\u274c";
398− case "cancelled": return "\u26d4";
399− }
400−}
401−
402−/**
403− * Shorten a tool path for display.
404− * "github.issues.issues_list_for_repo" → "issues_list_for_repo"
405− * "discover" → "discover"
406− */
407−function formatToolName(toolPath: string): string {
408− const parts = toolPath.split(".");
409− return `\`${parts[parts.length - 1]}\``;
410−}
411−
412−/**
413− * Format tool output for display. Special-cases discover results
414− * and truncates raw JSON.
415− */
416−function formatToolOutput(toolPath: string, outputPreview: string | undefined): string {
417− if (!outputPreview) return "";
418−
419− // Special-case discover results
420− if (toolPath === "discover" || toolPath.endsWith(".discover")) {
421− try {
422− const parsed = JSON.parse(outputPreview.endsWith("...") ? outputPreview.slice(0, -3) + "}" : outputPreview);
423− if (parsed.total !== undefined) {
424− return ` \u2192 found ${parsed.total} tools`;
425− }
426− } catch { /* fall through */ }
427− }
428−
429− // For other results, show a short preview
430− const clean = outputPreview.length > 80 ? outputPreview.slice(0, 80) + "..." : outputPreview;
431− return ` \u2192 ${clean}`;
432−}
433−
434−/**
435− * Collapse consecutive identical tool results into counts.
436− * ["✅ `delete` → ...", "✅ `delete` → ...", "✅ `delete` → ..."]
437− * becomes ["✅ `delete` ×3"]
438− */
439−function collapseToolResults(results: string[], maxLines: number): string[] {
440− if (results.length === 0) return [];
441−
442− const collapsed: string[] = [];
443− let lastBase = "";
444− let count = 0;
445−
446− for (const line of results) {
447− // Extract the tool name part (icon + name)
448− const base = line.replace(/ \u2192 .*$/, "");
449− if (base === lastBase) {
450− count++;
451− } else {
452− if (lastBase && count > 0) {
453− collapsed.push(count === 1 ? results[collapsed.length] || lastBase : `${lastBase} \u00d7${count}`);
454− }
455− lastBase = base;
456− count = 1;
457− }
458− }
459− // Push the last group
460− if (lastBase && count > 0) {
461− if (count === 1) {
462− collapsed.push(results[results.length - 1]!);
463− } else {
464− collapsed.push(`${lastBase} \u00d7${count}`);
465− }
466− }
467−
468− return collapsed.slice(-maxLines);
469−}
470−
471−/**
472− * Format an approval request for Discord display.
473− * Uses structured preview fields for a clean, scannable layout.
474− *
475− * Example output:
476− * 🛡️ **DELETE** `removeProjectDomain`
477− * > **Target:** personal-site
478− * > **domain:** something-123-domain.vercel.app
479− */
480−function formatApprovalDisplay(approval: PendingApproval): string {
481− const { preview, input } = approval;
482−
483− // Action verb from structured data, falling back to title
484− const actionLabel = preview.action
485− ? preview.action.toUpperCase()
486− : preview.title;
487−
488− // Short operation name
489− const opName = formatToolName(approval.toolPath);
490−
491− const lines: string[] = [];
492−
493− // Header: 🛡️ **DELETE** `removeProjectDomain`
494− const destructiveWarning = preview.isDestructive ? " ⚠️" : "";
495− lines.push(`\u{1f6e1}\ufe0f **${actionLabel}**${destructiveWarning} ${opName}`);
496−
497− // Target (resource IDs)
498− if (preview.resourceIds && preview.resourceIds.length > 0) {
499− lines.push(`> **Target:** ${preview.resourceIds.join(", ")}`);
500− }
501−
502− // Key fields from input (excluding IDs already shown in Target)
503− const shownIds = new Set(preview.resourceIds ?? []);
504− if (input && typeof input === "object") {
505− const idKeys = new Set(["id", "ids", "name", "slug", "key", "idOrName", "projectId"]);
506− for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
507− // Skip ID fields already shown as Target
508− if (idKeys.has(key) && typeof value === "string" && shownIds.has(value)) continue;
509− if (value === undefined || value === null) continue;
510− if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
511− lines.push(`> **${key}:** ${String(value)}`);
512− }
513− }
514− }
515−
516− // Link if present
517− if (preview.link) {
518− lines.push(`> ${preview.link}`);
519− }
520−
521− return lines.join("\n");
522−}
assistant/legacy/openassistant/apps/bot/tsconfig.json+0−13
@@ -1,13 +0,0 @@
1−{
2− "extends": "../../tsconfig.base.json",
3− "compilerOptions": {
4− "exactOptionalPropertyTypes": false,
5− "jsx": "react-jsx",
6− "module": "ESNext",
7− "moduleResolution": "Bundler",
8− "rootDir": "src",
9− "noUnusedLocals": false,
10− "noUnusedParameters": false
11− },
12− "include": ["src/**/*"]
13−}
assistant/legacy/openassistant/apps/executor/package.json+0−18
@@ -1,18 +0,0 @@
1−{
2− "name": "@openassistant/executor",
3− "private": true,
4− "type": "module",
5− "scripts": {
6− "dev": "bun --hot src/index.ts",
7− "start": "bun src/index.ts",
8− "typecheck": "tsgo --noEmit",
9− "test": "bun test src/"
10− },
11− "dependencies": {
12− "@openassistant/core": "workspace:*",
13− "zod": "^4.3.6"
14− },
15− "devDependencies": {
16− "@types/bun": "latest"
17− }
18−}
assistant/legacy/openassistant/apps/executor/src/index.ts+0−150
@@ -1,150 +0,0 @@
1−/**
2− * Executor service — runs untrusted generated TS/JS code in an isolated process.
3− *
4− * This service only executes code. Any tools.* invocation is proxied back to the
5− * control plane via an authenticated callback.
6− */
7−
8−import {
9− createRunner,
10− defineTool,
11− ToolDeniedError,
12− type ToolTree,
13−} from "@openassistant/core";
14−import type {
15− ExecutorInvokeResponse,
16− ExecutorRunRequest,
17− ExecutorToolManifestEntry,
18−} from "@openassistant/core/remote-runner";
19−import { z } from "zod";
20−
21−const ExecuteSchema: z.ZodType<ExecutorRunRequest> = z.object({
22− runId: z.string().min(1),
23− code: z.string(),
24− timeoutMs: z.number().int().positive(),
25− callbackBaseUrl: z.string().url(),
26− callbackToken: z.string().min(1),
27− tools: z.array(z.object({
28− toolPath: z.string().min(1),
29− approval: z.union([z.literal("auto"), z.literal("required")]),
30− })),
31−});
32−
33−const InvokeResponseSchema: z.ZodType<ExecutorInvokeResponse> = z.object({
34− ok: z.boolean(),
35− value: z.unknown().optional(),
36− error: z.string().optional(),
37− denied: z.boolean().optional(),
38−});
39−
40−function json(status: number, value: unknown): Response {
41− return new Response(JSON.stringify(value), {
42− status,
43− headers: {
44− "content-type": "application/json",
45− },
46− });
47−}
48−
49−function setToolPath(tree: Record<string, unknown>, entry: ExecutorToolManifestEntry, request: ExecutorRunRequest): void {
50− const parts = entry.toolPath.split(".").filter(Boolean);
51− if (parts.length === 0) return;
52−
53− let current = tree;
54− for (let i = 0; i < parts.length - 1; i++) {
55− const segment = parts[i]!;
56− const next = current[segment];
57− if (!next || typeof next !== "object") {
58− current[segment] = {};
59− }
60− current = current[segment] as Record<string, unknown>;
61− }
62−
63− const leaf = parts[parts.length - 1]!;
64− current[leaf] = defineTool({
65− description: `Remote callback tool: ${entry.toolPath}`,
66− approval: "auto",
67− args: z.any(),
68− returns: z.any(),
69− run: async (input: unknown) => {
70− const callbackUrl = `${request.callbackBaseUrl.replace(/\/$/, "")}/internal/runs/${encodeURIComponent(request.runId)}/invoke`;
71− const response = await fetch(callbackUrl, {
72− method: "POST",
73− headers: {
74− "content-type": "application/json",
75− authorization: `Bearer ${request.callbackToken}`,
76− },
77− body: JSON.stringify({
78− toolPath: entry.toolPath,
79− input,
80− }),
81− });
82−
83− if (!response.ok) {
84− throw new Error(`Tool callback failed: HTTP ${response.status}`);
85− }
86−
87− const payload = await response.json();
88− const parsed = InvokeResponseSchema.safeParse(payload);
89− if (!parsed.success) {
90− throw new Error(`Tool callback returned invalid payload: ${parsed.error.message}`);
91− }
92−
93− if (parsed.data.denied) {
94− throw new ToolDeniedError(parsed.data.error ?? "Tool call denied");
95− }
96−
97− if (!parsed.data.ok) {
98− throw new Error(parsed.data.error ?? "Tool callback failed");
99− }
100−
101− return parsed.data.value;
102− },
103− });
104−}
105−
106−function buildToolTree(request: ExecutorRunRequest): ToolTree {
107− const root: Record<string, unknown> = {};
108− for (const entry of request.tools) {
109− setToolPath(root, entry, request);
110− }
111− return root as ToolTree;
112−}
113−
114−const PORT = Number(process.env["PORT"] ?? 3001);
115−
116−Bun.serve({
117− port: PORT,
118− async fetch(request) {
119− const url = new URL(request.url);
120−
121− if (request.method === "GET" && url.pathname === "/health") {
122− return json(200, { ok: true });
123− }
124−
125− if (request.method === "POST" && url.pathname === "/internal/execute") {
126− const body = await request.json().catch(() => undefined);
127− const parsed = ExecuteSchema.safeParse(body);
128− if (!parsed.success) {
129− return json(400, {
130− ok: false,
131− error: `Invalid execute payload: ${parsed.error.message}`,
132− });
133− }
134−
135− const toolTree = buildToolTree(parsed.data);
136− const runner = createRunner({
137− tools: toolTree,
138− requestApproval: async () => "approved",
139− timeoutMs: parsed.data.timeoutMs,
140− });
141−
142− const result = await runner.run(parsed.data.code);
143− return json(200, result);
144− }
145−
146− return json(404, { ok: false, error: "Not found" });
147− },
148−});
149−
150−console.log(`OpenAssistant executor running at http://localhost:${PORT}`);
assistant/legacy/openassistant/apps/executor/src/smoke.test.ts+0−5
@@ -1,5 +0,0 @@
1−import { expect, test } from "bun:test";
2−
3−test("executor package is wired", () => {
4− expect(true).toBe(true);
5−});
assistant/legacy/openassistant/apps/executor/tsconfig.json+0−14
@@ -1,14 +0,0 @@
1−{
2− "extends": "../../tsconfig.base.json",
3− "compilerOptions": {
4− "rootDir": "src",
5− "outDir": "dist",
6− "composite": true,
7− "noUnusedLocals": false,
8− "noUnusedParameters": false
9− },
10− "include": ["src/**/*.ts"],
11− "references": [
12− { "path": "../../packages/core" }
13− ]
14−}
assistant/legacy/openassistant/apps/server/package.json+0−27
@@ -1,27 +0,0 @@
1−{
2− "name": "@openassistant/server",
3− "private": true,
4− "type": "module",
5− "exports": {
6− ".": "./src/index.ts",
7− "./client": "./src/client.ts",
8− "./routes": "./src/routes.ts"
9− },
10− "scripts": {
11− "with-env": "bun run --env-file=../../.env --",
12− "dev": "bun run with-env bun --hot src/index.ts",
13− "start": "bun run with-env bun src/index.ts",
14− "typecheck": "tsgo --noEmit",
15− "test": "bun test src/"
16− },
17− "dependencies": {
18− "@openassistant/core": "workspace:*",
19− "@openassistant/tool-gen": "workspace:*",
20− "@elysiajs/eden": "latest",
21− "elysia": "latest",
22− "zod": "^4.3.6"
23− },
24− "devDependencies": {
25− "@types/bun": "latest"
26− }
27−}
assistant/legacy/openassistant/apps/server/src/client.test.ts+0−150
@@ -1,150 +0,0 @@
1−/**
2− * Client tests — proves end-to-end type safety with Eden Treaty.
3− *
4− * Uses Elysia's direct app testing (no HTTP server) + Eden Treaty.
5− */
6−
7−import { test, expect, describe } from "bun:test";
8−import { treaty } from "@elysiajs/eden";
9−import { createApp } from "./routes.js";
10−import { ApiError, unwrap } from "./client.js";
11−import { defineTool } from "@openassistant/core/tools";
12−import type { ToolTree } from "@openassistant/core/tools";
13−import type { LanguageModel, GenerateResult } from "@openassistant/core/agent";
14−import { z } from "zod";
15−
16−// ---------------------------------------------------------------------------
17−// Fixtures
18−// ---------------------------------------------------------------------------
19−
20−const echoTool = defineTool({
21− description: "Echo",
22− approval: "auto",
23− args: z.object({ message: z.string() }),
24− returns: z.object({ echoed: z.string() }),
25− run: async (input) => ({ echoed: input.message }),
26−});
27−
28−const testTools: ToolTree = { echo: echoTool };
29−
30−function createSimpleModel(): LanguageModel {
31− return {
32− async generate(): Promise<GenerateResult> {
33− return { text: "All done." };
34− },
35− };
36−}
37−
38−function createTestApp() {
39− return createApp({
40− tools: testTools,
41− model: createSimpleModel(),
42− });
43−}
44−
45−// ---------------------------------------------------------------------------
46−// Tests
47−// ---------------------------------------------------------------------------
48−
49−describe("Eden Treaty client", () => {
50− test("unwrap extracts data from successful call", async () => {
51− const app = createTestApp();
52− const client = treaty(app);
53−
54− const data = await unwrap(
55− client.api.tasks.post({
56− prompt: "Hello",
57− requesterId: "user_1",
58− }),
59− );
60−
61− expect(data.taskId).toMatch(/^task_/);
62− expect(data.status).toBe("running");
63− });
64−
65− test("unwrap throws ApiError on 404", async () => {
66− const app = createTestApp();
67− const client = treaty(app);
68−
69− try {
70− await unwrap(client.api.tasks({ id: "nonexistent" }).get());
71− expect.unreachable("Should have thrown");
72− } catch (err) {
73− expect(err).toBeInstanceOf(ApiError);
74− expect((err as ApiError).status).toBe(404);
75− }
76− });
77−
78− test("type inference: task data has correct shape", async () => {
79− const app = createTestApp();
80− const client = treaty(app);
81−
82− // Create a task
83− const created = await unwrap(
84− client.api.tasks.post({
85− prompt: "Type test",
86− requesterId: "user_1",
87− }),
88− );
89−
90− // Wait for completion
91− await Bun.sleep(200);
92−
93− // Get task — the data should have the full serialized shape
94− const task = await unwrap(
95− client.api.tasks({ id: created.taskId }).get(),
96− );
97−
98− // These type-check at compile time thanks to Eden Treaty!
99− expect(typeof task.id).toBe("string");
100− expect(typeof task.prompt).toBe("string");
101− expect(typeof task.requesterId).toBe("string");
102− expect(typeof task.createdAt).toBe("number");
103− expect(typeof task.status).toBe("string");
104− expect(typeof task.eventCount).toBe("number");
105− expect(Array.isArray(task.pendingApprovals)).toBe(true);
106− });
107−
108− test("type inference: approval response has correct shape", async () => {
109− const app = createTestApp();
110− const client = treaty(app);
111−
112− // This should be a 404 since no approval exists
113− try {
114− await unwrap(
115− client.api.approvals({ callId: "fake" }).post({
116− decision: "approved",
117− }),
118− );
119− expect.unreachable("Should have thrown");
120− } catch (err) {
121− expect(err).toBeInstanceOf(ApiError);
122− }
123− });
124−});
125−
126−describe("Direct treaty usage (no unwrap)", () => {
127− test("data/error pattern works as expected", async () => {
128− const app = createTestApp();
129− const client = treaty(app);
130−
131− // Success case
132− const { data, error } = await client.api.tasks.post({
133− prompt: "Direct test",
134− requesterId: "user_1",
135− });
136−
137− expect(error).toBeNull();
138− expect(data).toBeDefined();
139− expect(data!.taskId).toBeDefined();
140−
141− // Error case
142− const { data: data2, error: error2 } = await client.api.tasks({
143− id: "nonexistent",
144− }).get();
145−
146− expect(data2).toBeNull();
147− expect(error2).toBeDefined();
148− expect(error2!.status).toBe(404);
149− });
150−});
assistant/legacy/openassistant/apps/server/src/client.ts+0−104
@@ -1,104 +0,0 @@
1−/**
2− * Eden Treaty client for OpenAssistant server.
3− *
4− * Provides a type-safe client that can be consumed by:
5− * - The Discord bot (Reacord) via Effect wrappers
6− * - Any other TypeScript client
7− *
8− * Usage:
9− * import { createClient, effect } from "@openassistant/server/client"
10− *
11− * // Plain Eden Treaty (Promise-based)
12− * const api = createClient("http://localhost:3000")
13− * const { data, error } = await api.api.tasks.post({ prompt: "...", requesterId: "..." })
14− *
15− * // Effect-wrapped
16− * const result = yield* effect(api.api.tasks.post({ prompt: "...", requesterId: "..." }))
17− */
18−
19−import { type Treaty, treaty } from "@elysiajs/eden";
20−import type { App } from "./routes.js";
21−
22−// ---------------------------------------------------------------------------
23−// Client factory
24−// ---------------------------------------------------------------------------
25−
26−export type Client = ReturnType<typeof treaty<App>>;
27−
28−export interface ClientConfig {
29− /** Base fetch configuration. */
30− fetch?: Omit<RequestInit, "headers" | "method">;
31−}
32−
33−/**
34− * Create a typed Eden Treaty client for the OpenAssistant server.
35− */
36−export function createClient(
37− baseUrl: string,
38− config?: ClientConfig,
39−): Client {
40− return treaty<App>(baseUrl, {
41− ...(config?.fetch ? { fetch: config.fetch } : {}),
42− });
43−}
44−
45−// ---------------------------------------------------------------------------
46−// Effect wrapper (lazy import to avoid hard dep for non-Effect consumers)
47−// ---------------------------------------------------------------------------
48−
49−/**
50− * Error from an Eden Treaty call.
51− */
52−export class ApiError {
53− readonly _tag = "ApiError";
54− constructor(
55− readonly status: number,
56− readonly value: unknown,
57− ) {}
58−}
59−
60−/**
61− * Wrap an Eden Treaty call in an Effect.
62− *
63− * Converts the { data, error } pattern into Effect's success/failure.
64− *
65− * @example
66− * ```ts
67− * import { Effect } from "effect"
68− * import { createClient, effectify } from "@openassistant/server/client"
69− *
70− * const api = createClient("http://localhost:3000")
71− * const program = Effect.gen(function* () {
72− * const task = yield* effectify(api.api.tasks.post({ prompt: "hello", requesterId: "user_1" }))
73− * // task is typed as { taskId: string, status: TaskStatus }
74− * })
75− * ```
76− */
77−export async function unwrap<T extends Record<number, unknown>>(
78− treatyCall: Promise<Treaty.TreatyResponse<T>>,
79−): Promise<Treaty.Data<Treaty.TreatyResponse<T>>> {
80− const response = await treatyCall;
81−
82− if (response.error) {
83− const err = response.error as unknown;
84− if (err && typeof err === "object" && "status" in err) {
85− throw new ApiError(
86− (err as { status: number }).status,
87− "value" in err ? (err as { value: unknown }).value : err,
88− );
89− }
90− throw new ApiError(0, err);
91− }
92−
93− if (response.data !== undefined) {
94− return response.data as Treaty.Data<Treaty.TreatyResponse<T>>;
95− }
96−
97− throw new ApiError(0, "No data returned from API");
98−}
99−
100−// ---------------------------------------------------------------------------
101−// Re-export types from routes
102−// ---------------------------------------------------------------------------
103−
104−export type { App } from "./routes.js";
assistant/legacy/openassistant/apps/server/src/index.ts+0−229
@@ -1,229 +0,0 @@
1−/**
2− * OpenAssistant Server — Elysia + Eden Treaty
3− *
4− * Starts the server with tool sources loaded from config.
5− * The exported App type is consumed by Eden Treaty clients.
6− */
7−
8−import { readFileSync } from "node:fs";
9−import { createApp } from "./routes.js";
10−import { createPiAiModel } from "@openassistant/core";
11−import { defineTool, mergeToolTrees, type ToolTree } from "@openassistant/core/tools";
12−import { generateMcpTools } from "@openassistant/tool-gen/mcp";
13−import type { McpToolSource } from "@openassistant/tool-gen/mcp";
14−import { generateOpenApiTools } from "@openassistant/tool-gen/openapi";
15−import type { OpenApiToolSource } from "@openassistant/tool-gen/openapi";
16−import { z } from "zod";
17−
18−// ---------------------------------------------------------------------------
19−// API key resolution
20−// ---------------------------------------------------------------------------
21−
22−/**
23− * Resolve the Anthropic API key from (in order):
24− * 1. ANTHROPIC_OAUTH_TOKEN env var
25− * 2. ANTHROPIC_API_KEY env var
26− * 3. Claude Code's credential store (~/.claude/.credentials.json)
27− */
28−function getAnthropicApiKey(): string | undefined {
29− if (process.env["ANTHROPIC_OAUTH_TOKEN"]) return process.env["ANTHROPIC_OAUTH_TOKEN"];
30− if (process.env["ANTHROPIC_API_KEY"]) return process.env["ANTHROPIC_API_KEY"];
31−
32− try {
33− const home = process.env["HOME"] ?? process.env["USERPROFILE"] ?? "";
34− const text = readFileSync(`${home}/.claude/.credentials.json`, "utf-8");
35− const creds = JSON.parse(text);
36− const token = (creds as Record<string, Record<string, unknown>>)?.["claudeAiOauth"]?.["accessToken"];
37− if (typeof token === "string" && token.startsWith("sk-ant-")) {
38− return token;
39− }
40− } catch {
41− // No credentials file
42− }
43−
44− return undefined;
45−}
46−
47−// ---------------------------------------------------------------------------
48−// Tool source config
49−// ---------------------------------------------------------------------------
50−
51−const mcpSources: McpToolSource[] = [
52− {
53− name: "answeroverflow",
54− url: "https://www.answeroverflow.com/mcp",
55− defaultApproval: "auto",
56− },
57−];
58−
59−const POSTHOG_API_KEY = process.env["POSTHOG_PERSONAL_API_KEY"];
60−const POSTHOG_PROJECT_ID = process.env["POSTHOG_PROJECT_ID"];
61−const GITHUB_TOKEN = process.env["OPENASSISTANT_GITHUB_TOKEN"];
62−const VERCEL_TOKEN = process.env["VERCEL_TOKEN"];
63−
64−const openApiSources: OpenApiToolSource[] = [
65− ...(POSTHOG_API_KEY ? [{
66− name: "posthog",
67− spec: "https://app.posthog.com/api/schema/?format=json",
68− baseUrl: "https://app.posthog.com",
69− auth: { type: "bearer" as const, token: POSTHOG_API_KEY },
70− defaultReadApproval: "auto" as const,
71− defaultWriteApproval: "required" as const,
72− }] : []),
73− ...(GITHUB_TOKEN ? [{
74− name: "github",
75− spec: "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json",
76− auth: { type: "bearer" as const, token: GITHUB_TOKEN },
77− defaultReadApproval: "auto" as const,
78− defaultWriteApproval: "required" as const,
79− }] : []),
80− ...(VERCEL_TOKEN ? [{
81− name: "vercel",
82− spec: "https://openapi.vercel.sh/",
83− auth: { type: "bearer" as const, token: VERCEL_TOKEN },
84− defaultReadApproval: "auto" as const,
85− defaultWriteApproval: "required" as const,
86− }] : []),
87−];
88−
89−// ---------------------------------------------------------------------------
90−// Hand-written tools (approval testing)
91−// ---------------------------------------------------------------------------
92−
93−const builtinTools: ToolTree = {
94− admin: {
95− /** Requires approval — lets you test the approval UI flow. */
96− send_announcement: defineTool({
97− description: "Send an announcement message to a channel. Requires approval because it posts publicly.",
98− approval: "required",
99− args: z.object({
100− channel: z.string().describe("Channel name to post in"),
101− message: z.string().describe("The announcement text"),
102− }),
103− returns: z.object({ sent: z.boolean(), channel: z.string(), message: z.string() }),
104− run: async (input) => ({ sent: true, channel: input.channel, message: input.message }),
105− formatApproval: (input) => ({
106− title: `Post to #${input.channel}`,
107− details: `Message: "${input.message}"`,
108− }),
109− }),
110−
111− /** Requires approval — destructive action. */
112− delete_data: defineTool({
113− description: "Delete stored data by key. Requires approval because it's destructive.",
114− approval: "required",
115− args: z.object({
116− key: z.string().describe("The data key to delete"),
117− }),
118− returns: z.object({ deleted: z.boolean(), key: z.string() }),
119− run: async (input) => ({ deleted: true, key: input.key }),
120− formatApproval: (input) => ({
121− title: `Delete "${input.key}"`,
122− details: "This action cannot be undone.",
123− }),
124− }),
125− },
126−
127− utils: {
128− /** Auto-approved — safe read-only tool. */
129− get_time: defineTool({
130− description: "Get the current date and time.",
131− approval: "auto",
132− args: z.object({}),
133− returns: z.object({ iso: z.string(), unix: z.number() }),
134− run: async () => ({ iso: new Date().toISOString(), unix: Date.now() }),
135− }),
136− },
137−};
138−
139−// ---------------------------------------------------------------------------
140−// Tool loading
141−// ---------------------------------------------------------------------------
142−
143−async function loadTools(): Promise<ToolTree> {
144− const trees: ToolTree[] = [builtinTools];
145−
146− // Load MCP tools
147− for (const source of mcpSources) {
148− try {
149− console.log(`Loading MCP tools from ${source.name} (${source.url})...`);
150− const result = await generateMcpTools(source);
151− trees.push(result.tools);
152− console.log(` Loaded ${Object.keys(result.tools[source.name] ?? {}).length} tools from ${source.name}`);
153− } catch (error) {
154− console.error(` Failed to load ${source.name}:`, error instanceof Error ? error.message : error);
155− }
156− }
157−
158− // Load OpenAPI tools
159− for (const source of openApiSources) {
160− try {
161− console.log(`Loading OpenAPI tools from ${source.name}...`);
162− const result = await generateOpenApiTools(source);
163− trees.push(result.tools);
164− const nsTools = result.tools[source.name];
165− const count = nsTools ? Object.values(nsTools).reduce((sum, tag) => {
166− return sum + (typeof tag === "object" && tag !== null ? Object.keys(tag).length : 1);
167− }, 0) : 0;
168− console.log(` Loaded ~${count} tools from ${source.name}`);
169− } catch (error) {
170− console.error(` Failed to load ${source.name}:`, error instanceof Error ? error.message : error);
171− }
172− }
173−
174− return mergeToolTrees(...trees);
175−}
176−
177−// ---------------------------------------------------------------------------
178−// Start
179−// ---------------------------------------------------------------------------
180−
181−const PORT = Number(process.env["PORT"] ?? 3000);
182−const EXECUTOR_URL = process.env["OPENASSISTANT_EXECUTOR_URL"];
183−const CALLBACK_BASE_URL = process.env["OPENASSISTANT_CALLBACK_BASE_URL"]
184− ?? `http://localhost:${PORT}`;
185−
186−const apiKey = getAnthropicApiKey();
187−if (!apiKey) {
188− console.error("WARNING: No Anthropic API key found. Set ANTHROPIC_API_KEY, ANTHROPIC_OAUTH_TOKEN, or have Claude Code credentials at ~/.claude/.credentials.json");
189−}
190−
191−console.log("Loading tools...");
192−const tools = await loadTools();
193−const model = createPiAiModel({ apiKey });
194−
195−// Build context for the system prompt
196−const contextLines: string[] = [];
197−if (POSTHOG_PROJECT_ID) {
198− contextLines.push(`- PostHog project ID: ${POSTHOG_PROJECT_ID} (use this for PostHog API calls that require a project_id)`);
199−}
200−if (GITHUB_TOKEN) {
201− contextLines.push(`- GitHub: authenticated via personal access token`);
202−}
203−if (VERCEL_TOKEN) {
204− contextLines.push(`- Vercel: authenticated via personal token`);
205−}
206−const context = contextLines.length > 0 ? contextLines.join("\n") : undefined;
207−
208−if (EXECUTOR_URL) {
209− console.log(`Using remote executor at ${EXECUTOR_URL}`);
210−}
211−
212−const app = createApp({
213− tools,
214− model,
215− context,
216− executor: EXECUTOR_URL
217− ? {
218− url: EXECUTOR_URL,
219− callbackBaseUrl: CALLBACK_BASE_URL,
220− }
221− : undefined,
222−});
223−
224−app.listen(PORT);
225−
226−console.log(`\u{1f98a} OpenAssistant server running at http://localhost:${PORT}`);
227−
228−// Re-export the app type for Eden Treaty clients
229−export type { App } from "./routes.js";
assistant/legacy/openassistant/apps/server/src/routes.test.ts+0−408
@@ -1,408 +0,0 @@
1−/**
2− * Server route tests.
3− *
4− * Uses Elysia's direct handler testing (no HTTP server needed)
5− * and Eden Treaty for type-safe client calls.
6− */
7−
8−import { test, expect, describe } from "bun:test";
9−import { treaty } from "@elysiajs/eden";
10−import { createApp } from "./routes.js";
11−import { registerRemoteRunSession, removeRemoteRunSession } from "./state.js";
12−import { defineTool } from "@openassistant/core/tools";
13−import type { ToolTree } from "@openassistant/core/tools";
14−import type { LanguageModel, GenerateResult, Message } from "@openassistant/core/agent";
15−import { z } from "zod";
16−
17−// ---------------------------------------------------------------------------
18−// Test fixtures
19−// ---------------------------------------------------------------------------
20−
21−/** A simple echo tool for testing. */
22−const echoTool = defineTool({
23− description: "Echo back the input",
24− approval: "auto",
25− args: z.object({ message: z.string() }),
26− returns: z.object({ echoed: z.string() }),
27− run: async (input) => ({ echoed: input.message }),
28−});
29−
30−/** A tool that requires approval. */
31−const dangerousTool = defineTool({
32− description: "A dangerous operation that needs approval",
33− approval: "required",
34− args: z.object({ target: z.string() }),
35− returns: z.object({ deleted: z.boolean() }),
36− run: async () => ({ deleted: true }),
37− formatApproval: (input) => ({
38− title: `Delete ${input.target}`,
39− details: `This will permanently delete ${input.target}`,
40− }),
41−});
42−
43−const testTools: ToolTree = {
44− echo: echoTool,
45− danger: dangerousTool,
46−};
47−
48−/**
49− * Create a mock LanguageModel for testing.
50− * By default, immediately returns text (no tool calls).
51− */
52−function createMockModel(
53− handler?: (messages: Message[]) => GenerateResult,
54−): LanguageModel {
55− return {
56− async generate(messages: Message[]): Promise<GenerateResult> {
57− if (handler) return handler(messages);
58− return { text: "Done! I processed your request." };
59− },
60− };
61−}
62−
63−/**
64− * Create a model that generates code calling the echo tool,
65− * then responds with text on the second call.
66− */
67−function createEchoModel(): LanguageModel {
68− let callCount = 0;
69− return {
70− async generate(): Promise<GenerateResult> {
71− callCount++;
72− if (callCount === 1) {
73− return {
74− toolCalls: [
75− {
76− id: "call_1",
77− name: "run_code",
78− args: {
79− code: `const result = await tools.echo({ message: "hello" });\nreturn result;`,
80− },
81− },
82− ],
83− };
84− }
85− return { text: "Echo completed successfully." };
86− },
87− };
88−}
89−
90−/**
91− * Create a model that generates code calling the dangerous tool,
92− * then responds with text.
93− */
94−function createDangerModel(): LanguageModel {
95− let callCount = 0;
96− return {
97− async generate(): Promise<GenerateResult> {
98− callCount++;
99− if (callCount === 1) {
100− return {
101− toolCalls: [
102− {
103− id: "call_1",
104− name: "run_code",
105− args: {
106− code: `const result = await tools.danger({ target: "everything" });\nreturn result;`,
107− },
108− },
109− ],
110− };
111− }
112− return { text: "Danger operation completed." };
113− },
114− };
115−}
116−
117−function createTestApp(model?: LanguageModel) {
118− return createApp({
119− tools: testTools,
120− model: model ?? createMockModel(),
121− });
122−}
123−
124−// ---------------------------------------------------------------------------
125−// Tests
126−// ---------------------------------------------------------------------------
127−
128−describe("POST /api/tasks", () => {
129− test("creates a task and returns taskId", async () => {
130− const app = createTestApp();
131− const client = treaty(app);
132−
133− const { data, error } = await client.api.tasks.post({
134− prompt: "Say hello",
135− requesterId: "user_1",
136− });
137−
138− expect(error).toBeNull();
139− expect(data).toBeDefined();
140− expect(data!.taskId).toMatch(/^task_/);
141− expect(data!.status).toBe("running");
142− expect(data!.executionMode).toBe("local");
143− });
144−
145− test("rejects empty prompt", async () => {
146− const app = createTestApp();
147− const client = treaty(app);
148−
149− const { error } = await client.api.tasks.post({
150− prompt: "",
151− requesterId: "user_1",
152− });
153−
154− expect(error).toBeDefined();
155− });
156−});
157−
158−describe("GET /api/tasks", () => {
159− test("lists created tasks", async () => {
160− const app = createTestApp();
161− const client = treaty(app);
162−
163− await client.api.tasks.post({
164− prompt: "Test task",
165− requesterId: "user_1",
166− });
167−
168− await Bun.sleep(10);
169−
170− const { data, error } = await client.api.tasks.get({
171− query: {},
172− });
173−
174− expect(error).toBeNull();
175− expect(data).toBeInstanceOf(Array);
176− expect(data!.length).toBeGreaterThanOrEqual(1);
177− });
178−});
179−
180−describe("GET /api/tasks/:id", () => {
181− test("returns task details", async () => {
182− const app = createTestApp();
183− const client = treaty(app);
184−
185− const { data: created } = await client.api.tasks.post({
186− prompt: "Detail test",
187− requesterId: "user_1",
188− });
189−
190− const { data, error } = await client.api.tasks({ id: created!.taskId }).get();
191−
192− expect(error).toBeNull();
193− expect(data).toBeDefined();
194− expect(data!.id).toBe(created!.taskId);
195− expect(data!.prompt).toBe("Detail test");
196− expect(data!.executionMode).toBe("local");
197− });
198−
199− test("returns 404 for unknown task", async () => {
200− const app = createTestApp();
201− const client = treaty(app);
202−
203− const { error } = await client.api.tasks({ id: "nonexistent" }).get();
204−
205− expect(error).toBeDefined();
206− expect(error!.status).toBe(404);
207− });
208−});
209−
210−describe("Agent execution flow", () => {
211− test("simple model completes task with text", async () => {
212− const model = createMockModel();
213− const app = createTestApp(model);
214− const client = treaty(app);
215−
216− const { data } = await client.api.tasks.post({
217− prompt: "Just respond",
218− requesterId: "user_1",
219− });
220−
221− // Wait for agent to finish
222− await Bun.sleep(500);
223−
224− const { data: task } = await client.api.tasks({ id: data!.taskId }).get();
225−
226− expect(task!.status).toBe("completed");
227− expect(task!.resultText).toBe("Done! I processed your request.");
228− });
229−
230− test("echo model generates code and executes it", async () => {
231− const model = createEchoModel();
232− const app = createTestApp(model);
233− const client = treaty(app);
234−
235− const { data } = await client.api.tasks.post({
236− prompt: "Echo hello",
237− requesterId: "user_1",
238− });
239−
240− // Wait for agent to finish
241− await Bun.sleep(1000);
242−
243− const { data: task } = await client.api.tasks({ id: data!.taskId }).get();
244−
245− expect(task!.status).toBe("completed");
246− expect(task!.eventCount).toBeGreaterThan(0);
247− });
248−});
249−
250−describe("Approval flow", () => {
251− test("dangerous tool creates approval request, resolving it completes task", async () => {
252− const model = createDangerModel();
253− const app = createTestApp(model);
254− const client = treaty(app);
255−
256− const { data } = await client.api.tasks.post({
257− prompt: "Delete everything",
258− requesterId: "user_1",
259− });
260−
261− const taskId = data!.taskId;
262−
263− // Poll for the approval request to appear
264− let approvals: Array<{ callId: string; toolPath: string }> = [];
265− for (let i = 0; i < 20; i++) {
266− await Bun.sleep(100);
267− const { data: task } = await client.api.tasks({ id: taskId }).get();
268− if (task && task.pendingApprovals.length > 0) {
269− approvals = task.pendingApprovals;
270− break;
271− }
272− }
273−
274− expect(approvals.length).toBeGreaterThan(0);
275−
276− // Resolve the approval
277− const callId = approvals[0]!.callId;
278− const { data: result, error } = await client.api.approvals({ callId }).post({
279− decision: "approved",
280− });
281−
282− expect(error).toBeNull();
283− expect(result!.decision).toBe("approved");
284−
285− // Wait for task to complete
286− await Bun.sleep(1000);
287−
288− const { data: finalTask } = await client.api.tasks({ id: taskId }).get();
289− expect(finalTask!.status).toBe("completed");
290− });
291−});
292−
293−describe("POST /api/approvals/:callId", () => {
294− test("returns 404 for unknown callId", async () => {
295− const app = createTestApp();
296− const client = treaty(app);
297−
298− const { error } = await client.api.approvals({ callId: "unknown" }).post({
299− decision: "approved",
300− });
301−
302− expect(error).toBeDefined();
303− expect(error!.status).toBe(404);
304− });
305−});
306−
307−describe("POST /api/tasks/:id/cancel", () => {
308− test("cancels a running task", async () => {
309− // Use a model that hangs forever (simulating a long-running task)
310− const hangingModel: LanguageModel = {
311− generate: () => new Promise(() => {}), // Never resolves
312− };
313−
314− const app = createTestApp(hangingModel);
315− const client = treaty(app);
316−
317− const { data } = await client.api.tasks.post({
318− prompt: "Hang forever",
319− requesterId: "user_1",
320− });
321−
322− await Bun.sleep(50);
323−
324− const { data: result } = await client.api.tasks({ id: data!.taskId }).cancel.post();
325−
326− expect(result!.status).toBe("cancelled");
327− });
328−
329− test("returns 404 for unknown task", async () => {
330− const app = createTestApp();
331− const client = treaty(app);
332−
333− const { error } = await client.api.tasks({ id: "nonexistent" }).cancel.post();
334−
335− expect(error).toBeDefined();
336− expect(error!.status).toBe(404);
337− });
338−});
339−
340−describe("POST /internal/runs/:runId/invoke", () => {
341− test("invokes registered remote run callback", async () => {
342− const app = createTestApp();
343− const runId = "run_test_invoke";
344−
345− registerRemoteRunSession({
346− runId,
347− token: "secret_token",
348− invokeTool: async (toolPath, input) => ({
349− ok: true,
350− value: { toolPath, input },
351− }),
352− });
353−
354− try {
355− const response = await app.handle(new Request(`http://localhost/internal/runs/${runId}/invoke`, {
356− method: "POST",
357− headers: {
358− "content-type": "application/json",
359− authorization: "Bearer secret_token",
360− },
361− body: JSON.stringify({
362− toolPath: "echo",
363− input: { message: "hello" },
364− }),
365− }));
366−
367− expect(response.status).toBe(200);
368− const body = await response.json() as {
369− ok: boolean;
370− value: { toolPath: string; input: { message: string } };
371− };
372− expect(body.ok).toBe(true);
373− expect(body.value.toolPath).toBe("echo");
374− expect(body.value.input.message).toBe("hello");
375− } finally {
376− removeRemoteRunSession(runId);
377− }
378− });
379−
380− test("rejects invalid callback token", async () => {
381− const app = createTestApp();
382− const runId = "run_test_unauthorized";
383−
384− registerRemoteRunSession({
385− runId,
386− token: "expected_token",
387− invokeTool: async () => ({ ok: true }),
388− });
389−
390− try {
391− const response = await app.handle(new Request(`http://localhost/internal/runs/${runId}/invoke`, {
392− method: "POST",
393− headers: {
394− "content-type": "application/json",
395− authorization: "Bearer wrong_token",
396− },
397− body: JSON.stringify({
398− toolPath: "echo",
399− input: { message: "hello" },
400− }),
401− }));
402−
403− expect(response.status).toBe(401);
404− } finally {
405− removeRemoteRunSession(runId);
406− }
407− });
408−});
assistant/legacy/openassistant/apps/server/src/routes.ts+0−313
@@ -1,313 +0,0 @@
1−/**
2− * Elysia server routes.
3− *
4− * Exports the Elysia app type for Eden Treaty consumption.
5− * Routes:
6− * POST /api/tasks — Create a new task
7− * GET /api/tasks — List tasks
8− * GET /api/tasks/:id — Get task status
9− * GET /api/tasks/:id/events — SSE stream of TaskEvents
10− * POST /api/tasks/:id/cancel — Cancel a task
11− * POST /api/approvals/:callId — Resolve an approval decision
12− */
13−
14−import { Elysia, sse, t } from "elysia";
15−import {
16− addApprovalRule,
17− createTask,
18− generateTaskId,
19− getTask,
20− listTasks,
21− listPendingApprovals,
22− getRemoteRunSession,
23− resolveApproval,
24− subscribeToTask,
25− type RuleOperator,
26−} from "./state.js";
27−import { runTask, type TaskRunnerOptions } from "./task-runner.js";
28−
29−// ---------------------------------------------------------------------------
30−// Elysia validation schemas (TypeBox — Elysia's native)
31−// ---------------------------------------------------------------------------
32−
33−const CreateTaskBody = t.Object({
34− prompt: t.String({ minLength: 1 }),
35− requesterId: t.String({ minLength: 1 }),
36− channelId: t.Optional(t.String()),
37−});
38−
39−const ApprovalBody = t.Object({
40− decision: t.Union([t.Literal("approved"), t.Literal("denied")]),
41−});
42−
43−const ApprovalRuleBody = t.Object({
44− toolPath: t.String({ minLength: 1 }),
45− field: t.String({ minLength: 1 }),
46− operator: t.Union([
47− t.Literal("equals"),
48− t.Literal("not_equals"),
49− t.Literal("includes"),
50− t.Literal("not_includes"),
51− ]),
52− value: t.String(),
53− decision: t.Union([t.Literal("approved"), t.Literal("denied")]),
54−});
55−
56−const RemoteInvokeBody = t.Object({
57− toolPath: t.String({ minLength: 1 }),
58− input: t.Any(),
59−});
60−
61−// ---------------------------------------------------------------------------
62−// Task serialization (strip internal fields)
63−// ---------------------------------------------------------------------------
64−
65−function serializeTask(task: NonNullable<ReturnType<typeof getTask>>) {
66− // Find the last error event if any
67− const lastError = [...task.events].reverse().find((e) => e.type === "error");
68− const errorMessage = lastError && lastError.type === "error" ? lastError.error : undefined;
69−
70− return {
71− id: task.id,
72− prompt: task.prompt,
73− requesterId: task.requesterId,
74− channelId: task.channelId,
75− executionMode: task.executionMode,
76− createdAt: task.createdAt,
77− status: task.status,
78− resultText: task.resultText,
79− errorMessage,
80− eventCount: task.events.length,
81− pendingApprovals: listPendingApprovals(task.id).map((a) => ({
82− callId: a.callId,
83− toolPath: a.toolPath,
84− })),
85− };
86−}
87−
88−// ---------------------------------------------------------------------------
89−// App factory
90−// ---------------------------------------------------------------------------
91−
92−export function createApp(runnerOptions: TaskRunnerOptions) {
93− const app = new Elysia()
94− // -----------------------------------------------------------------------
95− // POST /api/tasks — create and start a task
96− // -----------------------------------------------------------------------
97− .post(
98− "/api/tasks",
99− async ({ body }) => {
100− const taskId = generateTaskId();
101− const executionMode = runnerOptions.executor ? "remote" as const : "local" as const;
102− const task = createTask({
103− id: taskId,
104− prompt: body.prompt,
105− requesterId: body.requesterId,
106− channelId: body.channelId,
107− executionMode,
108− });
109−
110− // Fire-and-forget: run the agent in the background
111− runTask(taskId, body.prompt, runnerOptions).catch((err) => {
112− console.error(`[task ${taskId}] unhandled error:`, err);
113− });
114−
115− return { taskId: task.id, status: task.status, executionMode };
116− },
117− { body: CreateTaskBody },
118− )
119−
120− // -----------------------------------------------------------------------
121− // GET /api/tasks — list all tasks
122− // -----------------------------------------------------------------------
123− .get("/api/tasks", ({ query }) => {
124− const tasks = listTasks(query.requesterId);
125− return tasks.map(serializeTask);
126− }, {
127− query: t.Object({
128− requesterId: t.Optional(t.String()),
129− }),
130− })
131−
132− // -----------------------------------------------------------------------
133− // GET /api/tasks/:id — get task status
134− // -----------------------------------------------------------------------
135− .get(
136− "/api/tasks/:id",
137− ({ params, status }) => {
138− const task = getTask(params.id);
139− if (!task) {
140− return status(404, { error: "Task not found" as const });
141− }
142− return serializeTask(task);
143− },
144− )
145−
146− // -----------------------------------------------------------------------
147− // GET /api/tasks/:id/events — SSE stream of TaskEvents
148− // -----------------------------------------------------------------------
149− .get(
150− "/api/tasks/:id/events",
151− async function* ({ params }) {
152− const task = getTask(params.id);
153− if (!task) {
154− yield sse({ event: "error", data: { error: "Task not found" } });
155− return;
156− }
157−
158− // Subscribe FIRST to avoid race between replay and live events.
159− // Track how many events we've replayed so the subscriber can skip
160− // events that were already sent during replay.
161− type TaskEvent = (typeof task.events)[number];
162− const queue: TaskEvent[] = [];
163− let resolveWait: (() => void) | null = null;
164− let done = false;
165− let replayedCount = 0;
166−
167− const unsubscribe = subscribeToTask(params.id, (event) => {
168− // During replay, events that are ALSO live will arrive here.
169− // We track replay count and only queue events beyond what was replayed.
170− // Since events are append-only, the subscriber index == task.events.length
171− // at the time of the call. We skip anything <= replayedCount.
172− queue.push(event);
173− if (resolveWait) {
174− resolveWait();
175− resolveWait = null;
176− }
177− if (event.type === "completed" || event.type === "error") {
178− done = true;
179− }
180− });
181−
182− if (!unsubscribe) {
183− return;
184− }
185−
186− // Replay existing events. Snapshot the current count to avoid
187− // replaying events that arrive during iteration.
188− const eventsSnapshot = task.events.length;
189− for (let i = 0; i < eventsSnapshot; i++) {
190− yield sse({ event: task.events[i]!.type, data: task.events[i] });
191− }
192− replayedCount = eventsSnapshot;
193−
194− // If task is already done, close the stream
195− if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
196− unsubscribe();
197− return;
198− }
199−
200− // Now drain the queue. Any events that arrived between subscribe
201− // and replay-end with index < replayedCount are skipped (they were
202− // already yielded in the replay loop above). We detect this by
203− // checking if the event is the same reference as one in task.events.
204− try {
205− while (!done) {
206− if (queue.length === 0) {
207− await new Promise<void>((resolve) => {
208− resolveWait = resolve;
209− });
210− }
211−
212− while (queue.length > 0) {
213− const event = queue.shift()!;
214− // Skip events that were already replayed. The subscriber fires
215− // for ALL events (including ones emitted during replay). Check
216− // by finding this event's index in task.events — if it's within
217− // the replayed range, skip it.
218− const idx = task.events.indexOf(event);
219− if (idx !== -1 && idx < replayedCount) continue;
220− yield sse({ event: event.type, data: event });
221− }
222− }
223− } finally {
224− unsubscribe();
225− }
226− },
227− )
228−
229− // -----------------------------------------------------------------------
230− // POST /api/tasks/:id/cancel — cancel a task
231− // -----------------------------------------------------------------------
232− .post("/api/tasks/:id/cancel", ({ params, status }) => {
233− const task = getTask(params.id);
234− if (!task) {
235− return status(404, { error: "Task not found" as const });
236− }
237− if (task.status !== "running") {
238− return status(400, { error: "Task is not running" as const });
239− }
240− task.status = "cancelled";
241− return { taskId: task.id, status: task.status };
242− })
243−
244− // -----------------------------------------------------------------------
245− // POST /api/approvals/:callId — resolve a pending approval
246− // -----------------------------------------------------------------------
247− .post(
248− "/api/approvals/:callId",
249− ({ params, body, status }) => {
250− const resolved = resolveApproval(params.callId, body.decision);
251− if (!resolved) {
252− return status(404, { error: "Approval not found or already resolved" as const });
253− }
254− return { callId: params.callId, decision: body.decision };
255− },
256− { body: ApprovalBody },
257− )
258−
259− // -----------------------------------------------------------------------
260− // POST /api/tasks/:id/approval-rules — add an auto-approval rule
261− // -----------------------------------------------------------------------
262− .post(
263− "/api/tasks/:id/approval-rules",
264− ({ params, body, status }) => {
265− const task = getTask(params.id);
266− if (!task) {
267− return status(404, { error: "Task not found" as const });
268− }
269−
270− const ruleId = `rule_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
271− const resolved = addApprovalRule({
272− id: ruleId,
273− taskId: params.id,
274− toolPath: body.toolPath,
275− field: body.field,
276− operator: body.operator as RuleOperator,
277− value: body.value,
278− decision: body.decision,
279− });
280−
281− return { ruleId, resolved, toolPath: body.toolPath, field: body.field, operator: body.operator, value: body.value, decision: body.decision };
282− },
283− { body: ApprovalRuleBody },
284− )
285−
286− // -----------------------------------------------------------------------
287− // POST /internal/runs/:runId/invoke — executor callback for tools.* calls
288− // -----------------------------------------------------------------------
289− .post(
290− "/internal/runs/:runId/invoke",
291− async ({ params, body, headers, status }) => {
292− const session = getRemoteRunSession(params.runId);
293− if (!session) {
294− return status(404, { ok: false as const, error: "Run session not found" });
295− }
296−
297− const authHeader = headers["authorization"];
298− const bearer = typeof authHeader === "string" && authHeader.startsWith("Bearer ")
299− ? authHeader.slice("Bearer ".length)
300− : undefined;
301− if (!bearer || bearer !== session.token) {
302− return status(401, { ok: false as const, error: "Unauthorized" });
303− }
304−
305− return await session.invokeTool(body.toolPath, body.input);
306− },
307− { body: RemoteInvokeBody },
308− );
309−
310− return app;
311−}
312−
313−export type App = ReturnType<typeof createApp>;
assistant/legacy/openassistant/apps/server/src/state.ts+0−276
@@ -1,276 +0,0 @@
1−/**
2− * In-memory task state management.
3− *
4− * Tracks active tasks, their event streams, and pending approval resolvers.
5− * This is the MVP — swap for bun:sqlite later.
6− */
7−
8−import type { TaskEvent } from "@openassistant/core/events";
9−import type { ApprovalDecision } from "@openassistant/core/tools";
10−
11−// ---------------------------------------------------------------------------
12−// Types
13−// ---------------------------------------------------------------------------
14−
15−export type TaskStatus = "running" | "completed" | "failed" | "cancelled";
16−export type TaskExecutionMode = "local" | "remote";
17−
18−export interface Task {
19− readonly id: string;
20− readonly prompt: string;
21− readonly requesterId: string;
22− readonly channelId?: string | undefined;
23− readonly executionMode: TaskExecutionMode;
24− readonly createdAt: number;
25− status: TaskStatus;
26− events: TaskEvent[];
27− /** Subscribers get called for each new event. */
28− subscribers: Set<(event: TaskEvent) => void>;
29− /** Final result text, set on completion. */
30− resultText?: string | undefined;
31−}
32−
33−export interface PendingApproval {
34− readonly callId: string;
35− readonly taskId: string;
36− readonly toolPath: string;
37− readonly input: unknown;
38− resolve: (decision: ApprovalDecision) => void;
39−}
40−
41−export type RuleOperator = "equals" | "not_equals" | "includes" | "not_includes";
42−
43−export interface ApprovalRule {
44− readonly id: string;
45− readonly taskId: string;
46− /** Tool path the rule applies to (e.g. "vercel.projects.removeProjectDomain") */
47− readonly toolPath: string;
48− /** Dot-path into the input object (e.g. "idOrName", "owner") */
49− readonly field: string;
50− readonly operator: RuleOperator;
51− readonly value: string;
52− readonly decision: ApprovalDecision;
53−}
54−
55−export interface RemoteRunInvokeResult {
56− readonly ok: boolean;
57− readonly value?: unknown;
58− readonly error?: string;
59− readonly denied?: boolean;
60−}
61−
62−export interface RemoteRunSession {
63− readonly runId: string;
64− readonly token: string;
65− readonly invokeTool: (
66− toolPath: string,
67− input: unknown,
68− ) => Promise<RemoteRunInvokeResult>;
69−}
70−
71−// ---------------------------------------------------------------------------
72−// Store
73−// ---------------------------------------------------------------------------
74−
75−const tasks = new Map<string, Task>();
76−const pendingApprovals = new Map<string, PendingApproval>();
77−const approvalRules = new Map<string, ApprovalRule[]>(); // taskId → rules
78−const remoteRunSessions = new Map<string, RemoteRunSession>();
79−
80−let taskCounter = 0;
81−
82−export function generateTaskId(): string {
83− return `task_${Date.now()}_${++taskCounter}`;
84−}
85−
86−// -- Tasks --
87−
88−export function createTask(opts: {
89− id: string;
90− prompt: string;
91− requesterId: string;
92− channelId?: string | undefined;
93− executionMode: TaskExecutionMode;
94−}): Task {
95− const task: Task = {
96− id: opts.id,
97− prompt: opts.prompt,
98− requesterId: opts.requesterId,
99− channelId: opts.channelId,
100− executionMode: opts.executionMode,
101− createdAt: Date.now(),
102− status: "running",
103− events: [],
104− subscribers: new Set(),
105− };
106− tasks.set(task.id, task);
107− return task;
108−}
109−
110−export function getTask(id: string): Task | undefined {
111− return tasks.get(id);
112−}
113−
114−export function listTasks(requesterId?: string): Task[] {
115− const all = [...tasks.values()];
116− if (requesterId) {
117− return all.filter((t) => t.requesterId === requesterId);
118− }
119− return all;
120−}
121−
122−export function emitTaskEvent(taskId: string, event: TaskEvent): void {
123− const task = tasks.get(taskId);
124− if (!task) return;
125−
126− task.events.push(event);
127−
128− // Notify all subscribers
129− for (const subscriber of task.subscribers) {
130− try {
131− subscriber(event);
132− } catch {
133− // Subscriber threw — remove it
134− task.subscribers.delete(subscriber);
135− }
136− }
137−
138− // Update task status based on events
139− if (event.type === "completed") {
140− task.status = "completed";
141− } else if (event.type === "error") {
142− task.status = "failed";
143− } else if (event.type === "agent_message") {
144− task.resultText = event.text;
145− }
146−}
147−
148−export function subscribeToTask(
149− taskId: string,
150− callback: (event: TaskEvent) => void,
151−): (() => void) | undefined {
152− const task = tasks.get(taskId);
153− if (!task) return undefined;
154−
155− task.subscribers.add(callback);
156− return () => {
157− task.subscribers.delete(callback);
158− };
159−}
160−
161−// -- Approvals --
162−
163−export function registerApproval(approval: PendingApproval): void {
164− // Check rules first — auto-resolve if matched (scoped to same tool)
165− const autoDecision = checkApprovalRules(approval.taskId, approval.toolPath, approval.input);
166− if (autoDecision) {
167− // Resolve immediately without registering as pending
168− approval.resolve(autoDecision);
169− return;
170− }
171− pendingApprovals.set(approval.callId, approval);
172−}
173−
174−export function resolveApproval(
175− callId: string,
176− decision: ApprovalDecision,
177−): boolean {
178− const approval = pendingApprovals.get(callId);
179− if (!approval) return false;
180−
181− approval.resolve(decision);
182− pendingApprovals.delete(callId);
183− return true;
184−}
185−
186−export function getPendingApproval(callId: string): PendingApproval | undefined {
187− return pendingApprovals.get(callId);
188−}
189−
190−export function listPendingApprovals(taskId?: string): PendingApproval[] {
191− const all = [...pendingApprovals.values()];
192− if (taskId) {
193− return all.filter((a) => a.taskId === taskId);
194− }
195− return all;
196−}
197−
198−// -- Approval Rules --
199−
200−/**
201− * Get the value at a dot-path in an object.
202− * e.g. getFieldValue({ a: { b: "c" } }, "a.b") → "c"
203− */
204−function getFieldValue(obj: unknown, path: string): unknown {
205− let current: unknown = obj;
206− for (const key of path.split(".")) {
207− if (current == null || typeof current !== "object") return undefined;
208− current = (current as Record<string, unknown>)[key];
209− }
210− return current;
211−}
212−
213−/**
214− * Check if an approval input matches a rule.
215− */
216−function matchesRule(input: unknown, rule: ApprovalRule): boolean {
217− const fieldValue = String(getFieldValue(input, rule.field) ?? "");
218− switch (rule.operator) {
219− case "equals": return fieldValue === rule.value;
220− case "not_equals": return fieldValue !== rule.value;
221− case "includes": return fieldValue.includes(rule.value);
222− case "not_includes": return !fieldValue.includes(rule.value);
223− }
224−}
225−
226−/**
227− * Check if any rules match this approval. Returns the decision if matched.
228− * Rules only apply to the same tool path they were created for.
229− */
230−export function checkApprovalRules(taskId: string, toolPath: string, input: unknown): ApprovalDecision | undefined {
231− const rules = approvalRules.get(taskId);
232− if (!rules || rules.length === 0) return undefined;
233− for (const rule of rules) {
234− if (rule.toolPath === toolPath && matchesRule(input, rule)) return rule.decision;
235− }
236− return undefined;
237−}
238−
239−/**
240− * Add a rule for a task. Also retroactively applies to pending approvals
241− * for the same tool. Returns the number of approvals that were auto-resolved.
242− */
243−export function addApprovalRule(rule: ApprovalRule): number {
244− const existing = approvalRules.get(rule.taskId) ?? [];
245− existing.push(rule);
246− approvalRules.set(rule.taskId, existing);
247−
248− // Retroactively apply to pending approvals for the same tool
249− let resolved = 0;
250− const pending = listPendingApprovals(rule.taskId);
251− for (const approval of pending) {
252− if (approval.toolPath === rule.toolPath && matchesRule(approval.input, rule)) {
253− resolveApproval(approval.callId, rule.decision);
254− resolved++;
255− }
256− }
257− return resolved;
258−}
259−
260−export function listApprovalRules(taskId: string): ApprovalRule[] {
261− return approvalRules.get(taskId) ?? [];
262−}
263−
264−// -- Remote Runner Sessions --
265−
266−export function registerRemoteRunSession(session: RemoteRunSession): void {
267− remoteRunSessions.set(session.runId, session);
268−}
269−
270−export function getRemoteRunSession(runId: string): RemoteRunSession | undefined {
271− return remoteRunSessions.get(runId);
272−}
273−
274−export function removeRemoteRunSession(runId: string): void {
275− remoteRunSessions.delete(runId);
276−}
assistant/legacy/openassistant/apps/server/src/task-runner.ts+0−201
@@ -1,201 +0,0 @@
1−/**
2− * Task runner — wires createAgent to the task state system.
3− *
4− * Starts an agent run for a task, emitting TaskEvents to state,
5− * with approval resolution via the pending approval registry.
6− */
7−
8−import { createRemoteRunner } from "@openassistant/core";
9−import type { ToolDefinition, ToolTree, ApprovalRequest, ApprovalDecision } from "@openassistant/core/tools";
10−import { isToolDefinition } from "@openassistant/core/tools";
11−import type { LanguageModel } from "@openassistant/core/agent";
12−import { createAgent } from "@openassistant/core/agent";
13−import {
14− emitTaskEvent,
15− getTask,
16− registerRemoteRunSession,
17− registerApproval,
18− removeRemoteRunSession,
19− type RemoteRunInvokeResult,
20−} from "./state.js";
21−
22−export interface TaskRunnerOptions {
23− readonly tools: ToolTree;
24− readonly model: LanguageModel;
25− /** Additional context for the system prompt (project IDs, org info, etc.) */
26− readonly context?: string | undefined;
27− /** Optional remote executor config. If omitted, uses in-process runner. */
28− readonly executor?: {
29− readonly url: string;
30− readonly callbackBaseUrl: string;
31− } | undefined;
32−}
33−
34−function describeError(error: unknown): string {
35− if (error instanceof Error) return error.message;
36− return String(error);
37−}
38−
39−function buildFallbackApprovalPreview(toolPath: string, input: unknown) {
40− return {
41− title: `Run via ${toolPath}`,
42− details: `Arguments: ${JSON.stringify(input)}`,
43− action: "execute" as const,
44− };
45−}
46−
47−function resolveToolDefinition(tools: ToolTree, toolPath: string): ToolDefinition | undefined {
48− const parts = toolPath.split(".").filter(Boolean);
49− if (parts.length === 0) return undefined;
50−
51− let current: ToolTree | ToolDefinition = tools;
52− for (const part of parts) {
53− if (isToolDefinition(current)) return undefined;
54− const next = current[part];
55− if (!next) return undefined;
56− current = next as ToolTree | ToolDefinition;
57− }
58−
59− return isToolDefinition(current) ? current : undefined;
60−}
61−
62−/**
63− * Run an agent turn for a task. Emits events to the task's event stream
64− * and registers approval requests that can be resolved via the REST API.
65− */
66−export async function runTask(
67− taskId: string,
68− prompt: string,
69− options: TaskRunnerOptions,
70−): Promise<void> {
71− const task = getTask(taskId);
72− if (!task) {
73− throw new Error(`Task ${taskId} not found`);
74− }
75−
76− const requestApproval = (request: ApprovalRequest): Promise<ApprovalDecision> => {
77− // Emit the approval_request event so SSE subscribers see it
78− emitTaskEvent(taskId, {
79− type: "approval_request",
80− id: request.callId,
81− toolPath: request.toolPath,
82− input: request.input,
83− preview: request.preview,
84− });
85−
86− return new Promise<ApprovalDecision>((resolve) => {
87− registerApproval({
88− callId: request.callId,
89− taskId,
90− toolPath: request.toolPath,
91− input: request.input,
92− resolve: (decision: ApprovalDecision) => {
93− // Emit resolved event before unblocking the runner
94− emitTaskEvent(taskId, {
95− type: "approval_resolved",
96− id: request.callId,
97− decision,
98− });
99− resolve(decision);
100− },
101− });
102− });
103− };
104−
105− let approvalSeq = 0;
106− const invokeToolForRemoteRun = async (
107− toolPath: string,
108− input: unknown,
109− ): Promise<RemoteRunInvokeResult> => {
110− const tool = resolveToolDefinition(options.tools, toolPath);
111− if (!tool) {
112− return { ok: false, error: `Unknown tool: ${toolPath}` };
113− }
114−
115− const parseResult = tool.args.safeParse(input);
116− if (!parseResult.success) {
117− return {
118− ok: false,
119− error: `Input validation failed: ${parseResult.error.message}`,
120− };
121− }
122−
123− const validatedInput = parseResult.data;
124− if (tool.approval === "required") {
125− const approvalDecision = await requestApproval({
126− callId: `remote_${taskId}_${++approvalSeq}`,
127− toolPath,
128− input: validatedInput,
129− preview: tool.formatApproval
130− ? tool.formatApproval(validatedInput)
131− : buildFallbackApprovalPreview(toolPath, validatedInput),
132− });
133−
134− if (approvalDecision === "denied") {
135− return {
136− ok: true,
137− denied: true,
138− error: `Tool call denied: ${toolPath}`,
139− };
140− }
141− }
142−
143− try {
144− const value = await tool.run(validatedInput);
145− return { ok: true, value };
146− } catch (error) {
147− return { ok: false, error: describeError(error) };
148− }
149− };
150−
151− const runId = `run_${taskId}_${Date.now().toString(36)}`;
152− let registeredRemoteRun = false;
153−
154− const remoteRunner = options.executor
155− ? (() => {
156− const callbackToken = crypto.randomUUID();
157− registerRemoteRunSession({
158− runId,
159− token: callbackToken,
160− invokeTool: invokeToolForRemoteRun,
161− });
162− registeredRemoteRun = true;
163−
164− return createRemoteRunner({
165− tools: options.tools,
166− executorUrl: options.executor.url,
167− runId,
168− callbackBaseUrl: options.executor.callbackBaseUrl,
169− callbackToken,
170− });
171− })()
172− : undefined;
173−
174− const agent = createAgent({
175− tools: options.tools,
176− model: options.model,
177− context: options.context,
178− requestApproval,
179− runner: remoteRunner,
180− onEvent: (event) => {
181− emitTaskEvent(taskId, event);
182− },
183− });
184−
185− try {
186− await agent.run(prompt);
187− } catch (error) {
188− const message = describeError(error);
189− const stack = error instanceof Error ? error.stack : undefined;
190− console.error(`[task ${taskId}] agent error:`, message);
191− if (stack) console.error(stack);
192− emitTaskEvent(taskId, {
193− type: "error",
194− error: message,
195− });
196− } finally {
197− if (registeredRemoteRun) {
198− removeRemoteRunSession(runId);
199− }
200− }
201−}
assistant/legacy/openassistant/apps/server/tsconfig.json+0−15
@@ -1,15 +0,0 @@
1−{
2− "extends": "../../tsconfig.base.json",
3− "compilerOptions": {
4− "rootDir": "src",
5− "outDir": "dist",
6− "composite": true,
7− "noUnusedLocals": false,
8− "noUnusedParameters": false
9− },
10− "include": ["src/**/*.ts"],
11− "references": [
12− { "path": "../../packages/core" },
13− { "path": "../../packages/tool-gen" }
14− ]
15−}
assistant/legacy/openassistant/bun.lock+0−1127
@@ -1,1127 +0,0 @@
1−{
2− "lockfileVersion": 1,
3− "configVersion": 1,
4− "workspaces": {
5− "": {
6− "name": "assistant",
7− "dependencies": {
8− "@apidevtools/swagger-parser": "^12.1.0",
9− "@modelcontextprotocol/sdk": "^1.26.0",
10− "yaml": "^2.8.2",
11− },
12− "devDependencies": {
13− "@effect/language-service": "latest",
14− "@effect/vitest": "^0.27.0",
15− "@types/bun": "latest",
16− "@typescript/native-preview": "7.0.0-dev.20260205.1",
17− "typescript": "latest",
18− "vitest": "^3.2.0",
19− },
20− },
21− "apps/bot": {
22− "name": "@openassistant/bot",
23− "dependencies": {
24− "@elysiajs/eden": "latest",
25− "@openassistant/core": "workspace:*",
26− "@openassistant/reacord": "workspace:*",
27− "@openassistant/server": "workspace:*",
28− "discord.js": "^14.17.3",
29− "effect": "latest",
30− "react": "^19.0.0",
31− },
32− "devDependencies": {
33− "@types/bun": "latest",
34− "@types/react": "^19.0.0",
35− },
36− },
37− "apps/executor": {
38− "name": "@openassistant/executor",
39− "dependencies": {
40− "@openassistant/core": "workspace:*",
41− "zod": "^4.3.6",
42− },
43− "devDependencies": {
44− "@types/bun": "latest",
45− },
46− },
47− "apps/server": {
48− "name": "@openassistant/server",
49− "dependencies": {
50− "@elysiajs/eden": "latest",
51− "@openassistant/core": "workspace:*",
52− "@openassistant/tool-gen": "workspace:*",
53− "elysia": "latest",
54− "zod": "^4.3.6",
55− },
56− "devDependencies": {
57− "@types/bun": "latest",
58− },
59− },
60− "packages/core": {
61− "name": "@openassistant/core",
62− "dependencies": {
63− "@mariozechner/pi-ai": "^0.52.6",
64− "@sinclair/typebox": "^0.34.48",
65− "effect": "latest",
66− "zod": "^4.3.6",
67− },
68− },
69− "packages/reacord": {
70− "name": "@openassistant/reacord",
71− "dependencies": {
72− "@effect-atom/atom": "^0.4.11",
73− "@effect-atom/atom-react": "^0.4.4",
74− "discord.js": "^14.17.3",
75− "effect": "latest",
76− "react": "^19.0.0",
77− "react-reconciler": "^0.31.0",
78− },
79− "devDependencies": {
80− "@types/react": "^19.0.0",
81− "@types/react-reconciler": "^0.31.0",
82− },
83− },
84− "packages/tool-gen": {
85− "name": "@openassistant/tool-gen",
86− "dependencies": {
87− "@apidevtools/swagger-parser": "^12.1.0",
88− "@mariozechner/pi-ai": "^0.52.6",
89− "@modelcontextprotocol/sdk": "^1.26.0",
90− "@openassistant/core": "workspace:*",
91− "@sinclair/typebox": "^0.34.48",
92− "openapi-typescript": "^7.10.1",
93− "yaml": "^2.8.2",
94− "zod": "^4.3.6",
95− },
96− },
97− },
98− "overrides": {
99− "@ai-sdk/anthropic": "^2.0.0",
100− "@effect-atom/atom": "^0.4.11",
101− "@effect-atom/atom-react": "^0.4.4",
102− "@effect/platform": "latest",
103− "@effect/platform-bun": "latest",
104− "@effect/rpc": "latest",
105− "@types/react": "^19.0.0",
106− "@types/react-reconciler": "^0.31.0",
107− "ai": "^6.0.73",
108− "discord.js": "^14.17.3",
109− "effect": "latest",
110− "react": "^19.0.0",
111− "react-reconciler": "^0.31.0",
112− "zod": "^4.3.6",
113− },
114− "packages": {
115− "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.73.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw=="],
116−
117− "@apidevtools/json-schema-ref-parser": ["@apidevtools/json-schema-ref-parser@14.0.1", "", { "dependencies": { "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" } }, "sha512-Oc96zvmxx1fqoSEdUmfmvvb59/KDOnUoJ7s2t7bISyAn0XEz57LCCw8k2Y4Pf3mwKaZLMciESALORLgfe2frCw=="],
118−
119− "@apidevtools/openapi-schemas": ["@apidevtools/openapi-schemas@2.1.0", "", {}, "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ=="],
120−
121− "@apidevtools/swagger-methods": ["@apidevtools/swagger-methods@3.0.2", "", {}, "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="],
122−
123− "@apidevtools/swagger-parser": ["@apidevtools/swagger-parser@12.1.0", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "14.0.1", "@apidevtools/openapi-schemas": "^2.1.0", "@apidevtools/swagger-methods": "^3.0.2", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "call-me-maybe": "^1.0.2" }, "peerDependencies": { "openapi-types": ">=7" } }, "sha512-e5mJoswsnAX0jG+J09xHFYQXb/bUc5S3pLpMxUuRUA2H8T2kni3yEoyz2R3Dltw5f4A6j6rPNMpWTK+iVDFlng=="],
124−
125− "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
126−
127− "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
128−
129− "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
130−
131− "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
132−
133− "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
134−
135− "@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.984.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.6", "@aws-sdk/credential-provider-node": "^3.972.5", "@aws-sdk/eventstream-handler-node": "^3.972.5", "@aws-sdk/middleware-eventstream": "^3.972.3", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.6", "@aws-sdk/middleware-websocket": "^3.972.5", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/token-providers": "3.984.0", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.984.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.4", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.22.0", "@smithy/eventstream-serde-browser": "^4.2.8", "@smithy/eventstream-serde-config-resolver": "^4.3.8", "@smithy/eventstream-serde-node": "^4.2.8", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.12", "@smithy/middleware-retry": "^4.4.29", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.8", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.28", "@smithy/util-defaults-mode-node": "^4.2.31", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-stream": "^4.5.10", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iFrdkDXdo+ELZ5qD8ZYw9MHoOhcXyVutO8z7csnYpJO0rbET/X6B8cQlOCMsqJHxkyMwW21J4vt9S5k2/FgPCg=="],
136−
137− "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.982.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.6", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.6", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.982.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.4", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.22.0", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.12", "@smithy/middleware-retry": "^4.4.29", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.8", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.28", "@smithy/util-defaults-mode-node": "^4.2.31", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-qJrIiivmvujdGqJ0ldSUvhN3k3N7GtPesoOI1BSt0fNXovVnMz4C/JmnkhZihU7hJhDvxJaBROLYTU+lpild4w=="],
138−
139− "@aws-sdk/core": ["@aws-sdk/core@3.973.6", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@aws-sdk/xml-builder": "^3.972.4", "@smithy/core": "^3.22.0", "@smithy/node-config-provider": "^4.3.8", "@smithy/property-provider": "^4.2.8", "@smithy/protocol-http": "^5.3.8", "@smithy/signature-v4": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-pz4ZOw3BLG0NdF25HoB9ymSYyPbMiIjwQJ2aROXRhAzt+b+EOxStfFv8s5iZyP6Kiw7aYhyWxj5G3NhmkoOTKw=="],
140−
141− "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.4", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/types": "^3.973.1", "@smithy/property-provider": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-/8dnc7+XNMmViEom2xsNdArQxQPSgy4Z/lm6qaFPTrMFesT1bV3PsBhb19n09nmxHdrtQskYmViddUIjUQElXg=="],
142−
143− "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.6", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/types": "^3.973.1", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/node-http-handler": "^4.4.8", "@smithy/property-provider": "^4.2.8", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/util-stream": "^4.5.10", "tslib": "^2.6.2" } }, "sha512-5ERWqRljiZv44AIdvIRQ3k+EAV0Sq2WeJHvXuK7gL7bovSxOf8Al7MLH7Eh3rdovH4KHFnlIty7J71mzvQBl5Q=="],
144−
145− "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.4", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/credential-provider-env": "^3.972.4", "@aws-sdk/credential-provider-http": "^3.972.6", "@aws-sdk/credential-provider-login": "^3.972.4", "@aws-sdk/credential-provider-process": "^3.972.4", "@aws-sdk/credential-provider-sso": "^3.972.4", "@aws-sdk/credential-provider-web-identity": "^3.972.4", "@aws-sdk/nested-clients": "3.982.0", "@aws-sdk/types": "^3.973.1", "@smithy/credential-provider-imds": "^4.2.8", "@smithy/property-provider": "^4.2.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-eRUg+3HaUKuXWn/lEMirdiA5HOKmEl8hEHVuszIDt2MMBUKgVX5XNGmb3XmbgU17h6DZ+RtjbxQpjhz3SbTjZg=="],
146−
147− "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.4", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/nested-clients": "3.982.0", "@aws-sdk/types": "^3.973.1", "@smithy/property-provider": "^4.2.8", "@smithy/protocol-http": "^5.3.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-nLGjXuvWWDlQAp505xIONI7Gam0vw2p7Qu3P6on/W2q7rjJXtYjtpHbcsaOjJ/pAju3eTvEQuSuRedcRHVQIAQ=="],
148−
149− "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.5", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.4", "@aws-sdk/credential-provider-http": "^3.972.6", "@aws-sdk/credential-provider-ini": "^3.972.4", "@aws-sdk/credential-provider-process": "^3.972.4", "@aws-sdk/credential-provider-sso": "^3.972.4", "@aws-sdk/credential-provider-web-identity": "^3.972.4", "@aws-sdk/types": "^3.973.1", "@smithy/credential-provider-imds": "^4.2.8", "@smithy/property-provider": "^4.2.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-VWXKgSISQCI2GKN3zakTNHSiZ0+mux7v6YHmmbLQp/o3fvYUQJmKGcLZZzg2GFA+tGGBStplra9VFNf/WwxpYg=="],
150−
151− "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.4", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/types": "^3.973.1", "@smithy/property-provider": "^4.2.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-TCZpWUnBQN1YPk6grvd5x419OfXjHvhj5Oj44GYb84dOVChpg/+2VoEj+YVA4F4E/6huQPNnX7UYbTtxJqgihw=="],
152−
153− "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.4", "", { "dependencies": { "@aws-sdk/client-sso": "3.982.0", "@aws-sdk/core": "^3.973.6", "@aws-sdk/token-providers": "3.982.0", "@aws-sdk/types": "^3.973.1", "@smithy/property-provider": "^4.2.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-wzsGwv9mKlwJ3vHLyembBvGE/5nPUIwRR2I51B1cBV4Cb4ql9nIIfpmHzm050XYTY5fqTOKJQnhLj7zj89VG8g=="],
154−
155− "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.4", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/nested-clients": "3.982.0", "@aws-sdk/types": "^3.973.1", "@smithy/property-provider": "^4.2.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-hIzw2XzrG8jzsUSEatehmpkd5rWzASg5IHUfA+m01k/RtvfAML7ZJVVohuKdhAYx+wV2AThLiQJVzqn7F0khrw=="],
156−
157− "@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.972.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/eventstream-codec": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-xEmd3dnyn83K6t4AJxBJA63wpEoCD45ERFG0XMTViD2E/Ohls9TLxjOWPb1PAxR9/46cKy/TImez1GoqP6xVNQ=="],
158−
159− "@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.972.3", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-pbvZ6Ye/Ks6BAZPa3RhsNjHrvxU9li25PMhSdDpbX0jzdpKpAkIR65gXSNKmA/REnSdEMWSD4vKUW+5eMFzB6w=="],
160−
161− "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.3", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-aknPTb2M+G3s+0qLCx4Li/qGZH8IIYjugHMv15JTYMe6mgZO8VBpYgeGYsNMGCqCZOcWzuf900jFBG5bopfzmA=="],
162−
163− "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.3", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-Ftg09xNNRqaz9QNzlfdQWfpqMCJbsQdnZVJP55jfhbKi1+FTWxGuvfPoBhDHIovqWKjqbuiew3HuhxbJ0+OjgA=="],
164−
165− "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.3", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-PY57QhzNuXHnwbJgbWYTrqIDHYSeOlhfYERTAuc16LKZpTZRJUjzBFokp9hF7u1fuGeE3D70ERXzdbMBOqQz7Q=="],
166−
167− "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.6", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.982.0", "@smithy/core": "^3.22.0", "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-TehLN8W/kivl0U9HcS+keryElEWORROpghDXZBLfnb40DXM7hx/i+7OOjkogXQOF3QtUraJVRkHQ07bPhrWKlw=="],
168−
169− "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.972.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-format-url": "^3.972.3", "@smithy/eventstream-codec": "^4.2.8", "@smithy/eventstream-serde-browser": "^4.2.8", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/protocol-http": "^5.3.8", "@smithy/signature-v4": "^5.3.8", "@smithy/types": "^4.12.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-BN4A9K71WRIlpQ3+IYGdBC2wVyobZ95g6ZomodmJ8Te772GWo0iDk2Mv6JIHdr842tOTgi1b3npLIFDUS4hl4g=="],
170−
171− "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.984.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.6", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.6", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.984.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.4", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.22.0", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.12", "@smithy/middleware-retry": "^4.4.29", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.8", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.28", "@smithy/util-defaults-mode-node": "^4.2.31", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-E9Os+U9NWFoEJXbTVT8sCi+HMnzmsMA8cuCkvlUUfin/oWewUTnCkB/OwFwiUQ2N7v1oBk+i4ZSsI1PiuOy8/w=="],
172−
173− "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.3", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/config-resolver": "^4.4.6", "@smithy/node-config-provider": "^4.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow=="],
174−
175− "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.984.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/nested-clients": "3.984.0", "@aws-sdk/types": "^3.973.1", "@smithy/property-provider": "^4.2.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-UJ/+OzZv+4nAQ1bSspCSb4JlYbMB2Adn8CK7hySpKX5sjhRu1bm6w1PqQq59U67LZEKsPdhl1rzcZ7ybK8YQxw=="],
176−
177− "@aws-sdk/types": ["@aws-sdk/types@3.973.1", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-DwHBiMNOB468JiX6+i34c+THsKHErYUdNQ3HexeXZvVn4zouLjgaS4FejiGSi2HyBuzuyHg7SuOPmjSvoU9NRg=="],
178−
179− "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.984.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-9ebjLA0hMKHeVvXEtTDCCOBtwjb0bOXiuUV06HNeVdgAjH6gj4x4Zwt4IBti83TiyTGOCl5YfZqGx4ehVsasbQ=="],
180−
181− "@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.972.3", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/querystring-builder": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-n7F2ycckcKFXa01vAsT/SJdjFHfKH9s96QHcs5gn8AaaigASICeME8WdUL9uBp8XV/OVwEt8+6gzn6KFUgQa8g=="],
182−
183− "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.4", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-H1onv5SkgPBK2P6JR2MjGgbOnttoNzSPIRoeZTNPZYyaplwGg50zS3amXvXqF0/qfXpWEC9rLWU564QTB9bSog=="],
184−
185− "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.3", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw=="],
186−
187− "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.972.4", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.6", "@aws-sdk/types": "^3.973.1", "@smithy/node-config-provider": "^4.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-3WFCBLiM8QiHDfosQq3Py+lIMgWlFWwFQliUHUqwEiRqLnKyhgbU3AKa7AWJF7lW2Oc/2kFNY4MlAYVnVc0i8A=="],
188−
189− "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.4", "", { "dependencies": { "@smithy/types": "^4.12.0", "fast-xml-parser": "5.3.4", "tslib": "^2.6.2" } }, "sha512-0zJ05ANfYqI6+rGqj8samZBFod0dPPousBjLEqg8WdxSgbMAkRgLyn81lP215Do0rFJ/17LIXwr7q0yK24mP6Q=="],
190−
191− "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.3", "", {}, "sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw=="],
192−
193− "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
194−
195− "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
196−
197− "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="],
198−
199− "@borewit/text-codec": ["@borewit/text-codec@0.2.1", "", {}, "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw=="],
200−
201− "@discordjs/builders": ["@discordjs/builders@1.13.1", "", { "dependencies": { "@discordjs/formatters": "^0.6.2", "@discordjs/util": "^1.2.0", "@sapphire/shapeshift": "^4.0.0", "discord-api-types": "^0.38.33", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w=="],
202−
203− "@discordjs/collection": ["@discordjs/collection@1.5.3", "", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="],
204−
205− "@discordjs/formatters": ["@discordjs/formatters@0.6.2", "", { "dependencies": { "discord-api-types": "^0.38.33" } }, "sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ=="],
206−
207− "@discordjs/rest": ["@discordjs/rest@2.6.0", "", { "dependencies": { "@discordjs/collection": "^2.1.1", "@discordjs/util": "^1.1.1", "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", "@vladfrangu/async_event_emitter": "^2.4.6", "discord-api-types": "^0.38.16", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w=="],
208−
209− "@discordjs/util": ["@discordjs/util@1.2.0", "", { "dependencies": { "discord-api-types": "^0.38.33" } }, "sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg=="],
210−
211− "@discordjs/ws": ["@discordjs/ws@1.2.3", "", { "dependencies": { "@discordjs/collection": "^2.1.0", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", "discord-api-types": "^0.38.1", "tslib": "^2.6.2", "ws": "^8.17.0" } }, "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw=="],
212−
213− "@effect-atom/atom": ["@effect-atom/atom@0.4.13", "", { "peerDependencies": { "@effect/experimental": "^0.57.0", "@effect/platform": "^0.93.0", "@effect/rpc": "^0.72.1", "effect": "^3.19.0" } }, "sha512-wYCPDg/vN2IWTqxho7kTTSivh//V2TSAcdkQvLXMJWww8YzhcCGmCiDpT6cefyNXvHj+qZrqYB54mrUqG6EYCA=="],
214−
215− "@effect-atom/atom-react": ["@effect-atom/atom-react@0.4.6", "", { "dependencies": { "@effect-atom/atom": "^0.4.13" }, "peerDependencies": { "effect": "^3.19", "react": ">=18 <20", "scheduler": "*" } }, "sha512-ZvncuSQsCcUrsddD00JcKDMraPge0AiDMGiJqKc7ProvagCVrxB+Emy5uHM0l0SLGUx4X56bFE0d1tp9Z/Bf+g=="],
216−
217− "@effect/experimental": ["@effect/experimental@0.57.11", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/platform": "^0.93.6", "effect": "^3.19.9", "ioredis": "^5", "lmdb": "^3" }, "optionalPeers": ["ioredis", "lmdb"] }, "sha512-M5uug3Drs/gyTHLfA+XzcIZQGUEV/Jn5yi1POki4oZswhpzNmsVTHl4THpxAordRKwa5lFvTSlsRP684YH7pSw=="],
218−
219− "@effect/language-service": ["@effect/language-service@0.73.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-/SGoq50VDm/XwQI6d0cReYcLjwfdqwZv7uEJp92+ssx5vLCsm+QvHf4Ul6l6PYVzorsgAp/b6fhAwI2VSkqcJQ=="],
220−
221− "@effect/platform": ["@effect/platform@0.94.3", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.16" } }, "sha512-bvTR8xLQoRpKgHuprZDOeQdPkhyVw+WT05iI9jl2s8Qiblyk5Dz2JLwJU+EFeksIBaPYz49xa635Om91T1CefQ=="],
222−
223− "@effect/rpc": ["@effect/rpc@0.73.0", "", { "dependencies": { "msgpackr": "^1.11.4" }, "peerDependencies": { "@effect/platform": "^0.94.0", "effect": "^3.19.13" } }, "sha512-iMPf6tTriz8sK0l5x4koFId8Hz5nFptHYg8WqyjHGIIVLTpZxuiSqhmXZG7FnAs5N2n6uCEws4wWGcIgXNUrFg=="],
224−
225− "@effect/vitest": ["@effect/vitest@0.27.0", "", { "peerDependencies": { "effect": "^3.19.0", "vitest": "^3.2.0" } }, "sha512-8bM7n9xlMUYw9GqPIVgXFwFm2jf27m/R7psI64PGpwU5+26iwyxp9eAXEsfT5S6lqztYfpQQ1Ubp5o6HfNYzJQ=="],
226−
227− "@elysiajs/eden": ["@elysiajs/eden@1.4.6", "", { "peerDependencies": { "elysia": ">=1.4.19" } }, "sha512-Tsa4NwXEWg/u73vWiYZQ3L5/ecgZSxqiEjYwpS+4qBKXeTZqZKl2hcgHJSVBL+InEDMi35Xugct7qyAXE5oM4Q=="],
228−
229− "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
230−
231− "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
232−
233− "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="],
234−
235− "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="],
236−
237− "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="],
238−
239− "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="],
240−
241− "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="],
242−
243− "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="],
244−
245− "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="],
246−
247− "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="],
248−
249− "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="],
250−
251− "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="],
252−
253− "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="],
254−
255− "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="],
256−
257− "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="],
258−
259− "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="],
260−
261− "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="],
262−
263− "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="],
264−
265− "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="],
266−
267− "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="],
268−
269− "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="],
270−
271− "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="],
272−
273− "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="],
274−
275− "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="],
276−
277− "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="],
278−
279− "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="],
280−
281− "@google/genai": ["@google/genai@1.40.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-fhIww8smT0QYRX78qWOiz/nIQhHMF5wXOrlXvj33HBrz3vKDBb+wibLcEmTA+L9dmPD4KmfNr7UF3LDQVTXNjA=="],
282−
283− "@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="],
284−
285− "@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=="],
286−
287− "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
288−
289− "@mariozechner/pi-ai": ["@mariozechner/pi-ai@0.52.6", "", { "dependencies": { "@anthropic-ai/sdk": "^0.73.0", "@aws-sdk/client-bedrock-runtime": "^3.983.0", "@google/genai": "^1.40.0", "@mistralai/mistralai": "1.10.0", "@sinclair/typebox": "^0.34.41", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "chalk": "^5.6.2", "openai": "6.10.0", "partial-json": "^0.1.7", "proxy-agent": "^6.5.0", "undici": "^7.19.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-4oqhoFvYh5GQI8TzxhrXs3tXLOAw+/VvqEQRDJzo0k7Rye0ONWOLcaHAUSfBtOTn15gMUh6m+SjtWXmKVisdBg=="],
290−
291− "@mistralai/mistralai": ["@mistralai/mistralai@1.10.0", "", { "dependencies": { "zod": "^3.20.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg=="],
292−
293− "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.26.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg=="],
294−
295− "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="],
296−
297− "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="],
298−
299− "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3", "", { "os": "linux", "cpu": "arm" }, "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw=="],
300−
301− "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg=="],
302−
303− "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg=="],
304−
305− "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="],
306−
307− "@openassistant/bot": ["@openassistant/bot@workspace:apps/bot"],
308−
309− "@openassistant/core": ["@openassistant/core@workspace:packages/core"],
310−
311− "@openassistant/executor": ["@openassistant/executor@workspace:apps/executor"],
312−
313− "@openassistant/reacord": ["@openassistant/reacord@workspace:packages/reacord"],
314−
315− "@openassistant/server": ["@openassistant/server@workspace:apps/server"],
316−
317− "@openassistant/tool-gen": ["@openassistant/tool-gen@workspace:packages/tool-gen"],
318−
319− "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
320−
321− "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
322−
323− "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
324−
325− "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="],
326−
327− "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
328−
329− "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
330−
331− "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
332−
333− "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="],
334−
335− "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
336−
337− "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
338−
339− "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
340−
341− "@redocly/ajv": ["@redocly/ajv@8.17.3", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-NQsbJbB/GV7JVO88ebFkMndrnuGp/dTm5/2NISeg+JGcLzTfGBJZ01+V5zD8nKBOpi/dLLNFT+Ql6IcUk8ehng=="],
342−
343− "@redocly/config": ["@redocly/config@0.22.2", "", {}, "sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ=="],
344−
345− "@redocly/openapi-core": ["@redocly/openapi-core@1.34.6", "", { "dependencies": { "@redocly/ajv": "^8.11.2", "@redocly/config": "^0.22.0", "colorette": "^1.2.0", "https-proxy-agent": "^7.0.5", "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "minimatch": "^5.0.1", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" } }, "sha512-2+O+riuIUgVSuLl3Lyh5AplWZyVMNuG2F98/o6NrutKJfW4/GTZdPpZlIphS0HGgcOHgmWcCSHj+dWFlZaGSHw=="],
346−
347− "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="],
348−
349− "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="],
350−
351− "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="],
352−
353− "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="],
354−
355− "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="],
356−
357− "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="],
358−
359− "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="],
360−
361− "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="],
362−
363− "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="],
364−
365− "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="],
366−
367− "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="],
368−
369− "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="],
370−
371− "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="],
372−
373− "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="],
374−
375− "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="],
376−
377− "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="],
378−
379− "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="],
380−
381− "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="],
382−
383− "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="],
384−
385− "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="],
386−
387− "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="],
388−
389− "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="],
390−
391− "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="],
392−
393− "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="],
394−
395− "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="],
396−
397− "@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="],
398−
399− "@sapphire/shapeshift": ["@sapphire/shapeshift@4.0.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" } }, "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg=="],
400−
401− "@sapphire/snowflake": ["@sapphire/snowflake@3.5.3", "", {}, "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="],
402−
403− "@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="],
404−
405− "@smithy/abort-controller": ["@smithy/abort-controller@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw=="],
406−
407− "@smithy/config-resolver": ["@smithy/config-resolver@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.8", "@smithy/types": "^4.12.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "tslib": "^2.6.2" } }, "sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ=="],
408−
409− "@smithy/core": ["@smithy/core@3.22.1", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.9", "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.8", "@smithy/util-stream": "^4.5.11", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-x3ie6Crr58MWrm4viHqqy2Du2rHYZjwu8BekasrQx4ca+Y24dzVAwq3yErdqIbc2G3I0kLQA13PQ+/rde+u65g=="],
410−
411− "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.8", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.8", "@smithy/property-provider": "^4.2.8", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "tslib": "^2.6.2" } }, "sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw=="],
412−
413− "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.8", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.12.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-jS/O5Q14UsufqoGhov7dHLOPCzkYJl9QDzusI2Psh4wyYx/izhzvX9P4D69aTxcdfVhEPhjK+wYyn/PzLjKbbw=="],
414−
415− "@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.8", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-MTfQT/CRQz5g24ayXdjg53V0mhucZth4PESoA5IhvaWVDTOQLfo8qI9vzqHcPsdd2v6sqfTYqF5L/l+pea5Uyw=="],
416−
417− "@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-ah12+luBiDGzBruhu3efNy1IlbwSEdNiw8fOZksoKoWW1ZHvO/04MQsdnws/9Aj+5b0YXSSN2JXKy/ClIsW8MQ=="],
418−
419− "@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.8", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-cYpCpp29z6EJHa5T9WL0KAlq3SOKUQkcgSoeRfRVwjGgSFl7Uh32eYGt7IDYCX20skiEdRffyDpvF2efEZPC0A=="],
420−
421− "@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.8", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-iJ6YNJd0bntJYnX6s52NC4WFYcZeKrPUr1Kmmr5AwZcwCSzVpS7oavAmxMR7pMq7V+D1G4s9F5NJK0xwOsKAlQ=="],
422−
423− "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.9", "", { "dependencies": { "@smithy/protocol-http": "^5.3.8", "@smithy/querystring-builder": "^4.2.8", "@smithy/types": "^4.12.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA=="],
424−
425− "@smithy/hash-node": ["@smithy/hash-node@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7ZIlPbmaDGxVoxErDZnuFG18WekhbA/g2/i97wGj+wUBeS6pcUeAym8u4BXh/75RXWhgIJhyC11hBzig6MljwA=="],
426−
427− "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-N9iozRybwAQ2dn9Fot9kI6/w9vos2oTXLhtK7ovGqwZjlOcxu6XhPlpLpC+INsxktqHinn5gS2DXDjDF2kG5sQ=="],
428−
429− "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
430−
431− "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A=="],
432−
433− "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.13", "", { "dependencies": { "@smithy/core": "^3.22.1", "@smithy/middleware-serde": "^4.2.9", "@smithy/node-config-provider": "^4.3.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-middleware": "^4.2.8", "tslib": "^2.6.2" } }, "sha512-x6vn0PjYmGdNuKh/juUJJewZh7MoQ46jYaJ2mvekF4EesMuFfrl4LaW/k97Zjf8PTCPQmPgMvwewg7eNoH9n5w=="],
434−
435− "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.30", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.8", "@smithy/protocol-http": "^5.3.8", "@smithy/service-error-classification": "^4.2.8", "@smithy/smithy-client": "^4.11.2", "@smithy/types": "^4.12.0", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-CBGyFvN0f8hlnqKH/jckRDz78Snrp345+PVk8Ux7pnkUCW97Iinse59lY78hBt04h1GZ6hjBN94BRwZy1xC8Bg=="],
436−
437− "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.9", "", { "dependencies": { "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ=="],
438−
439− "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA=="],
440−
441− "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.8", "", { "dependencies": { "@smithy/property-provider": "^4.2.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg=="],
442−
443− "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.9", "", { "dependencies": { "@smithy/abort-controller": "^4.2.8", "@smithy/protocol-http": "^5.3.8", "@smithy/querystring-builder": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-KX5Wml5mF+luxm1szW4QDz32e3NObgJ4Fyw+irhph4I/2geXwUy4jkIMUs5ZPGflRBeR6BUkC2wqIab4Llgm3w=="],
444−
445− "@smithy/property-provider": ["@smithy/property-provider@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w=="],
446−
447− "@smithy/protocol-http": ["@smithy/protocol-http@5.3.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ=="],
448−
449− "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw=="],
450−
451− "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA=="],
452−
453− "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0" } }, "sha512-mZ5xddodpJhEt3RkCjbmUQuXUOaPNTkbMGR0bcS8FE0bJDLMZlhmpgrvPNCYglVw5rsYTpSnv19womw9WWXKQQ=="],
454−
455− "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.3", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg=="],
456−
457− "@smithy/signature-v4": ["@smithy/signature-v4@5.3.8", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.8", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg=="],
458−
459− "@smithy/smithy-client": ["@smithy/smithy-client@4.11.2", "", { "dependencies": { "@smithy/core": "^3.22.1", "@smithy/middleware-endpoint": "^4.4.13", "@smithy/middleware-stack": "^4.2.8", "@smithy/protocol-http": "^5.3.8", "@smithy/types": "^4.12.0", "@smithy/util-stream": "^4.5.11", "tslib": "^2.6.2" } }, "sha512-SCkGmFak/xC1n7hKRsUr6wOnBTJ3L22Qd4e8H1fQIuKTAjntwgU8lrdMe7uHdiT2mJAOWA/60qaW9tiMu69n1A=="],
460−
461− "@smithy/types": ["@smithy/types@4.12.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw=="],
462−
463− "@smithy/url-parser": ["@smithy/url-parser@4.2.8", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA=="],
464−
465− "@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
466−
467− "@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
468−
469− "@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
470−
471− "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
472−
473− "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
474−
475− "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.29", "", { "dependencies": { "@smithy/property-provider": "^4.2.8", "@smithy/smithy-client": "^4.11.2", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-nIGy3DNRmOjaYaaKcQDzmWsro9uxlaqUOhZDHQed9MW/GmkBZPtnU70Pu1+GT9IBmUXwRdDuiyaeiy9Xtpn3+Q=="],
476−
477− "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.32", "", { "dependencies": { "@smithy/config-resolver": "^4.4.6", "@smithy/credential-provider-imds": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/property-provider": "^4.2.8", "@smithy/smithy-client": "^4.11.2", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-7dtFff6pu5fsjqrVve0YMhrnzJtccCWDacNKOkiZjJ++fmjGExmmSu341x+WU6Oc1IccL7lDuaUj7SfrHpWc5Q=="],
478−
479− "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.8", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw=="],
480−
481− "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
482−
483− "@smithy/util-middleware": ["@smithy/util-middleware@4.2.8", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A=="],
484−
485− "@smithy/util-retry": ["@smithy/util-retry@4.2.8", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.8", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg=="],
486−
487− "@smithy/util-stream": ["@smithy/util-stream@4.5.11", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.9", "@smithy/node-http-handler": "^4.4.9", "@smithy/types": "^4.12.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-lKmZ0S/3Qj2OF5H1+VzvDLb6kRxGzZHq6f3rAsoSu5cTLGsn3v3VQBA8czkNNXlLjoFEtVu3OQT2jEeOtOE2CA=="],
488−
489− "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
490−
491− "@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
492−
493− "@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
494−
495− "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
496−
497− "@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="],
498−
499− "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
500−
501− "@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
502−
503− "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
504−
505− "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="],
506−
507− "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="],
508−
509− "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
510−
511− "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
512−
513− "@types/node": ["@types/node@25.2.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg=="],
514−
515− "@types/react": ["@types/react@19.2.13", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ=="],
516−
517− "@types/react-reconciler": ["@types/react-reconciler@0.31.0", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-wa1KtV3SHKnWeLHfZFg/7nrPSe/Ejdn+qbanNX4V6i9I7C3ECKPfBnC1KM3ef58KFWEohLmTvoTH5XuEIKGX2g=="],
518−
519− "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
520−
521− "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260205.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260205.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260205.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260205.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260205.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260205.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260205.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260205.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-eSgzYCbdCXP/E0XL53yIMZNLoY3z1xMOgGyjstVLgUCMLv1yNrFvkhKhHFjM84OTY/LxqRb6ACtvjFO/oSZzvQ=="],
522−
523− "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260205.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ULATKP9a26qh8vcmP4qPz8UugGKIwhQPKi3NhvlbTPwhl3fMd3GJd9/B9LJSHw7lIuELQGZxhSlDq9l0FMb/FQ=="],
524−
525− "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260205.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-moaKDZHK2dbgcHCnxcwhH8kYRgY69wzPcH5hCNaSrmpbC+Garr78oLtyXot2EDotRDT9foeYsWKdmD6Hx/ypxg=="],
526−
527− "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260205.1", "", { "os": "linux", "cpu": "arm" }, "sha512-3qfjUQlYCkwQmbpIeXMw75bLXkCI3Uo88Ug1n9p4j6KFaek5TjnHOTmlO6V3pkyH9pEXQEVXTn0pXzQytxqEqw=="],
528−
529− "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260205.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Wfp2bPmrTLb+dpp2bHDjMqMKGjQ9dp5KSw0jV4LSlbgcVvRSEWqs2ByVVj61Z4qiHgwlVyoPTewdan2CWnoBgQ=="],
530−
531− "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260205.1", "", { "os": "linux", "cpu": "x64" }, "sha512-p59oY35gvvmdy/iZYxdbFAUXusb7joX2i1Nwl15i4TOn52NcIcW3wb9U/uBrIXKev5VEdlH6BS6VA6dM57zD6w=="],
532−
533− "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260205.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-+NQTlmvtZEXwIlw8j+tvAAn1gLDqyWJEjnA5vmT9MoJuEBrxvuS8azn/q26MOp/w8bWfxe3haVyB+L4VurCF6w=="],
534−
535− "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260205.1", "", { "os": "win32", "cpu": "x64" }, "sha512-kRa4kaiORAWQx9sHylewUhKsNxz3dRBy6AM/U02UebJRlt6c+JnSjIxAFP+iNQaRpoYNs8UdKKGPrHc7Q0oYow=="],
536−
537− "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="],
538−
539− "@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="],
540−
541− "@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="],
542−
543− "@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="],
544−
545− "@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="],
546−
547− "@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="],
548−
549− "@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="],
550−
551− "@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.7", "", {}, "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g=="],
552−
553− "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
554−
555− "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
556−
557− "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
558−
559− "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="],
560−
561− "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
562−
563− "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="],
564−
565− "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
566−
567− "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
568−
569− "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
570−
571− "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
572−
573− "ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="],
574−
575− "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
576−
577− "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
578−
579− "basic-ftp": ["basic-ftp@5.1.0", "", {}, "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw=="],
580−
581− "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
582−
583− "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
584−
585− "bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="],
586−
587− "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
588−
589− "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
590−
591− "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
592−
593− "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
594−
595− "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
596−
597− "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
598−
599− "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
600−
601− "call-me-maybe": ["call-me-maybe@1.0.2", "", {}, "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="],
602−
603− "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="],
604−
605− "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
606−
607− "change-case": ["change-case@5.4.4", "", {}, "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w=="],
608−
609− "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="],
610−
611− "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
612−
613− "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
614−
615− "colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="],
616−
617− "content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="],
618−
619− "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
620−
621− "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
622−
623− "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
624−
625− "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
626−
627− "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
628−
629− "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
630−
631− "data-uri-to-buffer": ["data-uri-to-buffer@6.0.2", "", {}, "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="],
632−
633− "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
634−
635− "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
636−
637− "degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", "esprima": "^4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="],
638−
639− "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
640−
641− "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
642−
643− "discord-api-types": ["discord-api-types@0.38.38", "", {}, "sha512-7qcM5IeZrfb+LXW07HvoI5L+j4PQeMZXEkSm1htHAHh4Y9JSMXBWjy/r7zmUCOj4F7zNjMcm7IMWr131MT2h0Q=="],
644−
645− "discord.js": ["discord.js@14.25.1", "", { "dependencies": { "@discordjs/builders": "^1.13.0", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.2", "@discordjs/rest": "^2.6.0", "@discordjs/util": "^1.2.0", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.33", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g=="],
646−
647− "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
648−
649− "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
650−
651− "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
652−
653− "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
654−
655− "effect": ["effect@3.19.16", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-7+XC3vGrbAhCHd8LTFHvnZjRpZKZ8YHRZqJTkpNoxcJ2mCyNs2SwI+6VkV/ij8Y3YW7wfBN4EbU06/F5+m/wkQ=="],
656−
657− "elysia": ["elysia@1.4.22", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.6", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-Q90VCb1RVFxnFaRV0FDoSylESQQLWgLHFmWciQJdX9h3b2cSasji9KWEUvaJuy/L9ciAGg4RAhUVfsXHg5K2RQ=="],
658−
659− "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
660−
661− "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
662−
663− "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
664−
665− "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
666−
667− "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
668−
669− "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
670−
671− "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
672−
673− "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
674−
675− "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="],
676−
677− "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
678−
679− "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
680−
681− "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
682−
683− "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
684−
685− "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
686−
687− "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
688−
689− "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
690−
691− "exact-mirror": ["exact-mirror@0.2.6", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-7s059UIx9/tnOKSySzUk5cPGkoILhTE4p6ncf6uIPaQ+9aRBQzQjc9+q85l51+oZ+P6aBxh084pD0CzBQPcFUA=="],
692−
693− "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
694−
695− "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
696−
697− "express-rate-limit": ["express-rate-limit@8.2.1", "", { "dependencies": { "ip-address": "10.0.1" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g=="],
698−
699− "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
700−
701− "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
702−
703− "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
704−
705− "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
706−
707− "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
708−
709− "fast-xml-parser": ["fast-xml-parser@5.3.4", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA=="],
710−
711− "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
712−
713− "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
714−
715− "file-type": ["file-type@21.3.0", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA=="],
716−
717− "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
718−
719− "find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="],
720−
721− "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
722−
723− "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
724−
725− "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
726−
727− "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
728−
729− "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
730−
731− "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
732−
733− "gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="],
734−
735− "gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
736−
737− "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
738−
739− "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
740−
741− "get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="],
742−
743− "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=="],
744−
745− "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=="],
746−
747− "google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
748−
749− "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
750−
751− "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="],
752−
753− "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
754−
755− "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
756−
757− "hono": ["hono@4.11.8", "", {}, "sha512-eVkB/CYCCei7K2WElZW9yYQFWssG0DhaDhVvr7wy5jJ22K+ck8fWW0EsLpB0sITUTvPnc97+rrbQqIr5iqiy9Q=="],
758−
759− "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
760−
761− "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
762−
763− "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
764−
765− "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
766−
767− "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
768−
769− "index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="],
770−
771− "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
772−
773− "ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="],
774−
775− "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
776−
777− "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
778−
779− "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
780−
781− "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
782−
783− "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
784−
785− "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
786−
787− "js-levenshtein": ["js-levenshtein@1.1.6", "", {}, "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="],
788−
789− "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
790−
791− "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
792−
793− "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
794−
795− "json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="],
796−
797− "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
798−
799− "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
800−
801− "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
802−
803− "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=="],
804−
805− "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
806−
807− "lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="],
808−
809− "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
810−
811− "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="],
812−
813− "lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
814−
815− "magic-bytes.js": ["magic-bytes.js@1.13.0", "", {}, "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg=="],
816−
817− "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
818−
819− "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
820−
821− "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
822−
823− "memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="],
824−
825− "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
826−
827− "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
828−
829− "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
830−
831− "minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
832−
833− "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
834−
835− "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
836−
837− "msgpackr": ["msgpackr@1.11.8", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA=="],
838−
839− "msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="],
840−
841− "multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="],
842−
843− "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
844−
845− "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
846−
847− "netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="],
848−
849− "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
850−
851− "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
852−
853− "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
854−
855− "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
856−
857− "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
858−
859− "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
860−
861− "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
862−
863− "openai": ["openai@6.10.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-ITxOGo7rO3XRMiKA5l7tQ43iNNu+iXGFAcf2t+aWVzzqRaS0i7m1K2BhxNdaveB+5eENhO0VY1FkiZzhBk4v3A=="],
864−
865− "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
866−
867− "openapi-typescript": ["openapi-typescript@7.10.1", "", { "dependencies": { "@redocly/openapi-core": "^1.34.5", "ansi-colors": "^4.1.3", "change-case": "^5.4.4", "parse-json": "^8.3.0", "supports-color": "^10.2.2", "yargs-parser": "^21.1.1" }, "peerDependencies": { "typescript": "^5.x" }, "bin": { "openapi-typescript": "bin/cli.js" } }, "sha512-rBcU8bjKGGZQT4K2ekSTY2Q5veOQbVG/lTKZ49DeCyT9z62hM2Vj/LLHjDHC9W7LJG8YMHcdXpRZDqC1ojB/lw=="],
868−
869− "pac-proxy-agent": ["pac-proxy-agent@7.2.0", "", { "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.1.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.6", "pac-resolver": "^7.0.1", "socks-proxy-agent": "^8.0.5" } }, "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA=="],
870−
871− "pac-resolver": ["pac-resolver@7.0.1", "", { "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" } }, "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg=="],
872−
873− "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
874−
875− "parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="],
876−
877− "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
878−
879− "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="],
880−
881− "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
882−
883− "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
884−
885− "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
886−
887− "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
888−
889− "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="],
890−
891− "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
892−
893− "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
894−
895− "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
896−
897− "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="],
898−
899− "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
900−
901− "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
902−
903− "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
904−
905− "proxy-agent": ["proxy-agent@6.5.0", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", "socks-proxy-agent": "^8.0.5" } }, "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A=="],
906−
907− "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
908−
909− "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
910−
911− "qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="],
912−
913− "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
914−
915− "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
916−
917− "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
918−
919− "react-reconciler": ["react-reconciler@0.31.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ=="],
920−
921− "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
922−
923− "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
924−
925− "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="],
926−
927− "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
928−
929− "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
930−
931− "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
932−
933− "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="],
934−
935− "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
936−
937− "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
938−
939− "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
940−
941− "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
942−
943− "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
944−
945− "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
946−
947− "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
948−
949− "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
950−
951− "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
952−
953− "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
954−
955− "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
956−
957− "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
958−
959− "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="],
960−
961− "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=="],
962−
963− "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
964−
965− "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
966−
967− "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
968−
969− "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
970−
971− "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
972−
973− "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=="],
974−
975− "string-width-cjs": ["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=="],
976−
977− "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
978−
979− "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
980−
981− "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
982−
983− "strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="],
984−
985− "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
986−
987− "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="],
988−
989− "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
990−
991− "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
992−
993− "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
994−
995− "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="],
996−
997− "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="],
998−
999− "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="],
1000−
1001− "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
1002−
1003− "token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="],
1004−
1005− "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="],
1006−
1007− "ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
1008−
1009− "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
1010−
1011− "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
1012−
1013− "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
1014−
1015− "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
1016−
1017− "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
1018−
1019− "undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
1020−
1021− "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
1022−
1023− "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
1024−
1025− "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
1026−
1027− "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
1028−
1029− "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
1030−
1031− "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
1032−
1033− "vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="],
1034−
1035− "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
1036−
1037− "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
1038−
1039− "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
1040−
1041− "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
1042−
1043− "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
1044−
1045− "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
1046−
1047− "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
1048−
1049− "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
1050−
1051− "yaml-ast-parser": ["yaml-ast-parser@0.0.43", "", {}, "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A=="],
1052−
1053− "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
1054−
1055− "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
1056−
1057− "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
1058−
1059− "@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=="],
1060−
1061− "@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=="],
1062−
1063− "@aws-sdk/client-sso/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.982.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-M27u8FJP7O0Of9hMWX5dipp//8iglmV9jr7R8SR8RveU+Z50/8TqH68Tu6wUWBGMfXjzbVwn1INIAO5lZrlxXQ=="],
1064−
1065− "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.982.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.6", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.6", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.982.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.4", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.22.0", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.12", "@smithy/middleware-retry": "^4.4.29", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.8", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.28", "@smithy/util-defaults-mode-node": "^4.2.31", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-VVkaH27digrJfdVrT64rjkllvOp4oRiZuuJvrylLXAKl18ujToJR7AqpDldL/LS63RVne3QWIpkygIymxFtliQ=="],
1066−
1067− "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.982.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.6", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.6", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.982.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.4", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.22.0", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.12", "@smithy/middleware-retry": "^4.4.29", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.8", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.28", "@smithy/util-defaults-mode-node": "^4.2.31", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-VVkaH27digrJfdVrT64rjkllvOp4oRiZuuJvrylLXAKl18ujToJR7AqpDldL/LS63RVne3QWIpkygIymxFtliQ=="],
1068−
1069− "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.982.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.6", "@aws-sdk/nested-clients": "3.982.0", "@aws-sdk/types": "^3.973.1", "@smithy/property-provider": "^4.2.8", "@smithy/shared-ini-file-loader": "^4.4.3", "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-v3M0KYp2TVHYHNBT7jHD9lLTWAdS9CaWJ2jboRKt0WAB65bA7iUEpR+k4VqKYtpQN4+8kKSc4w+K6kUNZkHKQw=="],
1070−
1071− "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.982.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.6", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.6", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.982.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.4", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.22.0", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.12", "@smithy/middleware-retry": "^4.4.29", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.8", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.28", "@smithy/util-defaults-mode-node": "^4.2.31", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-VVkaH27digrJfdVrT64rjkllvOp4oRiZuuJvrylLXAKl18ujToJR7AqpDldL/LS63RVne3QWIpkygIymxFtliQ=="],
1072−
1073− "@aws-sdk/middleware-user-agent/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.982.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-M27u8FJP7O0Of9hMWX5dipp//8iglmV9jr7R8SR8RveU+Z50/8TqH68Tu6wUWBGMfXjzbVwn1INIAO5lZrlxXQ=="],
1074−
1075− "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
1076−
1077− "@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
1078−
1079− "@discordjs/ws/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
1080−
1081− "@mariozechner/pi-ai/undici": ["undici@7.20.0", "", {}, "sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ=="],
1082−
1083− "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
1084−
1085− "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
1086−
1087− "node-fetch/data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
1088−
1089− "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
1090−
1091− "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
1092−
1093− "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
1094−
1095− "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
1096−
1097− "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
1098−
1099− "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=="],
1100−
1101− "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
1102−
1103− "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
1104−
1105− "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
1106−
1107− "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.982.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-M27u8FJP7O0Of9hMWX5dipp//8iglmV9jr7R8SR8RveU+Z50/8TqH68Tu6wUWBGMfXjzbVwn1INIAO5lZrlxXQ=="],
1108−
1109− "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.982.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-M27u8FJP7O0Of9hMWX5dipp//8iglmV9jr7R8SR8RveU+Z50/8TqH68Tu6wUWBGMfXjzbVwn1INIAO5lZrlxXQ=="],
1110−
1111− "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.982.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.6", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.6", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.982.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.4", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.22.0", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.12", "@smithy/middleware-retry": "^4.4.29", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.8", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.28", "@smithy/util-defaults-mode-node": "^4.2.31", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-VVkaH27digrJfdVrT64rjkllvOp4oRiZuuJvrylLXAKl18ujToJR7AqpDldL/LS63RVne3QWIpkygIymxFtliQ=="],
1112−
1113− "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.982.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-M27u8FJP7O0Of9hMWX5dipp//8iglmV9jr7R8SR8RveU+Z50/8TqH68Tu6wUWBGMfXjzbVwn1INIAO5lZrlxXQ=="],
1114−
1115− "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
1116−
1117− "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
1118−
1119− "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
1120−
1121− "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
1122−
1123− "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
1124−
1125− "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.982.0", "", { "dependencies": { "@aws-sdk/types": "^3.973.1", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-endpoints": "^3.2.8", "tslib": "^2.6.2" } }, "sha512-M27u8FJP7O0Of9hMWX5dipp//8iglmV9jr7R8SR8RveU+Z50/8TqH68Tu6wUWBGMfXjzbVwn1INIAO5lZrlxXQ=="],
1126− }
1127−}
assistant/legacy/openassistant/index.ts+0−1
@@ -1 +0,0 @@
1−console.log("Hello via Bun!");
assistant/legacy/openassistant/package.json+0−52
@@ -1,52 +0,0 @@
1−{
2− "name": "openassistant",
3− "private": true,
4− "type": "module",
5− "workspaces": [
6− "apps/*",
7− "packages/*"
8− ],
9− "scripts": {
10− "with-env": "bun run --env-file=.env --",
11− "with-env:prod": "bun run --env-file=.env.production --",
12− "prepare": "effect-language-service patch",
13− "typecheck": "bun run --filter '@openassistant/core' typecheck && bun run --filter '@openassistant/reacord' typecheck && bun run --filter '@openassistant/server' typecheck && bun run --filter '@openassistant/executor' typecheck",
14− "typecheck:tsc": "tsc --build",
15− "build": "bun run typecheck",
16− "test": "bun test packages/ apps/",
17− "test:watch": "bun test --watch packages/ apps/",
18− "dev": "bun run dev:server & bun run dev:executor & bun run dev:bot & wait",
19− "dev:server": "bun run --filter '@openassistant/server' dev",
20− "dev:executor": "bun run --filter '@openassistant/executor' dev",
21− "dev:bot": "bun run --filter '@openassistant/bot' dev"
22− },
23− "devDependencies": {
24− "@effect/language-service": "latest",
25− "@effect/vitest": "^0.27.0",
26− "@types/bun": "latest",
27− "@typescript/native-preview": "7.0.0-dev.20260205.1",
28− "typescript": "latest",
29− "vitest": "^3.2.0"
30− },
31− "overrides": {
32− "@ai-sdk/anthropic": "^2.0.0",
33− "@effect/platform": "latest",
34− "@effect/platform-bun": "latest",
35− "@effect/rpc": "latest",
36− "@effect-atom/atom": "^0.4.11",
37− "@effect-atom/atom-react": "^0.4.4",
38− "@types/react": "^19.0.0",
39− "@types/react-reconciler": "^0.31.0",
40− "ai": "^6.0.73",
41− "discord.js": "^14.17.3",
42− "effect": "latest",
43− "react": "^19.0.0",
44− "react-reconciler": "^0.31.0",
45− "zod": "^4.3.6"
46− },
47− "dependencies": {
48− "@apidevtools/swagger-parser": "^12.1.0",
49− "@modelcontextprotocol/sdk": "^1.26.0",
50− "yaml": "^2.8.2"
51− }
52−}
assistant/legacy/openassistant/packages/core/package.json+0−25
@@ -1,25 +0,0 @@
1−{
2− "name": "@openassistant/core",
3− "private": true,
4− "type": "module",
5− "exports": {
6− ".": "./src/index.ts",
7− "./tools": "./src/tools.ts",
8− "./runner": "./src/runner.ts",
9− "./remote-runner": "./src/remote-runner.ts",
10− "./typechecker": "./src/typechecker.ts",
11− "./agent": "./src/agent.ts",
12− "./events": "./src/events.ts",
13− "./discovery": "./src/discovery.ts"
14− },
15− "scripts": {
16− "test": "bun test",
17− "typecheck": "tsgo --noEmit --incremental false -p tsconfig.json"
18− },
19− "dependencies": {
20− "@mariozechner/pi-ai": "^0.52.6",
21− "@sinclair/typebox": "^0.34.48",
22− "effect": "latest",
23− "zod": "^4.3.6"
24− }
25−}
assistant/legacy/openassistant/packages/core/src/agent.test.ts+0−218
@@ -1,218 +0,0 @@
1−import { describe, test, expect } from "bun:test";
2−import { z } from "zod";
3−import { defineTool, type ToolTree } from "./tools.js";
4−import { createAgent, type LanguageModel, type Message, type GenerateResult } from "./agent.js";
5−import type { TaskEvent } from "./events.js";
6−
7−// ---------------------------------------------------------------------------
8−// Test helpers
9−// ---------------------------------------------------------------------------
10−
11−function mathTools(): ToolTree {
12− return {
13− math: {
14− add: defineTool({
15− description: "Add two numbers",
16− approval: "auto",
17− args: z.object({ a: z.number(), b: z.number() }),
18− returns: z.number(),
19− run: async (input) => input.a + input.b,
20− }),
21− multiply: defineTool({
22− description: "Multiply two numbers",
23− approval: "auto",
24− args: z.object({ a: z.number(), b: z.number() }),
25− returns: z.number(),
26− run: async (input) => input.a * input.b,
27− }),
28− },
29− };
30−}
31−
32−/**
33− * Create a fake model that returns pre-scripted responses.
34− * Each call to generate() returns the next response in the sequence.
35− */
36−function fakeModel(responses: GenerateResult[]): LanguageModel {
37− let callIndex = 0;
38− return {
39− async generate(_messages: Message[]): Promise<GenerateResult> {
40− const response = responses[callIndex];
41− if (!response) {
42− return { text: "No more scripted responses." };
43− }
44− callIndex++;
45− return response;
46− },
47− };
48−}
49−
50−// ---------------------------------------------------------------------------
51−// Tests
52−// ---------------------------------------------------------------------------
53−
54−describe("agent — basic flow", () => {
55− test("model returns text without tool calls", async () => {
56− const model = fakeModel([{ text: "Hello! How can I help?" }]);
57−
58− const agent = createAgent({
59− tools: mathTools(),
60− model,
61− requestApproval: async () => "approved",
62− });
63−
64− const result = await agent.run("Hi there");
65− expect(result.text).toBe("Hello! How can I help?");
66− expect(result.runs).toHaveLength(0);
67− expect(result.allReceipts).toHaveLength(0);
68− });
69−
70− test("model calls run_code, then returns text", async () => {
71− const model = fakeModel([
72− // First call: model wants to run code
73− {
74− toolCalls: [
75− {
76− id: "tc_1",
77− name: "run_code",
78− args: { code: "return await tools.math.add({ a: 3, b: 4 })" },
79− },
80− ],
81− },
82− // Second call: model sees the result and responds with text
83− { text: "The result of 3 + 4 is 7." },
84− ]);
85−
86− const agent = createAgent({
87− tools: mathTools(),
88− model,
89− requestApproval: async () => "approved",
90− });
91−
92− const result = await agent.run("What is 3 + 4?");
93− expect(result.text).toBe("The result of 3 + 4 is 7.");
94− expect(result.runs).toHaveLength(1);
95− expect(result.runs[0]!.result.ok).toBe(true);
96− expect(result.runs[0]!.result.value).toBe(7);
97− expect(result.allReceipts).toHaveLength(1);
98− });
99−
100− test("model chains multiple run_code calls", async () => {
101− const model = fakeModel([
102− {
103− toolCalls: [
104− {
105− id: "tc_1",
106− name: "run_code",
107− args: { code: "return await tools.math.add({ a: 1, b: 2 })" },
108− },
109− ],
110− },
111− {
112− toolCalls: [
113− {
114− id: "tc_2",
115− name: "run_code",
116− args: { code: "return await tools.math.multiply({ a: 3, b: 4 })" },
117− },
118− ],
119− },
120− { text: "1 + 2 = 3, then 3 * 4 = 12." },
121− ]);
122−
123− const agent = createAgent({
124− tools: mathTools(),
125− model,
126− requestApproval: async () => "approved",
127− });
128−
129− const result = await agent.run("Add 1+2 then multiply 3*4");
130− expect(result.text).toBe("1 + 2 = 3, then 3 * 4 = 12.");
131− expect(result.runs).toHaveLength(2);
132− expect(result.allReceipts).toHaveLength(2);
133− });
134−
135− test("emits events throughout execution", async () => {
136− const model = fakeModel([
137− {
138− toolCalls: [
139− {
140− id: "tc_1",
141− name: "run_code",
142− args: { code: "return await tools.math.add({ a: 1, b: 2 })" },
143− },
144− ],
145− },
146− { text: "Done." },
147− ]);
148−
149− const events: TaskEvent[] = [];
150−
151− const agent = createAgent({
152− tools: mathTools(),
153− model,
154− requestApproval: async () => "approved",
155− onEvent: (e) => events.push(e),
156− });
157−
158− await agent.run("Add 1+2");
159−
160− const eventTypes = events.map((e) => e.type);
161− expect(eventTypes).toContain("status");
162− expect(eventTypes).toContain("code_generated");
163− expect(eventTypes).toContain("tool_result");
164− expect(eventTypes).toContain("agent_message");
165− expect(eventTypes).toContain("completed");
166− });
167−
168− test("handles code that fails in sandbox", async () => {
169− const model = fakeModel([
170− {
171− toolCalls: [
172− {
173− id: "tc_1",
174− name: "run_code",
175− // This passes typecheck but fails at runtime (undefined access)
176− args: { code: "const x: any = undefined;\nreturn x.foo.bar;" },
177− },
178− ],
179− },
180− { text: "The code failed." },
181− ]);
182−
183− const agent = createAgent({
184− tools: mathTools(),
185− model,
186− requestApproval: async () => "approved",
187− });
188−
189− const result = await agent.run("Do something that fails");
190− expect(result.text).toBe("The code failed.");
191− expect(result.runs).toHaveLength(1);
192− expect(result.runs[0]!.result.ok).toBe(false);
193− });
194−
195− test("respects maxCodeRuns limit", async () => {
196− // Model always wants to run more code
197− const infiniteModel: LanguageModel = {
198− async generate(): Promise<GenerateResult> {
199− return {
200− toolCalls: [
201− { id: `tc_${Date.now()}`, name: "run_code", args: { code: "return 1" } },
202− ],
203− };
204− },
205− };
206−
207− const agent = createAgent({
208− tools: mathTools(),
209− model: infiniteModel,
210− requestApproval: async () => "approved",
211− maxCodeRuns: 3,
212− });
213−
214− const result = await agent.run("Keep running");
215− expect(result.runs).toHaveLength(3);
216− expect(result.text).toContain("maximum");
217− });
218−});
assistant/legacy/openassistant/packages/core/src/agent.ts+0−455
@@ -1,455 +0,0 @@
1−/**
2− * Agent loop — orchestrates Claude + codemode runner.
3− *
4− * 1. Build system prompt from tool descriptions
5− * 2. Call Claude with the prompt and the run_code tool
6− * 3. Claude responds with run_code({ code: "..." })
7− * 4. Typecheck the code
8− * 5. If typecheck fails: feed error back, retry (up to maxRetries)
9− * 6. Execute in sandbox
10− * 7. Collect receipts, feed back to Claude
11− * 8. Claude may call run_code again or produce final text
12− *
13− * When the tool count exceeds DISCOVERY_THRESHOLD, the agent injects
14− * a `tools.discover()` meta-tool so the LLM can search for relevant
15− * tools by keyword instead of having all tools described in the prompt.
16− */
17−
18−import type { ToolTree, ApprovalDecision, ApprovalRequest, ToolCallReceipt } from "./tools.js";
19−import type { RunResult, Runner } from "./runner.js";
20−import { createRunner } from "./runner.js";
21−import { generateToolDeclarations, generatePromptGuidance, typecheckCode } from "./typechecker.js";
22−import { countTools, createDiscoverTool } from "./discovery.js";
23−import type { TaskEvent } from "./events.js";
24−
25−// ---------------------------------------------------------------------------
26−// Types
27−// ---------------------------------------------------------------------------
28−
29−/**
30− * A language model interface — thin abstraction over AI SDK or any LLM.
31− * We don't import AI SDK directly to keep core dependency-free.
32− */
33−export interface LanguageModel {
34− /**
35− * Generate a response given messages.
36− * The model should be configured with the run_code tool.
37− * Returns either text or a tool call.
38− */
39− generate(messages: Message[]): Promise<GenerateResult>;
40−}
41−
42−export type Message =
43− | { role: "system"; content: string }
44− | { role: "user"; content: string }
45− | { role: "assistant"; content: string }
46− | { role: "assistant"; content: string; toolCalls: ToolCall[] }
47− | { role: "tool"; toolCallId: string; content: string };
48−
49−export interface ToolCall {
50− id: string;
51− name: string;
52− args: Record<string, unknown>;
53−}
54−
55−export interface GenerateResult {
56− text?: string | undefined;
57− toolCalls?: ToolCall[] | undefined;
58−}
59−
60−export interface AgentOptions {
61− /** The tool tree to expose to the agent. */
62− readonly tools: ToolTree;
63− /** The language model to use. */
64− readonly model: LanguageModel;
65− /** Called when a tool needs approval (required when `runner` is not provided). */
66− readonly requestApproval?: ((request: ApprovalRequest) => Promise<ApprovalDecision>) | undefined;
67− /** Optional custom runner (e.g. remote executor transport). */
68− readonly runner?: Runner | undefined;
69− /** Called for each task event. */
70− readonly onEvent?: ((event: TaskEvent) => void) | undefined;
71− /** Maximum typecheck retries per run_code call. Defaults to 3. */
72− readonly maxTypecheckRetries?: number | undefined;
73− /** Maximum total run_code calls per agent turn. Defaults to 10. */
74− readonly maxCodeRuns?: number | undefined;
75− /** Execution timeout per code run in ms. Defaults to 30_000. */
76− readonly timeoutMs?: number | undefined;
77− /**
78− * Tool count threshold for enabling discovery mode.
79− * When total tools exceed this, inject `tools.discover()` and
80− * only describe small tool sources in the system prompt.
81− * Defaults to 50.
82− */
83− readonly discoveryThreshold?: number | undefined;
84− /**
85− * Additional context to include in the system prompt.
86− * Use this to provide environment-specific info like project IDs,
87− * usernames, organization names, etc. that the agent may need.
88− */
89− readonly context?: string | undefined;
90−}
91−
92−export interface AgentResult {
93− readonly text: string;
94− readonly runs: readonly CodeRun[];
95− readonly allReceipts: readonly ToolCallReceipt[];
96−}
97−
98−export interface CodeRun {
99− readonly code: string;
100− readonly typecheckOk: boolean;
101− readonly result: RunResult;
102−}
103−
104−// ---------------------------------------------------------------------------
105−// Discovery mode
106−// ---------------------------------------------------------------------------
107−
108−const DISCOVERY_THRESHOLD = 50;
109−
110−/**
111− * When discovery mode is active, separate tools into:
112− * - "small" tools that fit in the prompt (under the threshold)
113− * - "large" tools that are only available via discover()
114− *
115− * The discover tool searches ALL tools. Small tools are described
116− * in the prompt AND available via discover.
117− */
118−function prepareToolsForAgent(
119− tools: ToolTree,
120− threshold: number,
121−): {
122− /** Tools actually wired in the sandbox (always all of them + discover if needed) */
123− sandboxTools: ToolTree;
124− /** Prompt guidance (subset or all) */
125− promptGuidance: string;
126− /** Tool declarations for typechecker (subset or all) */
127− toolDeclarations: string;
128− /** Whether discovery mode is active */
129− discoveryMode: boolean;
130−} {
131− const totalCount = countTools(tools);
132−
133− if (totalCount <= threshold) {
134− // Small enough — describe everything in the prompt
135− return {
136− sandboxTools: tools,
137− promptGuidance: generatePromptGuidance(tools),
138− toolDeclarations: generateToolDeclarations(tools),
139− discoveryMode: false,
140− };
141− }
142−
143− // Discovery mode: inject discover tool, only describe small namespaces in prompt
144− const discoverTool = createDiscoverTool(tools);
145−
146− // Separate namespaces into small (described) and large (discover-only)
147− const described: Record<string, ToolTree | import("./tools.js").ToolDefinition> = { discover: discoverTool };
148− const largeNamespaces: string[] = [];
149−
150− for (const [key, value] of Object.entries(tools)) {
151− const nsCount = countTools({ [key]: value });
152− if (nsCount <= threshold) {
153− described[key] = value;
154− } else {
155− largeNamespaces.push(`${key} (${nsCount} tools)`);
156− }
157− }
158−
159− const describedTree = described as ToolTree;
160−
161− // Sandbox gets ALL tools + discover
162− const sandboxTools = { ...tools, discover: discoverTool } as ToolTree;
163−
164− // Prompt only describes the small namespaces + discover
165− const promptGuidance = generatePromptGuidance(describedTree);
166−
167− // Typechecker: small namespaces are fully typed, large namespaces
168− // are declared as `Record<string, any>` so the LLM can call
169− // discovered tools without typecheck errors.
170− const largeNsDeclarations = Object.entries(tools)
171− .filter(([key]) => !described[key])
172− .map(([key]) => ` ${key}: Record<string, Record<string, (...args: any[]) => Promise<any>>>;`)
173− .join("\n");
174−
175− const toolDeclarations = generateToolDeclarations(describedTree).replace(
176− /\};$/,
177− largeNsDeclarations ? `${largeNsDeclarations}\n};` : "};",
178− );
179−
180− return {
181− sandboxTools,
182− promptGuidance,
183− toolDeclarations,
184− discoveryMode: true,
185− };
186−}
187−
188−// ---------------------------------------------------------------------------
189−// System prompt
190−// ---------------------------------------------------------------------------
191−
192−function buildSystemPrompt(guidance: string, discoveryMode: boolean, context?: string): string {
193− const discoveryInstructions = discoveryMode
194− ? `
195−## Tool Discovery
196−
197−Some tool namespaces are too large to list here. Use \`tools.discover({ query })\` to search for tools by keyword.
198−
199−By default, discover returns the top 5 matches with **full type signatures** (input args + return types). Check the return type to understand response structure — look for pagination fields (\`next\`, \`cursor\`, \`page\`), wrapper objects, etc.
200−
201−Options:
202−- \`depth: 0\` — hide return types, just show input args. Use with \`limit: 20\` to browse broadly.
203−- \`depth: 2\` — include JSDoc comments and examples. Use for exact details.
204−- \`limit: N\` — control how many results (default 5, max 20).
205−
206−**Workflow:**
207−1. Discover tools to find what's available and see their types
208−2. Write a SINGLE self-contained script that does the entire task. If the return type has pagination, loop until all pages are fetched.
209−
210−Example — "close all open issues on acme/myapp":
211−
212−Call 1 (discover tools — returns types by default):
213−\`\`\`ts
214−return await tools.discover({ query: "issues list update repo" });
215−\`\`\`
216−
217−Call 2 (do the work — everything in one script):
218−\`\`\`ts
219−const issues = await tools.github.issues.issues_list_for_repo({
220− owner: "acme", repo: "myapp", state: "open", per_page: 100
221−});
222−
223−const results = [];
224−for (const issue of issues) {
225− const closed = await tools.github.issues.issues_update({
226− owner: "acme", repo: "myapp", issue_number: issue.number, state: "closed"
227− });
228− results.push({ number: issue.number, title: issue.title, state: closed.state });
229−}
230−
231−return { closed: results.length, issues: results };
232−\`\`\`
233−`
234− : "";
235−
236− const contextSection = context
237− ? `
238−## Context
239−
240−${context}
241−`
242− : "";
243−
244− return `You are an AI assistant that executes tasks by generating TypeScript code.
245−
246−You have access to a set of tools via the \`tools\` object. When the user asks you to do something, generate TypeScript code that calls these tools to accomplish the task.
247−${contextSection}
248−## Available Tools
249−
250−${guidance}
251−${discoveryInstructions}
252−## Instructions
253−
254−- Use the \`run_code\` tool to execute TypeScript code
255−- **Write complete, self-contained scripts.** Once you know what tools are available, do all the work in a single run_code call — fetch data, loop, transform, write back, and return results. Don't do reads in one call and writes in another.
256−- The code runs in a sandboxed environment — only \`tools.*\` calls are available
257−- No \`fetch\`, \`process\`, \`require\`, or \`import\` — use tools for all external interactions
258−- Write clean, straightforward TypeScript — use for loops, map, filter, Promise.all as needed
259−- Handle errors gracefully with try/catch — if a tool call fails or is denied, continue with remaining work
260−- **Pagination:** If a list endpoint's return type has \`pagination\`, \`next\`, \`cursor\`, or similar fields, the results may be paginated. Check \`pagination.next\` (or equivalent) in the response — if it's not null, there are more pages. Paginate when the user needs complete results. Example pattern:
261− \`\`\`ts
262− let allItems = [];
263− let cursor = undefined;
264− while (true) {
265− const resp = await tools.api.list({ limit: 100, since: cursor });
266− allItems.push(...resp.items);
267− if (!resp.pagination?.next) break;
268− cursor = resp.pagination.next;
269− }
270− \`\`\`
271−- Return a structured result from your script, then summarize what happened
272−- Be concise and accurate — base your response on actual tool results, not assumptions`;
273−}
274−
275−// ---------------------------------------------------------------------------
276−// Agent
277−// ---------------------------------------------------------------------------
278−
279−export function createAgent(options: AgentOptions): {
280− run(prompt: string): Promise<AgentResult>;
281−} {
282− const {
283− tools,
284− model,
285− requestApproval,
286− runner: providedRunner,
287− onEvent,
288− maxTypecheckRetries = 3,
289− maxCodeRuns = 100,
290− timeoutMs = 30_000,
291− discoveryThreshold = DISCOVERY_THRESHOLD,
292− context,
293− } = options;
294−
295− const { sandboxTools, promptGuidance, toolDeclarations, discoveryMode } =
296− prepareToolsForAgent(tools, discoveryThreshold);
297−
298− const runner = providedRunner ?? (() => {
299− if (!requestApproval) {
300− throw new Error("createAgent requires requestApproval when runner is not provided");
301− }
302− return createRunner({
303− tools: sandboxTools,
304− requestApproval,
305− timeoutMs,
306− });
307− })();
308−
309− function emit(event: TaskEvent): void {
310− onEvent?.(event);
311− }
312−
313− return {
314− async run(prompt: string): Promise<AgentResult> {
315− const systemPrompt = buildSystemPrompt(promptGuidance, discoveryMode, context);
316− const runs: CodeRun[] = [];
317− const allReceipts: ToolCallReceipt[] = [];
318−
319− const messages: Message[] = [
320− { role: "system", content: systemPrompt },
321− { role: "user", content: prompt },
322− ];
323−
324− emit({ type: "status", message: "Thinking..." });
325−
326− let codeRunCount = 0;
327−
328− while (codeRunCount < maxCodeRuns) {
329− const response = await model.generate(messages);
330−
331− // If the model returned text without tool calls, we're done
332− if (!response.toolCalls || response.toolCalls.length === 0) {
333− const text = response.text ?? "";
334− emit({ type: "agent_message", text });
335− emit({ type: "completed", receipts: allReceipts });
336− return { text, runs, allReceipts };
337− }
338−
339− // Process each tool call (should be run_code)
340− for (const toolCall of response.toolCalls) {
341− if (toolCall.name !== "run_code") {
342− // Unknown tool call — tell the model
343− messages.push({
344− role: "assistant",
345− content: "",
346− toolCalls: [toolCall],
347− });
348− messages.push({
349− role: "tool",
350− toolCallId: toolCall.id,
351− content: `Error: Unknown tool "${toolCall.name}". Use run_code to execute TypeScript code.`,
352− });
353− continue;
354− }
355−
356− const code = String(toolCall.args["code"] ?? "");
357− codeRunCount++;
358−
359− emit({ type: "code_generated", code });
360−
361− // Typecheck with retries
362− let finalCode = code;
363− let typecheckOk = false;
364− let typecheckErrors: readonly string[] = [];
365−
366− for (let attempt = 0; attempt <= maxTypecheckRetries; attempt++) {
367− const check = typecheckCode(finalCode, toolDeclarations);
368− if (check.ok) {
369− typecheckOk = true;
370− break;
371− }
372−
373− typecheckErrors = check.errors;
374−
375− if (attempt < maxTypecheckRetries) {
376− emit({
377− type: "status",
378− message: `Typecheck failed (attempt ${attempt + 1}/${maxTypecheckRetries + 1}), retrying...`,
379− });
380−
381− // Ask the model to fix the code
382− const fixMessages: Message[] = [
383− ...messages,
384− {
385− role: "assistant",
386− content: "",
387− toolCalls: [toolCall],
388− },
389− {
390− role: "tool",
391− toolCallId: toolCall.id,
392− content: `Typecheck errors:\n${check.errors.join("\n")}\n\nPlease fix the code and try again.`,
393− },
394− ];
395−
396− const fixResponse = await model.generate(fixMessages);
397− if (fixResponse.toolCalls?.[0]?.name === "run_code") {
398− finalCode = String(fixResponse.toolCalls[0].args["code"] ?? "");
399− emit({ type: "code_generated", code: finalCode });
400− } else {
401− // Model gave up — use the original code
402− break;
403− }
404− }
405− }
406−
407− // Execute the code
408− emit({ type: "status", message: "Running code..." });
409− const result = await runner.run(finalCode);
410−
411− // Emit receipts
412− for (const receipt of result.receipts) {
413− emit({ type: "tool_result", receipt });
414− allReceipts.push(receipt);
415− }
416−
417− runs.push({ code: finalCode, typecheckOk, result });
418−
419− // Build the tool result message for the model
420− const receiptSummary = result.receipts
421− .map((r) => {
422− const status = r.status === "succeeded" ? "OK" : r.status === "denied" ? "DENIED" : "FAILED";
423− const output = r.outputPreview ? ` → ${r.outputPreview}` : "";
424− const error = r.error ? ` (${r.error})` : "";
425− return `[${status}] ${r.toolPath}(${r.inputPreview})${output}${error}`;
426− })
427− .join("\n");
428−
429− const resultContent = typecheckOk
430− ? result.ok
431− ? `Code executed successfully.\n\nTool call results:\n${receiptSummary}\n\nReturn value: ${JSON.stringify(result.value)}`
432− : `Code execution had issues.\n\nTool call results:\n${receiptSummary}\n\nError: ${result.error}`
433− : `Typecheck failed after ${maxTypecheckRetries + 1} attempts:\n${typecheckErrors.join("\n")}`;
434−
435− messages.push({
436− role: "assistant",
437− content: "",
438− toolCalls: [{ ...toolCall, args: { code: finalCode } }],
439− });
440− messages.push({
441− role: "tool",
442− toolCallId: toolCall.id,
443− content: resultContent,
444− });
445− }
446− }
447−
448− // Hit max code runs
449− const text = "I've reached the maximum number of code executions for this task.";
450− emit({ type: "agent_message", text });
451− emit({ type: "completed", receipts: allReceipts });
452− return { text, runs, allReceipts };
453− },
454− };
455−}
assistant/legacy/openassistant/packages/core/src/discovery.ts+0−237
@@ -1,237 +0,0 @@
1−/**
2− * Tool discovery — searchable index of tools for large APIs.
3− *
4− * The LLM uses `tools.discover({ query, depth? })` to find tools and
5− * control how much type detail to retrieve:
6− *
7− * - depth 0 (default): paths, descriptions, input args only. Cheap in tokens.
8− * - depth 1: adds return types with top-level properties.
9− * - depth 2: full return types with nested objects expanded.
10− *
11− * The discovered tools are already wired in the sandbox — the LLM
12− * just doesn't get told about all of them in the system prompt.
13− * `discover` fills that gap on demand.
14− */
15−
16−import { defineTool, isToolDefinition, type ToolDefinition, type ToolTree } from "./tools.js";
17−import { getArgsTypeString, getReturnsTypeString } from "./typechecker.js";
18−import { z } from "zod";
19−
20−// ---------------------------------------------------------------------------
21−// Index entry
22−// ---------------------------------------------------------------------------
23−
24−export interface ToolIndexEntry {
25− /** Full dotted path: "posthog.feature_flags.list" */
26− readonly path: string;
27− /** Tool description */
28− readonly description: string;
29− /** Approval mode */
30− readonly approval: "auto" | "required";
31− /** Full args type string (always available) */
32− readonly argsType: string;
33− /** Full returns type string (may be large for OpenAPI tools) */
34− readonly returnsType: string;
35− /** Searchable text (lowercase): path + description */
36− readonly searchText: string;
37−}
38−
39−// ---------------------------------------------------------------------------
40−// Build index
41−// ---------------------------------------------------------------------------
42−
43−export function buildToolIndex(tree: ToolTree): ToolIndexEntry[] {
44− const entries: ToolIndexEntry[] = [];
45−
46− function walk(node: ToolTree, prefix: string) {
47− for (const [key, value] of Object.entries(node)) {
48− const path = prefix ? `${prefix}.${key}` : key;
49− if (isToolDefinition(value)) {
50− const tool = value as ToolDefinition;
51− const returnsType = getReturnsTypeString(tool);
52− // Detect paginated endpoints from return type
53− const isPaginated = /\bpagination\b|\bnext_cursor\b|\bhas_more\b|\bnextPage\b/.test(returnsType);
54− const description = isPaginated
55− ? `${tool.description} (⚠️ paginated — loop until pagination.next is null to get all results)`
56− : tool.description;
57− entries.push({
58− path,
59− description,
60− approval: tool.approval,
61− argsType: getArgsTypeString(tool),
62− returnsType,
63− searchText: `${path} ${description}`.toLowerCase(),
64− });
65− } else {
66− walk(value as ToolTree, path);
67− }
68− }
69− }
70−
71− walk(tree, "");
72− return entries;
73−}
74−
75−// ---------------------------------------------------------------------------
76−// Strip JSDoc comments from type strings
77−// ---------------------------------------------------------------------------
78−
79−function stripJSDoc(typeStr: string): string {
80− return typeStr
81− .replace(/\/\*\*[^]*?\*\//g, "") // block comments
82− .replace(/\n\s*\n/g, "\n") // collapse blank lines
83− .trim();
84−}
85−
86−// ---------------------------------------------------------------------------
87−// Format signature at different depths
88−// ---------------------------------------------------------------------------
89−
90−/**
91− * Build a signature string for a tool at a given depth:
92− * - depth 0: input args only, no return type
93− * - depth 1: input args + return type (JSDoc stripped for conciseness)
94− * - depth 2: input args + full return type (with JSDoc)
95− */
96−function formatSignature(entry: ToolIndexEntry, depth: number): string {
97− const args = depth >= 2 ? entry.argsType : stripJSDoc(entry.argsType);
98−
99− if (depth === 0) {
100− return `(input: ${args}): Promise<...>`;
101− }
102−
103− const returns = depth >= 2 ? entry.returnsType : stripJSDoc(entry.returnsType);
104− return `(input: ${args}): Promise<${returns}>`;
105−}
106−
107−// ---------------------------------------------------------------------------
108−// Search
109−// ---------------------------------------------------------------------------
110−
111−/**
112− * Keyword search with fuzzy matching. Scores entries by how many
113− * query terms match, with bonuses for path matches. An entry only
114− * needs to match at least half the terms (rounded up) to be included,
115− * so "github issues list update" finds tools matching any 2+ of those words.
116− */
117−function searchIndex(
118− index: ToolIndexEntry[],
119− query: string,
120− limit: number,
121−): ToolIndexEntry[] {
122− const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
123− if (terms.length === 0) return index.slice(0, limit);
124−
125− // Minimum terms that must match: at least 1, or half rounded up for 3+ terms
126− const minMatches = terms.length <= 2 ? 1 : Math.ceil(terms.length / 2);
127−
128− const scored = index
129− .map((entry) => {
130− let score = 0;
131− let matched = 0;
132−
133− for (const term of terms) {
134− const inText = entry.searchText.includes(term);
135− const inPath = entry.path.toLowerCase().includes(term);
136−
137− if (!inText && !inPath) continue;
138−
139− matched++;
140− score += 1;
141− // Bonus for path match (more specific)
142− if (inPath) score += 2;
143− // Bonus for exact word boundary match
144− if (entry.searchText.includes(` ${term}`) || entry.searchText.startsWith(term)) score += 1;
145− }
146−
147− if (matched < minMatches) return { entry, score: -1 };
148− // Bonus for matching more terms
149− score += matched * 2;
150− return { entry, score };
151− })
152− .filter((s) => s.score > 0)
153− .sort((a, b) => b.score - a.score)
154− .slice(0, limit);
155−
156− return scored.map((s) => s.entry);
157−}
158−
159−// ---------------------------------------------------------------------------
160−// Create discover tool
161−// ---------------------------------------------------------------------------
162−
163−export interface DiscoverToolOptions {
164− /** Max results to return per query. Defaults to 20. */
165− readonly maxResults?: number;
166−}
167−
168−/**
169− * Create a `discover` tool that searches the tool index.
170− *
171− * Usage in LLM-generated code:
172− * // Find tools — returns top 5 with input args + return types
173− * const results = await tools.discover({ query: "feature flags" });
174− * // Then call: await tools.posthog.feature_flags.list({ ... })
175− */
176−export function createDiscoverTool(
177− tree: ToolTree,
178− options?: DiscoverToolOptions,
179−) {
180− const index = buildToolIndex(tree);
181− const maxResults = options?.maxResults ?? 20;
182−
183− return defineTool({
184− description: `Search for available tools by keyword. Returns matching tool paths, descriptions, and type signatures (including return types). There are ${index.length} tools available.
185−
186−depth controls how much type detail to return:
187−- depth 0: input args only, return type hidden. Use to browse many results cheaply.
188−- depth 1 (default): input args + return types. Shows response shapes so you can handle pagination, nested fields, etc.
189−- depth 2: full signatures with JSDoc comments and examples. Use when you need exact details.
190−
191−limit controls how many results to return (default: 5, max: ${maxResults}). Use higher limits with depth 0 for broad browsing.`,
192− approval: "auto" as const,
193− args: z.object({
194− query: z.string().describe("Search keywords (e.g. 'feature flags', 'create user', 'list issues')"),
195− depth: z.number().optional().describe("Type detail level: 0 = args only, 1 (default) = + return types, 2 = + JSDoc comments"),
196− limit: z.number().optional().describe("Max results to return (default: 5)"),
197− }),
198− returns: z.object({
199− results: z.array(z.object({
200− path: z.string(),
201− description: z.string(),
202− approval: z.string(),
203− signature: z.string(),
204− })),
205− total: z.number(),
206− }),
207− run: async (input) => {
208− const depth = input.depth ?? 1;
209− const limit = Math.min(input.limit ?? 5, maxResults);
210− const results = searchIndex(index, input.query, limit);
211− return {
212− results: results.map((e) => ({
213− path: e.path,
214− description: e.description,
215− approval: e.approval,
216− signature: formatSignature(e, depth),
217− })),
218− total: results.length,
219− };
220− },
221− });
222−}
223−
224−/**
225− * Count the total number of tool definitions in a tree.
226− */
227−export function countTools(tree: ToolTree): number {
228− let count = 0;
229− for (const value of Object.values(tree)) {
230− if (isToolDefinition(value)) {
231− count++;
232− } else {
233− count += countTools(value as ToolTree);
234− }
235− }
236− return count;
237−}
assistant/legacy/openassistant/packages/core/src/events.ts+0−60
@@ -1,60 +0,0 @@
1−/**
2− * Task event types — the stream of events produced by every task run.
3− * Clients subscribe to these and render them however they want.
4− */
5−
6−import type { ApprovalPresentation, ToolCallReceipt } from "./tools.js";
7−
8−export type TaskEvent =
9− | TaskStatusEvent
10− | TaskCodeGeneratedEvent
11− | TaskApprovalRequestEvent
12− | TaskApprovalResolvedEvent
13− | TaskToolResultEvent
14− | TaskAgentMessageEvent
15− | TaskErrorEvent
16− | TaskCompletedEvent;
17−
18−export interface TaskStatusEvent {
19− readonly type: "status";
20− readonly message: string;
21−}
22−
23−export interface TaskCodeGeneratedEvent {
24− readonly type: "code_generated";
25− readonly code: string;
26−}
27−
28−export interface TaskApprovalRequestEvent {
29− readonly type: "approval_request";
30− readonly id: string;
31− readonly toolPath: string;
32− readonly input: unknown;
33− readonly preview: ApprovalPresentation;
34−}
35−
36−export interface TaskApprovalResolvedEvent {
37− readonly type: "approval_resolved";
38− readonly id: string;
39− readonly decision: "approved" | "denied";
40−}
41−
42−export interface TaskToolResultEvent {
43− readonly type: "tool_result";
44− readonly receipt: ToolCallReceipt;
45−}
46−
47−export interface TaskAgentMessageEvent {
48− readonly type: "agent_message";
49− readonly text: string;
50−}
51−
52−export interface TaskErrorEvent {
53− readonly type: "error";
54− readonly error: string;
55−}
56−
57−export interface TaskCompletedEvent {
58− readonly type: "completed";
59− readonly receipts: readonly ToolCallReceipt[];
60−}
assistant/legacy/openassistant/packages/core/src/index.ts+0−85
@@ -1,85 +0,0 @@
1−// Tool system
2−export {
3− defineTool,
4− isToolDefinition,
5− walkToolTree,
6− mergeToolTrees,
7− type ApprovalMode,
8− type ApprovalDecision,
9− type ApprovalPresentation,
10− type ApprovalRequest,
11− type ReceiptDecision,
12− type ReceiptStatus,
13− type ToolCallReceipt,
14− type ToolDefinition,
15− type ToolTree,
16− type DefineToolInput,
17−} from "./tools.js";
18−
19−// Runner (sandbox execution)
20−export {
21− createRunner,
22− ToolDeniedError,
23− type Runner,
24− type RunnerOptions,
25− type RunResult,
26−} from "./runner.js";
27−
28−// Remote runner (executor HTTP transport)
29−export {
30− createRemoteRunner,
31− type RemoteRunnerOptions,
32− type ExecutorRunRequest,
33− type ExecutorInvokeRequest,
34− type ExecutorInvokeResponse,
35− type ExecutorToolManifestEntry,
36−} from "./remote-runner.js";
37−
38−// Typechecker
39−export {
40− zodToTypeString,
41− generateToolDeclarations,
42− generatePromptGuidance,
43− typecheckCode,
44− type TypecheckResult,
45−} from "./typechecker.js";
46−
47−// Agent loop
48−export {
49− createAgent,
50− type LanguageModel,
51− type Message,
52− type ToolCall,
53− type GenerateResult,
54− type AgentOptions,
55− type AgentResult,
56− type CodeRun,
57−} from "./agent.js";
58−
59−// pi-ai adapter
60−export {
61− createPiAiModel,
62− type PiAiModelOptions,
63−} from "./pi-ai-adapter.js";
64−
65−// Discovery
66−export {
67− buildToolIndex,
68− createDiscoverTool,
69− countTools,
70− type ToolIndexEntry,
71− type DiscoverToolOptions,
72−} from "./discovery.js";
73−
74−// Events
75−export type {
76− TaskEvent,
77− TaskStatusEvent,
78− TaskCodeGeneratedEvent,
79− TaskApprovalRequestEvent,
80− TaskApprovalResolvedEvent,
81− TaskToolResultEvent,
82− TaskAgentMessageEvent,
83− TaskErrorEvent,
84− TaskCompletedEvent,
85−} from "./events.js";
assistant/legacy/openassistant/packages/core/src/loop.test.ts+0−219
@@ -1,219 +0,0 @@
1−/**
2− * Test: sandbox loop behavior — list items, then mutate each in a for loop.
3− * Reproduces the "works for 1, breaks for many" issue.
4− */
5−
6−import { test, expect, describe } from "bun:test";
7−import { createRunner } from "./runner.js";
8−import { defineTool, type ToolTree } from "./tools.js";
9−import { z } from "zod";
10−
11−// Simulate an API: list items, then update each
12−const items = [
13− { id: 1, title: "Issue 1", state: "closed" },
14− { id: 2, title: "Issue 2", state: "closed" },
15− { id: 3, title: "Issue 3", state: "closed" },
16− { id: 4, title: "Issue 4", state: "closed" },
17− { id: 5, title: "Issue 5", state: "closed" },
18−];
19−
20−let updateCallCount = 0;
21−
22−const tools: ToolTree = {
23− api: {
24− list_items: defineTool({
25− description: "List items",
26− approval: "auto",
27− args: z.object({ state: z.string().optional() }),
28− returns: z.array(z.object({ id: z.number(), title: z.string(), state: z.string() })),
29− run: async (input) => {
30− const filtered = input.state
31− ? items.filter((i) => i.state === input.state)
32− : items;
33− return filtered;
34− },
35− }),
36− update_item: defineTool({
37− description: "Update an item",
38− approval: "auto",
39− args: z.object({ id: z.number(), state: z.string() }),
40− returns: z.object({ id: z.number(), state: z.string() }),
41− run: async (input) => {
42− updateCallCount++;
43− // Simulate a small network delay
44− await new Promise((r) => setTimeout(r, 10));
45− return { id: input.id, state: input.state };
46− },
47− }),
48− },
49−};
50−
51−describe("sandbox loop — list then mutate each", () => {
52− test("for loop with await works for multiple items", async () => {
53− updateCallCount = 0;
54−
55− const runner = createRunner({
56− tools,
57− requestApproval: async () => "approved",
58− timeoutMs: 30_000,
59− });
60−
61− const code = `
62−const items = await tools.api.list_items({ state: "closed" });
63−
64−const results = [];
65−for (const item of items) {
66− const updated = await tools.api.update_item({ id: item.id, state: "open" });
67− results.push(updated);
68−}
69−
70−return { total: results.length, results };
71−`;
72−
73− const result = await runner.run(code);
74−
75− console.log("Result:", JSON.stringify(result.value));
76− console.log("OK:", result.ok);
77− console.log("Error:", result.error);
78− console.log("Receipts:", result.receipts.length);
79− console.log("Update calls:", updateCallCount);
80−
81− expect(result.ok).toBe(true);
82− expect(result.receipts.length).toBe(6); // 1 list + 5 updates
83− expect(updateCallCount).toBe(5);
84− expect((result.value as any).total).toBe(5);
85− });
86−
87− test("Promise.all with map works for multiple items", async () => {
88− updateCallCount = 0;
89−
90− const runner = createRunner({
91− tools,
92− requestApproval: async () => "approved",
93− timeoutMs: 30_000,
94− });
95−
96− const code = `
97−const items = await tools.api.list_items({ state: "closed" });
98−
99−const results = await Promise.all(
100− items.map((item) => tools.api.update_item({ id: item.id, state: "open" }))
101−);
102−
103−return { total: results.length, results };
104−`;
105−
106− const result = await runner.run(code);
107−
108− console.log("Result:", JSON.stringify(result.value));
109− console.log("OK:", result.ok);
110− console.log("Error:", result.error);
111−
112− expect(result.ok).toBe(true);
113− expect(result.receipts.length).toBe(6);
114− expect(updateCallCount).toBe(5);
115− });
116−
117− test("for loop with approval-required tools", async () => {
118− const approvalTools: ToolTree = {
119− api: {
120− list_items: defineTool({
121− description: "List items",
122− approval: "auto",
123− args: z.object({}),
124− returns: z.array(z.object({ id: z.number() })),
125− run: async () => [{ id: 1 }, { id: 2 }, { id: 3 }],
126− }),
127− update_item: defineTool({
128− description: "Update item",
129− approval: "required",
130− args: z.object({ id: z.number(), state: z.string() }),
131− returns: z.object({ id: z.number(), state: z.string() }),
132− run: async (input) => ({ id: input.id, state: input.state }),
133− }),
134− },
135− };
136−
137− const runner = createRunner({
138− tools: approvalTools,
139− requestApproval: async () => "approved",
140− timeoutMs: 30_000,
141− });
142−
143− const code = `
144−const items = await tools.api.list_items({});
145−const results = [];
146−for (const item of items) {
147− const updated = await tools.api.update_item({ id: item.id, state: "open" });
148− results.push(updated);
149−}
150−return { total: results.length, results };
151−`;
152−
153− const result = await runner.run(code);
154−
155− console.log("Approval loop result:", JSON.stringify(result.value));
156− console.log("OK:", result.ok);
157− console.log("Error:", result.error);
158− console.log("Receipts:", result.receipts.length);
159−
160− expect(result.ok).toBe(true);
161− expect(result.receipts.length).toBe(4); // 1 list + 3 updates
162− expect((result.value as any).total).toBe(3);
163− });
164−
165− test("large loop — 20 items", async () => {
166− const manyItems = Array.from({ length: 20 }, (_, i) => ({
167− id: i + 1,
168− title: `Issue ${i + 1}`,
169− state: "closed",
170− }));
171−
172− const manyTools: ToolTree = {
173− api: {
174− list_items: defineTool({
175− description: "List items",
176− approval: "auto",
177− args: z.object({}),
178− returns: z.any(),
179− run: async () => manyItems,
180− }),
181− update_item: defineTool({
182− description: "Update item",
183− approval: "auto",
184− args: z.object({ id: z.number(), state: z.string() }),
185− returns: z.object({ id: z.number(), state: z.string() }),
186− run: async (input) => {
187− await new Promise((r) => setTimeout(r, 5));
188− return { id: input.id, state: input.state };
189− },
190− }),
191− },
192− };
193−
194− const runner = createRunner({
195− tools: manyTools,
196− requestApproval: async () => "approved",
197− timeoutMs: 30_000,
198− });
199−
200− const code = `
201−const items = await tools.api.list_items({});
202−const results = [];
203−for (const item of items) {
204− const updated = await tools.api.update_item({ id: item.id, state: "open" });
205− results.push(updated);
206−}
207−return { total: results.length };
208−`;
209−
210− const result = await runner.run(code);
211−
212− console.log("20 items result:", JSON.stringify(result.value));
213− console.log("OK:", result.ok);
214− console.log("Error:", result.error);
215−
216− expect(result.ok).toBe(true);
217− expect((result.value as any).total).toBe(20);
218− });
219−});
assistant/legacy/openassistant/packages/core/src/pi-ai-adapter.ts+0−217
@@ -1,217 +0,0 @@
1−/**
2− * pi-ai adapter — implements our LanguageModel interface using pi-ai.
3− *
4− * Supports Claude Max (via ANTHROPIC_OAUTH_TOKEN), Anthropic API keys,
5− * and any other provider pi-ai supports.
6− */
7−
8−import {
9− completeSimple,
10− getModel,
11− type Context as PiContext,
12− type Message as PiMessage,
13− type UserMessage,
14− type AssistantMessage as PiAssistantMessage,
15− type ToolResultMessage,
16− type Tool as PiTool,
17− type SimpleStreamOptions,
18− type TextContent,
19− type ToolCall as PiToolCall,
20−} from "@mariozechner/pi-ai";
21−import { Type } from "@sinclair/typebox";
22−import type { LanguageModel, Message, GenerateResult, ToolCall } from "./agent.js";
23−
24−// ---------------------------------------------------------------------------
25−// Config
26−// ---------------------------------------------------------------------------
27−
28−export interface PiAiModelOptions {
29− /** pi-ai provider name (e.g., "anthropic", "openai"). Defaults to "anthropic". */
30− readonly provider?: string | undefined;
31− /** pi-ai model ID (e.g., "claude-sonnet-4-5"). Defaults to "claude-sonnet-4-5". */
32− readonly modelId?: string | undefined;
33− /** API key. If not provided, uses ANTHROPIC_OAUTH_TOKEN or ANTHROPIC_API_KEY env vars. */
34− readonly apiKey?: string | undefined;
35− /** Thinking level for reasoning models. */
36− readonly reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh" | undefined;
37− /** Max tokens for the response. */
38− readonly maxTokens?: number | undefined;
39−}
40−
41−// ---------------------------------------------------------------------------
42−// The run_code tool definition for pi-ai (TypeBox schema)
43−// ---------------------------------------------------------------------------
44−
45−const RUN_CODE_TOOL: PiTool = {
46− name: "run_code",
47− description:
48− "Execute TypeScript code in a sandboxed environment. The code has access to a `tools` object with typed methods for interacting with external services. The code should use `return` to return a value.",
49− parameters: Type.Object({
50− code: Type.String({
51− description: "The TypeScript code to execute. Use `await tools.<namespace>.<method>(input)` to call tools. Use `return` to return a value.",
52− }),
53− }),
54−};
55−
56−// ---------------------------------------------------------------------------
57−// Message conversion: our format → pi-ai format
58−// ---------------------------------------------------------------------------
59−
60−function convertMessages(messages: Message[]): { systemPrompt: string | undefined; piMessages: PiMessage[] } {
61− let systemPrompt: string | undefined;
62− const piMessages: PiMessage[] = [];
63−
64− for (const msg of messages) {
65− if (msg.role === "system") {
66− systemPrompt = msg.content;
67− continue;
68− }
69−
70− if (msg.role === "user") {
71− piMessages.push({
72− role: "user",
73− content: msg.content,
74− timestamp: Date.now(),
75− } satisfies UserMessage);
76− continue;
77− }
78−
79− if (msg.role === "assistant") {
80− if ("toolCalls" in msg && msg.toolCalls) {
81− // Assistant message with tool calls
82− const content: (TextContent | PiToolCall)[] = [];
83− if (msg.content) {
84− content.push({ type: "text", text: msg.content });
85− }
86− for (const tc of msg.toolCalls) {
87− content.push({
88− type: "toolCall",
89− id: tc.id,
90− name: tc.name,
91− arguments: tc.args,
92− });
93− }
94− piMessages.push({
95− role: "assistant",
96− content,
97− api: "anthropic-messages",
98− provider: "anthropic",
99− model: "",
100− usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
101− stopReason: "toolUse",
102− timestamp: Date.now(),
103− } satisfies PiAssistantMessage);
104− } else {
105− // Plain text assistant message
106− piMessages.push({
107− role: "assistant",
108− content: [{ type: "text", text: msg.content }],
109− api: "anthropic-messages",
110− provider: "anthropic",
111− model: "",
112− usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
113− stopReason: "stop",
114− timestamp: Date.now(),
115− } satisfies PiAssistantMessage);
116− }
117− continue;
118− }
119−
120− if (msg.role === "tool") {
121− piMessages.push({
122− role: "toolResult",
123− toolCallId: msg.toolCallId,
124− toolName: "run_code",
125− content: [{ type: "text", text: msg.content }],
126− isError: false,
127− timestamp: Date.now(),
128− } satisfies ToolResultMessage);
129− continue;
130− }
131− }
132−
133− return { systemPrompt, piMessages };
134−}
135−
136−// ---------------------------------------------------------------------------
137−// Response conversion: pi-ai format → our format
138−// ---------------------------------------------------------------------------
139−
140−function convertResponse(response: PiAssistantMessage): GenerateResult {
141− const toolCalls: ToolCall[] = [];
142− const textParts: string[] = [];
143−
144− for (const block of response.content) {
145− if (block.type === "text") {
146− textParts.push((block as TextContent).text);
147− } else if (block.type === "toolCall") {
148− const tc = block as PiToolCall;
149− toolCalls.push({
150− id: tc.id,
151− name: tc.name,
152− args: tc.arguments,
153− });
154− }
155− // Skip thinking blocks
156− }
157−
158− const text = textParts.join("") || undefined;
159−
160− if (toolCalls.length > 0) {
161− return { text, toolCalls };
162− }
163−
164− return { text };
165−}
166−
167−// ---------------------------------------------------------------------------
168−// Adapter
169−// ---------------------------------------------------------------------------
170−
171−/**
172− * Create a LanguageModel backed by pi-ai.
173− *
174− * Works with Claude Max (set ANTHROPIC_OAUTH_TOKEN env var),
175− * Anthropic API keys (set ANTHROPIC_API_KEY), or any pi-ai provider.
176− */
177−export function createPiAiModel(options: PiAiModelOptions = {}): LanguageModel {
178− const {
179− provider = "anthropic",
180− modelId = "claude-sonnet-4-5",
181− apiKey,
182− reasoning,
183− maxTokens = 8192,
184− } = options;
185−
186− const model = getModel(provider as Parameters<typeof getModel>[0], modelId as never);
187−
188− return {
189− async generate(messages: Message[]): Promise<GenerateResult> {
190− const { systemPrompt, piMessages } = convertMessages(messages);
191−
192− const context: PiContext = {
193− messages: piMessages,
194− tools: [RUN_CODE_TOOL],
195− };
196− if (systemPrompt !== undefined) {
197− context.systemPrompt = systemPrompt;
198− }
199−
200− const streamOptions: SimpleStreamOptions = {
201− maxTokens,
202− };
203−
204− if (apiKey) {
205− streamOptions.apiKey = apiKey;
206− }
207−
208− if (reasoning) {
209− streamOptions.reasoning = reasoning;
210− }
211−
212− const response = await completeSimple(model, context, streamOptions);
213−
214− return convertResponse(response);
215− },
216− };
217−}
assistant/legacy/openassistant/packages/core/src/remote-runner.test.ts+0−89
@@ -1,89 +0,0 @@
1−import { describe, expect, test } from "bun:test";
2−import { z } from "zod";
3−import { defineTool, type ToolTree } from "./tools.js";
4−import { createRemoteRunner } from "./remote-runner.js";
5−
6−describe("remote runner", () => {
7− test("sends run request with tool manifest", async () => {
8− let capturedUrl = "";
9− let capturedBody: unknown;
10−
11− const tools: ToolTree = {
12− math: {
13− add: defineTool({
14− description: "Add two numbers",
15− approval: "auto",
16− args: z.object({ a: z.number(), b: z.number() }),
17− returns: z.number(),
18− run: async (input) => input.a + input.b,
19− }),
20− },
21− db: {
22− delete: defineTool({
23− description: "Delete a row",
24− approval: "required",
25− args: z.object({ id: z.string() }),
26− returns: z.object({ deleted: z.boolean() }),
27− run: async () => ({ deleted: true }),
28− }),
29− },
30− };
31−
32− const runner = createRemoteRunner({
33− tools,
34− executorUrl: "http://executor.local",
35− runId: "run_123",
36− callbackBaseUrl: "http://api.local",
37− callbackToken: "token_123",
38− timeoutMs: 5_000,
39− fetchImpl: async (url, init) => {
40− capturedUrl = String(url);
41− capturedBody = JSON.parse(String(init?.body ?? "{}"));
42− return new Response(
43− JSON.stringify({ ok: true, value: 42, receipts: [] }),
44− { status: 200, headers: { "content-type": "application/json" } },
45− );
46− },
47− });
48−
49− const result = await runner.run("return 42;");
50−
51− expect(capturedUrl).toBe("http://executor.local/internal/execute");
52− expect(result.ok).toBe(true);
53− expect(result.value).toBe(42);
54−
55− const request = capturedBody as {
56− runId: string;
57− timeoutMs: number;
58− callbackBaseUrl: string;
59− callbackToken: string;
60− tools: Array<{ toolPath: string; approval: string }>;
61− };
62− expect(request.runId).toBe("run_123");
63− expect(request.timeoutMs).toBe(5_000);
64− expect(request.callbackBaseUrl).toBe("http://api.local");
65− expect(request.callbackToken).toBe("token_123");
66− expect(request.tools).toContainEqual({ toolPath: "math.add", approval: "auto" });
67− expect(request.tools).toContainEqual({ toolPath: "db.delete", approval: "required" });
68− });
69−
70− test("returns error when executor response is invalid", async () => {
71− const runner = createRemoteRunner({
72− tools: {},
73− executorUrl: "http://executor.local",
74− runId: "run_456",
75− callbackBaseUrl: "http://api.local",
76− callbackToken: "token_456",
77− fetchImpl: async () => {
78− return new Response(JSON.stringify({ nope: true }), {
79− status: 200,
80− headers: { "content-type": "application/json" },
81− });
82− },
83− });
84−
85− const result = await runner.run("return 1;");
86− expect(result.ok).toBe(false);
87− expect(result.error).toContain("invalid response");
88− });
89−});
assistant/legacy/openassistant/packages/core/src/remote-runner.ts+0−124
@@ -1,124 +0,0 @@
1−import type { ApprovalMode, ToolTree } from "./tools.js";
2−import { walkToolTree } from "./tools.js";
3−import type { RunResult, Runner } from "./runner.js";
4−
5−export interface ExecutorToolManifestEntry {
6− readonly toolPath: string;
7− readonly approval: ApprovalMode;
8−}
9−
10−export interface ExecutorRunRequest {
11− readonly runId: string;
12− readonly code: string;
13− readonly timeoutMs: number;
14− readonly callbackBaseUrl: string;
15− readonly callbackToken: string;
16− readonly tools: readonly ExecutorToolManifestEntry[];
17−}
18−
19−export interface ExecutorInvokeRequest {
20− readonly toolPath: string;
21− readonly input: unknown;
22−}
23−
24−export interface ExecutorInvokeResponse {
25− readonly ok: boolean;
26− readonly value?: unknown;
27− readonly error?: string;
28− readonly denied?: boolean;
29−}
30−
31−export interface RemoteRunnerOptions {
32− readonly tools: ToolTree;
33− readonly executorUrl: string;
34− readonly runId: string;
35− readonly callbackBaseUrl: string;
36− readonly callbackToken: string;
37− readonly timeoutMs?: number | undefined;
38− readonly fetchImpl?: FetchLike | undefined;
39−}
40−
41−const DEFAULT_TIMEOUT_MS = 30_000;
42−type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
43−
44−function trimTrailingSlash(value: string): string {
45− return value.endsWith("/") ? value.slice(0, -1) : value;
46−}
47−
48−function buildToolManifest(tools: ToolTree): ExecutorToolManifestEntry[] {
49− const manifest: ExecutorToolManifestEntry[] = [];
50− walkToolTree(tools, (toolPath, tool) => {
51− manifest.push({ toolPath, approval: tool.approval });
52− });
53− return manifest;
54−}
55−
56−function isRunResult(value: unknown): value is RunResult {
57− if (!value || typeof value !== "object") return false;
58− const record = value as Record<string, unknown>;
59− return typeof record["ok"] === "boolean" && Array.isArray(record["receipts"]);
60−}
61−
62−export function createRemoteRunner(options: RemoteRunnerOptions): Runner {
63− const {
64− tools,
65− executorUrl,
66− runId,
67− callbackBaseUrl,
68− callbackToken,
69− timeoutMs = DEFAULT_TIMEOUT_MS,
70− fetchImpl = fetch as FetchLike,
71− } = options;
72−
73− const endpoint = `${trimTrailingSlash(executorUrl)}/internal/execute`;
74− const manifest = buildToolManifest(tools);
75−
76− return {
77− async run(code: string): Promise<RunResult> {
78− const payload: ExecutorRunRequest = {
79− runId,
80− code,
81− timeoutMs,
82− callbackBaseUrl,
83− callbackToken,
84− tools: manifest,
85− };
86−
87− try {
88− const response = await fetchImpl(endpoint, {
89− method: "POST",
90− headers: {
91− "content-type": "application/json",
92− },
93− body: JSON.stringify(payload),
94− });
95−
96− if (!response.ok) {
97− return {
98− ok: false,
99− error: `Executor request failed: HTTP ${response.status}`,
100− receipts: [],
101− };
102− }
103−
104− const result = await response.json();
105− if (!isRunResult(result)) {
106− return {
107− ok: false,
108− error: "Executor returned an invalid response",
109− receipts: [],
110− };
111− }
112−
113− return result;
114− } catch (error) {
115− const message = error instanceof Error ? error.message : String(error);
116− return {
117− ok: false,
118− error: `Executor request failed: ${message}`,
119− receipts: [],
120− };
121− }
122− },
123− };
124−}
assistant/legacy/openassistant/packages/core/src/runner.test.ts+0−453
@@ -1,453 +0,0 @@
1−import { describe, test, expect } from "bun:test";
2−import { z } from "zod";
3−import { defineTool, type ToolTree, type ApprovalDecision } from "./tools.js";
4−import { createRunner, ToolDeniedError } from "./runner.js";
5−
6−// ---------------------------------------------------------------------------
7−// Test helpers
8−// ---------------------------------------------------------------------------
9−
10−function mathTools() {
11− return {
12− math: {
13− add: defineTool({
14− description: "Add two numbers",
15− approval: "auto",
16− args: z.object({ a: z.number(), b: z.number() }),
17− returns: z.number(),
18− run: async (input) => input.a + input.b,
19− }),
20− multiply: defineTool({
21− description: "Multiply two numbers",
22− approval: "auto",
23− args: z.object({ a: z.number(), b: z.number() }),
24− returns: z.number(),
25− run: async (input) => input.a * input.b,
26− }),
27− },
28− } satisfies ToolTree;
29−}
30−
31−function writeTools(sideEffects: string[]) {
32− return {
33− db: {
34− insert: defineTool({
35− description: "Insert a record",
36− approval: "required",
37− args: z.object({ table: z.string(), data: z.record(z.string(), z.unknown()) }),
38− returns: z.object({ id: z.string() }),
39− run: async (input) => {
40− sideEffects.push(`insert:${input.table}`);
41− return { id: "new_1" };
42− },
43− formatApproval: (input) => ({
44− title: `Insert into ${input.table}`,
45− }),
46− }),
47− delete: defineTool({
48− description: "Delete a record",
49− approval: "required",
50− args: z.object({ table: z.string(), id: z.string() }),
51− returns: z.object({ deleted: z.boolean() }),
52− run: async (input) => {
53− sideEffects.push(`delete:${input.table}:${input.id}`);
54− return { deleted: true };
55− },
56− formatApproval: (input) => ({
57− title: `Delete ${input.id} from ${input.table}`,
58− }),
59− }),
60− },
61− } satisfies ToolTree;
62−}
63−
64−let callIdSeq = 0;
65−function testCallId() {
66− return `test_${++callIdSeq}`;
67−}
68−
69−function alwaysApprove() {
70− return async (_req: unknown) => "approved" as ApprovalDecision;
71−}
72−
73−function alwaysDeny() {
74− return async (_req: unknown) => "denied" as ApprovalDecision;
75−}
76−
77−// ---------------------------------------------------------------------------
78−// Tests
79−// ---------------------------------------------------------------------------
80−
81−describe("runner — sandbox isolation", () => {
82− test("blocks fetch", async () => {
83− const runner = createRunner({
84− tools: mathTools(),
85− requestApproval: alwaysApprove(),
86− newCallId: testCallId,
87− });
88−
89− const result = await runner.run('return fetch("https://evil.com")');
90− expect(result.ok).toBe(false);
91− expect(result.error).toContain("not available in the sandbox");
92− });
93−
94− test("blocks process", async () => {
95− const runner = createRunner({
96− tools: mathTools(),
97− requestApproval: alwaysApprove(),
98− newCallId: testCallId,
99− });
100−
101− const result = await runner.run("return process.env");
102− expect(result.ok).toBe(false);
103− expect(result.error).toContain("not available in the sandbox");
104− });
105−
106− test("blocks require", async () => {
107− const runner = createRunner({
108− tools: mathTools(),
109− requestApproval: alwaysApprove(),
110− newCallId: testCallId,
111− });
112−
113− const result = await runner.run('return require("fs")');
114− expect(result.ok).toBe(false);
115− expect(result.error).toContain("not available in the sandbox");
116− });
117−
118− test("blocks Bun", async () => {
119− const runner = createRunner({
120− tools: mathTools(),
121− requestApproval: alwaysApprove(),
122− newCallId: testCallId,
123− });
124−
125− const result = await runner.run("return Bun.env");
126− expect(result.ok).toBe(false);
127− expect(result.error).toContain("not available in the sandbox");
128− });
129−
130− test("blocks dynamic import", async () => {
131− const runner = createRunner({
132− tools: mathTools(),
133− requestApproval: alwaysApprove(),
134− newCallId: testCallId,
135− });
136−
137− const result = await runner.run('return await import("node:fs")');
138− expect(result.ok).toBe(false);
139− // The error message varies but it should fail
140− expect(result.error).toBeDefined();
141− });
142−
143− test("constructor chain escape returns sandbox global (no host access)", async () => {
144− const runner = createRunner({
145− tools: mathTools(),
146− requestApproval: alwaysApprove(),
147− newCallId: testCallId,
148− });
149−
150− // The escape returns the sandbox global. Accessing 'process' on it
151− // triggers our blocker getter which throws — that's the correct behavior.
152− // The key thing is: process.env.SECRET etc. are never reachable.
153− const result = await runner.run(`
154− const escaped = [].constructor.constructor("return this")();
155− // escaped is the sandbox global — has no host APIs
156− // Only our injected properties exist on it
157− try {
158− escaped.process;
159− return "BAD: process was accessible";
160− } catch (e) {
161− return "GOOD: process blocked";
162− }
163− `);
164− expect(result.ok).toBe(true);
165− expect(result.value).toBe("GOOD: process blocked");
166− });
167−
168− test("tool function toString is hidden", async () => {
169− const runner = createRunner({
170− tools: mathTools(),
171− requestApproval: alwaysApprove(),
172− newCallId: testCallId,
173− });
174−
175− const result = await runner.run("return tools.math.add.toString()");
176− expect(result.ok).toBe(true);
177− expect(result.value).toBe("function() { [native code] }");
178− });
179−
180− test("execution timeout", async () => {
181− const runner = createRunner({
182− tools: mathTools(),
183− requestApproval: alwaysApprove(),
184− timeoutMs: 100,
185− newCallId: testCallId,
186− });
187−
188− const result = await runner.run("while(true) {}");
189− expect(result.ok).toBe(false);
190− expect(result.error).toContain("timed out");
191− });
192−});
193−
194−describe("runner — auto-approved read tools", () => {
195− test("executes tool and returns result", async () => {
196− const runner = createRunner({
197− tools: mathTools(),
198− requestApproval: alwaysDeny(), // should never be called
199− newCallId: testCallId,
200− });
201−
202− const result = await runner.run("return await tools.math.add({ a: 3, b: 4 })");
203− expect(result.ok).toBe(true);
204− expect(result.value).toBe(7);
205− expect(result.receipts).toHaveLength(1);
206− expect(result.receipts[0]!.decision).toBe("auto");
207− expect(result.receipts[0]!.status).toBe("succeeded");
208− });
209−
210− test("multiple tool calls collect receipts", async () => {
211− const runner = createRunner({
212− tools: mathTools(),
213− requestApproval: alwaysDeny(),
214− newCallId: testCallId,
215− });
216−
217− const result = await runner.run(`
218− const a = await tools.math.add({ a: 1, b: 2 });
219− const b = await tools.math.multiply({ a: a, b: 3 });
220− return b;
221− `);
222− expect(result.ok).toBe(true);
223− expect(result.value).toBe(9);
224− expect(result.receipts).toHaveLength(2);
225− });
226−
227− test("validates input with zod", async () => {
228− const runner = createRunner({
229− tools: mathTools(),
230− requestApproval: alwaysApprove(),
231− newCallId: testCallId,
232− });
233−
234− const result = await runner.run(
235− 'return await tools.math.add({ a: "not a number", b: 2 })',
236− );
237− expect(result.ok).toBe(false);
238− expect(result.receipts).toHaveLength(1);
239− expect(result.receipts[0]!.status).toBe("failed");
240− expect(result.receipts[0]!.error).toContain("validation failed");
241− });
242−});
243−
244−describe("runner — approval flow", () => {
245− test("approved write tool runs", async () => {
246− const sideEffects: string[] = [];
247− const runner = createRunner({
248− tools: writeTools(sideEffects),
249− requestApproval: alwaysApprove(),
250− newCallId: testCallId,
251− });
252−
253− const result = await runner.run(
254− 'return await tools.db.insert({ table: "users", data: { name: "Alice" } })',
255− );
256− expect(result.ok).toBe(true);
257− expect(result.value).toEqual({ id: "new_1" });
258− expect(sideEffects).toEqual(["insert:users"]);
259− expect(result.receipts).toHaveLength(1);
260− expect(result.receipts[0]!.decision).toBe("approved");
261− expect(result.receipts[0]!.status).toBe("succeeded");
262− });
263−
264− test("denied write tool returns undefined and doesn't run", async () => {
265− const sideEffects: string[] = [];
266− const runner = createRunner({
267− tools: writeTools(sideEffects),
268− requestApproval: alwaysDeny(),
269− newCallId: testCallId,
270− });
271−
272− const result = await runner.run(
273− 'return await tools.db.insert({ table: "users", data: { name: "Alice" } })',
274− );
275− expect(result.ok).toBe(false);
276− expect(sideEffects).toEqual([]); // run was never called
277− expect(result.receipts).toHaveLength(1);
278− expect(result.receipts[0]!.decision).toBe("denied");
279− expect(result.receipts[0]!.status).toBe("denied");
280− });
281−
282− test("continues after one denial", async () => {
283− const sideEffects: string[] = [];
284− let callCount = 0;
285− const approveOddDenyEven = async () => {
286− callCount++;
287− return (callCount % 2 === 1 ? "approved" : "denied") as ApprovalDecision;
288− };
289−
290− const runner = createRunner({
291− tools: writeTools(sideEffects),
292− requestApproval: approveOddDenyEven,
293− newCallId: testCallId,
294− });
295−
296− const result = await runner.run(`
297− const r1 = await tools.db.insert({ table: "a", data: {} });
298− const r2 = await tools.db.insert({ table: "b", data: {} });
299− const r3 = await tools.db.insert({ table: "c", data: {} });
300− return [r1, r2, r3];
301− `);
302−
303− // r1 approved, r2 denied (undefined), r3 approved
304− expect(result.ok).toBe(false); // had a denial
305− expect(sideEffects).toEqual(["insert:a", "insert:c"]);
306− expect(result.receipts).toHaveLength(3);
307− expect(result.receipts[0]!.decision).toBe("approved");
308− expect(result.receipts[1]!.decision).toBe("denied");
309− expect(result.receipts[2]!.decision).toBe("approved");
310− });
311−
312− test("approval request includes formatApproval data", async () => {
313− const sideEffects: string[] = [];
314− let capturedRequest: unknown;
315− const runner = createRunner({
316− tools: writeTools(sideEffects),
317− requestApproval: async (req) => {
318− capturedRequest = req;
319− return "approved";
320− },
321− newCallId: testCallId,
322− });
323−
324− await runner.run(
325− 'await tools.db.delete({ table: "users", id: "user_42" })',
326− );
327−
328− expect(capturedRequest).toBeDefined();
329− const req = capturedRequest as { preview: { title: string } };
330− expect(req.preview.title).toBe("Delete user_42 from users");
331− });
332−
333− test("approval request falls back to default preview when formatApproval is missing", async () => {
334− let capturedRequest: unknown;
335− const tools: ToolTree = {
336− vercel: {
337− projects: {
338− deleteProject: defineTool({
339− description: "Delete a project",
340− approval: "required",
341− args: z.object({ idOrName: z.string() }),
342− returns: z.object({ ok: z.boolean() }),
343− run: async () => ({ ok: true }),
344− }),
345− },
346− },
347− };
348−
349− const runner = createRunner({
350− tools,
351− requestApproval: async (req) => {
352− capturedRequest = req;
353− return "denied";
354− },
355− newCallId: testCallId,
356− });
357−
358− await runner.run('await tools.vercel.projects.deleteProject({ idOrName: "prj_123" })');
359−
360− const req = capturedRequest as {
361− preview: {
362− title: string;
363− details?: string;
364− action?: string;
365− resourceIds?: string[];
366− isDestructive?: boolean;
367− };
368− };
369− expect(req.preview.title).toBe("Delete via vercel.projects.deleteProject");
370− expect(req.preview.details).toContain("Target: prj_123");
371− expect(req.preview.action).toBe("delete");
372− expect(req.preview.resourceIds).toEqual(["prj_123"]);
373− expect(req.preview.isDestructive).toBe(true);
374− });
375−});
376−
377−describe("runner — error handling", () => {
378− test("tool denied error is recorded as denied receipt", async () => {
379− const tools: ToolTree = {
380− gated: defineTool({
381− description: "Denied by policy",
382− approval: "auto",
383− args: z.object({}),
384− returns: z.void(),
385− run: async () => {
386− throw new ToolDeniedError("Denied by broker");
387− },
388− }),
389− };
390−
391− const runner = createRunner({
392− tools,
393− requestApproval: alwaysApprove(),
394− newCallId: testCallId,
395− });
396−
397− const result = await runner.run("await tools.gated({})");
398− expect(result.ok).toBe(false);
399− expect(result.receipts).toHaveLength(1);
400− expect(result.receipts[0]!.status).toBe("denied");
401− expect(result.receipts[0]!.decision).toBe("denied");
402− });
403−
404− test("tool run error is caught and recorded", async () => {
405− const tools: ToolTree = {
406− broken: defineTool({
407− description: "Always fails",
408− approval: "auto",
409− args: z.object({}),
410− returns: z.void(),
411− run: async () => {
412− throw new Error("Something went wrong");
413− },
414− }),
415− };
416−
417− const runner = createRunner({
418− tools,
419− requestApproval: alwaysApprove(),
420− newCallId: testCallId,
421− });
422−
423− const result = await runner.run("await tools.broken({})");
424− expect(result.ok).toBe(false);
425− expect(result.receipts).toHaveLength(1);
426− expect(result.receipts[0]!.status).toBe("failed");
427− expect(result.receipts[0]!.error).toBe("Something went wrong");
428− });
429−
430− test("syntax error in code is caught", async () => {
431− const runner = createRunner({
432− tools: mathTools(),
433− requestApproval: alwaysApprove(),
434− newCallId: testCallId,
435− });
436−
437− const result = await runner.run("const x = {{{");
438− expect(result.ok).toBe(false);
439− expect(result.error).toBeDefined();
440− });
441−
442− test("runtime error in code is caught", async () => {
443− const runner = createRunner({
444− tools: mathTools(),
445− requestApproval: alwaysApprove(),
446− newCallId: testCallId,
447− });
448−
449− const result = await runner.run("null.toString()");
450− expect(result.ok).toBe(false);
451− expect(result.error).toBeDefined();
452− });
453−});
assistant/legacy/openassistant/packages/core/src/runner.ts+0−565
@@ -1,565 +0,0 @@
1−/**
2− * Codemode runner — executes LLM-generated TypeScript in a node:vm sandbox.
3− *
4− * The sandbox exposes only the `tools` object. No fetch, no process, no Bun,
5− * no require, no import. Tool functions are wrapped so toString() doesn't
6− * leak implementation source.
7− */
8−
9−import { createContext, runInContext } from "node:vm";
10−import type {
11− ApprovalDecision,
12− ApprovalPresentation,
13− ApprovalRequest,
14− ToolCallReceipt,
15− ToolDefinition,
16− ToolTree,
17−} from "./tools.js";
18−import { isToolDefinition } from "./tools.js";
19−
20−// ---------------------------------------------------------------------------
21−// Types
22−// ---------------------------------------------------------------------------
23−
24−export interface RunResult {
25− readonly ok: boolean;
26− readonly value?: unknown;
27− readonly error?: string;
28− readonly receipts: readonly ToolCallReceipt[];
29−}
30−
31−export interface RunnerOptions {
32− /** The tool tree to expose in the sandbox. */
33− readonly tools: ToolTree;
34− /** Called when a tool with `approval: "required"` is invoked. */
35− readonly requestApproval: (
36− request: ApprovalRequest,
37− ) => Promise<ApprovalDecision>;
38− /** Execution timeout in ms. Defaults to 30_000. */
39− readonly timeoutMs?: number | undefined;
40− /** Injectable clock for testing. */
41− readonly now?: (() => number) | undefined;
42− /** Injectable ID generator for testing. */
43− readonly newCallId?: (() => string) | undefined;
44−}
45−
46−export interface Runner {
47− /** Execute a code string in the sandbox. Never throws. */
48− run(code: string): Promise<RunResult>;
49−}
50−
51−export class ToolDeniedError extends Error {
52− constructor(message = "Tool call denied") {
53− super(message);
54− this.name = "ToolDeniedError";
55− }
56−}
57−
58−// ---------------------------------------------------------------------------
59−// Helpers
60−// ---------------------------------------------------------------------------
61−
62−const MAX_PREVIEW = 180;
63−const MAX_APPROVAL_DETAILS = 500;
64−
65−/**
66− * Generate a human-readable preview of a tool's output value.
67− * Instead of raw JSON, extracts meaningful fields and formats them concisely.
68− */
69−function preview(value: unknown): string {
70− if (value === undefined) return "undefined";
71− if (value === null) return "null";
72− if (typeof value === "string") {
73− return value.length > MAX_PREVIEW ? value.slice(0, MAX_PREVIEW) + "..." : value;
74− }
75− if (typeof value === "number" || typeof value === "boolean") return String(value);
76−
77− // Arrays — show count + preview of first item
78− if (Array.isArray(value)) {
79− if (value.length === 0) return "[] (empty)";
80− const first = previewObject(value[0]);
81− return value.length === 1 ? `[${first}]` : `${value.length} items, first: ${first}`;
82− }
83−
84− // Objects — show key fields concisely
85− if (typeof value === "object" && value !== null) {
86− return previewObject(value);
87− }
88−
89− return String(value);
90−}
91−
92−/**
93− * Preview an object by extracting its most meaningful fields.
94− * Prioritizes fields like name, title, id, status, message, count, total.
95− */
96−function previewObject(obj: unknown): string {
97− if (!obj || typeof obj !== "object") return String(obj);
98−
99− const record = obj as Record<string, unknown>;
100− const keys = Object.keys(record);
101−
102− // Priority fields — show these first if they exist
103− const priority = ["name", "title", "id", "status", "state", "message", "count", "total", "url", "login", "number"];
104− const parts: string[] = [];
105−
106− for (const key of priority) {
107− if (key in record && record[key] != null) {
108− const val = record[key];
109− if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
110− parts.push(`${key}: ${val}`);
111− }
112− }
113− if (parts.length >= 3) break;
114− }
115−
116− // If no priority fields matched, show the first few keys
117− if (parts.length === 0) {
118− for (const key of keys.slice(0, 3)) {
119− const val = record[key];
120− if (val == null) continue;
121− if (typeof val === "string") {
122− parts.push(`${key}: ${val.length > 40 ? val.slice(0, 40) + "..." : val}`);
123− } else if (typeof val === "number" || typeof val === "boolean") {
124− parts.push(`${key}: ${val}`);
125− } else if (Array.isArray(val)) {
126− parts.push(`${key}: [${val.length} items]`);
127− } else {
128− parts.push(`${key}: {...}`);
129− }
130− }
131− }
132−
133− if (parts.length === 0) return `{${keys.length} fields}`;
134−
135− const extra = keys.length > parts.length ? ` +${keys.length - parts.length} more` : "";
136− const result = parts.join(", ") + extra;
137− return result.length > MAX_PREVIEW ? result.slice(0, MAX_PREVIEW) + "..." : result;
138−}
139−
140−function isRecord(value: unknown): value is Record<string, unknown> {
141− return typeof value === "object" && value !== null && !Array.isArray(value);
142−}
143−
144−function inferApprovalAction(toolPath: string): {
145− action: NonNullable<ApprovalPresentation["action"]>;
146− isDestructive: boolean;
147−} {
148− const lower = toolPath.toLowerCase();
149− if (/(delete|remove|destroy|purge)/.test(lower)) {
150− return { action: "delete", isDestructive: true };
151− }
152− if (/(create|add|insert|provision)/.test(lower)) {
153− return { action: "create", isDestructive: false };
154− }
155− if (/(update|set|patch|edit|rename)/.test(lower)) {
156− return { action: "update", isDestructive: false };
157− }
158− if (/(get|list|search|find|read)/.test(lower)) {
159− return { action: "read", isDestructive: false };
160− }
161− return { action: "execute", isDestructive: false };
162−}
163−
164−function inferResourceType(toolPath: string): string | undefined {
165− const parts = toolPath.split(".").filter(Boolean);
166− const candidate = parts.at(-2) ?? parts.at(-1);
167− if (!candidate) return undefined;
168− return candidate
169− .replace(/_/g, " ")
170− .replace(/\b\w/g, (m) => m.toUpperCase());
171−}
172−
173−function extractResourceIds(input: unknown): string[] {
174− if (!isRecord(input)) return [];
175− const ids: string[] = [];
176− const candidateKeys = ["id", "ids", "name", "slug", "key", "idOrName"];
177− for (const key of candidateKeys) {
178− const value = input[key];
179− if (typeof value === "string" || typeof value === "number") {
180− ids.push(String(value));
181− continue;
182− }
183− if (Array.isArray(value)) {
184− for (const item of value) {
185− if (typeof item === "string" || typeof item === "number") {
186− ids.push(String(item));
187− }
188− }
189− }
190− }
191− return ids.slice(0, 5);
192−}
193−
194−function extractCount(input: unknown): number | undefined {
195− if (!isRecord(input)) return undefined;
196− const raw = input["count"];
197− return typeof raw === "number" && Number.isFinite(raw) ? raw : undefined;
198−}
199−
200−function buildDefaultApprovalPresentation(
201− toolPath: string,
202− input: unknown,
203−): ApprovalPresentation {
204− const { action, isDestructive } = inferApprovalAction(toolPath);
205− const actionVerb = action === "execute"
206− ? "Run"
207− : action.charAt(0).toUpperCase() + action.slice(1);
208− const resourceType = inferResourceType(toolPath);
209− const resourceIds = extractResourceIds(input);
210− const count = extractCount(input);
211− const rawPreview = preview(input);
212−
213− const idDetail = resourceIds.length > 0 ? `Target: ${resourceIds.join(", ")}` : undefined;
214− const argsDetail = `Arguments: ${rawPreview}`;
215− const details = [idDetail, argsDetail].filter(Boolean).join("\n");
216−
217− return {
218− title: `${actionVerb} via ${toolPath}`,
219− details: details.length > MAX_APPROVAL_DETAILS
220− ? `${details.slice(0, MAX_APPROVAL_DETAILS)}...`
221− : details,
222− action,
223− isDestructive,
224− ...(resourceType ? { resourceType } : {}),
225− ...(resourceIds.length > 0 ? { resourceIds } : {}),
226− ...(count !== undefined ? { count } : {}),
227− };
228−}
229−
230−function describeError(error: unknown): string {
231− if (error instanceof Error) {
232− // Include cause if present (e.g. nested API errors)
233− const msg = error.message;
234− if (error.cause) {
235− return `${msg} (cause: ${describeError(error.cause)})`;
236− }
237− return msg;
238− }
239− if (typeof error === "string") return error;
240− if (error === null || error === undefined) return String(error);
241− // Try to get a meaningful representation
242− try {
243− const json = JSON.stringify(error, null, 0);
244− // If it's just "{}", try to find something useful
245− if (json === "{}" || json === "[]") {
246− const proto = Object.getPrototypeOf(error);
247− const name = proto?.constructor?.name;
248− return name && name !== "Object" ? `[${name}]` : String(error);
249− }
250− return json;
251− } catch {
252− return String(error);
253− }
254−}
255−
256−let callIdCounter = 0;
257−function defaultNewCallId(): string {
258− return `call_${++callIdCounter}_${Date.now().toString(36)}`;
259−}
260−
261−/**
262− * Wrap a function so toString() doesn't leak the source.
263− */
264−function wrapFn<T extends (...args: unknown[]) => unknown>(fn: T): T {
265− const wrapped = ((...args: unknown[]) => fn(...args)) as T;
266− Object.defineProperty(wrapped, "toString", {
267− value: () => "function() { [native code] }",
268− configurable: false,
269− writable: false,
270− });
271− Object.defineProperty(wrapped, "name", {
272− value: fn.name || "tool",
273− configurable: false,
274− writable: false,
275− });
276− return wrapped;
277−}
278−
279−// ---------------------------------------------------------------------------
280−// Materializer — converts ToolTree to plain JS objects for the sandbox
281−// ---------------------------------------------------------------------------
282−
283−interface MaterializeContext {
284− receipts: ToolCallReceipt[];
285− requestApproval: RunnerOptions["requestApproval"];
286− now: () => number;
287− newCallId: () => string;
288−}
289−
290−function materializeToolTree(
291− tree: ToolTree,
292− ctx: MaterializeContext,
293− prefix = "",
294−): Record<string, unknown> {
295− const result: Record<string, unknown> = {};
296−
297− for (const [key, value] of Object.entries(tree)) {
298− const path = prefix ? `${prefix}.${key}` : key;
299− if (isToolDefinition(value)) {
300− result[key] = createToolInvoker(path, value, ctx);
301− } else {
302− result[key] = materializeToolTree(value as ToolTree, ctx, path);
303− }
304− }
305−
306− return result;
307−}
308−
309−function createToolInvoker(
310− toolPath: string,
311− tool: ToolDefinition,
312− ctx: MaterializeContext,
313−): (...args: unknown[]) => Promise<unknown> {
314− return wrapFn(async (input: unknown) => {
315− const callId = ctx.newCallId();
316− const timestamp = ctx.now();
317− const inputPreview = preview(input);
318−
319− // Validate input with Zod
320− const parseResult = tool.args.safeParse(input);
321− if (!parseResult.success) {
322− const errorMsg = `Input validation failed: ${parseResult.error.message}`;
323− ctx.receipts.push({
324− callId,
325− toolPath,
326− approval: tool.approval,
327− decision: "auto",
328− status: "failed",
329− timestamp,
330− inputPreview,
331− error: errorMsg,
332− });
333− throw new Error(errorMsg);
334− }
335−
336− const validatedInput = parseResult.data;
337−
338− // Check approval for "required" tools
339− if (tool.approval === "required") {
340− const presentation: ApprovalPresentation = tool.formatApproval
341− ? tool.formatApproval(validatedInput)
342− : buildDefaultApprovalPresentation(toolPath, validatedInput);
343−
344− const decision = await ctx.requestApproval({
345− callId,
346− toolPath,
347− input: validatedInput,
348− preview: presentation,
349− });
350−
351− if (decision === "denied") {
352− ctx.receipts.push({
353− callId,
354− toolPath,
355− approval: "required",
356− decision: "denied",
357− status: "denied",
358− timestamp,
359− inputPreview,
360− });
361− return undefined;
362− }
363−
364− // Approved — continue to execution
365− try {
366− const output = await tool.run(validatedInput);
367− ctx.receipts.push({
368− callId,
369− toolPath,
370− approval: "required",
371− decision: "approved",
372− status: "succeeded",
373− timestamp,
374− inputPreview,
375− outputPreview: preview(output),
376− });
377− return output;
378− } catch (error) {
379− const errorMsg = describeError(error);
380− ctx.receipts.push({
381− callId,
382− toolPath,
383− approval: "required",
384− decision: "approved",
385− status: "failed",
386− timestamp,
387− inputPreview,
388− error: errorMsg,
389− });
390− throw error;
391− }
392− }
393−
394− // Auto-approved tool
395− try {
396− const output = await tool.run(validatedInput);
397− ctx.receipts.push({
398− callId,
399− toolPath,
400− approval: "auto",
401− decision: "auto",
402− status: "succeeded",
403− timestamp,
404− inputPreview,
405− outputPreview: preview(output),
406− });
407− return output;
408− } catch (error) {
409− if (error instanceof ToolDeniedError) {
410− ctx.receipts.push({
411− callId,
412− toolPath,
413− approval: "auto",
414− decision: "denied",
415− status: "denied",
416− timestamp,
417− inputPreview,
418− error: error.message,
419− });
420− return undefined;
421− }
422− const errorMsg = describeError(error);
423− ctx.receipts.push({
424− callId,
425− toolPath,
426− approval: "auto",
427− decision: "auto",
428− status: "failed",
429− timestamp,
430− inputPreview,
431− error: errorMsg,
432− });
433− throw error;
434− }
435− });
436−}
437−
438−// ---------------------------------------------------------------------------
439−// Sandbox
440−// ---------------------------------------------------------------------------
441−
442−function createSandboxContext(tools: Record<string, unknown>): object {
443− // Object.create(null) as base — the VM gets its own built-in globals
444− // (Array, Object, Promise, etc.) but nothing from the host.
445− const ctx = createContext(Object.create(null));
446− const g: Record<string, unknown> = runInContext("globalThis", ctx);
447−
448− // Inject tools — the only external capability
449− g["tools"] = tools;
450−
451− // No-op console (sandbox already has no console)
452− g["console"] = {
453− log: () => {},
454− warn: () => {},
455− error: () => {},
456− info: () => {},
457− debug: () => {},
458− };
459−
460− // Explicitly block dangerous things with clear error messages.
461− // The VM's own globals (Array, Object, Math, JSON, Date, Promise, etc.)
462− // are already present and safe — they're sandbox-scoped copies.
463− const blocked = (name: string) => {
464− Object.defineProperty(g, name, {
465− get() {
466− throw new Error(
467− `${name} is not available in the sandbox. Use tools.* to interact with external services.`,
468− );
469− },
470− configurable: false,
471− });
472− };
473− blocked("fetch");
474− blocked("require");
475− blocked("process");
476− blocked("Bun");
477− blocked("setTimeout");
478− blocked("setInterval");
479−
480− return ctx;
481−}
482−
483−// ---------------------------------------------------------------------------
484−// TypeScript → JavaScript transpilation
485−// ---------------------------------------------------------------------------
486−
487−/**
488− * Strip TypeScript syntax (type annotations, `as` casts, interfaces, etc.)
489− * from LLM-generated code so it can run in the `node:vm` sandbox which
490− * only executes JavaScript.
491− *
492− * Uses Bun's built-in transpiler. Falls back to the original code if
493− * transpilation fails (the code might already be valid JS).
494− */
495−function transpileToJS(code: string): string {
496− try {
497− const transpiler = new Bun.Transpiler({ loader: "ts", target: "browser" });
498− // Wrap in an async function so `return` and `await` are valid syntax
499− const wrapped = `async function __run(tools: any) {\n${code}\n}`;
500− const jsWrapped = transpiler.transformSync(wrapped);
501− // Extract the function body
502− const bodyStart = jsWrapped.indexOf("{");
503− const bodyEnd = jsWrapped.lastIndexOf("}");
504− if (bodyStart === -1 || bodyEnd === -1) return code;
505− return jsWrapped.slice(bodyStart + 1, bodyEnd).trim();
506− } catch {
507− // If transpilation fails, return original code — it may already be JS
508− return code;
509− }
510−}
511−
512−// ---------------------------------------------------------------------------
513−// Runner
514−// ---------------------------------------------------------------------------
515−
516−export function createRunner(options: RunnerOptions): Runner {
517− const {
518− tools,
519− requestApproval,
520− timeoutMs = 30_000,
521− now = Date.now,
522− newCallId = defaultNewCallId,
523− } = options;
524−
525− return {
526− async run(code: string): Promise<RunResult> {
527− const receipts: ToolCallReceipt[] = [];
528−
529− const materialCtx: MaterializeContext = {
530− receipts,
531− requestApproval,
532− now,
533− newCallId,
534− };
535−
536− const materializedTools = materializeToolTree(tools, materialCtx);
537− const sandbox = createSandboxContext(materializedTools);
538−
539− try {
540− // Transpile TS → JS (strips type annotations, `as` casts, interfaces, etc.)
541− const jsCode = transpileToJS(code);
542− const wrappedCode = `(async (tools) => {\n"use strict";\n${jsCode}\n})(tools)`;
543− const resultPromise = runInContext(wrappedCode, sandbox, {
544− timeout: timeoutMs,
545− });
546−
547− // runInContext returns a Promise for async code
548− const value = await resultPromise;
549−
550− const hasDenial = receipts.some((r) => r.status === "denied");
551− if (hasDenial) {
552− return { ok: false, value, receipts, error: "One or more tool calls were denied" };
553− }
554−
555− return { ok: true, value, receipts };
556− } catch (error) {
557− return {
558− ok: false,
559− error: describeError(error),
560− receipts,
561− };
562− }
563− },
564− };
565−}
assistant/legacy/openassistant/packages/core/src/tools.test.ts+0−143
@@ -1,143 +0,0 @@
1−import { describe, test, expect } from "bun:test";
2−import { z } from "zod";
3−import {
4− defineTool,
5− isToolDefinition,
6− walkToolTree,
7− mergeToolTrees,
8− type ToolTree,
9−} from "./tools.js";
10−
11−describe("defineTool", () => {
12− test("creates a tool with _tag", () => {
13− const tool = defineTool({
14− description: "Add two numbers",
15− approval: "auto",
16− args: z.object({ a: z.number(), b: z.number() }),
17− returns: z.number(),
18− run: async (input) => input.a + input.b,
19− });
20−
21− expect(tool._tag).toBe("ToolDefinition");
22− expect(tool.description).toBe("Add two numbers");
23− expect(tool.approval).toBe("auto");
24− });
25−
26− test("run function works", async () => {
27− const tool = defineTool({
28− description: "Add",
29− approval: "auto",
30− args: z.object({ a: z.number(), b: z.number() }),
31− returns: z.number(),
32− run: async (input) => input.a + input.b,
33− });
34−
35− expect(await tool.run({ a: 1, b: 2 })).toBe(3);
36− });
37−});
38−
39−describe("isToolDefinition", () => {
40− test("identifies tool definitions", () => {
41− const tool = defineTool({
42− description: "test",
43− approval: "auto",
44− args: z.object({}),
45− returns: z.void(),
46− run: async () => {},
47− });
48−
49− expect(isToolDefinition(tool)).toBe(true);
50− expect(isToolDefinition({ _tag: "ToolDefinition" })).toBe(true);
51− expect(isToolDefinition({})).toBe(false);
52− expect(isToolDefinition(null)).toBe(false);
53− expect(isToolDefinition("string")).toBe(false);
54− });
55−});
56−
57−describe("walkToolTree", () => {
58− test("walks flat tree", () => {
59− const add = defineTool({
60− description: "add",
61− approval: "auto",
62− args: z.object({ a: z.number(), b: z.number() }),
63− returns: z.number(),
64− run: async (input) => input.a + input.b,
65− });
66−
67− const paths: string[] = [];
68− walkToolTree({ add }, (path) => paths.push(path));
69−
70− expect(paths).toEqual(["add"]);
71− });
72−
73− test("walks nested tree", () => {
74− const tool = defineTool({
75− description: "test",
76− approval: "auto",
77− args: z.object({}),
78− returns: z.void(),
79− run: async () => {},
80− });
81−
82− const tree: ToolTree = {
83− github: {
84− issues: {
85− list: tool,
86− close: tool,
87− },
88− },
89− calendar: {
90− update: tool,
91− },
92− };
93−
94− const paths: string[] = [];
95− walkToolTree(tree, (path) => paths.push(path));
96−
97− expect(paths.sort()).toEqual([
98− "calendar.update",
99− "github.issues.close",
100− "github.issues.list",
101− ]);
102− });
103−});
104−
105−describe("mergeToolTrees", () => {
106− test("merges non-overlapping trees", () => {
107− const tool = defineTool({
108− description: "test",
109− approval: "auto",
110− args: z.object({}),
111− returns: z.void(),
112− run: async () => {},
113− });
114−
115− const a: ToolTree = { github: { list: tool } };
116− const b: ToolTree = { calendar: { update: tool } };
117− const merged = mergeToolTrees(a, b);
118−
119− const paths: string[] = [];
120− walkToolTree(merged, (path) => paths.push(path));
121−
122− expect(paths.sort()).toEqual(["calendar.update", "github.list"]);
123− });
124−
125− test("merges overlapping sub-trees", () => {
126− const tool = defineTool({
127− description: "test",
128− approval: "auto",
129− args: z.object({}),
130− returns: z.void(),
131− run: async () => {},
132− });
133−
134− const a: ToolTree = { github: { issues: { list: tool } } };
135− const b: ToolTree = { github: { issues: { close: tool } } };
136− const merged = mergeToolTrees(a, b);
137−
138− const paths: string[] = [];
139− walkToolTree(merged, (path) => paths.push(path));
140−
141− expect(paths.sort()).toEqual(["github.issues.close", "github.issues.list"]);
142− });
143−});
assistant/legacy/openassistant/packages/core/src/tools.ts+0−226
@@ -1,226 +0,0 @@
1−/**
2− * Tool definition system.
3− *
4− * Tools are the capabilities exposed to LLM-generated code in the sandbox.
5− * They can come from hand-written plugins, MCP servers, or OpenAPI specs —
6− * all produce the same ToolTree + TypeScript declarations.
7− */
8−
9−import type { z } from "zod";
10−
11−// ---------------------------------------------------------------------------
12−// Types
13−// ---------------------------------------------------------------------------
14−
15−export type ApprovalMode = "auto" | "required";
16−
17−export type ApprovalDecision = "approved" | "denied";
18−
19−export type ReceiptDecision = "auto" | ApprovalDecision;
20−
21−export type ReceiptStatus = "succeeded" | "failed" | "denied";
22−
23−/**
24− * Presentation data for rendering an approval request in any client.
25− */
26−export interface ApprovalPresentation {
27− title: string;
28− details?: string;
29− link?: string;
30− /**
31− * Optional structured metadata for policy and richer UIs.
32− * These fields are additive and backward-compatible.
33− */
34− action?: "create" | "update" | "delete" | "read" | "execute" | "other";
35− resourceType?: string;
36− resourceIds?: string[];
37− count?: number;
38− isDestructive?: boolean;
39− selector?: string;
40−}
41−
42−/**
43− * Immutable record of a single tool invocation.
44− */
45−export interface ToolCallReceipt {
46− readonly callId: string;
47− readonly toolPath: string;
48− readonly approval: ApprovalMode;
49− readonly decision: ReceiptDecision;
50− readonly status: ReceiptStatus;
51− readonly timestamp: number;
52− readonly inputPreview: string;
53− readonly outputPreview?: string;
54− readonly error?: string;
55−}
56−
57−/**
58− * Request sent to the approval callback for "required" tools.
59− */
60−export interface ApprovalRequest {
61− readonly callId: string;
62− readonly toolPath: string;
63− readonly input: unknown;
64− readonly preview: ApprovalPresentation;
65−}
66−
67−/**
68− * A single tool definition. The public API for tool authors.
69− *
70− * - `args` and `returns` are Zod schemas used for:
71− * - Input validation at invocation time
72− * - TypeScript declaration generation for the typechecker
73− * - LLM prompt guidance generation
74− *
75− * - `metadata.argsType` and `metadata.returnsType` are optional pre-computed
76− * TypeScript type strings. When present, the typechecker and discovery index
77− * use these instead of deriving types from Zod schemas. This is critical for
78− * OpenAPI tools where `returns` is `z.any()` but the spec defines a rich
79− * response schema.
80− *
81− * - `run` is a plain async function (Effect is an internal detail)
82− *
83− * - `formatApproval` provides rich presentation for approval UIs
84− */
85−export interface ToolDefinition<
86− TArgs extends z.ZodType = z.ZodType,
87− TReturns extends z.ZodType = z.ZodType,
88−> {
89− readonly _tag: "ToolDefinition";
90− readonly description: string;
91− readonly approval: ApprovalMode;
92− readonly args: TArgs;
93− readonly returns: TReturns;
94− readonly run: (input: z.output<TArgs>) => Promise<z.output<TReturns>>;
95− readonly formatApproval?: ((
96− input: z.output<TArgs>,
97− ) => ApprovalPresentation) | undefined;
98− /** Pre-computed type metadata. Preferred over Zod-derived types when present. */
99− readonly metadata?: {
100− /** TypeScript type string for the input args (e.g. "{ owner: string; repo: string }") */
101− readonly argsType?: string | undefined;
102− /** TypeScript type string for the return value (e.g. "{ id: number; title: string }") */
103− readonly returnsType?: string | undefined;
104− } | undefined;
105−}
106−
107−/**
108− * Recursive tree of tools. Allows nested namespaces like `tools.github.issues.close`.
109− */
110−export type ToolTree = {
111− readonly [name: string]: ToolTree | ToolDefinition;
112−};
113−
114−// ---------------------------------------------------------------------------
115−// Constructors
116−// ---------------------------------------------------------------------------
117−
118−export interface DefineToolInput<
119− TArgs extends z.ZodType,
120− TReturns extends z.ZodType,
121−> {
122− description: string;
123− approval: ApprovalMode;
124− args: TArgs;
125− returns: TReturns;
126− run: (input: z.output<TArgs>) => Promise<z.output<TReturns>>;
127− formatApproval?: (input: z.output<TArgs>) => ApprovalPresentation;
128− /** Pre-computed type metadata. Preferred over Zod-derived types when present. */
129− metadata?: {
130− argsType?: string;
131− returnsType?: string;
132− };
133−}
134−
135−/**
136− * Create a tool definition. This is the primary public API for tool authors.
137− *
138− * @example
139− * ```ts
140− * const closeTool = defineTool({
141− * description: "Close a GitHub issue",
142− * approval: "required",
143− * args: z.object({ owner: z.string(), repo: z.string(), issueNumber: z.number() }),
144− * returns: z.object({ number: z.number(), title: z.string(), state: z.string() }),
145− * run: async (input) => { ... },
146− * formatApproval: (input) => ({ title: `Close ${input.owner}/${input.repo}#${input.issueNumber}` }),
147− * });
148− * ```
149− */
150−export function defineTool<
151− TArgs extends z.ZodType,
152− TReturns extends z.ZodType,
153−>(input: DefineToolInput<TArgs, TReturns>): ToolDefinition<TArgs, TReturns> {
154− return {
155− _tag: "ToolDefinition",
156− description: input.description,
157− approval: input.approval,
158− args: input.args,
159− returns: input.returns,
160− run: input.run,
161− formatApproval: input.formatApproval,
162− metadata: input.metadata,
163− };
164−}
165−
166−// ---------------------------------------------------------------------------
167−// ToolTree Utilities
168−// ---------------------------------------------------------------------------
169−
170−/**
171− * Check if a value is a ToolDefinition.
172− */
173−export function isToolDefinition(
174− value: unknown,
175−): value is ToolDefinition {
176− return (
177− typeof value === "object" &&
178− value !== null &&
179− "_tag" in value &&
180− (value as { _tag: unknown })._tag === "ToolDefinition"
181− );
182−}
183−
184−/**
185− * Walk a ToolTree and call `fn` for each tool with its dot-separated path.
186− */
187−export function walkToolTree(
188− tree: ToolTree,
189− fn: (path: string, tool: ToolDefinition) => void,
190− prefix = "",
191−): void {
192− for (const [key, value] of Object.entries(tree)) {
193− const path = prefix ? `${prefix}.${key}` : key;
194− if (isToolDefinition(value)) {
195− fn(path, value);
196− } else {
197− walkToolTree(value as ToolTree, fn, path);
198− }
199− }
200−}
201−
202−/**
203− * Merge multiple ToolTrees into one. Later trees override earlier ones on conflict.
204− */
205−export function mergeToolTrees(...trees: readonly ToolTree[]): ToolTree {
206− const result: Record<string, ToolTree | ToolDefinition> = {};
207− for (const tree of trees) {
208− for (const [key, value] of Object.entries(tree)) {
209− const existing = result[key];
210− if (
211− existing &&
212− !isToolDefinition(existing) &&
213− !isToolDefinition(value)
214− ) {
215− // Both are sub-trees — merge recursively
216− result[key] = mergeToolTrees(
217− existing as ToolTree,
218− value as ToolTree,
219− );
220− } else {
221− result[key] = value;
222− }
223− }
224− }
225− return result;
226−}
assistant/legacy/openassistant/packages/core/src/typechecker.test.ts+0−160
@@ -1,160 +0,0 @@
1−import { describe, test, expect } from "bun:test";
2−import { z } from "zod";
3−import { defineTool, type ToolTree } from "./tools.js";
4−import {
5− zodToTypeString,
6− generateToolDeclarations,
7− generatePromptGuidance,
8− typecheckCode,
9−} from "./typechecker.js";
10−
11−describe("zodToTypeString", () => {
12− test("primitives", () => {
13− expect(zodToTypeString(z.string())).toBe("string");
14− expect(zodToTypeString(z.number())).toBe("number");
15− expect(zodToTypeString(z.boolean())).toBe("boolean");
16− expect(zodToTypeString(z.void())).toBe("void");
17− expect(zodToTypeString(z.null())).toBe("null");
18− expect(zodToTypeString(z.undefined())).toBe("undefined");
19− });
20−
21− test("objects", () => {
22− const schema = z.object({ name: z.string(), age: z.number() });
23− expect(zodToTypeString(schema)).toBe("{ name: string; age: number }");
24− });
25−
26− test("optional fields", () => {
27− const schema = z.object({ name: z.string(), age: z.number().optional() });
28− const result = zodToTypeString(schema);
29− expect(result).toContain("name: string");
30− expect(result).toContain("age?:");
31− });
32−
33− test("arrays", () => {
34− const schema = z.array(z.string());
35− expect(zodToTypeString(schema)).toBe("Array<string>");
36− });
37−
38− test("nested objects", () => {
39− const schema = z.object({
40− user: z.object({ name: z.string() }),
41− });
42− expect(zodToTypeString(schema)).toBe("{ user: { name: string } }");
43− });
44−
45− test("enums", () => {
46− const schema = z.enum(["a", "b", "c"]);
47− expect(zodToTypeString(schema)).toBe('"a" | "b" | "c"');
48− });
49−
50− test("records", () => {
51− const schema = z.record(z.string(), z.number());
52− expect(zodToTypeString(schema)).toBe("Record<string, number>");
53− });
54−});
55−
56−describe("generateToolDeclarations", () => {
57− test("generates declarations for a tool tree", () => {
58− const tree: ToolTree = {
59− math: {
60− add: defineTool({
61− description: "Add two numbers",
62− approval: "auto",
63− args: z.object({ a: z.number(), b: z.number() }),
64− returns: z.number(),
65− run: async (input) => input.a + input.b,
66− }),
67− },
68− github: {
69− issues: {
70− close: defineTool({
71− description: "Close an issue",
72− approval: "required",
73− args: z.object({ owner: z.string(), repo: z.string(), issueNumber: z.number() }),
74− returns: z.object({ state: z.string() }),
75− run: async () => ({ state: "closed" }),
76− }),
77− },
78− },
79− };
80−
81− const declarations = generateToolDeclarations(tree);
82−
83− expect(declarations).toContain("declare const tools:");
84− expect(declarations).toContain("add(input: { a: number; b: number }): Promise<number>;");
85− expect(declarations).toContain("close(input: { owner: string; repo: string; issueNumber: number }): Promise<{ state: string }>;");
86− });
87−});
88−
89−describe("generatePromptGuidance", () => {
90− test("generates guidance for tools", () => {
91− const tree: ToolTree = {
92− math: {
93− add: defineTool({
94− description: "Add two numbers",
95− approval: "auto",
96− args: z.object({ a: z.number(), b: z.number() }),
97− returns: z.number(),
98− run: async (input) => input.a + input.b,
99− }),
100− },
101− };
102−
103− const guidance = generatePromptGuidance(tree);
104− expect(guidance).toContain("tools.math.add");
105− expect(guidance).toContain("Add two numbers");
106− expect(guidance).toContain("auto-approved");
107− });
108−});
109−
110−describe("typecheckCode", () => {
111− const tree: ToolTree = {
112− math: {
113− add: defineTool({
114− description: "Add two numbers",
115− approval: "auto",
116− args: z.object({ a: z.number(), b: z.number() }),
117− returns: z.number(),
118− run: async (input) => input.a + input.b,
119− }),
120− },
121− };
122−
123− const declarations = generateToolDeclarations(tree);
124−
125− test("valid code passes", () => {
126− const result = typecheckCode(
127− 'const result = await tools.math.add({ a: 1, b: 2 });\nreturn result;',
128− declarations,
129− );
130− expect(result.ok).toBe(true);
131− expect(result.errors).toHaveLength(0);
132− });
133−
134− test("wrong argument type fails", () => {
135− const result = typecheckCode(
136− 'const result = await tools.math.add({ a: "not a number", b: 2 });',
137− declarations,
138− );
139− expect(result.ok).toBe(false);
140− expect(result.errors.length).toBeGreaterThan(0);
141− });
142−
143− test("non-existent tool fails", () => {
144− const result = typecheckCode(
145− "const result = await tools.math.subtract({ a: 1, b: 2 });",
146− declarations,
147− );
148− expect(result.ok).toBe(false);
149− expect(result.errors.length).toBeGreaterThan(0);
150− });
151−
152− test("non-existent namespace fails", () => {
153− const result = typecheckCode(
154− 'const result = await tools.calendar.create({ title: "test" });',
155− declarations,
156− );
157− expect(result.ok).toBe(false);
158− expect(result.errors.length).toBeGreaterThan(0);
159− });
160−});
assistant/legacy/openassistant/packages/core/src/typechecker.ts+0−286
@@ -1,286 +0,0 @@
1−/**
2− * TypeScript typechecker for LLM-generated code.
3− *
4− * Takes a ToolTree, generates TypeScript declarations from Zod schemas,
5− * and validates code strings against them using the TypeScript compiler API.
6− */
7−
8−import type { z } from "zod";
9−import type { ToolDefinition, ToolTree } from "./tools.js";
10−import { isToolDefinition } from "./tools.js";
11−
12−// ---------------------------------------------------------------------------
13−// Zod → TypeScript declaration generation
14−// ---------------------------------------------------------------------------
15−
16−// Zod v4 internal def accessor
17−interface ZodDef {
18− type: string;
19− // object
20− shape?: Record<string, z.ZodType>;
21− // array
22− element?: z.ZodType;
23− // optional / nullable
24− innerType?: z.ZodType;
25− // record
26− keyType?: z.ZodType;
27− valueType?: z.ZodType;
28− // union
29− options?: z.ZodType[];
30− // enum (v4 uses entries: { a: "a", b: "b" })
31− entries?: Record<string, string>;
32− // literal
33− value?: unknown;
34− // tuple
35− items?: z.ZodType[];
36−}
37−
38−function getDef(schema: z.ZodType): ZodDef | undefined {
39− // Zod v4: schema._zod.def
40− const zod = (schema as unknown as { _zod?: { def?: ZodDef } })._zod;
41− return zod?.def;
42−}
43−
44−/**
45− * Convert a Zod schema to a TypeScript type string.
46− * Handles the common cases for tool input/output types.
47− * Compatible with Zod v4.
48− */
49−export function zodToTypeString(schema: z.ZodType): string {
50− const def = getDef(schema);
51− if (!def) return "unknown";
52−
53− switch (def.type) {
54− case "string":
55− return "string";
56− case "number":
57− return "number";
58− case "boolean":
59− return "boolean";
60− case "null":
61− return "null";
62− case "undefined":
63− return "undefined";
64− case "void":
65− return "void";
66− case "any":
67− return "any";
68− case "unknown":
69− return "unknown";
70− case "never":
71− return "never";
72− case "literal": {
73− const value = def.value;
74− return typeof value === "string" ? `"${value}"` : String(value);
75− }
76− case "array": {
77− if (!def.element) return "Array<unknown>";
78− return `Array<${zodToTypeString(def.element)}>`;
79− }
80− case "object": {
81− const shape = def.shape;
82− if (!shape || Object.keys(shape).length === 0) return "{}";
83−
84− const entries = Object.entries(shape).map(([key, value]) => {
85− const innerDef = getDef(value);
86− const isOptional = innerDef?.type === "optional";
87− const innerType = isOptional && innerDef?.innerType ? innerDef.innerType : value;
88− const optMark = isOptional ? "?" : "";
89− return `${key}${optMark}: ${zodToTypeString(innerType)}`;
90− });
91− return `{ ${entries.join("; ")} }`;
92− }
93− case "record": {
94− const keyType = def.keyType ? zodToTypeString(def.keyType) : "string";
95− const valueType = def.valueType ? zodToTypeString(def.valueType) : "unknown";
96− return `Record<${keyType}, ${valueType}>`;
97− }
98− case "union": {
99− if (!def.options) return "unknown";
100− return def.options.map((o) => zodToTypeString(o)).join(" | ");
101− }
102− case "optional": {
103− if (!def.innerType) return "unknown | undefined";
104− return `${zodToTypeString(def.innerType)} | undefined`;
105− }
106− case "nullable": {
107− if (!def.innerType) return "unknown | null";
108− return `${zodToTypeString(def.innerType)} | null`;
109− }
110− case "enum": {
111− if (!def.entries) return "unknown";
112− return Object.keys(def.entries).map((v) => `"${v}"`).join(" | ");
113− }
114− case "tuple": {
115− if (!def.items) return "[]";
116− return `[${def.items.map((i) => zodToTypeString(i)).join(", ")}]`;
117− }
118− case "promise": {
119− // Zod v4 may use 'innerType' or similar for promise
120− if (!def.innerType) return "Promise<unknown>";
121− return `Promise<${zodToTypeString(def.innerType)}>`;
122− }
123− default:
124− return "unknown";
125− }
126−}
127−
128−// ---------------------------------------------------------------------------
129−// Type string resolution
130−// ---------------------------------------------------------------------------
131−
132−/**
133− * Get the TypeScript type string for a tool's args.
134− * Prefers metadata.argsType when available, falls back to Zod-derived type.
135− */
136−export function getArgsTypeString(tool: ToolDefinition): string {
137− return tool.metadata?.argsType ?? zodToTypeString(tool.args);
138−}
139−
140−/**
141− * Get the TypeScript type string for a tool's return value.
142− * Prefers metadata.returnsType when available, falls back to Zod-derived type.
143− */
144−export function getReturnsTypeString(tool: ToolDefinition): string {
145− return tool.metadata?.returnsType ?? zodToTypeString(tool.returns);
146−}
147−
148−// ---------------------------------------------------------------------------
149−// ToolTree → TypeScript declaration
150−// ---------------------------------------------------------------------------
151−
152−/**
153− * Generate a TypeScript declaration string for a ToolTree.
154− * This is what goes into the typechecker to validate LLM-generated code.
155− */
156−export function generateToolDeclarations(tree: ToolTree): string {
157− return `declare const tools: {\n${generateTreeType(tree, 1)}\n};`;
158−}
159−
160−function generateTreeType(tree: ToolTree, indent: number): string {
161− const pad = " ".repeat(indent);
162− const lines: string[] = [];
163−
164− for (const [key, value] of Object.entries(tree)) {
165− if (isToolDefinition(value)) {
166− const tool = value as ToolDefinition;
167− const argsType = getArgsTypeString(tool);
168− const returnsType = getReturnsTypeString(tool);
169− lines.push(`${pad}${key}(input: ${argsType}): Promise<${returnsType}>;`);
170− } else {
171− lines.push(`${pad}${key}: {`);
172− lines.push(generateTreeType(value as ToolTree, indent + 1));
173− lines.push(`${pad}};`);
174− }
175− }
176−
177− return lines.join("\n");
178−}
179−
180−// ---------------------------------------------------------------------------
181−// Prompt guidance generation
182−// ---------------------------------------------------------------------------
183−
184−/**
185− * Generate LLM prompt guidance from a ToolTree.
186− * Describes each tool with its path, description, and signature.
187− */
188−export function generatePromptGuidance(tree: ToolTree): string {
189− const lines: string[] = [];
190−
191− function walk(node: ToolTree, prefix: string) {
192− for (const [key, value] of Object.entries(node)) {
193− const path = prefix ? `${prefix}.${key}` : key;
194− if (isToolDefinition(value)) {
195− const tool = value as ToolDefinition;
196− const argsType = getArgsTypeString(tool);
197− const returnsType = getReturnsTypeString(tool);
198− const approvalNote =
199− tool.approval === "required" ? " (approval required)" : " (auto-approved)";
200− lines.push(
201− `- tools.${path}(${argsType}): Promise<${returnsType}>${approvalNote} — ${tool.description}`,
202− );
203− } else {
204− walk(value as ToolTree, path);
205− }
206− }
207− }
208−
209− walk(tree, "");
210− return lines.join("\n");
211−}
212−
213−// ---------------------------------------------------------------------------
214−// TypeScript typechecking
215−// ---------------------------------------------------------------------------
216−
217−export interface TypecheckResult {
218− readonly ok: boolean;
219− readonly errors: readonly string[];
220−}
221−
222−/**
223− * Typecheck a code snippet against tool declarations using the TypeScript compiler.
224− */
225−export function typecheckCode(
226− code: string,
227− toolDeclarations: string,
228−): TypecheckResult {
229− // We use the TypeScript compiler API directly
230− let ts: typeof import("typescript");
231− try {
232− ts = require("typescript");
233− } catch {
234− // If typescript isn't available, skip typechecking
235− return { ok: true, errors: [] };
236− }
237−
238− // Use a separate type alias to avoid "referenced in its own annotation" error
239− const wrappedCode = `${toolDeclarations}\ntype __Tools = typeof tools;\nasync function __generated(__tools: __Tools) {\nconst tools = __tools;\n${code}\n}`;
240−
241− const sourceFile = ts.createSourceFile(
242− "generated.ts",
243− wrappedCode,
244− ts.ScriptTarget.ESNext,
245− true,
246− ts.ScriptKind.TS,
247− );
248−
249− const compilerOptions: import("typescript").CompilerOptions = {
250− target: ts.ScriptTarget.ESNext,
251− module: ts.ModuleKind.ESNext,
252− strict: true,
253− noEmit: true,
254− lib: ["lib.es2022.d.ts"],
255− };
256−
257− // Create a minimal compiler host
258− const host = ts.createCompilerHost(compilerOptions);
259− const originalGetSourceFile = host.getSourceFile.bind(host);
260− host.getSourceFile = (fileName, languageVersion) => {
261− if (fileName === "generated.ts") {
262− return sourceFile;
263− }
264− return originalGetSourceFile(fileName, languageVersion);
265− };
266−
267− const program = ts.createProgram(["generated.ts"], compilerOptions, host);
268− const diagnostics = program.getSemanticDiagnostics(sourceFile);
269−
270− if (diagnostics.length === 0) {
271− return { ok: true, errors: [] };
272− }
273−
274− const errors = diagnostics.map((d) => {
275− const message = ts.flattenDiagnosticMessageText(d.messageText, "\n");
276− if (d.start !== undefined && d.file) {
277− const { line } = d.file.getLineAndCharacterOfPosition(d.start);
278− // Adjust line number to account for the declarations wrapper
279− const declLines = toolDeclarations.split("\n").length + 2; // +2 for blank line + function header
280− return `Line ${line + 1 - declLines}: ${message}`;
281− }
282− return message;
283− });
284−
285− return { ok: false, errors };
286−}
assistant/legacy/openassistant/packages/core/tsconfig.json+0−11
@@ -1,11 +0,0 @@
1−{
2− "extends": "../../tsconfig.base.json",
3− "compilerOptions": {
4− "rootDir": "src",
5− "outDir": "dist",
6− "composite": true
7− },
8− "include": [
9− "src/**/*.ts"
10− ]
11−}
assistant/legacy/openassistant/packages/tool-gen/package.json+0−24
@@ -1,24 +0,0 @@
1−{
2− "name": "@openassistant/tool-gen",
3− "private": true,
4− "type": "module",
5− "exports": {
6− ".": "./src/index.ts",
7− "./mcp": "./src/mcp.ts",
8− "./openapi": "./src/openapi.ts"
9− },
10− "scripts": {
11− "test": "bun test",
12− "typecheck": "tsgo --noEmit --incremental false -p tsconfig.json"
13− },
14− "dependencies": {
15− "@apidevtools/swagger-parser": "^12.1.0",
16− "@mariozechner/pi-ai": "^0.52.6",
17− "@modelcontextprotocol/sdk": "^1.26.0",
18− "@openassistant/core": "workspace:*",
19− "@sinclair/typebox": "^0.34.48",
20− "openapi-typescript": "^7.10.1",
21− "yaml": "^2.8.2",
22− "zod": "^4.3.6"
23− }
24−}
assistant/legacy/openassistant/packages/tool-gen/src/e2e.test.ts+0−109
@@ -1,109 +0,0 @@
1−/**
2− * End-to-end test: Real Claude → generates code → typechecks → runs in sandbox → calls real MCP tools.
3− *
4− * This test uses:
5− * - pi-ai with Claude (via ANTHROPIC_OAUTH_TOKEN or ANTHROPIC_API_KEY)
6− * - MCP tools from AnswerOverflow
7− * - The full agent loop: prompt → Claude → run_code → typecheck → sandbox → receipts → response
8− *
9− * Requires: ANTHROPIC_OAUTH_TOKEN or ANTHROPIC_API_KEY env var to be set.
10− */
11−
12−import { describe, test, expect } from "bun:test";
13−import { createAgent, createPiAiModel, type TaskEvent } from "@openassistant/core";
14−import { generateMcpTools } from "./mcp.js";
15−
16−/**
17− * Resolve an Anthropic API key from (in priority order):
18− * 1. ANTHROPIC_OAUTH_TOKEN env var
19− * 2. ANTHROPIC_API_KEY env var
20− * 3. Claude Code's credential file (~/.claude/.credentials.json)
21− */
22−function getAnthropicApiKey(): string | undefined {
23− if (process.env["ANTHROPIC_OAUTH_TOKEN"]) return process.env["ANTHROPIC_OAUTH_TOKEN"];
24− if (process.env["ANTHROPIC_API_KEY"]) return process.env["ANTHROPIC_API_KEY"];
25−
26− // Try Claude Code's credential store
27− try {
28− const home = process.env["HOME"] ?? process.env["USERPROFILE"] ?? "";
29− const text = require("fs").readFileSync(`${home}/.claude/.credentials.json`, "utf-8");
30− const creds = JSON.parse(text);
31− const token = creds?.claudeAiOauth?.accessToken;
32− if (typeof token === "string" && token.startsWith("sk-ant-")) {
33− return token;
34− }
35− } catch {
36− // No credentials file
37− }
38−
39− return undefined;
40−}
41−
42−const apiKey = getAnthropicApiKey();
43−const hasApiKey = !!apiKey;
44−
45−describe.skipIf(!hasApiKey)("e2e — Claude + MCP + sandbox", () => {
46− test("agent generates code to search AnswerOverflow and returns results", async () => {
47− // 1. Generate tools from AnswerOverflow MCP
48− const mcpResult = await generateMcpTools({
49− name: "answeroverflow",
50− url: "https://www.answeroverflow.com/mcp",
51− });
52−
53− try {
54− // 2. Create real Claude model via pi-ai
55− const model = createPiAiModel({
56− provider: "anthropic",
57− modelId: "claude-sonnet-4-5",
58− apiKey,
59− });
60−
61− // 3. Collect events
62− const events: TaskEvent[] = [];
63−
64− // 4. Create agent with real tools + real model
65− const agent = createAgent({
66− tools: mcpResult.tools,
67− model,
68− requestApproval: async () => "approved",
69− onEvent: (e) => events.push(e),
70− maxCodeRuns: 3,
71− timeoutMs: 20_000,
72− });
73−
74− // 5. Run a real prompt
75− const result = await agent.run(
76− "Search AnswerOverflow for 'react hooks' and tell me how many results you found.",
77− );
78−
79− // 6. Verify the agent actually ran code
80− expect(result.runs.length).toBeGreaterThan(0);
81− expect(result.runs[0]!.result.ok).toBe(true);
82−
83− // 7. Verify MCP tool was called
84− expect(result.allReceipts.length).toBeGreaterThan(0);
85− const mcpReceipt = result.allReceipts.find(
86− (r) => r.toolPath === "answeroverflow.search_answeroverflow",
87− );
88− expect(mcpReceipt).toBeDefined();
89− expect(mcpReceipt!.status).toBe("succeeded");
90−
91− // 8. Verify Claude produced a final text response
92− expect(result.text).toBeDefined();
93− expect(result.text.length).toBeGreaterThan(0);
94−
95− // 9. Verify events were emitted
96− const eventTypes = events.map((e) => e.type);
97− expect(eventTypes).toContain("status");
98− expect(eventTypes).toContain("code_generated");
99− expect(eventTypes).toContain("tool_result");
100− expect(eventTypes).toContain("agent_message");
101− expect(eventTypes).toContain("completed");
102−
103− console.log("Agent response:", result.text);
104− console.log("Receipts:", result.allReceipts.map((r) => `${r.toolPath}: ${r.status}`));
105− } finally {
106− await mcpResult.close();
107− }
108− }, { timeout: 60_000 });
109−});
assistant/legacy/openassistant/packages/tool-gen/src/index.ts+0−18
@@ -1,18 +0,0 @@
1−export {
2− generateMcpTools,
3− type McpToolSource,
4− type McpGenerateResult,
5−} from "./mcp.js";
6−
7−export {
8− generateOpenApiTools,
9− type OpenApiToolSource,
10− type OpenApiAuth,
11− type OpenApiGenerateResult,
12−} from "./openapi.js";
13−
14−export {
15− jsonSchemaToTypeString,
16− jsonSchemaToZod,
17− type JsonSchema,
18−} from "./json-schema-to-ts.js";
assistant/legacy/openassistant/packages/tool-gen/src/integration.test.ts+0−105
@@ -1,105 +0,0 @@
1−/**
2− * Integration test: MCP tools → runner sandbox execution.
3− *
4− * Generates tools from a real MCP server, wires them into the runner,
5− * and executes code in the sandbox that calls the MCP tools.
6− */
7−
8−import { describe, test, expect } from "bun:test";
9−import {
10− createRunner,
11− generateToolDeclarations,
12− typecheckCode,
13−} from "@openassistant/core";
14−import { generateMcpTools } from "./mcp.js";
15−
16−describe("MCP → runner integration", () => {
17− test("generated MCP tools are callable from the sandbox", async () => {
18− // 1. Generate tools from the real AnswerOverflow MCP server
19− const mcpResult = await generateMcpTools({
20− name: "answeroverflow",
21− url: "https://www.answeroverflow.com/mcp",
22− });
23−
24− try {
25− // 2. Create a runner with the generated tools
26− const runner = createRunner({
27− tools: mcpResult.tools,
28− requestApproval: async () => "approved",
29− timeoutMs: 15_000,
30− });
31−
32− // 3. Execute code in the sandbox that calls the MCP tool
33− const result = await runner.run(
34− `const servers = await tools.answeroverflow.search_servers({ query: "discord" });\nreturn servers;`,
35− );
36−
37− // 4. Verify it worked
38− expect(result.ok).toBe(true);
39− expect(result.value).toBeDefined();
40− expect(result.receipts).toHaveLength(1);
41− expect(result.receipts[0]!.toolPath).toBe("answeroverflow.search_servers");
42− expect(result.receipts[0]!.status).toBe("succeeded");
43− expect(result.receipts[0]!.decision).toBe("auto");
44− } finally {
45− await mcpResult.close();
46− }
47− }, { timeout: 30_000 });
48−
49− test("generated type declarations pass the typechecker", async () => {
50− const mcpResult = await generateMcpTools({
51− name: "answeroverflow",
52− url: "https://www.answeroverflow.com/mcp",
53− });
54−
55− try {
56− // Generate full declarations from the tool tree
57− const declarations = generateToolDeclarations(mcpResult.tools);
58−
59− // Valid code should pass (limit is required by the MCP schema)
60− const validResult = typecheckCode(
61− `const servers = await tools.answeroverflow.search_servers({ query: "test", limit: 10 });\nreturn servers;`,
62− declarations,
63− );
64− expect(validResult.ok).toBe(true);
65−
66− // Invalid tool name should fail
67− const invalidResult = typecheckCode(
68− `const r = await tools.answeroverflow.nonexistent_tool({ query: "test" });`,
69− declarations,
70− );
71− expect(invalidResult.ok).toBe(false);
72− } finally {
73− await mcpResult.close();
74− }
75− }, { timeout: 30_000 });
76−
77− test("chained MCP calls work in the sandbox", async () => {
78− const mcpResult = await generateMcpTools({
79− name: "answeroverflow",
80− url: "https://www.answeroverflow.com/mcp",
81− });
82−
83− try {
84− const runner = createRunner({
85− tools: mcpResult.tools,
86− requestApproval: async () => "approved",
87− timeoutMs: 20_000,
88− });
89−
90− // Chain two MCP calls — search for servers, then search content
91− const result = await runner.run(`
92− const searchResult = await tools.answeroverflow.search_answeroverflow({ query: "react hooks" });
93− const servers = await tools.answeroverflow.search_servers({ query: "javascript" });
94− return { searchResult: typeof searchResult, servers: typeof servers };
95− `);
96−
97− expect(result.ok).toBe(true);
98− expect(result.receipts).toHaveLength(2);
99− expect(result.receipts[0]!.toolPath).toBe("answeroverflow.search_answeroverflow");
100− expect(result.receipts[1]!.toolPath).toBe("answeroverflow.search_servers");
101− } finally {
102− await mcpResult.close();
103− }
104− }, { timeout: 30_000 });
105−});
assistant/legacy/openassistant/packages/tool-gen/src/json-schema-to-ts.test.ts+0−126
@@ -1,126 +0,0 @@
1−import { describe, test, expect } from "bun:test";
2−import { jsonSchemaToTypeString, jsonSchemaToZod, type JsonSchema } from "./json-schema-to-ts.js";
3−
4−describe("jsonSchemaToTypeString", () => {
5− test("primitives", () => {
6− expect(jsonSchemaToTypeString({ type: "string" })).toBe("string");
7− expect(jsonSchemaToTypeString({ type: "number" })).toBe("number");
8− expect(jsonSchemaToTypeString({ type: "integer" })).toBe("number");
9− expect(jsonSchemaToTypeString({ type: "boolean" })).toBe("boolean");
10− expect(jsonSchemaToTypeString({ type: "null" })).toBe("null");
11− });
12−
13− test("object with properties", () => {
14− const schema: JsonSchema = {
15− type: "object",
16− properties: {
17− name: { type: "string" },
18− age: { type: "number" },
19− },
20− required: ["name"],
21− };
22− const result = jsonSchemaToTypeString(schema);
23− expect(result).toContain("name: string");
24− expect(result).toContain("age?: number");
25− });
26−
27− test("object with no properties", () => {
28− const result = jsonSchemaToTypeString({ type: "object" });
29− // openapi-typescript produces Record<string, never> for empty objects
30− expect(result).toBe("Record<string, never>");
31− });
32−
33− test("array", () => {
34− const schema: JsonSchema = {
35− type: "array",
36− items: { type: "string" },
37− };
38− // openapi-typescript uses T[] syntax instead of Array<T>
39− expect(jsonSchemaToTypeString(schema)).toBe("string[]");
40− });
41−
42− test("enum", () => {
43− const schema: JsonSchema = {
44− enum: ["a", "b", "c"],
45− };
46− expect(jsonSchemaToTypeString(schema)).toBe('"a" | "b" | "c"');
47− });
48−
49− test("nested objects", () => {
50− const schema: JsonSchema = {
51− type: "object",
52− properties: {
53− user: {
54− type: "object",
55− properties: {
56− name: { type: "string" },
57− },
58− required: ["name"],
59− },
60− },
61− required: ["user"],
62− };
63− const result = jsonSchemaToTypeString(schema);
64− expect(result).toContain("user: {");
65− expect(result).toContain("name: string");
66− });
67−
68− test("implicit object (no type but has properties)", () => {
69− const schema: JsonSchema = {
70− properties: {
71− query: { type: "string" },
72− },
73− required: ["query"],
74− };
75− const result = jsonSchemaToTypeString(schema);
76− expect(result).toContain("query: string");
77− });
78−});
79−
80−describe("jsonSchemaToZod", () => {
81− test("string validates correctly", () => {
82− const schema = jsonSchemaToZod({ type: "string" });
83− expect(schema.safeParse("hello").success).toBe(true);
84− expect(schema.safeParse(123).success).toBe(false);
85− });
86−
87− test("number validates correctly", () => {
88− const schema = jsonSchemaToZod({ type: "number" });
89− expect(schema.safeParse(42).success).toBe(true);
90− expect(schema.safeParse("hello").success).toBe(false);
91− });
92−
93− test("object with required fields", () => {
94− const schema = jsonSchemaToZod({
95− type: "object",
96− properties: {
97− name: { type: "string" },
98− age: { type: "number" },
99− },
100− required: ["name"],
101− });
102−
103− expect(schema.safeParse({ name: "Alice" }).success).toBe(true);
104− expect(schema.safeParse({ name: "Alice", age: 30 }).success).toBe(true);
105− expect(schema.safeParse({}).success).toBe(false); // missing required 'name'
106− });
107−
108− test("array of strings", () => {
109− const schema = jsonSchemaToZod({
110− type: "array",
111− items: { type: "string" },
112− });
113−
114− expect(schema.safeParse(["a", "b"]).success).toBe(true);
115− expect(schema.safeParse([1, 2]).success).toBe(false);
116− });
117−
118− test("enum", () => {
119− const schema = jsonSchemaToZod({
120− enum: ["a", "b", "c"],
121− });
122−
123− expect(schema.safeParse("a").success).toBe(true);
124− expect(schema.safeParse("d").success).toBe(false);
125− });
126−});
assistant/legacy/openassistant/packages/tool-gen/src/json-schema-to-ts.ts+0−164
@@ -1,164 +0,0 @@
1−/**
2− * Convert JSON Schema to TypeScript type strings.
3− *
4− * Both MCP tools and OpenAPI specs use JSON Schema for their type definitions.
5− * This module converts them to TypeScript type strings for the typechecker,
6− * and also creates Zod schemas for runtime validation.
7− *
8− * Type string generation uses openapi-typescript's `transformSchemaObject` for
9− * high-fidelity conversion (handles allOf, oneOf, enums, nullable, etc.).
10− * Falls back to our simpler hand-rolled converter for edge cases.
11− */
12−
13−import { astToString, transformSchemaObject } from "openapi-typescript";
14−import { z } from "zod";
15−
16−// ---------------------------------------------------------------------------
17−// openapi-typescript context (for individual schema conversion)
18−// ---------------------------------------------------------------------------
19−
20−function makeTransformCtx() {
21− return {
22− additionalProperties: false,
23− alphabetize: false,
24− arrayLength: false,
25− defaultNonNullable: true,
26− discriminators: { refsHandled: [] as string[], objects: {} as Record<string, unknown> },
27− emptyObjectsUnknown: false,
28− enum: false,
29− enumValues: false,
30− excludeDeprecated: false,
31− exportType: false,
32− immutable: false,
33− indentLv: 0,
34− pathParamsAsTypes: false,
35− postTransform: undefined,
36− propertiesRequiredByDefault: false,
37− redoc: undefined,
38− silent: true,
39− resolve(_ref: string) { return undefined as unknown; },
40− };
41−}
42−
43−// ---------------------------------------------------------------------------
44−// JSON Schema types (minimal subset we need)
45−// ---------------------------------------------------------------------------
46−
47−export interface JsonSchema {
48− type?: string | string[] | undefined;
49− properties?: Record<string, JsonSchema> | undefined;
50− required?: string[] | undefined;
51− items?: JsonSchema | undefined;
52− enum?: unknown[] | undefined;
53− const?: unknown;
54− oneOf?: JsonSchema[] | undefined;
55− anyOf?: JsonSchema[] | undefined;
56− allOf?: JsonSchema[] | undefined;
57− $ref?: string | undefined;
58− description?: string | undefined;
59− format?: string | undefined;
60− additionalProperties?: boolean | JsonSchema | undefined;
61−}
62−
63−// ---------------------------------------------------------------------------
64−// JSON Schema → TypeScript string (via openapi-typescript)
65−// ---------------------------------------------------------------------------
66−
67−/**
68− * Convert a JSON Schema to a TypeScript type string.
69− *
70− * Uses openapi-typescript's `transformSchemaObject` for high-fidelity conversion
71− * that handles allOf, oneOf, enums, nullable, additionalProperties, etc.
72− * Falls back to "any" for schemas that can't be converted (e.g. circular refs).
73− */
74−export function jsonSchemaToTypeString(schema: JsonSchema): string {
75− if (!schema) return "any";
76− try {
77− const node = transformSchemaObject(schema as never, {
78− path: "#",
79− ctx: makeTransformCtx() as never,
80− });
81− return astToString(node).trim();
82− } catch {
83− return "any";
84− }
85−}
86−
87−// ---------------------------------------------------------------------------
88−// JSON Schema → Zod schema
89−// ---------------------------------------------------------------------------
90−
91−export function jsonSchemaToZod(schema: JsonSchema): z.ZodType {
92− if (!schema.type && schema.properties) {
93− return objectToZod(schema);
94− }
95−
96− if (schema.enum) {
97− if (
98− schema.enum.length > 0 &&
99− schema.enum.every((v): v is string => typeof v === "string")
100− ) {
101− return z.enum(schema.enum as [string, ...string[]]);
102− }
103− return z.any();
104− }
105−
106− if (schema.const !== undefined) {
107− return z.literal(schema.const as string | number | boolean);
108− }
109−
110− if (schema.oneOf) {
111− const schemas = schema.oneOf.map(jsonSchemaToZod);
112− if (schemas.length === 0) return z.any();
113− if (schemas.length === 1) return schemas[0]!;
114− return z.union([schemas[0]!, schemas[1]!, ...schemas.slice(2)]);
115− }
116−
117− if (schema.anyOf) {
118− const schemas = schema.anyOf.map(jsonSchemaToZod);
119− if (schemas.length === 0) return z.any();
120− if (schemas.length === 1) return schemas[0]!;
121− return z.union([schemas[0]!, schemas[1]!, ...schemas.slice(2)]);
122− }
123−
124− const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
125−
126− switch (type) {
127− case "string":
128− return z.string();
129− case "number":
130− case "integer":
131− return z.number();
132− case "boolean":
133− return z.boolean();
134− case "null":
135− return z.null();
136− case "array": {
137− if (schema.items) {
138− return z.array(jsonSchemaToZod(schema.items));
139− }
140− return z.array(z.unknown());
141− }
142− case "object":
143− return objectToZod(schema);
144− default:
145− return z.any();
146− }
147−}
148−
149−function objectToZod(schema: JsonSchema): z.ZodType {
150− const props = schema.properties;
151− if (!props || Object.keys(props).length === 0) {
152− return z.record(z.string(), z.unknown());
153− }
154−
155− const required = new Set(schema.required ?? []);
156− const shape: Record<string, z.ZodType> = {};
157−
158− for (const [key, propSchema] of Object.entries(props)) {
159− const zodType = jsonSchemaToZod(propSchema);
160− shape[key] = required.has(key) ? zodType : zodType.optional();
161− }
162−
163− return z.object(shape);
164−}
assistant/legacy/openassistant/packages/tool-gen/src/mcp.test.ts+0−121
@@ -1,121 +0,0 @@
1−import { describe, test, expect } from "bun:test";
2−import { walkToolTree, isToolDefinition } from "@openassistant/core";
3−import { generateMcpTools } from "./mcp.js";
4−
5−describe("generateMcpTools — AnswerOverflow MCP", () => {
6− test("connects and generates tools from AnswerOverflow MCP", async () => {
7− const result = await generateMcpTools({
8− name: "answeroverflow",
9− url: "https://www.answeroverflow.com/mcp",
10− });
11−
12− try {
13− // Should produce a tool tree under "answeroverflow"
14− expect(result.tools["answeroverflow"]).toBeDefined();
15−
16− // Collect all tool paths
17− const paths: string[] = [];
18− walkToolTree(result.tools, (path) => paths.push(path));
19−
20− // AnswerOverflow has 4 known tools
21− expect(paths.length).toBe(4);
22− expect(paths).toContain("answeroverflow.search_answeroverflow");
23− expect(paths).toContain("answeroverflow.search_servers");
24− expect(paths).toContain("answeroverflow.get_thread_messages");
25− expect(paths).toContain("answeroverflow.find_similar_threads");
26−
27− // Each tool should be a valid ToolDefinition
28− walkToolTree(result.tools, (_path, tool) => {
29− expect(isToolDefinition(tool)).toBe(true);
30− expect(tool.description).toBeDefined();
31− expect(tool.description.length).toBeGreaterThan(0);
32− expect(tool.approval).toBe("auto"); // default
33− expect(typeof tool.formatApproval).toBe("function");
34− });
35−
36− // TypeScript declarations should be generated
37− expect(result.typeDeclaration).toContain("answeroverflow:");
38− expect(result.typeDeclaration).toContain("search_answeroverflow");
39− expect(result.typeDeclaration).toContain("query: string");
40−
41− // Prompt guidance should be generated
42− expect(result.promptGuidance).toContain("tools.answeroverflow.search_answeroverflow");
43− } finally {
44− await result.close();
45− }
46− }, { timeout: 30_000 });
47−
48− test("respects approval overrides", async () => {
49− const result = await generateMcpTools({
50− name: "answeroverflow",
51− url: "https://www.answeroverflow.com/mcp",
52− overrides: {
53− search_answeroverflow: { approval: "required" },
54− },
55− });
56−
57− try {
58− let found = false;
59− walkToolTree(result.tools, (path, tool) => {
60− if (path === "answeroverflow.search_answeroverflow") {
61− expect(tool.approval).toBe("required");
62− found = true;
63− }
64− });
65− expect(found).toBe(true);
66− } finally {
67− await result.close();
68− }
69− }, { timeout: 30_000 });
70−
71− test("generated tools can actually call the MCP server", async () => {
72− const result = await generateMcpTools({
73− name: "answeroverflow",
74− url: "https://www.answeroverflow.com/mcp",
75− });
76−
77− try {
78− // Find the search tool
79− let searchTool: ReturnType<typeof isToolDefinition extends (v: unknown) => v is infer T ? () => T : never> | undefined;
80− walkToolTree(result.tools, (path, tool) => {
81− if (path === "answeroverflow.search_servers") {
82− searchTool = tool;
83− }
84− });
85−
86− expect(searchTool).toBeDefined();
87−
88− // Actually call the MCP tool
89− const searchResult = await searchTool!.run({ query: "discord" });
90− expect(searchResult).toBeDefined();
91− } finally {
92− await result.close();
93− }
94− }, { timeout: 30_000 });
95−
96− test("generated tools include approval preview formatter", async () => {
97− const result = await generateMcpTools({
98− name: "answeroverflow",
99− url: "https://www.answeroverflow.com/mcp",
100− overrides: {
101− search_servers: { approval: "required" },
102− },
103− });
104−
105− try {
106− let foundPreview = false;
107− walkToolTree(result.tools, (path, tool) => {
108− if (path === "answeroverflow.search_servers") {
109− const preview = tool.formatApproval?.({ query: "bun" });
110− expect(preview).toBeDefined();
111− expect(preview?.title).toBe("Run search_servers");
112− expect(preview?.details).toContain("query");
113− foundPreview = true;
114− }
115− });
116− expect(foundPreview).toBe(true);
117− } finally {
118− await result.close();
119− }
120− }, { timeout: 30_000 });
121−});
assistant/legacy/openassistant/packages/tool-gen/src/mcp.ts+0−271
@@ -1,271 +0,0 @@
1−/**
2− * MCP tool generator — introspects an MCP server and produces a ToolTree.
3− *
4− * Connects to an MCP server via SSE or Streamable HTTP transport,
5− * fetches the tool list, and converts each tool into a defineTool()
6− * with Zod schemas derived from the JSON Schema in the tool definitions.
7− */
8−
9−import { Client } from "@modelcontextprotocol/sdk/client/index.js";
10−import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
11−import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
12−import { defineTool, type ApprovalMode, type ToolTree } from "@openassistant/core";
13−import { jsonSchemaToZod, jsonSchemaToTypeString, type JsonSchema } from "./json-schema-to-ts.js";
14−import { z } from "zod";
15−
16−// ---------------------------------------------------------------------------
17−// Config
18−// ---------------------------------------------------------------------------
19−
20−export interface McpToolSource {
21− /** Namespace in the tool tree: `tools.<name>.<toolName>` */
22− readonly name: string;
23− /** URL of the MCP server (SSE or Streamable HTTP endpoint) */
24− readonly url: string;
25− /** Transport type. Defaults to trying streamable HTTP first, falling back to SSE. */
26− readonly transport?: "sse" | "streamable-http" | undefined;
27− /** Per-tool overrides for approval mode. Key is the MCP tool name. */
28− readonly overrides?: Readonly<Record<string, {
29− readonly approval?: ApprovalMode | undefined;
30− }>> | undefined;
31− /** Default approval mode for tools. Defaults to "auto". */
32− readonly defaultApproval?: ApprovalMode | undefined;
33−}
34−
35−// ---------------------------------------------------------------------------
36−// Result
37−// ---------------------------------------------------------------------------
38−
39−export interface McpGenerateResult {
40− /** The generated tool tree, namespaced under the source name. */
41− readonly tools: ToolTree;
42− /** TypeScript declarations for the typechecker. */
43− readonly typeDeclaration: string;
44− /** Human-readable descriptions for the LLM prompt. */
45− readonly promptGuidance: string;
46− /** The MCP client (keep alive for making tool calls). */
47− readonly client: Client;
48− /** Cleanup function to close the connection. */
49− readonly close: () => Promise<void>;
50−}
51−
52−// ---------------------------------------------------------------------------
53−// Connection
54−// ---------------------------------------------------------------------------
55−
56−const MAX_APPROVAL_PREVIEW = 240;
57−
58−function isRecord(value: unknown): value is Record<string, unknown> {
59− return typeof value === "object" && value !== null && !Array.isArray(value);
60−}
61−
62−function toPreview(value: unknown): string {
63− if (value === undefined) return "undefined";
64− if (value === null) return "null";
65− try {
66− const text = typeof value === "string" ? value : JSON.stringify(value);
67− return text.length > MAX_APPROVAL_PREVIEW
68− ? `${text.slice(0, MAX_APPROVAL_PREVIEW)}...`
69− : text;
70− } catch {
71− return String(value);
72− }
73−}
74−
75−function inferMcpAction(toolName: string): {
76− action: "create" | "update" | "delete" | "read" | "execute" | "other";
77− isDestructive: boolean;
78−} {
79− const lower = toolName.toLowerCase();
80− if (/(delete|remove|destroy|purge)/.test(lower)) {
81− return { action: "delete", isDestructive: true };
82− }
83− if (/(create|add|insert)/.test(lower)) {
84− return { action: "create", isDestructive: false };
85− }
86− if (/(update|set|patch|edit)/.test(lower)) {
87− return { action: "update", isDestructive: false };
88− }
89− if (/(get|list|search|find|read)/.test(lower)) {
90− return { action: "read", isDestructive: false };
91− }
92− return { action: "execute", isDestructive: false };
93−}
94−
95−function extractIds(input: unknown): string[] {
96− if (!isRecord(input)) return [];
97− const ids: string[] = [];
98− for (const key of ["id", "ids", "idOrName", "name", "slug", "key"]) {
99− const value = input[key];
100− if (typeof value === "string" || typeof value === "number") {
101− ids.push(String(value));
102− continue;
103− }
104− if (Array.isArray(value)) {
105− for (const item of value) {
106− if (typeof item === "string" || typeof item === "number") {
107− ids.push(String(item));
108− }
109− }
110− }
111− }
112− return ids.slice(0, 5);
113−}
114−
115−function buildMcpApprovalPreview(toolName: string, input: unknown) {
116− const { action, isDestructive } = inferMcpAction(toolName);
117− const ids = extractIds(input);
118− const details = [
119− ids.length > 0 ? `Target: ${ids.join(", ")}` : undefined,
120− `Arguments: ${toPreview(input)}`,
121− ].filter(Boolean).join("\n");
122− return {
123− title: `Run ${toolName}`,
124− details,
125− action,
126− resourceType: toolName.replace(/[_-]/g, " "),
127− resourceIds: ids.length > 0 ? ids : undefined,
128− isDestructive,
129− } as const;
130−}
131−
132−async function connectMcp(
133− url: string,
134− transport?: "sse" | "streamable-http",
135−): Promise<{ client: Client; close: () => Promise<void> }> {
136− const client = new Client(
137− { name: "openassistant-tool-gen", version: "0.1.0" },
138− { capabilities: {} },
139− );
140−
141− const parsedUrl = new URL(url);
142−
143− if (transport === "sse") {
144− const sseTransport = new SSEClientTransport(parsedUrl);
145− await client.connect(sseTransport);
146− return { client, close: () => client.close() };
147− }
148−
149− if (transport === "streamable-http") {
150− const httpTransport = new StreamableHTTPClientTransport(parsedUrl);
151− await client.connect(httpTransport as Parameters<typeof client.connect>[0]);
152− return { client, close: () => client.close() };
153− }
154−
155− // Try streamable HTTP first, fall back to SSE
156− try {
157− const httpTransport = new StreamableHTTPClientTransport(parsedUrl);
158− await client.connect(httpTransport as Parameters<typeof client.connect>[0]);
159− return { client, close: () => client.close() };
160− } catch {
161− const sseTransport = new SSEClientTransport(parsedUrl);
162− await client.connect(sseTransport);
163− return { client, close: () => client.close() };
164− }
165−}
166−
167−// ---------------------------------------------------------------------------
168−// Generator
169−// ---------------------------------------------------------------------------
170−
171−export async function generateMcpTools(
172− source: McpToolSource,
173−): Promise<McpGenerateResult> {
174− let connection = await connectMcp(source.url, source.transport);
175−
176− /**
177− * Call an MCP tool with automatic reconnection on socket errors.
178− * If the connection dropped, reconnect and retry once.
179− */
180− async function callToolWithReconnect(
181− toolName: string,
182− args: Record<string, unknown>,
183− ) {
184− try {
185− return await connection.client.callTool({ name: toolName, arguments: args });
186− } catch (error) {
187− const msg = error instanceof Error ? error.message : String(error);
188− // Detect connection errors and retry with a fresh connection
189− if (msg.includes("socket") || msg.includes("closed") || msg.includes("ECONNRESET") || msg.includes("fetch failed")) {
190− console.warn(`[MCP ${source.name}] Connection lost, reconnecting...`);
191− try { await connection.close(); } catch { /* ignore */ }
192− connection = await connectMcp(source.url, source.transport);
193− return await connection.client.callTool({ name: toolName, arguments: args });
194− }
195− throw error;
196− }
197− }
198−
199− const { tools: mcpTools } = await connection.client.listTools();
200−
201− const toolTree: Record<string, ReturnType<typeof defineTool>> = {};
202− const typeLines: string[] = [];
203− const guidanceLines: string[] = [];
204−
205− for (const mcpTool of mcpTools) {
206− const toolName = mcpTool.name;
207− const description = mcpTool.description ?? `MCP tool: ${toolName}`;
208− const inputSchema = (mcpTool.inputSchema as JsonSchema | undefined) ?? { type: "object" };
209−
210− const approval =
211− source.overrides?.[toolName]?.approval ??
212− source.defaultApproval ??
213− "auto";
214−
215− // Generate Zod schema from JSON Schema
216− const argsZod = jsonSchemaToZod(inputSchema);
217−
218− // Generate TypeScript type string using openapi-typescript
219− const argsTypeString = jsonSchemaToTypeString(inputSchema);
220−
221− // Create the tool definition
222− toolTree[toolName] = defineTool({
223− description,
224− approval,
225− args: argsZod,
226− returns: z.any(), // MCP tools return opaque content
227− metadata: {
228− argsType: argsTypeString,
229− // MCP tools don't declare output schemas, so no returnsType
230− },
231− run: async (input: unknown) => {
232− const result = await callToolWithReconnect(
233− toolName,
234− input as Record<string, unknown>,
235− );
236− // MCP returns { content: [{ type, text, ... }] }
237− // Extract text content for simplicity
238− if (result.content && Array.isArray(result.content)) {
239− const textParts = result.content
240− .filter((c: { type: string }) => c.type === "text")
241− .map((c: { text?: string }) => c.text)
242− .filter(Boolean);
243− if (textParts.length === 1) return textParts[0];
244− if (textParts.length > 1) return textParts;
245− }
246− return result.content;
247− },
248− formatApproval: (input) => buildMcpApprovalPreview(toolName, input),
249− });
250−
251− // Build TypeScript declaration
252− const approvalNote = approval === "required" ? " (approval required)" : " (auto-approved)";
253− typeLines.push(` /** ${description} */`);
254− typeLines.push(` ${toolName}(input: ${argsTypeString}): Promise<any>;`);
255−
256− guidanceLines.push(
257− `- tools.${source.name}.${toolName}(${argsTypeString}): Promise<any>${approvalNote} — ${description}`,
258− );
259− }
260−
261− const typeDeclaration = `${source.name}: {\n${typeLines.join("\n")}\n}`;
262− const promptGuidance = guidanceLines.join("\n");
263−
264− return {
265− tools: { [source.name]: toolTree },
266− typeDeclaration,
267− promptGuidance,
268− client: connection.client,
269− close: () => connection.close(),
270− };
271−}
assistant/legacy/openassistant/packages/tool-gen/src/openapi-integration.test.ts+0−283
@@ -1,283 +0,0 @@
1−/**
2− * Integration test: OpenAPI tools → runner sandbox execution.
3− *
4− * Uses JSONPlaceholder (https://jsonplaceholder.typicode.com) — a free,
5− * no-auth REST API — with an inline OpenAPI spec.
6− */
7−
8−import { describe, test, expect } from "bun:test";
9−import {
10− createRunner,
11− generateToolDeclarations,
12− typecheckCode,
13−} from "@openassistant/core";
14−import { generateOpenApiTools } from "./openapi.js";
15−
16−const jsonPlaceholderSpec = {
17− openapi: "3.0.0",
18− info: { title: "JSONPlaceholder", version: "1.0.0" },
19− servers: [{ url: "https://jsonplaceholder.typicode.com" }],
20− paths: {
21− "/posts": {
22− get: {
23− tags: ["posts"],
24− operationId: "listPosts",
25− summary: "List all posts",
26− parameters: [
27− {
28− name: "_limit",
29− in: "query",
30− required: false,
31− schema: { type: "integer" },
32− description: "Limit the number of results",
33− },
34− {
35− name: "userId",
36− in: "query",
37− required: false,
38− schema: { type: "integer" },
39− description: "Filter by user ID",
40− },
41− ],
42− responses: {
43− "200": {
44− description: "A list of posts",
45− content: {
46− "application/json": {
47− schema: {
48− type: "array",
49− items: {
50− type: "object",
51− properties: {
52− userId: { type: "integer" },
53− id: { type: "integer" },
54− title: { type: "string" },
55− body: { type: "string" },
56− },
57− required: ["userId", "id", "title", "body"],
58− },
59− },
60− },
61− },
62− },
63− },
64− },
65− },
66− "/posts/{id}": {
67− get: {
68− tags: ["posts"],
69− operationId: "getPost",
70− summary: "Get a post by ID",
71− parameters: [
72− {
73− name: "id",
74− in: "path",
75− required: true,
76− schema: { type: "integer" },
77− description: "Post ID",
78− },
79− ],
80− responses: {
81− "200": {
82− description: "A post",
83− content: {
84− "application/json": {
85− schema: {
86− type: "object",
87− properties: {
88− userId: { type: "integer" },
89− id: { type: "integer" },
90− title: { type: "string" },
91− body: { type: "string" },
92− },
93− required: ["userId", "id", "title", "body"],
94− },
95− },
96− },
97− },
98− },
99− },
100− },
101− "/users": {
102− get: {
103− tags: ["users"],
104− operationId: "listUsers",
105− summary: "List all users",
106− parameters: [],
107− responses: {
108− "200": {
109− description: "A list of users",
110− content: {
111− "application/json": {
112− schema: {
113− type: "array",
114− items: {
115− type: "object",
116− properties: {
117− id: { type: "integer" },
118− name: { type: "string" },
119− email: { type: "string" },
120− },
121− required: ["id", "name", "email"],
122− },
123− },
124− },
125− },
126− },
127− },
128− },
129− },
130− "/users/{id}": {
131− get: {
132− tags: ["users"],
133− operationId: "getUser",
134− summary: "Get a user by ID",
135− parameters: [
136− {
137− name: "id",
138− in: "path",
139− required: true,
140− schema: { type: "integer" },
141− },
142− ],
143− responses: {
144− "200": {
145− description: "A user",
146− content: {
147− "application/json": {
148− schema: {
149− type: "object",
150− properties: {
151− id: { type: "integer" },
152− name: { type: "string" },
153− email: { type: "string" },
154− },
155− required: ["id", "name", "email"],
156− },
157− },
158− },
159− },
160− },
161− },
162− },
163− },
164−};
165−
166−describe("OpenAPI → runner integration", () => {
167− test("generated OpenAPI tools are callable from the sandbox", async () => {
168− const result = await generateOpenApiTools({
169− name: "placeholder",
170− spec: jsonPlaceholderSpec as unknown as string,
171− });
172−
173− const runner = createRunner({
174− tools: result.tools,
175− requestApproval: async () => "approved",
176− timeoutMs: 15_000,
177− });
178−
179− // Call the real JSONPlaceholder API from the sandbox
180− const runResult = await runner.run(
181− `const post = await tools.placeholder.posts.getPost({ id: 1 });\nreturn post;`,
182− );
183−
184− expect(runResult.ok).toBe(true);
185− expect(runResult.value).toBeDefined();
186−
187− const post = runResult.value as { id: number; userId: number; title: string };
188− expect(post.id).toBe(1);
189− expect(post.userId).toBe(1);
190− expect(typeof post.title).toBe("string");
191−
192− expect(runResult.receipts).toHaveLength(1);
193− expect(runResult.receipts[0]!.toolPath).toBe("placeholder.posts.getPost");
194− expect(runResult.receipts[0]!.status).toBe("succeeded");
195− }, { timeout: 15_000 });
196−
197− test("chained OpenAPI calls work in the sandbox", async () => {
198− const result = await generateOpenApiTools({
199− name: "placeholder",
200− spec: jsonPlaceholderSpec as unknown as string,
201− });
202−
203− const runner = createRunner({
204− tools: result.tools,
205− requestApproval: async () => "approved",
206− timeoutMs: 15_000,
207− });
208−
209− // Get a user, then get their posts
210− const runResult = await runner.run(`
211− const user = await tools.placeholder.users.getUser({ id: 1 });
212− const posts = await tools.placeholder.posts.listPosts({ userId: 1, _limit: 3 });
213− return { userName: user.name, postCount: posts.length };
214− `);
215−
216− expect(runResult.ok).toBe(true);
217−
218− const value = runResult.value as { userName: string; postCount: number };
219− expect(value.userName).toBe("Leanne Graham");
220− expect(value.postCount).toBe(3);
221−
222− expect(runResult.receipts).toHaveLength(2);
223− expect(runResult.receipts[0]!.toolPath).toBe("placeholder.users.getUser");
224− expect(runResult.receipts[1]!.toolPath).toBe("placeholder.posts.listPosts");
225− }, { timeout: 15_000 });
226−
227− test("type declarations + typechecker work for generated OpenAPI tools", async () => {
228− const result = await generateOpenApiTools({
229− name: "placeholder",
230− spec: jsonPlaceholderSpec as unknown as string,
231− });
232−
233− const declarations = generateToolDeclarations(result.tools);
234−
235− // Valid code passes
236− const validResult = typecheckCode(
237− `const post = await tools.placeholder.posts.getPost({ id: 1 });\nreturn post;`,
238− declarations,
239− );
240− expect(validResult.ok).toBe(true);
241−
242− // Invalid tool name fails
243− const invalidResult = typecheckCode(
244− `await tools.placeholder.posts.deleteSomething({ id: 1 });`,
245− declarations,
246− );
247− expect(invalidResult.ok).toBe(false);
248− }, { timeout: 15_000 });
249−
250− test("loop over API results in the sandbox", async () => {
251− const result = await generateOpenApiTools({
252− name: "placeholder",
253− spec: jsonPlaceholderSpec as unknown as string,
254− });
255−
256− const runner = createRunner({
257− tools: result.tools,
258− requestApproval: async () => "approved",
259− timeoutMs: 15_000,
260− });
261−
262− // Fetch 3 posts, then fetch the user for each one
263− const runResult = await runner.run(`
264− const posts = await tools.placeholder.posts.listPosts({ _limit: 3 });
265− const results = [];
266− for (const post of posts) {
267− const user = await tools.placeholder.users.getUser({ id: post.userId });
268− results.push({ postTitle: post.title, authorName: user.name });
269− }
270− return results;
271− `);
272−
273− expect(runResult.ok).toBe(true);
274−
275− const value = runResult.value as Array<{ postTitle: string; authorName: string }>;
276− expect(value).toHaveLength(3);
277− expect(typeof value[0]!.postTitle).toBe("string");
278− expect(typeof value[0]!.authorName).toBe("string");
279−
280− // 1 listPosts + 3 getUser = 4 receipts
281− expect(runResult.receipts).toHaveLength(4);
282− }, { timeout: 15_000 });
283−});
assistant/legacy/openassistant/packages/tool-gen/src/openapi.test.ts+0−143
@@ -1,143 +0,0 @@
1−import { describe, test, expect } from "bun:test";
2−import { walkToolTree, isToolDefinition } from "@openassistant/core";
3−import { generateOpenApiTools } from "./openapi.js";
4−
5−describe("generateOpenApiTools — FastSpring spec", () => {
6− test("generated write tools include approval preview formatter", async () => {
7− const result = await generateOpenApiTools({
8− name: "vercel",
9− spec: {
10− openapi: "3.0.0",
11− info: { title: "Test", version: "1.0.0" },
12− servers: [{ url: "https://api.example.com" }],
13− paths: {
14− "/v1/projects/{idOrName}": {
15− delete: {
16− tags: ["projects"],
17− operationId: "deleteProject",
18− summary: "Delete project",
19− parameters: [
20− {
21− name: "idOrName",
22− in: "path",
23− required: true,
24− schema: { type: "string" },
25− },
26− ],
27− responses: {
28− "200": {
29− description: "ok",
30− content: {
31− "application/json": {
32− schema: { type: "object", properties: { ok: { type: "boolean" } } },
33− },
34− },
35− },
36− },
37− },
38− },
39− },
40− },
41− });
42−
43− const ns = result.tools["vercel"] as Record<string, unknown>;
44− const projects = ns["projects"] as Record<string, unknown>;
45− const deleteTool = projects["deleteProject"];
46−
47− expect(isToolDefinition(deleteTool)).toBe(true);
48− const preview = deleteTool.formatApproval?.({ idOrName: "prj_123" });
49− expect(preview).toBeDefined();
50− expect(preview?.title).toBe("DELETE /v1/projects/{idOrName}");
51− expect(preview?.details).toContain("Target: prj_123");
52− expect(preview?.action).toBe("delete");
53− expect(preview?.isDestructive).toBe(true);
54− });
55−
56− test("parses the FastSpring OpenAPI spec and generates tools", async () => {
57− const result = await generateOpenApiTools({
58− name: "fastspring",
59− spec: "https://raw.githubusercontent.com/konfig-sdks/openapi-examples/refs/heads/main/fastspring/openapi.yaml",
60− });
61−
62− // Should produce a nested tool tree under "fastspring"
63− expect(result.tools["fastspring"]).toBeDefined();
64−
65− // Collect all tool paths
66− const paths: string[] = [];
67− walkToolTree(result.tools, (path) => paths.push(path));
68−
69− // Should have a meaningful number of tools
70− expect(paths.length).toBeGreaterThan(10);
71−
72− // Should have common FastSpring endpoints
73− const hasAccounts = paths.some((p) => p.includes("accounts"));
74− const hasProducts = paths.some((p) => p.includes("products"));
75− const hasOrders = paths.some((p) => p.includes("orders"));
76− const hasSubscriptions = paths.some((p) => p.includes("subscriptions"));
77−
78− expect(hasAccounts).toBe(true);
79− expect(hasProducts).toBe(true);
80− expect(hasOrders).toBe(true);
81− expect(hasSubscriptions).toBe(true);
82−
83− // GET operations should be auto-approved by default
84− const accountsTree = result.tools["fastspring"] as Record<string, unknown>;
85− const accountsGroup = accountsTree["accounts"] as Record<string, unknown>;
86− // Find a GET operation
87− for (const [_name, tool] of Object.entries(accountsGroup)) {
88− if (isToolDefinition(tool)) {
89− // At least one tool should exist in accounts
90− expect(tool.description).toBeDefined();
91− break;
92− }
93− }
94−
95− // TypeScript declarations should be generated
96− expect(result.typeDeclaration).toContain("fastspring:");
97− expect(result.typeDeclaration.length).toBeGreaterThan(100);
98−
99− // Prompt guidance should be generated
100− expect(result.promptGuidance).toContain("tools.fastspring");
101− expect(result.promptGuidance.length).toBeGreaterThan(100);
102− }, { timeout: 30_000 });
103−
104− test("respects approval overrides", async () => {
105− const result = await generateOpenApiTools({
106− name: "fastspring",
107− spec: "https://raw.githubusercontent.com/konfig-sdks/openapi-examples/refs/heads/main/fastspring/openapi.yaml",
108− overrides: {
109− "Accounts_getAccountById": { approval: "required" },
110− },
111− });
112−
113− // Find the overridden tool
114− let found = false;
115− walkToolTree(result.tools, (path, tool) => {
116− if (path.includes("Accounts_getAccountById")) {
117− expect(tool.approval).toBe("required");
118− found = true;
119− }
120− });
121−
122− expect(found).toBe(true);
123− }, { timeout: 30_000 });
124−
125− test("write operations default to required approval", async () => {
126− const result = await generateOpenApiTools({
127− name: "fastspring",
128− spec: "https://raw.githubusercontent.com/konfig-sdks/openapi-examples/refs/heads/main/fastspring/openapi.yaml",
129− });
130−
131− // POST/PUT/DELETE operations should require approval
132− let foundWriteWithApproval = false;
133− walkToolTree(result.tools, (path, tool) => {
134− // createNewAccount is a POST
135− if (path.includes("createNewAccount") || path.includes("createAndUpdate")) {
136− expect(tool.approval).toBe("required");
137− foundWriteWithApproval = true;
138− }
139− });
140−
141− expect(foundWriteWithApproval).toBe(true);
142− }, { timeout: 30_000 });
143−});
assistant/legacy/openassistant/packages/tool-gen/src/openapi.ts+0−514
@@ -1,514 +0,0 @@
1−/**
2− * OpenAPI tool generator — parses an OpenAPI spec and produces a ToolTree.
3− *
4− * Takes an OpenAPI 3.x spec (URL, file path, or inline object),
5− * groups operations by tag, and converts each into a defineTool()
6− * with Zod schemas derived from the JSON Schema in the spec.
7− */
8−
9−import SwaggerParser from "@apidevtools/swagger-parser";
10−import { defineTool, type ApprovalMode, type ToolTree } from "@openassistant/core";
11−import { jsonSchemaToZod, jsonSchemaToTypeString, type JsonSchema } from "./json-schema-to-ts.js";
12−import { z } from "zod";
13−
14−// ---------------------------------------------------------------------------
15−// Config
16−// ---------------------------------------------------------------------------
17−
18−export interface OpenApiToolSource {
19− /** Namespace in the tool tree: `tools.<name>.<tag>.<operation>` */
20− readonly name: string;
21− /** URL or file path to the OpenAPI spec, or an inline spec object. */
22− readonly spec: string | Record<string, unknown>;
23− /** Authentication configuration. */
24− readonly auth?: OpenApiAuth | undefined;
25− /** Per-operation overrides. Key is the operationId. */
26− readonly overrides?: Readonly<Record<string, {
27− readonly approval?: ApprovalMode | undefined;
28− }>> | undefined;
29− /** Default approval mode for read operations (GET/HEAD/OPTIONS). Defaults to "auto". */
30− readonly defaultReadApproval?: ApprovalMode | undefined;
31− /** Default approval mode for write operations (POST/PUT/DELETE/PATCH). Defaults to "required". */
32− readonly defaultWriteApproval?: ApprovalMode | undefined;
33− /** Override the base URL from the spec. Useful when the spec has no `servers` or you're targeting a different environment. */
34− readonly baseUrl?: string | undefined;
35−}
36−
37−export type OpenApiAuth =
38− | { readonly type: "basic"; readonly username: string; readonly password: string }
39− | { readonly type: "bearer"; readonly token: string }
40− | { readonly type: "apiKey"; readonly header: string; readonly value: string };
41−
42−// ---------------------------------------------------------------------------
43−// Result
44−// ---------------------------------------------------------------------------
45−
46−export interface OpenApiGenerateResult {
47− /** The generated tool tree, namespaced under the source name. */
48− readonly tools: ToolTree;
49− /** TypeScript declarations for the typechecker. */
50− readonly typeDeclaration: string;
51− /** Human-readable descriptions for the LLM prompt. */
52− readonly promptGuidance: string;
53−}
54−
55−// ---------------------------------------------------------------------------
56−// Internal types
57−// ---------------------------------------------------------------------------
58−
59−interface ParsedOperation {
60− tag: string;
61− operationId: string;
62− method: string;
63− path: string;
64− summary: string;
65− description: string;
66− parameters: ParsedParameter[];
67− requestBodySchema: JsonSchema | undefined;
68− responseSchema: JsonSchema | undefined;
69−}
70−
71−interface ParsedParameter {
72− name: string;
73− in: "path" | "query" | "header" | "cookie";
74− required: boolean;
75− schema: JsonSchema;
76− description?: string | undefined;
77−}
78−
79−// ---------------------------------------------------------------------------
80−// Helpers
81−// ---------------------------------------------------------------------------
82−
83−const READ_METHODS = new Set(["get", "head", "options"]);
84−const MAX_APPROVAL_PREVIEW = 240;
85−
86−
87−function buildAuthHeaders(auth: OpenApiAuth | undefined): Record<string, string> {
88− if (!auth) return {};
89− switch (auth.type) {
90− case "basic":
91− return { Authorization: `Basic ${btoa(`${auth.username}:${auth.password}`)}` };
92− case "bearer":
93− return { Authorization: `Bearer ${auth.token}` };
94− case "apiKey":
95− return { [auth.header]: auth.value };
96− }
97−}
98−
99−function buildUrl(
100− baseUrl: string,
101− path: string,
102− params: ParsedParameter[],
103− input: Record<string, unknown>,
104−): { url: string; remainingInput: Record<string, unknown> } {
105− let resolvedPath = path;
106− const queryParams: string[] = [];
107− const remainingInput = { ...input };
108−
109− for (const param of params) {
110− const value = input[param.name];
111− if (value === undefined) continue;
112−
113− if (param.in === "path") {
114− resolvedPath = resolvedPath.replace(`{${param.name}}`, encodeURIComponent(String(value)));
115− delete remainingInput[param.name];
116− } else if (param.in === "query") {
117− queryParams.push(`${encodeURIComponent(param.name)}=${encodeURIComponent(String(value))}`);
118− delete remainingInput[param.name];
119− }
120− }
121−
122− const queryString = queryParams.length > 0 ? `?${queryParams.join("&")}` : "";
123− return {
124− url: `${baseUrl}${resolvedPath}${queryString}`,
125− remainingInput,
126− };
127−}
128−
129−function sanitizeOperationId(operationId: string): string {
130− // Convert to camelCase-safe identifier
131− return operationId
132− .replace(/[^a-zA-Z0-9_]/g, "_")
133− .replace(/_+/g, "_")
134− .replace(/^_|_$/g, "");
135−}
136−
137−function sanitizeTag(tag: string): string {
138− return tag
139− .toLowerCase()
140− .replace(/[^a-zA-Z0-9_]/g, "_")
141− .replace(/_+/g, "_")
142− .replace(/^_|_$/g, "") || "default";
143−}
144−
145−function isRecord(value: unknown): value is Record<string, unknown> {
146− return typeof value === "object" && value !== null && !Array.isArray(value);
147−}
148−
149−function toPreview(value: unknown): string {
150− if (value === undefined) return "undefined";
151− if (value === null) return "null";
152− try {
153− const text = typeof value === "string" ? value : JSON.stringify(value);
154− return text.length > MAX_APPROVAL_PREVIEW
155− ? `${text.slice(0, MAX_APPROVAL_PREVIEW)}...`
156− : text;
157− } catch {
158− return String(value);
159− }
160−}
161−
162−function actionFromMethod(method: string): "create" | "update" | "delete" | "read" | "execute" {
163− switch (method.toLowerCase()) {
164− case "get":
165− case "head":
166− case "options":
167− return "read";
168− case "post":
169− return "create";
170− case "put":
171− case "patch":
172− return "update";
173− case "delete":
174− return "delete";
175− default:
176− return "execute";
177− }
178−}
179−
180−function resourceTypeFromPath(path: string): string | undefined {
181− const segments = path.split("/").filter(Boolean).filter((segment) => !segment.startsWith("{"));
182− const raw = segments.at(-1);
183− if (!raw) return undefined;
184− const normalized = raw.endsWith("s") ? raw.slice(0, -1) : raw;
185− return normalized.replace(/[_-]/g, " ");
186−}
187−
188−function extractIds(input: unknown): string[] {
189− if (!isRecord(input)) return [];
190− const ids: string[] = [];
191− for (const key of ["id", "ids", "idOrName", "name", "slug", "projectId"]) {
192− const value = input[key];
193− if (typeof value === "string" || typeof value === "number") {
194− ids.push(String(value));
195− continue;
196− }
197− if (Array.isArray(value)) {
198− for (const item of value) {
199− if (typeof item === "string" || typeof item === "number") {
200− ids.push(String(item));
201− }
202− }
203− }
204− }
205− return ids.slice(0, 5);
206−}
207−
208−function buildSelector(input: unknown): string | undefined {
209− if (!isRecord(input)) return undefined;
210− const selectors: string[] = [];
211− for (const [key, value] of Object.entries(input)) {
212− if (key === "id" || key === "ids" || key === "idOrName") continue;
213− if (value === undefined || value === null) continue;
214− if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
215− selectors.push(`${key}=${String(value)}`);
216− if (selectors.length >= 3) break;
217− }
218− }
219− return selectors.length > 0 ? selectors.join(", ") : undefined;
220−}
221−
222−function buildOpenApiApprovalPreview(
223− op: Pick<ParsedOperation, "method" | "path" | "operationId">,
224− input: unknown,
225−) {
226− const action = actionFromMethod(op.method);
227− const ids = extractIds(input);
228− const selector = buildSelector(input);
229− const resourceType = resourceTypeFromPath(op.path);
230− const title = `${op.method.toUpperCase()} ${op.path}`;
231− const detailsParts = [
232− `Operation: ${op.operationId}`,
233− ids.length > 0 ? `Target: ${ids.join(", ")}` : undefined,
234− selector ? `Selector: ${selector}` : undefined,
235− `Arguments: ${toPreview(input)}`,
236− ].filter(Boolean);
237− return {
238− title,
239− details: detailsParts.join("\n"),
240− action,
241− resourceType,
242− resourceIds: ids.length > 0 ? ids : undefined,
243− isDestructive: action === "delete",
244− selector,
245− } as const;
246−}
247−
248−// ---------------------------------------------------------------------------
249−// Spec parsing
250−// ---------------------------------------------------------------------------
251−
252−function parseOperations(api: Record<string, unknown>): ParsedOperation[] {
253− const paths = (api as { paths?: Record<string, Record<string, unknown>> }).paths ?? {};
254− const operations: ParsedOperation[] = [];
255−
256− for (const [path, pathItem] of Object.entries(paths)) {
257− if (!pathItem || typeof pathItem !== "object") continue;
258−
259− for (const method of ["get", "post", "put", "delete", "patch", "head", "options"]) {
260− const operation = (pathItem as Record<string, unknown>)[method] as Record<string, unknown> | undefined;
261− if (!operation) continue;
262−
263− const tags = (operation["tags"] as string[] | undefined) ?? ["default"];
264− const tag = sanitizeTag(tags[0] ?? "default");
265− const operationId = sanitizeOperationId(
266− (operation["operationId"] as string | undefined) ?? `${method}_${path.replace(/\//g, "_")}`,
267− );
268− const summary = (operation["summary"] as string | undefined) ?? "";
269− const description = (operation["description"] as string | undefined) ?? summary;
270−
271− // Parse parameters
272− const rawParams = [
273− ...((pathItem["parameters"] as unknown[] | undefined) ?? []),
274− ...((operation["parameters"] as unknown[] | undefined) ?? []),
275− ];
276− const parameters: ParsedParameter[] = rawParams
277− .filter((p): p is Record<string, unknown> => !!p && typeof p === "object")
278− .map((p) => ({
279− name: String(p["name"] ?? ""),
280− in: String(p["in"] ?? "query") as ParsedParameter["in"],
281− required: Boolean(p["required"]),
282− schema: (p["schema"] as JsonSchema | undefined) ?? { type: "string" },
283− description: p["description"] as string | undefined,
284− }));
285−
286− // Parse request body
287− let requestBodySchema: JsonSchema | undefined;
288− const requestBody = operation["requestBody"] as Record<string, unknown> | undefined;
289− if (requestBody) {
290− const content = requestBody["content"] as Record<string, unknown> | undefined;
291− if (content) {
292− const jsonContent = (content["application/json"] ?? content["*/*"]) as Record<string, unknown> | undefined;
293− if (jsonContent) {
294− requestBodySchema = jsonContent["schema"] as JsonSchema | undefined;
295− }
296− }
297− }
298−
299− // Parse response schema (from first 2xx response)
300− let responseSchema: JsonSchema | undefined;
301− const responses = operation["responses"] as Record<string, unknown> | undefined;
302− if (responses) {
303− for (const statusCode of Object.keys(responses)) {
304− if (statusCode.startsWith("2")) {
305− const response = responses[statusCode] as Record<string, unknown> | undefined;
306− if (response) {
307− const content = response["content"] as Record<string, unknown> | undefined;
308− if (content) {
309− const jsonContent = (content["application/json"] ?? content["*/*"]) as Record<string, unknown> | undefined;
310− if (jsonContent) {
311− responseSchema = jsonContent["schema"] as JsonSchema | undefined;
312− break;
313− }
314− }
315− }
316− }
317− }
318− }
319−
320− operations.push({
321− tag,
322− operationId,
323− method,
324− path,
325− summary,
326− description: description.slice(0, 200), // Truncate long descriptions
327− parameters,
328− requestBodySchema,
329− responseSchema,
330− });
331− }
332− }
333−
334− return operations;
335−}
336−
337−// ---------------------------------------------------------------------------
338−// Generator
339−// ---------------------------------------------------------------------------
340−
341−export async function generateOpenApiTools(
342− source: OpenApiToolSource,
343−): Promise<OpenApiGenerateResult> {
344− // Parse and dereference the spec
345− const api = await SwaggerParser.dereference(source.spec as string) as Record<string, unknown>;
346−
347− // Get base URL (config override > spec servers > empty)
348− const servers = (api["servers"] as Array<{ url: string }> | undefined) ?? [];
349− const baseUrl = source.baseUrl ?? servers[0]?.url ?? "";
350−
351− const operations = parseOperations(api);
352− const authHeaders = buildAuthHeaders(source.auth);
353−
354− // Group operations by tag
355− const byTag = new Map<string, ParsedOperation[]>();
356− for (const op of operations) {
357− const existing = byTag.get(op.tag) ?? [];
358− existing.push(op);
359− byTag.set(op.tag, existing);
360− }
361−
362− // Build tool tree
363− const namespacedTree: Record<string, Record<string, ReturnType<typeof defineTool>>> = {};
364− const typeLines: string[] = [];
365− const guidanceLines: string[] = [];
366−
367− for (const [tag, ops] of byTag) {
368− namespacedTree[tag] ??= {};
369− const tagTypeLines: string[] = [];
370−
371− for (const op of ops) {
372− const isRead = READ_METHODS.has(op.method);
373− const approval =
374− source.overrides?.[op.operationId]?.approval ??
375− (isRead
376− ? (source.defaultReadApproval ?? "auto")
377− : (source.defaultWriteApproval ?? "required"));
378−
379− // Build combined input schema from parameters + request body
380− const inputProperties: Record<string, JsonSchema> = {};
381− const inputRequired: string[] = [];
382−
383− for (const param of op.parameters) {
384− inputProperties[param.name] = {
385− ...param.schema,
386− description: param.description ?? param.schema.description,
387− };
388− if (param.required) inputRequired.push(param.name);
389− }
390−
391− if (op.requestBodySchema) {
392− // Merge request body properties into input
393− const bodyProps = (op.requestBodySchema as { properties?: Record<string, JsonSchema> }).properties;
394− const bodyRequired = (op.requestBodySchema as { required?: string[] }).required ?? [];
395− if (bodyProps) {
396− for (const [key, value] of Object.entries(bodyProps)) {
397− inputProperties[key] = value;
398− }
399− inputRequired.push(...bodyRequired);
400− } else {
401− // If the body is a single schema without properties, use "body" as the key
402− inputProperties["body"] = op.requestBodySchema;
403− }
404− }
405−
406− const combinedInputSchema: JsonSchema = {
407− type: "object",
408− properties: inputProperties,
409− required: inputRequired.length > 0 ? inputRequired : undefined,
410− };
411−
412− let argsZod: z.ZodType;
413−
414− try {
415− argsZod = jsonSchemaToZod(combinedInputSchema);
416− } catch {
417− // Recursive/circular schemas — fall back to z.any()
418− argsZod = z.any();
419− }
420−
421− // Use openapi-typescript for type strings (handles allOf, oneOf, enums, etc.)
422− const argsTypeString = jsonSchemaToTypeString(combinedInputSchema);
423− const returnsTypeString = op.responseSchema
424− ? jsonSchemaToTypeString(op.responseSchema)
425− : "any";
426−
427− const description = op.summary || op.description || `${op.method.toUpperCase()} ${op.path}`;
428−
429− namespacedTree[tag]![op.operationId] = defineTool({
430− description,
431− approval,
432− args: argsZod,
433− returns: z.any(), // OpenAPI responses are complex; use any for runtime
434− metadata: {
435− argsType: argsTypeString,
436− returnsType: returnsTypeString,
437− },
438− run: async (input: unknown) => {
439− const { url, remainingInput } = buildUrl(
440− baseUrl,
441− op.path,
442− op.parameters,
443− input as Record<string, unknown>,
444− );
445−
446− const hasBody = !isRead && Object.keys(remainingInput).length > 0;
447−
448− const fetchInit: RequestInit = {
449− method: op.method.toUpperCase(),
450− headers: {
451− ...authHeaders,
452− ...(hasBody ? { "Content-Type": "application/json" } : {}),
453− "User-Agent": "openassistant/0.1.0",
454− },
455− };
456− if (hasBody) {
457− fetchInit.body = JSON.stringify(remainingInput);
458− }
459−
460− // Retry once on any fetch error (stale keep-alive sockets, DNS, etc.).
461− // On retry, force Connection: close to bypass dead pooled sockets.
462− let response: Response;
463− try {
464− response = await fetch(url, fetchInit);
465− } catch (firstError) {
466− try {
467− const retryInit = {
468− ...fetchInit,
469− headers: { ...(fetchInit.headers as Record<string, string>), Connection: "close" },
470− };
471− response = await fetch(url, retryInit);
472− } catch {
473− throw firstError; // retry failed too, throw the original
474− }
475− }
476−
477− if (!response.ok) {
478− const text = await response.text().catch(() => "");
479− throw new Error(`HTTP ${response.status} ${response.statusText} (${op.method.toUpperCase()} ${url}): ${text.slice(0, 500)}`);
480− }
481−
482− const contentType = response.headers.get("content-type") ?? "";
483− if (contentType.includes("json")) {
484− return response.json();
485− }
486− return response.text();
487− },
488− formatApproval: (input) => buildOpenApiApprovalPreview(op, input),
489− });
490−
491− // Build TypeScript declaration
492− const approvalNote = approval === "required" ? " (approval required)" : " (auto-approved)";
493− tagTypeLines.push(` /** ${description} */`);
494− tagTypeLines.push(` ${op.operationId}(input: ${argsTypeString}): Promise<${returnsTypeString}>;`);
495−
496− guidanceLines.push(
497− `- tools.${source.name}.${tag}.${op.operationId}(${argsTypeString}): Promise<${returnsTypeString}>${approvalNote} — ${description}`,
498− );
499− }
500−
501− typeLines.push(` ${tag}: {`);
502− typeLines.push(tagTypeLines.join("\n"));
503− typeLines.push(` };`);
504− }
505−
506− const typeDeclaration = `${source.name}: {\n${typeLines.join("\n")}\n}`;
507− const promptGuidance = guidanceLines.join("\n");
508−
509− return {
510− tools: { [source.name]: namespacedTree },
511− typeDeclaration,
512− promptGuidance,
513− };
514−}
assistant/legacy/openassistant/packages/tool-gen/tsconfig.json+0−12
@@ -1,12 +0,0 @@
1−{
2− "extends": "../../tsconfig.base.json",
3− "compilerOptions": {
4− "composite": true,
5− "rootDir": "src",
6− "outDir": "dist"
7− },
8− "include": ["src"],
9− "references": [
10− { "path": "../core" }
11− ]
12−}
assistant/legacy/openassistant/tsconfig.base.json+0−22
@@ -1,22 +0,0 @@
1−{
2− "compilerOptions": {
3− "target": "ES2022",
4− "module": "NodeNext",
5− "moduleResolution": "NodeNext",
6− "moduleDetection": "force",
7− "verbatimModuleSyntax": true,
8− "rewriteRelativeImportExtensions": true,
9− "strict": true,
10− "exactOptionalPropertyTypes": true,
11− "noUncheckedIndexedAccess": true,
12− "noImplicitOverride": true,
13− "noUnusedLocals": true,
14− "noUnusedParameters": true,
15− "skipLibCheck": true,
16− "plugins": [
17− {
18− "name": "@effect/language-service"
19− }
20− ]
21− }
22−}
assistant/legacy/openassistant/tsconfig.json+0−9
@@ -1,9 +0,0 @@
1−{
2− "files": [],
3− "references": [
4− { "path": "./packages/core" },
5− { "path": "./packages/tool-gen" },
6− { "path": "./apps/server" },
7− { "path": "./apps/executor" }
8− ]
9−}
assistant/legacy/openassistant/vitest.config.ts+0−8
@@ -1,8 +0,0 @@
1−import { defineConfig } from "vitest/config";
2−
3−export default defineConfig({
4− test: {
5− include: ["packages/**/*.test.ts", "apps/**/*.test.ts"],
6− exclude: ["**/node_modules/**", ".context/**", ".reference/**"],
7− },
8−});
assistant/package.json+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
33 "private": true,
44 "type": "module",
55 "scripts": {
6− "test": "bun test packages/core/src/ packages/agent-executor-adapter/src/",
6+ "test": "bun test packages/core/src/",
77 "dev:server": "bun run --filter @assistant/server dev",
88 "dev:bot": "bun run --filter @assistant/bot dev"
99 },
assistant/packages/agent-executor-adapter/package.json+0−18
@@ -1,18 +0,0 @@
1−{
2− "name": "@assistant/agent-executor-adapter",
3− "private": true,
4− "type": "module",
5− "exports": {
6− ".": "./src/index.ts"
7− },
8− "scripts": {
9− "test": "bun test src/"
10− },
11− "dependencies": {
12− "@elysiajs/eden": "^1.4.6",
13− "elysia": "^1.4.22"
14− },
15− "devDependencies": {
16− "@types/bun": "latest"
17− }
18−}
assistant/packages/agent-executor-adapter/src/index.test.ts+0−87
@@ -1,87 +0,0 @@
1−import { expect, test } from "bun:test";
2−import { Elysia, t } from "elysia";
3−import { treaty } from "@elysiajs/eden";
4−
5−// Minimal Elysia server that mimics the executor's task creation route
6−function createTestServer() {
7− return new Elysia()
8− .get("/api/health", () => ({ ok: true as const, tools: 5 }))
9− .post("/api/tasks", ({ body }) => ({
10− taskId: "task_test_1",
11− status: "queued" as const,
12− }), {
13− body: t.Object({
14− code: t.String(),
15− timeoutMs: t.Optional(t.Number()),
16− runtimeId: t.Optional(t.String()),
17− metadata: t.Optional(t.Record(t.String(), t.Unknown())),
18− workspaceId: t.String(),
19− actorId: t.String(),
20− clientId: t.Optional(t.String()),
21− }),
22− })
23− .post("/api/auth/anonymous/bootstrap", ({ body }) => ({
24− sessionId: body.sessionId ?? "sess_test",
25− workspaceId: "ws_anon",
26− actorId: "actor_anon",
27− clientId: "client_anon",
28− createdAt: Date.now(),
29− lastSeenAt: Date.now(),
30− }), {
31− body: t.Object({
32− sessionId: t.Optional(t.String()),
33− }),
34− })
35− .listen(0);
36−}
37−
38−test("Eden Treaty client can create a task with full type safety", async () => {
39− const server = createTestServer();
40− const client = treaty<typeof server>(`http://127.0.0.1:${server.server!.port}`);
41−
42− try {
43− const { data, error } = await client.api.tasks.post({
44− code: "console.log('hello')",
45− workspaceId: "ws_test",
46− actorId: "actor_test",
47− });
48−
49− expect(error).toBeNull();
50− expect(data!.taskId).toBe("task_test_1");
51− expect(data!.status).toBe("queued");
52− } finally {
53− server.stop(true);
54− }
55−});
56−
57−test("Eden Treaty client can check health", async () => {
58− const server = createTestServer();
59− const client = treaty<typeof server>(`http://127.0.0.1:${server.server!.port}`);
60−
61− try {
62− const { data, error } = await client.api.health.get();
63−
64− expect(error).toBeNull();
65− expect(data!.ok).toBe(true);
66− expect(data!.tools).toBe(5);
67− } finally {
68− server.stop(true);
69− }
70−});
71−
72−test("Eden Treaty client can bootstrap anonymous context", async () => {
73− const server = createTestServer();
74− const client = treaty<typeof server>(`http://127.0.0.1:${server.server!.port}`);
75−
76− try {
77− const { data, error } = await client.api.auth.anonymous.bootstrap.post({
78− sessionId: "my-session",
79− });
80−
81− expect(error).toBeNull();
82− expect(data!.workspaceId).toBe("ws_anon");
83− expect(data!.sessionId).toBe("my-session");
84− } finally {
85− server.stop(true);
86− }
87−});
assistant/packages/agent-executor-adapter/src/index.ts+0−8
@@ -1,8 +0,0 @@
1−import { treaty } from "@elysiajs/eden";
2−import type { App } from "@executor/server/src/index";
3−
4−export function createExecutorClient(baseUrl: string) {
5− return treaty<App>(baseUrl);
6−}
7−
8−export type ExecutorClient = ReturnType<typeof createExecutorClient>;
assistant/packages/agent-executor-adapter/tsconfig.json+0−14
@@ -1,14 +0,0 @@
1−{
2− "compilerOptions": {
3− "target": "ESNext",
4− "module": "ESNext",
5− "moduleResolution": "bundler",
6− "strict": true,
7− "esModuleInterop": true,
8− "skipLibCheck": true,
9− "paths": {
10− "@executor/server/*": ["../../../executor/apps/server/*"]
11− }
12− },
13− "include": ["src"]
14−}
assistant/packages/reacord/package.jsonrenamed from assistant/legacy/openassistant/packages/reacord/package.json+0−0

File renamed without changes.

assistant/packages/reacord/src/components/action-row.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/action-row.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/attachment.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/attachment.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/button.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/button.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/container.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/container.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/file.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/file.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/link.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/link.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/loading-select.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/loading-select.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/loading.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/loading.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/media-gallery.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/media-gallery.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/modal-button.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/modal-button.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/option.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/option.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/section.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/section.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/select.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/select.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/separator.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/separator.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/text-display.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/text-display.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/thumbnail.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/thumbnail.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/components/user-select.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/components/user-select.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/create-component.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/create-component.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/index.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/index.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/instance-context.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/instance-context.tsx+0−0

File renamed without changes.

assistant/packages/reacord/src/instance.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/instance.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/container.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/container.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/element.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/element.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/errors.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/errors.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/helpers.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/helpers.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/interaction.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/interaction.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/message.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/message.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/node.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/node.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/reconciler.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/reconciler.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/renderer.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/renderer.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/internal/text-node.tsrenamed from assistant/legacy/openassistant/packages/reacord/src/internal/text-node.ts+0−0

File renamed without changes.

assistant/packages/reacord/src/reacord.tsxrenamed from assistant/legacy/openassistant/packages/reacord/src/reacord.tsx+0−0

File renamed without changes.

assistant/packages/reacord/tsconfig.jsonrenamed from assistant/legacy/openassistant/packages/reacord/tsconfig.json+9−3
@@ -1,10 +1,16 @@
11 {
2− "extends": "../../tsconfig.base.json",
32 "compilerOptions": {
4− "exactOptionalPropertyTypes": false,
5− "jsx": "react-jsx",
3+ "target": "ES2022",
64 "module": "ESNext",
75 "moduleResolution": "Bundler",
6+ "moduleDetection": "force",
7+ "verbatimModuleSyntax": true,
8+ "jsx": "react-jsx",
9+ "strict": true,
10+ "exactOptionalPropertyTypes": false,
11+ "noUncheckedIndexedAccess": true,
12+ "noImplicitOverride": true,
13+ "skipLibCheck": true,
814 "rootDir": "src"
915 },
1016 "include": [
bun.lock+54−116
@@ -12,31 +12,6 @@ · 11 unmodified lines
1212 "typescript": "latest",
1313 },
1414 },
15− "assistant/legacy/openassistant/packages/reacord": {
16− "name": "@openassistant/reacord",
17− "dependencies": {
18− "@effect-atom/atom": "^0.4.11",
19− "@effect-atom/atom-react": "^0.4.4",
20− "discord.js": "^14.17.3",
21− "effect": "latest",
22− "react": "^19.0.0",
23− "react-reconciler": "^0.31.0",
24− },
25− "devDependencies": {
26− "@types/react": "^19.0.0",
27− "@types/react-reconciler": "^0.31.0",
28− },
29− },
30− "assistant/packages/agent-executor-adapter": {
31− "name": "@assistant/agent-executor-adapter",
32− "dependencies": {
33− "@elysiajs/eden": "^1.4.6",
34− "elysia": "^1.4.22",
35− },
36− "devDependencies": {
37− "@types/bun": "latest",
38− },
39− },
4015 "assistant/packages/bot": {
4116 "name": "@assistant/bot",
4217 "dependencies": {
@@ -61,11 +36,24 @@ · 18 unmodified lines
6136 "@modelcontextprotocol/sdk": "^1.26.0",
6237 },
6338 "devDependencies": {
64− "@elysiajs/eden": "^1.4.6",
65− "elysia": "^1.4.22",
6639 "zod": "^4.3.6",
6740 },
6841 },
42+ "assistant/packages/reacord": {
43+ "name": "@openassistant/reacord",
44+ "dependencies": {
45+ "@effect-atom/atom": "^0.4.11",
46+ "@effect-atom/atom-react": "^0.4.4",
47+ "discord.js": "^14.17.3",
48+ "effect": "latest",
49+ "react": "^19.0.0",
50+ "react-reconciler": "^0.31.0",
51+ },
52+ "devDependencies": {
53+ "@types/react": "^19.0.0",
54+ "@types/react-reconciler": "^0.31.0",
55+ },
56+ },
6957 "assistant/packages/server": {
7058 "name": "@assistant/server",
7159 "dependencies": {
@@ -81,12 +69,11 @@ · 9 unmodified lines
8169 "executor": {
8270 "name": "executor-monorepo",
8371 "dependencies": {
84− "convex": "latest",
72+ "convex": "^1.31.7",
8573 },
8674 "devDependencies": {
8775 "@types/bun": "latest",
8876 "convex-test": "^0.0.41",
89− "esbuild": "^0.27.3",
9077 "typescript": "latest",
9178 },
9279 },
@@ -94,10 +81,10 @@ · 1 unmodified line
9481 "name": "@executor/server",
9582 "dependencies": {
9683 "@apidevtools/swagger-parser": "^12.1.0",
97− "@elysiajs/eden": "^1.4.6",
84+ "@executor/contracts": "workspace:*",
9885 "@modelcontextprotocol/sdk": "^1.26.0",
9986 "@vercel/sandbox": "latest",
100− "convex": "latest",
87+ "convex": "^1.31.7",
10188 "elysia": "^1.4.22",
10289 "openapi-typescript": "^7.10.1",
10390 "zod": "^4.3.6",
@@ -111,10 +98,11 @@ · 7 unmodified lines
11198 "name": "@executor/web",
11299 "version": "0.1.0",
113100 "dependencies": {
101+ "@executor/contracts": "workspace:*",
114102 "@monaco-editor/react": "^4.7.0",
115103 "class-variance-authority": "^0.7.1",
116104 "clsx": "^2.1.1",
117− "convex": "latest",
105+ "convex": "^1.31.7",
118106 "lucide-react": "^0.563.0",
119107 "monaco-editor": "^0.55.1",
120108 "next": "16.1.6",
@@ -139,6 +127,10 @@ · 18 unmodified lines
139127 "typescript": "^5",
140128 },
141129 },
130+ "executor/packages/contracts": {
131+ "name": "@executor/contracts",
132+ "version": "0.0.1",
133+ },
142134 },
143135 "trustedDependencies": [
144136 "sharp",
@@ -159,8 +151,6 @@ · 14 unmodified lines
159151
160152 "@apidevtools/swagger-parser": ["@apidevtools/swagger-parser@12.1.0", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "14.0.1", "@apidevtools/openapi-schemas": "^2.1.0", "@apidevtools/swagger-methods": "^3.0.2", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "call-me-maybe": "^1.0.2" }, "peerDependencies": { "openapi-types": ">=7" } }, "sha512-e5mJoswsnAX0jG+J09xHFYQXb/bUc5S3pLpMxUuRUA2H8T2kni3yEoyz2R3Dltw5f4A6j6rPNMpWTK+iVDFlng=="],
161153
162− "@assistant/agent-executor-adapter": ["@assistant/agent-executor-adapter@workspace:assistant/packages/agent-executor-adapter"],
163−
164154 "@assistant/bot": ["@assistant/bot@workspace:assistant/packages/bot"],
165155
166156 "@assistant/core": ["@assistant/core@workspace:assistant/packages/core"],
@@ -329,57 +319,57 @@ · 162 unmodified lines
329319
330320 "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
331321
332− "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
322+ "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="],
333323
334− "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
324+ "@esbuild/android-arm": ["@esbuild/android-arm@0.27.0", "", { "os": "android", "cpu": "arm" }, "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ=="],
335325
336− "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="],
326+ "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ=="],
337327
338− "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="],
328+ "@esbuild/android-x64": ["@esbuild/android-x64@0.27.0", "", { "os": "android", "cpu": "x64" }, "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q=="],
339329
340− "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="],
330+ "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg=="],
341331
342− "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="],
332+ "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g=="],
343333
344− "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="],
334+ "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw=="],
345335
346− "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="],
336+ "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g=="],
347337
348− "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="],
338+ "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ=="],
349339
350− "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="],
340+ "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ=="],
351341
352− "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="],
342+ "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw=="],
353343
354− "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="],
344+ "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg=="],
355345
356− "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="],
346+ "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg=="],
357347
358− "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="],
348+ "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA=="],
359349
360− "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="],
350+ "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ=="],
361351
362− "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="],
352+ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w=="],
363353
364− "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="],
354+ "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.0", "", { "os": "linux", "cpu": "x64" }, "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw=="],
365355
366− "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="],
356+ "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w=="],
367357
368− "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="],
358+ "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.0", "", { "os": "none", "cpu": "x64" }, "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA=="],
369359
370− "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="],
360+ "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ=="],
371361
372− "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="],
362+ "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A=="],
373363
374− "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="],
364+ "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA=="],
375365
376− "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="],
366+ "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA=="],
377367
378− "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="],
368+ "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg=="],
379369
380− "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="],
370+ "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ=="],
381371
382− "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="],
372+ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.0", "", { "os": "win32", "cpu": "x64" }, "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg=="],
383373
384374 "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
385375
@@ -399,6 +389,8 @@ · 13 unmodified lines
399389
400390 "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
401391
392+ "@executor/contracts": ["@executor/contracts@workspace:executor/packages/contracts"],
393+
402394 "@executor/server": ["@executor/server@workspace:executor/apps/server"],
403395
404396 "@executor/web": ["@executor/web@workspace:executor/apps/web"],
@@ -565,7 +557,7 @@ · 160 unmodified lines
565557
566558 "@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="],
567559
568− "@openassistant/reacord": ["@openassistant/reacord@workspace:assistant/legacy/openassistant/packages/reacord"],
560+ "@openassistant/reacord": ["@openassistant/reacord@workspace:assistant/packages/reacord"],
569561
570562 "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
571563
@@ -1199,7 +1191,7 @@ · 627 unmodified lines
11991191
12001192 "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="],
12011193
1202− "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
1194+ "esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="],
12031195
12041196 "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
12051197
@@ -2171,8 +2163,6 @@ · 965 unmodified lines
21712163
21722164 "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
21732165
2174− "convex/esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="],
2175−
21762166 "cosmiconfig/parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
21772167
21782168 "degenerator/ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="],
@@ -2275,58 +2265,6 @@ · 96 unmodified lines
22752265
22762266 "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
22772267
2278− "convex/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="],
2279−
2280− "convex/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.0", "", { "os": "android", "cpu": "arm" }, "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ=="],
2281−
2282− "convex/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ=="],
2283−
2284− "convex/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.0", "", { "os": "android", "cpu": "x64" }, "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q=="],
2285−
2286− "convex/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg=="],
2287−
2288− "convex/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g=="],
2289−
2290− "convex/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw=="],
2291−
2292− "convex/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g=="],
2293−
2294− "convex/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ=="],
2295−
2296− "convex/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ=="],
2297−
2298− "convex/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw=="],
2299−
2300− "convex/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg=="],
2301−
2302− "convex/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg=="],
2303−
2304− "convex/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA=="],
2305−
2306− "convex/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ=="],
2307−
2308− "convex/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w=="],
2309−
2310− "convex/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.0", "", { "os": "linux", "cpu": "x64" }, "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw=="],
2311−
2312− "convex/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w=="],
2313−
2314− "convex/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.0", "", { "os": "none", "cpu": "x64" }, "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA=="],
2315−
2316− "convex/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ=="],
2317−
2318− "convex/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A=="],
2319−
2320− "convex/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA=="],
2321−
2322− "convex/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA=="],
2323−
2324− "convex/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg=="],
2325−
2326− "convex/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ=="],
2327−
2328− "convex/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.0", "", { "os": "win32", "cpu": "x64" }, "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg=="],
2329−
23302268 "eslint-plugin-import/tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
23312269
23322270 "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
package.json+1−1
@@ -8,7 +8,7 @@ · 7 unmodified lines
88 "executor/packages/*",
99 "assistant",
1010 "assistant/packages/*",
11− "assistant/legacy/openassistant/packages/reacord"
11+ "assistant/packages/reacord"
1212 ],
1313 "scripts": {
1414 "dev": "bun run dev.ts",

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t