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
2 2
3Assistant-side code lives here.3Assistant-side code lives here.
4 4
5- `packages/agent-executor-adapter`: lightweight adapter for talking to the executor API.
6- `legacy/openassistant`: previous prototype code moved out of the executor-focused workspace.5- `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
5An 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
41The server never POSTs to clients. Instead:
421. Every task produces a stream of `TaskEvent`s (persisted, resumable)
432. Clients subscribe via SSE/WebSocket/polling
443. When a tool needs approval, the server emits an `approval_request` event
454. Any client renders approval UI and POSTs the decision to `POST /api/approvals/:callId`
465. The server picks up the decision and continues execution
47
48This is client-agnostic. Discord, web, CLI — they all implement the same protocol.
49
50## Execution Sandbox
51
52LLM-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
61Tool 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
73All 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"
77export 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"
84export 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"
93export 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
106async 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
120import { z } from "zod";
121
122defineTool({
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
151All produce the same `ToolTree` + TypeScript declarations. The runner doesn't know the difference.
152
153**1. Hand-written plugins**
154```ts
155export 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
183const 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
1941. Agent generates code that calls `tools.github.issues.close(...)`
1952. Runner hits the approval gate for `approval: "required"` tools
1963. Runner emits `{ type: "approval_request", id, toolPath, preview }` to the task event stream
1974. Runner polls `getApprovalDecision(callId)` in a loop
1985. Client (Discord/web/CLI) sees the event, renders approval UI
1996. User clicks Approve → client POSTs to `POST /api/approvals/:callId`
2007. Decision is written to DB
2018. Runner's poll picks it up, execution continues
202
203### Background tasks (recurring/event-triggered, no active conversation)
204
205Same flow, but the client sends a proactive DM/notification with approval buttons. The user approves asynchronously.
206
207### Batch approval (future enhancement)
208
209For 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
213Every task run produces events. Clients subscribe and render them however they want.
214
215```ts
216type 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
229The agent has task management tools (so the user speaks natural language):
230
231```
232tools.tasks.list() → active tasks for this user
233tools.tasks.createRecurring(...) → starts a recurring workflow
234tools.tasks.createEventTrigger(...) → starts an event-triggered workflow
235tools.tasks.cancel({ taskId }) → cancels a workflow run
236tools.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
2491. Build system prompt from tool descriptions + type declarations + task context
2502. Call Claude with the prompt and the `run_code` tool
2513. Claude responds with `run_code({ code: "..." })`
2524. Typecheck the code against generated TypeScript declarations
2535. If typecheck fails: feed error back to Claude, retry (up to 3 times)
2546. Execute code in `node:vm` sandbox
2557. Collect receipts from all tool calls
2568. Feed receipts back to Claude
2579. Claude may call `run_code` again, or produce final text response
25810. Emit `agent_message` event to the stream
259
260## Effect Usage
261
262Effect 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
268The 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```
273POST /.well-known/workflow/v1/flow Workflow flow handler
274POST /.well-known/workflow/v1/step Workflow step handler
275* /.well-known/workflow/v1/webhook/:token Workflow webhook handler
276
277POST /api/tasks Create a new task
278GET /api/tasks List tasks for a user
279GET /api/tasks/:id Get task status
280GET /api/tasks/:id/events SSE stream of TaskEvents
281POST /api/tasks/:id/cancel Cancel a task
282
283POST /api/approvals/:callId Resolve an approval decision
284
285POST /api/hooks/:token Webhook ingestion (external services POST here)
286```
287
288## Monorepo Layout
289
290```
291apps/
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
304packages/
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
3231. **packages/core** — defineTool, ToolTree, runner (node:vm), typechecker, agent loop, TaskEvent types. Tested with real Claude calls.
3242. **packages/tool-gen** — MCP + OpenAPI generation. Uses existing parsers (@modelcontextprotocol/sdk, swagger-parser).
3253. **apps/server** — Bun.serve + Workflow integration + REST API + SSE streams.
3264. **apps/bot** — Discord client consuming event streams.
327
328## Testing
329
330Real 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
6bun install
7```
8
9## Local MVP (remote executor mode)
10
11Start the executor (private code runner):
12
13```bash
14bun run --filter '@openassistant/executor' dev
15```
16
17Start the server (agent + approvals + tool broker):
18
19```bash
20OPENASSISTANT_EXECUTOR_URL=http://localhost:3001 \
21OPENASSISTANT_CALLBACK_BASE_URL=http://localhost:3000 \
22bun run --filter '@openassistant/server' dev
23```
24
25Or run all services together:
26
27```bash
28bun 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
9import type { ChatInputCommandInteraction, CommandInteraction } from "discord.js";
10import type { Client as ApiClient } from "@openassistant/server/client";
11import { unwrap } from "@openassistant/server/client";
12import type { ReacordInstance } from "@openassistant/reacord";
13import { Effect, Runtime } from "effect";
14import { TaskMessage } from "../views/task-message";
15
16// ---------------------------------------------------------------------------
17// Types
18// ---------------------------------------------------------------------------
19
20interface 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
31export 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
10import {
11 Client,
12 GatewayIntentBits,
13 REST,
14 Routes,
15 SlashCommandBuilder,
16 type ChatInputCommandInteraction,
17} from "discord.js";
18import { makeReacord } from "@openassistant/reacord";
19import { createClient } from "@openassistant/server/client";
20import { handleAskCommand } from "./commands/ask";
21
22// ---------------------------------------------------------------------------
23// Config
24// ---------------------------------------------------------------------------
25
26const DISCORD_TOKEN = process.env["DISCORD_BOT_TOKEN"];
27if (!DISCORD_TOKEN) {
28 throw new Error("DISCORD_BOT_TOKEN is required");
29}
30
31const SERVER_URL = process.env["OPENASSISTANT_SERVER_URL"] ?? "http://localhost:3000";
32
33// ---------------------------------------------------------------------------
34// Discord client
35// ---------------------------------------------------------------------------
36
37const client = new Client({
38 intents: [
39 GatewayIntentBits.Guilds,
40 GatewayIntentBits.GuildMessages,
41 ],
42});
43
44// ---------------------------------------------------------------------------
45// Reacord
46// ---------------------------------------------------------------------------
47
48const reacord = makeReacord(client, { maxInstances: 50 });
49
50// ---------------------------------------------------------------------------
51// Eden Treaty API client
52// ---------------------------------------------------------------------------
53
54const api = createClient(SERVER_URL);
55
56// ---------------------------------------------------------------------------
57// Slash command definitions
58// ---------------------------------------------------------------------------
59
60const 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
79async 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
97client.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
116client.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
122client.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
11import { useState, useEffect } from "react";
12import {
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";
24import type { Client as ApiClient } from "@openassistant/server/client";
25import { unwrap } from "@openassistant/server/client";
26import type { TaskEvent } from "@openassistant/core/events";
27import type { ApprovalPresentation } from "@openassistant/core/tools";
28
29// ---------------------------------------------------------------------------
30// State
31// ---------------------------------------------------------------------------
32
33interface PendingApproval {
34 readonly id: string;
35 readonly toolPath: string;
36 readonly input: unknown;
37 readonly preview: ApprovalPresentation;
38}
39
40interface 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
52const 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
63function 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
114export interface TaskMessageProps {
115 readonly taskId: string;
116 readonly prompt: string;
117 readonly api: ApiClient;
118 readonly executionMode: "local" | "remote";
119}
120
121export 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
236function 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
365interface FieldInfo {
366 readonly name: string;
367 readonly path: string;
368 readonly preview?: string;
369}
370
371function 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
393function 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 */
407function 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 */
416function 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 */
439function 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 */
480function 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
8import {
9 createRunner,
10 defineTool,
11 ToolDeniedError,
12 type ToolTree,
13} from "@openassistant/core";
14import type {
15 ExecutorInvokeResponse,
16 ExecutorRunRequest,
17 ExecutorToolManifestEntry,
18} from "@openassistant/core/remote-runner";
19import { z } from "zod";
20
21const 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
33const 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
40function 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
49function 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
106function 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
114const PORT = Number(process.env["PORT"] ?? 3001);
115
116Bun.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
150console.log(`OpenAssistant executor running at http://localhost:${PORT}`);
assistant/legacy/openassistant/apps/executor/src/smoke.test.ts+0−5
@@ -1,5 +0,0 @@
1import { expect, test } from "bun:test";
2
3test("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
7import { test, expect, describe } from "bun:test";
8import { treaty } from "@elysiajs/eden";
9import { createApp } from "./routes.js";
10import { ApiError, unwrap } from "./client.js";
11import { defineTool } from "@openassistant/core/tools";
12import type { ToolTree } from "@openassistant/core/tools";
13import type { LanguageModel, GenerateResult } from "@openassistant/core/agent";
14import { z } from "zod";
15
16// ---------------------------------------------------------------------------
17// Fixtures
18// ---------------------------------------------------------------------------
19
20const 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
28const testTools: ToolTree = { echo: echoTool };
29
30function createSimpleModel(): LanguageModel {
31 return {
32 async generate(): Promise<GenerateResult> {
33 return { text: "All done." };
34 },
35 };
36}
37
38function createTestApp() {
39 return createApp({
40 tools: testTools,
41 model: createSimpleModel(),
42 });
43}
44
45// ---------------------------------------------------------------------------
46// Tests
47// ---------------------------------------------------------------------------
48
49describe("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
126describe("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
19import { type Treaty, treaty } from "@elysiajs/eden";
20import type { App } from "./routes.js";
21
22// ---------------------------------------------------------------------------
23// Client factory
24// ---------------------------------------------------------------------------
25
26export type Client = ReturnType<typeof treaty<App>>;
27
28export 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 */
36export 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 */
52export 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 */
77export 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
104export 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
8import { readFileSync } from "node:fs";
9import { createApp } from "./routes.js";
10import { createPiAiModel } from "@openassistant/core";
11import { defineTool, mergeToolTrees, type ToolTree } from "@openassistant/core/tools";
12import { generateMcpTools } from "@openassistant/tool-gen/mcp";
13import type { McpToolSource } from "@openassistant/tool-gen/mcp";
14import { generateOpenApiTools } from "@openassistant/tool-gen/openapi";
15import type { OpenApiToolSource } from "@openassistant/tool-gen/openapi";
16import { 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 */
28function 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
51const mcpSources: McpToolSource[] = [
52 {
53 name: "answeroverflow",
54 url: "https://www.answeroverflow.com/mcp",
55 defaultApproval: "auto",
56 },
57];
58
59const POSTHOG_API_KEY = process.env["POSTHOG_PERSONAL_API_KEY"];
60const POSTHOG_PROJECT_ID = process.env["POSTHOG_PROJECT_ID"];
61const GITHUB_TOKEN = process.env["OPENASSISTANT_GITHUB_TOKEN"];
62const VERCEL_TOKEN = process.env["VERCEL_TOKEN"];
63
64const 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
93const 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
143async 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
181const PORT = Number(process.env["PORT"] ?? 3000);
182const EXECUTOR_URL = process.env["OPENASSISTANT_EXECUTOR_URL"];
183const CALLBACK_BASE_URL = process.env["OPENASSISTANT_CALLBACK_BASE_URL"]
184 ?? `http://localhost:${PORT}`;
185
186const apiKey = getAnthropicApiKey();
187if (!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
191console.log("Loading tools...");
192const tools = await loadTools();
193const model = createPiAiModel({ apiKey });
194
195// Build context for the system prompt
196const contextLines: string[] = [];
197if (POSTHOG_PROJECT_ID) {
198 contextLines.push(`- PostHog project ID: ${POSTHOG_PROJECT_ID} (use this for PostHog API calls that require a project_id)`);
199}
200if (GITHUB_TOKEN) {
201 contextLines.push(`- GitHub: authenticated via personal access token`);
202}
203if (VERCEL_TOKEN) {
204 contextLines.push(`- Vercel: authenticated via personal token`);
205}
206const context = contextLines.length > 0 ? contextLines.join("\n") : undefined;
207
208if (EXECUTOR_URL) {
209 console.log(`Using remote executor at ${EXECUTOR_URL}`);
210}
211
212const 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
224app.listen(PORT);
225
226console.log(`\u{1f98a} OpenAssistant server running at http://localhost:${PORT}`);
227
228// Re-export the app type for Eden Treaty clients
229export 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
8import { test, expect, describe } from "bun:test";
9import { treaty } from "@elysiajs/eden";
10import { createApp } from "./routes.js";
11import { registerRemoteRunSession, removeRemoteRunSession } from "./state.js";
12import { defineTool } from "@openassistant/core/tools";
13import type { ToolTree } from "@openassistant/core/tools";
14import type { LanguageModel, GenerateResult, Message } from "@openassistant/core/agent";
15import { z } from "zod";
16
17// ---------------------------------------------------------------------------
18// Test fixtures
19// ---------------------------------------------------------------------------
20
21/** A simple echo tool for testing. */
22const 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. */
31const 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
43const 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 */
52function 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 */
67function 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 */
94function 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
117function createTestApp(model?: LanguageModel) {
118 return createApp({
119 tools: testTools,
120 model: model ?? createMockModel(),
121 });
122}
123
124// ---------------------------------------------------------------------------
125// Tests
126// ---------------------------------------------------------------------------
127
128describe("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
158describe("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
180describe("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
210describe("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
250describe("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
293describe("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
307describe("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
340describe("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
14import { Elysia, sse, t } from "elysia";
15import {
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";
27import { runTask, type TaskRunnerOptions } from "./task-runner.js";
28
29// ---------------------------------------------------------------------------
30// Elysia validation schemas (TypeBox — Elysia's native)
31// ---------------------------------------------------------------------------
32
33const CreateTaskBody = t.Object({
34 prompt: t.String({ minLength: 1 }),
35 requesterId: t.String({ minLength: 1 }),
36 channelId: t.Optional(t.String()),
37});
38
39const ApprovalBody = t.Object({
40 decision: t.Union([t.Literal("approved"), t.Literal("denied")]),
41});
42
43const 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
56const RemoteInvokeBody = t.Object({
57 toolPath: t.String({ minLength: 1 }),
58 input: t.Any(),
59});
60
61// ---------------------------------------------------------------------------
62// Task serialization (strip internal fields)
63// ---------------------------------------------------------------------------
64
65function 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
92export 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
313export 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
8import type { TaskEvent } from "@openassistant/core/events";
9import type { ApprovalDecision } from "@openassistant/core/tools";
10
11// ---------------------------------------------------------------------------
12// Types
13// ---------------------------------------------------------------------------
14
15export type TaskStatus = "running" | "completed" | "failed" | "cancelled";
16export type TaskExecutionMode = "local" | "remote";
17
18export 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
33export 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
41export type RuleOperator = "equals" | "not_equals" | "includes" | "not_includes";
42
43export 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
55export interface RemoteRunInvokeResult {
56 readonly ok: boolean;
57 readonly value?: unknown;
58 readonly error?: string;
59 readonly denied?: boolean;
60}
61
62export 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
75const tasks = new Map<string, Task>();
76const pendingApprovals = new Map<string, PendingApproval>();
77const approvalRules = new Map<string, ApprovalRule[]>(); // taskId → rules
78const remoteRunSessions = new Map<string, RemoteRunSession>();
79
80let taskCounter = 0;
81
82export function generateTaskId(): string {
83 return `task_${Date.now()}_${++taskCounter}`;
84}
85
86// -- Tasks --
87
88export 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
110export function getTask(id: string): Task | undefined {
111 return tasks.get(id);
112}
113
114export 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
122export 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
148export 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
163export 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
174export 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
186export function getPendingApproval(callId: string): PendingApproval | undefined {
187 return pendingApprovals.get(callId);
188}
189
190export 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 */
204function 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 */
216function 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 */
230export 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 */
243export 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
260export function listApprovalRules(taskId: string): ApprovalRule[] {
261 return approvalRules.get(taskId) ?? [];
262}
263
264// -- Remote Runner Sessions --
265
266export function registerRemoteRunSession(session: RemoteRunSession): void {
267 remoteRunSessions.set(session.runId, session);
268}
269
270export function getRemoteRunSession(runId: string): RemoteRunSession | undefined {
271 return remoteRunSessions.get(runId);
272}
273
274export 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
8import { createRemoteRunner } from "@openassistant/core";
9import type { ToolDefinition, ToolTree, ApprovalRequest, ApprovalDecision } from "@openassistant/core/tools";
10import { isToolDefinition } from "@openassistant/core/tools";
11import type { LanguageModel } from "@openassistant/core/agent";
12import { createAgent } from "@openassistant/core/agent";
13import {
14 emitTaskEvent,
15 getTask,
16 registerRemoteRunSession,
17 registerApproval,
18 removeRemoteRunSession,
19 type RemoteRunInvokeResult,
20} from "./state.js";
21
22export 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
34function describeError(error: unknown): string {
35 if (error instanceof Error) return error.message;
36 return String(error);
37}
38
39function 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
47function 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 */
66export 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 @@
1console.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 @@
1import { describe, test, expect } from "bun:test";
2import { z } from "zod";
3import { defineTool, type ToolTree } from "./tools.js";
4import { createAgent, type LanguageModel, type Message, type GenerateResult } from "./agent.js";
5import type { TaskEvent } from "./events.js";
6
7// ---------------------------------------------------------------------------
8// Test helpers
9// ---------------------------------------------------------------------------
10
11function 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 */
36function 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
54describe("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
18import type { ToolTree, ApprovalDecision, ApprovalRequest, ToolCallReceipt } from "./tools.js";
19import type { RunResult, Runner } from "./runner.js";
20import { createRunner } from "./runner.js";
21import { generateToolDeclarations, generatePromptGuidance, typecheckCode } from "./typechecker.js";
22import { countTools, createDiscoverTool } from "./discovery.js";
23import 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 */
33export 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
42export 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
49export interface ToolCall {
50 id: string;
51 name: string;
52 args: Record<string, unknown>;
53}
54
55export interface GenerateResult {
56 text?: string | undefined;
57 toolCalls?: ToolCall[] | undefined;
58}
59
60export 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
92export interface AgentResult {
93 readonly text: string;
94 readonly runs: readonly CodeRun[];
95 readonly allReceipts: readonly ToolCallReceipt[];
96}
97
98export interface CodeRun {
99 readonly code: string;
100 readonly typecheckOk: boolean;
101 readonly result: RunResult;
102}
103
104// ---------------------------------------------------------------------------
105// Discovery mode
106// ---------------------------------------------------------------------------
107
108const 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 */
118function 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
192function buildSystemPrompt(guidance: string, discoveryMode: boolean, context?: string): string {
193 const discoveryInstructions = discoveryMode
194 ? `
195## Tool Discovery
196
197Some tool namespaces are too large to list here. Use \`tools.discover({ query })\` to search for tools by keyword.
198
199By 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
201Options:
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:**
2071. Discover tools to find what's available and see their types
2082. Write a SINGLE self-contained script that does the entire task. If the return type has pagination, loop until all pages are fetched.
209
210Example — "close all open issues on acme/myapp":
211
212Call 1 (discover tools — returns types by default):
213\`\`\`ts
214return await tools.discover({ query: "issues list update repo" });
215\`\`\`
216
217Call 2 (do the work — everything in one script):
218\`\`\`ts
219const issues = await tools.github.issues.issues_list_for_repo({
220 owner: "acme", repo: "myapp", state: "open", per_page: 100
221});
222
223const results = [];
224for (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
231return { 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
246You 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
279export 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
16import { defineTool, isToolDefinition, type ToolDefinition, type ToolTree } from "./tools.js";
17import { getArgsTypeString, getReturnsTypeString } from "./typechecker.js";
18import { z } from "zod";
19
20// ---------------------------------------------------------------------------
21// Index entry
22// ---------------------------------------------------------------------------
23
24export 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
43export 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
79function 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 */
96function 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 */
117function 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
163export 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 */
176export 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
186depth 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
191limit 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 */
227export 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
6import type { ApprovalPresentation, ToolCallReceipt } from "./tools.js";
7
8export type TaskEvent =
9 | TaskStatusEvent
10 | TaskCodeGeneratedEvent
11 | TaskApprovalRequestEvent
12 | TaskApprovalResolvedEvent
13 | TaskToolResultEvent
14 | TaskAgentMessageEvent
15 | TaskErrorEvent
16 | TaskCompletedEvent;
17
18export interface TaskStatusEvent {
19 readonly type: "status";
20 readonly message: string;
21}
22
23export interface TaskCodeGeneratedEvent {
24 readonly type: "code_generated";
25 readonly code: string;
26}
27
28export 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
36export interface TaskApprovalResolvedEvent {
37 readonly type: "approval_resolved";
38 readonly id: string;
39 readonly decision: "approved" | "denied";
40}
41
42export interface TaskToolResultEvent {
43 readonly type: "tool_result";
44 readonly receipt: ToolCallReceipt;
45}
46
47export interface TaskAgentMessageEvent {
48 readonly type: "agent_message";
49 readonly text: string;
50}
51
52export interface TaskErrorEvent {
53 readonly type: "error";
54 readonly error: string;
55}
56
57export 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
2export {
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)
20export {
21 createRunner,
22 ToolDeniedError,
23 type Runner,
24 type RunnerOptions,
25 type RunResult,
26} from "./runner.js";
27
28// Remote runner (executor HTTP transport)
29export {
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
39export {
40 zodToTypeString,
41 generateToolDeclarations,
42 generatePromptGuidance,
43 typecheckCode,
44 type TypecheckResult,
45} from "./typechecker.js";
46
47// Agent loop
48export {
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
60export {
61 createPiAiModel,
62 type PiAiModelOptions,
63} from "./pi-ai-adapter.js";
64
65// Discovery
66export {
67 buildToolIndex,
68 createDiscoverTool,
69 countTools,
70 type ToolIndexEntry,
71 type DiscoverToolOptions,
72} from "./discovery.js";
73
74// Events
75export 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
6import { test, expect, describe } from "bun:test";
7import { createRunner } from "./runner.js";
8import { defineTool, type ToolTree } from "./tools.js";
9import { z } from "zod";
10
11// Simulate an API: list items, then update each
12const 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
20let updateCallCount = 0;
21
22const 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
51describe("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 = `
62const items = await tools.api.list_items({ state: "closed" });
63
64const results = [];
65for (const item of items) {
66 const updated = await tools.api.update_item({ id: item.id, state: "open" });
67 results.push(updated);
68}
69
70return { 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 = `
97const items = await tools.api.list_items({ state: "closed" });
98
99const results = await Promise.all(
100 items.map((item) => tools.api.update_item({ id: item.id, state: "open" }))
101);
102
103return { 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 = `
144const items = await tools.api.list_items({});
145const results = [];
146for (const item of items) {
147 const updated = await tools.api.update_item({ id: item.id, state: "open" });
148 results.push(updated);
149}
150return { 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 = `
201const items = await tools.api.list_items({});
202const results = [];
203for (const item of items) {
204 const updated = await tools.api.update_item({ id: item.id, state: "open" });
205 results.push(updated);
206}
207return { 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
8import {
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";
21import { Type } from "@sinclair/typebox";
22import type { LanguageModel, Message, GenerateResult, ToolCall } from "./agent.js";
23
24// ---------------------------------------------------------------------------
25// Config
26// ---------------------------------------------------------------------------
27
28export 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
45const 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
60function 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
140function 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 */
177export 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 @@
1import { describe, expect, test } from "bun:test";
2import { z } from "zod";
3import { defineTool, type ToolTree } from "./tools.js";
4import { createRemoteRunner } from "./remote-runner.js";
5
6describe("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 @@
1import type { ApprovalMode, ToolTree } from "./tools.js";
2import { walkToolTree } from "./tools.js";
3import type { RunResult, Runner } from "./runner.js";
4
5export interface ExecutorToolManifestEntry {
6 readonly toolPath: string;
7 readonly approval: ApprovalMode;
8}
9
10export 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
19export interface ExecutorInvokeRequest {
20 readonly toolPath: string;
21 readonly input: unknown;
22}
23
24export interface ExecutorInvokeResponse {
25 readonly ok: boolean;
26 readonly value?: unknown;
27 readonly error?: string;
28 readonly denied?: boolean;
29}
30
31export 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
41const DEFAULT_TIMEOUT_MS = 30_000;
42type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
43
44function trimTrailingSlash(value: string): string {
45 return value.endsWith("/") ? value.slice(0, -1) : value;
46}
47
48function 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
56function 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
62export 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 @@
1import { describe, test, expect } from "bun:test";
2import { z } from "zod";
3import { defineTool, type ToolTree, type ApprovalDecision } from "./tools.js";
4import { createRunner, ToolDeniedError } from "./runner.js";
5
6// ---------------------------------------------------------------------------
7// Test helpers
8// ---------------------------------------------------------------------------
9
10function 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
31function 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
64let callIdSeq = 0;
65function testCallId() {
66 return `test_${++callIdSeq}`;
67}
68
69function alwaysApprove() {
70 return async (_req: unknown) => "approved" as ApprovalDecision;
71}
72
73function alwaysDeny() {
74 return async (_req: unknown) => "denied" as ApprovalDecision;
75}
76
77// ---------------------------------------------------------------------------
78// Tests
79// ---------------------------------------------------------------------------
80
81describe("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
194describe("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
244describe("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
377describe("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
9import { createContext, runInContext } from "node:vm";
10import type {
11 ApprovalDecision,
12 ApprovalPresentation,
13 ApprovalRequest,
14 ToolCallReceipt,
15 ToolDefinition,
16 ToolTree,
17} from "./tools.js";
18import { isToolDefinition } from "./tools.js";
19
20// ---------------------------------------------------------------------------
21// Types
22// ---------------------------------------------------------------------------
23
24export interface RunResult {
25 readonly ok: boolean;
26 readonly value?: unknown;
27 readonly error?: string;
28 readonly receipts: readonly ToolCallReceipt[];
29}
30
31export 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
46export interface Runner {
47 /** Execute a code string in the sandbox. Never throws. */
48 run(code: string): Promise<RunResult>;
49}
50
51export 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
62const MAX_PREVIEW = 180;
63const 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 */
69function 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 */
96function 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
140function isRecord(value: unknown): value is Record<string, unknown> {
141 return typeof value === "object" && value !== null && !Array.isArray(value);
142}
143
144function 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
164function 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
173function 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
194function 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
200function 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
230function 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
256let callIdCounter = 0;
257function 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 */
264function 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
283interface MaterializeContext {
284 receipts: ToolCallReceipt[];
285 requestApproval: RunnerOptions["requestApproval"];
286 now: () => number;
287 newCallId: () => string;
288}
289
290function 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
309function 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
442function 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 */
495function 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
516export 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 @@
1import { describe, test, expect } from "bun:test";
2import { z } from "zod";
3import {
4 defineTool,
5 isToolDefinition,
6 walkToolTree,
7 mergeToolTrees,
8 type ToolTree,
9} from "./tools.js";
10
11describe("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
39describe("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
57describe("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
105describe("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
9import type { z } from "zod";
10
11// ---------------------------------------------------------------------------
12// Types
13// ---------------------------------------------------------------------------
14
15export type ApprovalMode = "auto" | "required";
16
17export type ApprovalDecision = "approved" | "denied";
18
19export type ReceiptDecision = "auto" | ApprovalDecision;
20
21export type ReceiptStatus = "succeeded" | "failed" | "denied";
22
23/**
24 * Presentation data for rendering an approval request in any client.
25 */
26export 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 */
45export 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 */
60export 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 */
85export 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 */
110export type ToolTree = {
111 readonly [name: string]: ToolTree | ToolDefinition;
112};
113
114// ---------------------------------------------------------------------------
115// Constructors
116// ---------------------------------------------------------------------------
117
118export 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 */
150export 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 */
173export 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 */
187export 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 */
205export 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 @@
1import { describe, test, expect } from "bun:test";
2import { z } from "zod";
3import { defineTool, type ToolTree } from "./tools.js";
4import {
5 zodToTypeString,
6 generateToolDeclarations,
7 generatePromptGuidance,
8 typecheckCode,
9} from "./typechecker.js";
10
11describe("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
56describe("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
89describe("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
110describe("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
8import type { z } from "zod";
9import type { ToolDefinition, ToolTree } from "./tools.js";
10import { isToolDefinition } from "./tools.js";
11
12// ---------------------------------------------------------------------------
13// Zod → TypeScript declaration generation
14// ---------------------------------------------------------------------------
15
16// Zod v4 internal def accessor
17interface 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
38function 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 */
49export 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 */
136export 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 */
144export 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 */
156export function generateToolDeclarations(tree: ToolTree): string {
157 return `declare const tools: {\n${generateTreeType(tree, 1)}\n};`;
158}
159
160function 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 */
188export 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
217export 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 */
225export 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
12import { describe, test, expect } from "bun:test";
13import { createAgent, createPiAiModel, type TaskEvent } from "@openassistant/core";
14import { 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 */
22function 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
42const apiKey = getAnthropicApiKey();
43const hasApiKey = !!apiKey;
44
45describe.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 @@
1export {
2 generateMcpTools,
3 type McpToolSource,
4 type McpGenerateResult,
5} from "./mcp.js";
6
7export {
8 generateOpenApiTools,
9 type OpenApiToolSource,
10 type OpenApiAuth,
11 type OpenApiGenerateResult,
12} from "./openapi.js";
13
14export {
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
8import { describe, test, expect } from "bun:test";
9import {
10 createRunner,
11 generateToolDeclarations,
12 typecheckCode,
13} from "@openassistant/core";
14import { generateMcpTools } from "./mcp.js";
15
16describe("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 @@
1import { describe, test, expect } from "bun:test";
2import { jsonSchemaToTypeString, jsonSchemaToZod, type JsonSchema } from "./json-schema-to-ts.js";
3
4describe("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
80describe("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
13import { astToString, transformSchemaObject } from "openapi-typescript";
14import { z } from "zod";
15
16// ---------------------------------------------------------------------------
17// openapi-typescript context (for individual schema conversion)
18// ---------------------------------------------------------------------------
19
20function 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
47export 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 */
74export 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
91export 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
149function 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 @@
1import { describe, test, expect } from "bun:test";
2import { walkToolTree, isToolDefinition } from "@openassistant/core";
3import { generateMcpTools } from "./mcp.js";
4
5describe("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
9import { Client } from "@modelcontextprotocol/sdk/client/index.js";
10import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
11import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
12import { defineTool, type ApprovalMode, type ToolTree } from "@openassistant/core";
13import { jsonSchemaToZod, jsonSchemaToTypeString, type JsonSchema } from "./json-schema-to-ts.js";
14import { z } from "zod";
15
16// ---------------------------------------------------------------------------
17// Config
18// ---------------------------------------------------------------------------
19
20export 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
39export 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
56const MAX_APPROVAL_PREVIEW = 240;
57
58function isRecord(value: unknown): value is Record<string, unknown> {
59 return typeof value === "object" && value !== null && !Array.isArray(value);
60}
61
62function 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
75function 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
95function 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
115function 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
132async 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
171export 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
8import { describe, test, expect } from "bun:test";
9import {
10 createRunner,
11 generateToolDeclarations,
12 typecheckCode,
13} from "@openassistant/core";
14import { generateOpenApiTools } from "./openapi.js";
15
16const 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
166describe("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 @@
1import { describe, test, expect } from "bun:test";
2import { walkToolTree, isToolDefinition } from "@openassistant/core";
3import { generateOpenApiTools } from "./openapi.js";
4
5describe("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
9import SwaggerParser from "@apidevtools/swagger-parser";
10import { defineTool, type ApprovalMode, type ToolTree } from "@openassistant/core";
11import { jsonSchemaToZod, jsonSchemaToTypeString, type JsonSchema } from "./json-schema-to-ts.js";
12import { z } from "zod";
13
14// ---------------------------------------------------------------------------
15// Config
16// ---------------------------------------------------------------------------
17
18export 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
37export 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
46export 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
59interface 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
71interface 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
83const READ_METHODS = new Set(["get", "head", "options"]);
84const MAX_APPROVAL_PREVIEW = 240;
85
86
87function 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
99function 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
129function 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
137function 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
145function isRecord(value: unknown): value is Record<string, unknown> {
146 return typeof value === "object" && value !== null && !Array.isArray(value);
147}
148
149function 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
162function 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
180function 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
188function 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
208function 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
222function 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
252function 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
341export 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 @@
1import { defineConfig } from "vitest/config";
2
3export 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
3 "private": true,3 "private": true,
4 "type": "module",4 "type": "module",
5 "scripts": {5 "scripts": {
6 "test": "bun test packages/core/src/ packages/agent-executor-adapter/src/",6 "test": "bun test packages/core/src/",
7 "dev:server": "bun run --filter @assistant/server dev",7 "dev:server": "bun run --filter @assistant/server dev",
8 "dev:bot": "bun run --filter @assistant/bot dev"8 "dev:bot": "bun run --filter @assistant/bot dev"
9 },9 },
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 @@
1import { expect, test } from "bun:test";
2import { Elysia, t } from "elysia";
3import { treaty } from "@elysiajs/eden";
4
5// Minimal Elysia server that mimics the executor's task creation route
6function 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
38test("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
57test("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
72test("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 @@
1import { treaty } from "@elysiajs/eden";
2import type { App } from "@executor/server/src/index";
3
4export function createExecutorClient(baseUrl: string) {
5 return treaty<App>(baseUrl);
6}
7
8export 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 @@
1{1{
2 "extends": "../../tsconfig.base.json",
3 "compilerOptions": {2 "compilerOptions": {
4 "exactOptionalPropertyTypes": false,3 "target": "ES2022",
5 "jsx": "react-jsx",
6 "module": "ESNext",4 "module": "ESNext",
7 "moduleResolution": "Bundler",5 "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,
8 "rootDir": "src"14 "rootDir": "src"
9 },15 },
10 "include": [16 "include": [
bun.lock+54−116
@@ -12,31 +12,6 @@ · 11 unmodified lines
12 "typescript": "latest",12 "typescript": "latest",
13 },13 },
14 },14 },
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 },
40 "assistant/packages/bot": {15 "assistant/packages/bot": {
41 "name": "@assistant/bot",16 "name": "@assistant/bot",
42 "dependencies": {17 "dependencies": {
@@ -61,11 +36,24 @@ · 18 unmodified lines
61 "@modelcontextprotocol/sdk": "^1.26.0",36 "@modelcontextprotocol/sdk": "^1.26.0",
62 },37 },
63 "devDependencies": {38 "devDependencies": {
64 "@elysiajs/eden": "^1.4.6",
65 "elysia": "^1.4.22",
66 "zod": "^4.3.6",39 "zod": "^4.3.6",
67 },40 },
68 },41 },
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 },
69 "assistant/packages/server": {57 "assistant/packages/server": {
70 "name": "@assistant/server",58 "name": "@assistant/server",
71 "dependencies": {59 "dependencies": {
@@ -81,12 +69,11 @@ · 9 unmodified lines
81 "executor": {69 "executor": {
82 "name": "executor-monorepo",70 "name": "executor-monorepo",
83 "dependencies": {71 "dependencies": {
84 "convex": "latest",72 "convex": "^1.31.7",
85 },73 },
86 "devDependencies": {74 "devDependencies": {
87 "@types/bun": "latest",75 "@types/bun": "latest",
88 "convex-test": "^0.0.41",76 "convex-test": "^0.0.41",
89 "esbuild": "^0.27.3",
90 "typescript": "latest",77 "typescript": "latest",
91 },78 },
92 },79 },
@@ -94,10 +81,10 @@ · 1 unmodified line
94 "name": "@executor/server",81 "name": "@executor/server",
95 "dependencies": {82 "dependencies": {
96 "@apidevtools/swagger-parser": "^12.1.0",83 "@apidevtools/swagger-parser": "^12.1.0",
97 "@elysiajs/eden": "^1.4.6",84 "@executor/contracts": "workspace:*",
98 "@modelcontextprotocol/sdk": "^1.26.0",85 "@modelcontextprotocol/sdk": "^1.26.0",
99 "@vercel/sandbox": "latest",86 "@vercel/sandbox": "latest",
100 "convex": "latest",87 "convex": "^1.31.7",
101 "elysia": "^1.4.22",88 "elysia": "^1.4.22",
102 "openapi-typescript": "^7.10.1",89 "openapi-typescript": "^7.10.1",
103 "zod": "^4.3.6",90 "zod": "^4.3.6",
@@ -111,10 +98,11 @@ · 7 unmodified lines
111 "name": "@executor/web",98 "name": "@executor/web",
112 "version": "0.1.0",99 "version": "0.1.0",
113 "dependencies": {100 "dependencies": {
101 "@executor/contracts": "workspace:*",
114 "@monaco-editor/react": "^4.7.0",102 "@monaco-editor/react": "^4.7.0",
115 "class-variance-authority": "^0.7.1",103 "class-variance-authority": "^0.7.1",
116 "clsx": "^2.1.1",104 "clsx": "^2.1.1",
117 "convex": "latest",105 "convex": "^1.31.7",
118 "lucide-react": "^0.563.0",106 "lucide-react": "^0.563.0",
119 "monaco-editor": "^0.55.1",107 "monaco-editor": "^0.55.1",
120 "next": "16.1.6",108 "next": "16.1.6",
@@ -139,6 +127,10 @@ · 18 unmodified lines
139 "typescript": "^5",127 "typescript": "^5",
140 },128 },
141 },129 },
130 "executor/packages/contracts": {
131 "name": "@executor/contracts",
132 "version": "0.0.1",
133 },
142 },134 },
143 "trustedDependencies": [135 "trustedDependencies": [
144 "sharp",136 "sharp",
@@ -159,8 +151,6 @@ · 14 unmodified lines
159 151
160 "@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=="],152 "@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=="],
161 153
162 "@assistant/agent-executor-adapter": ["@assistant/agent-executor-adapter@workspace:assistant/packages/agent-executor-adapter"],
163
164 "@assistant/bot": ["@assistant/bot@workspace:assistant/packages/bot"],154 "@assistant/bot": ["@assistant/bot@workspace:assistant/packages/bot"],
165 155
166 "@assistant/core": ["@assistant/core@workspace:assistant/packages/core"],156 "@assistant/core": ["@assistant/core@workspace:assistant/packages/core"],
@@ -329,57 +319,57 @@ · 162 unmodified lines
329 319
330 "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],320 "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
331 321
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=="],
333 323
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=="],
335 325
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=="],
337 327
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=="],
339 329
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=="],
341 331
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=="],
343 333
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=="],
345 335
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=="],
347 337
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=="],
349 339
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=="],
351 341
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=="],
353 343
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=="],
355 345
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=="],
357 347
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=="],
359 349
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=="],
361 351
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=="],
363 353
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=="],
365 355
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=="],
367 357
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=="],
369 359
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=="],
371 361
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=="],
373 363
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=="],
375 365
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=="],
377 367
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=="],
379 369
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=="],
381 371
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=="],
383 373
384 "@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=="],374 "@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=="],
385 375
@@ -399,6 +389,8 @@ · 13 unmodified lines
399 389
400 "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],390 "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
401 391
392 "@executor/contracts": ["@executor/contracts@workspace:executor/packages/contracts"],
393
402 "@executor/server": ["@executor/server@workspace:executor/apps/server"],394 "@executor/server": ["@executor/server@workspace:executor/apps/server"],
403 395
404 "@executor/web": ["@executor/web@workspace:executor/apps/web"],396 "@executor/web": ["@executor/web@workspace:executor/apps/web"],
@@ -565,7 +557,7 @@ · 160 unmodified lines
565 557
566 "@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="],558 "@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="],
567 559
568 "@openassistant/reacord": ["@openassistant/reacord@workspace:assistant/legacy/openassistant/packages/reacord"],560 "@openassistant/reacord": ["@openassistant/reacord@workspace:assistant/packages/reacord"],
569 561
570 "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],562 "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
571 563
@@ -1199,7 +1191,7 @@ · 627 unmodified lines
1199 1191
1200 "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=="],1192 "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=="],
1201 1193
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=="],
1203 1195
1204 "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],1196 "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
1205 1197
@@ -2171,8 +2163,6 @@ · 965 unmodified lines
2171 2163
2172 "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=="],2164 "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=="],
2173 2165
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
2176 "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=="],2166 "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=="],
2177 2167
2178 "degenerator/ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="],2168 "degenerator/ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="],
@@ -2275,58 +2265,6 @@ · 96 unmodified lines
2275 2265
2276 "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],2266 "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
2277 2267
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
2330 "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=="],2268 "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=="],
2331 2269
2332 "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],2270 "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
8 "executor/packages/*",8 "executor/packages/*",
9 "assistant",9 "assistant",
10 "assistant/packages/*",10 "assistant/packages/*",
11 "assistant/legacy/openassistant/packages/reacord"11 "assistant/packages/reacord"
12 ],12 ],
13 "scripts": {13 "scripts": {
14 "dev": "bun run dev.ts",14 "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