diff --git a/api-report/apps/api/src/modules/llm/contract.d.ts b/api-report/apps/api/src/modules/llm/contract.d.ts index 8683e97..14f2741 100644 --- a/api-report/apps/api/src/modules/llm/contract.d.ts +++ b/api-report/apps/api/src/modules/llm/contract.d.ts @@ -63,12 +63,26 @@ export type ModelResult = { }; readonly mode: GatewayMode; }; +/** 解好的模型端点(四元 + 明文密钥)—— app 层装配专用,见 ModelGateway.resolve */ +export type ResolvedEndpoint = { + readonly provider: LlmProvider; + readonly baseUrl: string; + readonly model: string; + readonly apiKey: string; +}; /** * 模型网关 —— 活动基座六件里的「LLM 调用」。 * 活动只见自定义模型名;解析、凭证、录制回放全在此。 */ export type ModelGateway = { readonly mode: GatewayMode; + /** + * 解绑定:名 → 四元(含当场解出的密钥)—— **只给 app 层装配用**: + * Mastra Agent 那类需要真模型对象做 tool-calling 往返的场合, + * `generate` 的 text-in/text-out 抽象承载不了。 + * 密钥与 endpoint 仍不入 domain、不入包、不入留痕明文(OS 7.3 凭证隔离)。 + */ + resolve(modelName: string): Promise; generate(call: ModelCall): Promise; /** 换模式的网关 —— 回放审用 replay 模式重跑引擎(§7.3) */ withMode(mode: GatewayMode): ModelGateway; diff --git a/api-report/apps/api/src/modules/llm/index.d.ts b/api-report/apps/api/src/modules/llm/index.d.ts index aa6efe7..b335457 100644 --- a/api-report/apps/api/src/modules/llm/index.d.ts +++ b/api-report/apps/api/src/modules/llm/index.d.ts @@ -1,7 +1,7 @@ /** * module: llm —— 唯一出口。只做 re-export,不写逻辑(编码规范 §10.1)。 */ -export type { BindingViolation, GatewayMode, LlmInstanceView, LlmProvider, LlmService, ModelBinding, ModelCall, ModelGateway, ModelResult, ModelUsage, UpsertLlmInstance, } from './contract.ts'; +export type { BindingViolation, GatewayMode, LlmInstanceView, LlmProvider, LlmService, ModelBinding, ModelCall, ModelGateway, ResolvedEndpoint, ModelResult, ModelUsage, UpsertLlmInstance, } from './contract.ts'; export { GATEWAY_MODES, ModelDisabledError, ModelNotBoundError, ReplayMissError } from './contract.ts'; export type { Clock, IdGenerator, LlmInstanceRepository, ProviderInvoker, ReplayRecord, ReplayStore, SecretBox, } from './port.ts'; export type { LlmServiceDeps } from './internal/usecase/llm-service.ts'; diff --git a/api-report/apps/api/src/modules/loop-engine/contract.d.ts b/api-report/apps/api/src/modules/loop-engine/contract.d.ts index cad3d5f..b0452f7 100644 --- a/api-report/apps/api/src/modules/loop-engine/contract.d.ts +++ b/api-report/apps/api/src/modules/loop-engine/contract.d.ts @@ -70,6 +70,16 @@ export type AgentAction = | { readonly kind: 'submit'; readonly rationale: string; +} +/** + * 本回合**已在工具循环里调过人**:卡已发、监听已立(工具总线执行的)。 + * 引擎只收尾把这一拍置 awaiting —— 不能再发一张,否则负责人工位上堆两张同样的卡。 + * 开环模式(Mastra Agent 自主连环调工具)专用;单拍模式给不出这一型。 + */ + | { + readonly kind: 'asked'; + readonly cardId: string; + readonly rationale: string; }; export type TurnOutcome = { readonly runtime: CaseRuntime; diff --git a/api-report/apps/api/src/modules/toolbox/index.d.ts b/api-report/apps/api/src/modules/toolbox/index.d.ts index 50375b4..49ceb17 100644 --- a/api-report/apps/api/src/modules/toolbox/index.d.ts +++ b/api-report/apps/api/src/modules/toolbox/index.d.ts @@ -9,6 +9,8 @@ export { createToolInvoker, toolReplayKey } from './internal/usecase/tool-invoke export type { ToolboxServiceDeps } from './internal/usecase/toolbox-service.ts'; export { createToolboxService } from './internal/usecase/toolbox-service.ts'; export { checkEvolution, dispositionOf, EFFECT_LEVEL_LABEL, EFFECT_LEVELS } from './internal/domain/tool-contract.ts'; +export type { BusTool, CatalogEntry, ToolBusInput, ToolBusReport } from './internal/domain/tool-bus.ts'; +export { compileToolBus, HUMAN_TOOL, LLM_TOOLS } from './internal/domain/tool-bus.ts'; export { auditPassed, staticAudit } from './internal/domain/registration-audit.ts'; export type { ToolHandler } from './internal/adapter/toolbox-store.ts'; export { createSchemaValidator, createToolRegistry, createToolReplayStore, createToolRuntime, isAllowed, } from './internal/adapter/toolbox-store.ts'; diff --git a/apps/api/package.json b/apps/api/package.json index 010d3ef..05ad668 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -18,6 +18,7 @@ "dependencies": { "@ai-sdk/openai-compatible": "^3.0.14", "@hono/node-server": "^2.0.12", + "@mastra/core": "^1.53.0", "ai": "^7.0.37", "ajv": "^8.20.0", "ajv-formats": "^3.0.1", diff --git a/apps/api/src/app/mastra-agent-runner.ts b/apps/api/src/app/mastra-agent-runner.ts new file mode 100644 index 0000000..2200817 --- /dev/null +++ b/apps/api/src/app/mastra-agent-runner.ts @@ -0,0 +1,197 @@ +/** + * loop 的 Agent 回路(**开环**)—— `AgentPort` 的 Mastra 实现(M5-2;app 层装配 §5.2)。 + * + * 与单拍版(`agent-runner.ts`)的分工: + * · 单拍版:问一次模型、要一个行动,引擎替它执行 —— 保守、每步可拦; + * · **开环版(此处)**:给它一张**工具总线**,让它在一拍内自主连环调工具 + * (读类真调、写类登记意向、LLM 五件、调人),拍末只交回**这一拍的结论**。 + * + * 放开的是工具循环,**不是规矩**: + * · 能调什么由活动声明定死(工具总线在编译期出清单,白名单在缝里再把一次关); + * · 写类工具**过程中一律不落地**,只登记动作意向 —— 放行那一刻才由系统执行; + * · 调人由总线执行(发卡 + 立监听),引擎收到 `asked` 就把这一拍挂起,不重复发卡; + * · 终局唯放行:Agent 只能 `submit`(提交放行),不能自己宣布完成; + * · 用量按 Mastra 回报的 usage 计入任务预算 —— 不计,预算熔断永远不会响。 + * + * 代价(如实记 debt M5-2):开环下模型的**逐轮**调用不经模型网关的录制回放 + * (tool-calling 往返 `generate` 的 text-in/text-out 抽象承载不了)—— + * 四元绑定与凭证隔离照旧走网关 `resolve`;**工具调用一缝完整**,工具侧录制回放不破。 + */ +import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; +import { Agent } from '@mastra/core/agent'; +import { z } from 'zod'; +import type { TaskId } from '@contracts'; +import type { AgentAction, EnabledSet } from '@modules/loop-engine'; +import type { ModelGateway } from '@modules/llm'; +import type { BusTool } from '@modules/toolbox'; +import { buildMastraTools } from './tool-bus.ts'; +import type { ToolBusContext, ToolBusPorts } from './tool-bus.ts'; + +/** 拍末结论 —— Agent 干完活要说清「这一拍算什么」,不能只是聊完就走 */ +const TURN_RESULT = z.object({ + kind: z.enum(['start', 'plan', 'disable', 'judge', 'submit', 'idle']).describe('这一拍的结论'), + itemId: z.string().optional().describe('start / plan / disable 针对哪个计划项'), + reason: z.string().optional(), + criterion: z.string().optional().describe('judge:评估的是哪条语义性前提'), + satisfied: z.boolean().optional().describe('judge:满足与否'), + rationale: z.string().optional().describe('结论理由 —— 留痕要看,写实'), +}); + +export type MastraAgentRunnerDeps = { + readonly gateway: ModelGateway; + /** 活动声明的自定义模型名 */ + readonly modelOf: (taskId: TaskId) => Promise; + /** 这一单能调什么:工具总线清单(声明 × 目录编译而来) */ + readonly busOf: (taskId: TaskId) => Promise; + /** 三路缝 */ + readonly ports: ToolBusPorts; + /** 拍内上下文:负责人与人工调用上限 */ + readonly contextOf: (taskId: TaskId) => Promise>; + /** token 回报:计入任务预算 */ + readonly onUsage: (taskId: TaskId, tokens: number) => Promise; + /** 一拍内最多几轮工具调用 —— 环外还有 Harness 的预算硬闸,这只是拍内的礼貌上限 */ + readonly maxToolRounds?: number; +}; + +export function createMastraAgentRunner(deps: MastraAgentRunnerDeps): { + decide(input: { taskId: TaskId; narrative: string; enabled: EnabledSet; scope: Record }): Promise; +} { + return { + async decide({ taskId, narrative, enabled, scope }) { + const modelName = await deps.modelOf(taskId); + const base = await deps.contextOf(taskId); + const bus = await deps.busOf(taskId); + const trace: { askedCardId?: string } = {}; + + const instructions = [ + '你是这一单任务的案例工作者。你有一组工具可用,可以连续调用它们把这一拍的活干完。', + '', + '规矩(硬约束,违反即被系统拦下):', + '① **写类工具不会当场生效** —— 调了只是登记动作意向,放行那一刻系统才真执行。', + ' 所以不要假设世界已经改变,更不要因为「已经调过」就跳过必要的确认。', + '② **调人(human.ask)会让这一拍就此挂起等回传** —— 只在真需要人裁断/补料时调,', + ' 而且必须把卡填实:title 一句话说清要什么、ask 写明具体问题、basis 给出判断依据。', + ' 一张只写「请处理」的卡等于白发。调完人就结束这一拍,别再调别的。', + '③ **终局唯放行**:成果齐了就 submit(提交放行),由人验收 —— 你不能自己宣布完成。', + '④ 干完活必须给出这一拍的结论(见输出格式);拿不准就 idle 并说清卡在哪。', + '', + `【案例说明书与记忆】\n${narrative}`, + ].join('\n'); + + const endpoint = await deps.gateway.resolve(modelName); + const provider = createOpenAICompatible({ + name: endpoint.provider, + apiKey: endpoint.apiKey, + baseURL: endpoint.baseUrl, + }); + + const agent = new Agent({ + id: `loop-${taskId}`, + name: '案例工作者', + instructions, + model: provider.chatModel(endpoint.model), + tools: buildMastraTools(bus, deps.ports, { ...base, model: modelName }, trace), + }); + + const prompt = [ + `【当下可为(Enabled 集)】\n${ + enabled.entries + .map((e) => `- ${e.id} ${e.name}(${e.type}${e.requiresManualStart ? ' · 须你启动' : ''}${e.discretionary ? ' · 裁量项' : ''})`) + .join('\n') || '(空)' + }`, + `【目标缺口】\n${enabled.gaps.join('、') || '(无)'}`, + enabled.judgements.length === 0 + ? '' + : `【待你评估的语义性前提】\n${enabled.judgements.map((j) => `- ${j.criterion}:${j.statement}`).join('\n')}`, + enabled.entries.length === 0 ? '【注意】当下可为 ∩ 目标所需 = 空 —— 这是依赖断点,调人或说清卡在哪。' : '', + `【任务数据】\n${JSON.stringify(scope).slice(0, 4000)}`, + '', + '干这一拍该干的活(可以连续调工具),最后给出结论。', + ] + .filter((line) => line !== '') + .join('\n'); + + try { + const result = await agent.generate(prompt, { + maxSteps: deps.maxToolRounds ?? 8, + structuredOutput: { schema: TURN_RESULT }, + } as never); + + const usage = (result as { usage?: { totalTokens?: number; inputTokens?: number; outputTokens?: number } }).usage; + const tokens = usage?.totalTokens ?? (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0); + if (tokens > 0) await deps.onUsage(taskId, tokens); + + // 调过人就必须收在 asked:卡已发、监听已立,引擎只收尾挂起(再发一张就是重复调人) + if (trace.askedCardId !== undefined) { + return { kind: 'asked', cardId: trace.askedCardId, rationale: '本回合已调人,等回传' }; + } + + return normalizeTurn((result as { object?: unknown }).object, enabled); + } catch (error) { + /* + * 这一拍问不出结果(端点不可达、鉴权失败、超时、工具连环炸)—— + * **不是异常路径,是断点的一种**:机器当下决断不了就该调人。 + * 抛出去只会让任务空转:推进器每一拍重试、预算照烧,负责人却什么都看不到。 + * + * 但**已经调过人**的那一拍例外:卡在世界上了,老老实实收成 asked, + * 不要再叠一张「模型出错」的卡上去。 + */ + if (trace.askedCardId !== undefined) { + return { kind: 'asked', cardId: trace.askedCardId, rationale: '本回合已调人(其后模型出错)' }; + } + const detail = error instanceof Error ? error.message : String(error); + return { + kind: 'human', + itemId: enabled.entries[0]?.id ?? 'breakpoint', + workOrder: 'execution', + card: { + title: '模型这一轮未能决断,转人裁断', + reason: detail, + basis: [ + { k: '当下可为', v: enabled.entries.map((e) => e.name).join('、') || '(空)' }, + { k: '目标缺口', v: enabled.gaps.join('、') || '(无)' }, + ], + ask: '请判断下一步:接着走哪一项,或补齐缺口后让环继续。', + fields: ['decision'], + }, + }; + } + }, + }; +} + +/** 拍末结论归一为 AgentAction;给不出结论就当空拍(idle → judge 留痕),绝不乱动世界 */ +function normalizeTurn(object: unknown, enabled: EnabledSet): AgentAction { + const raw = (object ?? {}) as Record; + const kind = String(raw['kind'] ?? 'idle'); + const itemId = String(raw['itemId'] ?? enabled.entries[0]?.id ?? ''); + const rationale = String(raw['rationale'] ?? ''); + + switch (kind) { + case 'start': + case 'plan': + return { kind: kind as 'start' | 'plan', itemId }; + case 'disable': + return { kind: 'disable', itemId, reason: String(raw['reason'] ?? '此单不走这条') }; + case 'judge': + return { + kind: 'judge', + criterion: String(raw['criterion'] ?? ''), + satisfied: raw['satisfied'] === true, + rationale, + }; + case 'submit': + return { kind: 'submit', rationale: rationale === '' ? '判定成果已齐' : rationale }; + default: + /* + * idle:这一拍干了活(工具调用已经落在总线上)但推不动局面。 + * 记成一条 judge 留痕 —— 空拍也要说清卡在哪,不然人看不见环在原地打转。 + */ + return { + kind: 'judge', + criterion: '本回合是否推动了局面', + satisfied: false, + rationale: rationale === '' ? '模型未给出结论' : rationale, + }; + } +} diff --git a/apps/api/src/app/tool-bus.ts b/apps/api/src/app/tool-bus.ts new file mode 100644 index 0000000..4d47202 --- /dev/null +++ b/apps/api/src/app/tool-bus.ts @@ -0,0 +1,219 @@ +/** + * 工具总线的**装配面** —— 声明清单 → 可调用的 Mastra tools(编码规范 §6.2: + * `@mastra` 只准出现在 adapter 与 app)。 + * + * 声明面(纯逻辑,`toolbox/internal/domain/tool-bus.ts`)决定**能调什么**; + * 这里决定**怎么调** —— 三路各自穿过它该穿的那道缝,一道都不许绕: + * · `function` → **工具调用一缝**(`ToolInvoker`):白名单、录制回放、契约校验; + * 写类**不当场落地**,只登记动作意向,放行那一刻才由系统执行; + * · `human` → 人类工具:发工单到负责人工位 + 立监听听回传,本回合就此等待; + * · `llm` → **模型网关一缝**(`ModelGateway`):四元绑定、录制回放、用量计预算。 + * + * 每件工具的入参 schema 由清单里的 JSON Schema 现译成 zod —— 模型照它填参, + * 填错当场被 Mastra 拦下,不会带着脏参数穿过缝。 + */ +import { createTool } from '@mastra/core/tools'; +import type { ToolsInput } from '@mastra/core/agent'; +import { z } from 'zod'; +import type { StaffId, TaskId } from '@contracts'; +import type { BusTool } from '@modules/toolbox'; + +/** 三路缝的最小口子 —— 各自只要这一点点能力,不把整个服务拖进来 */ +export type ToolBusPorts = { + /** 功能工具:读类当场调;写类先登记意向(放行才落地) */ + readonly invoke: (input: { + taskId: TaskId; + tool: string; + input: Record; + }) => Promise<{ ok: boolean; output?: Record; error?: { message: string } }>; + readonly isWriteEffect: (tool: string) => Promise; + readonly registerIntent: (input: { + taskId: TaskId; + tool: string; + input: Record; + label: string; + }) => Promise; + /** 人类工具:发工单 */ + readonly issueCard: (input: { + taskId: TaskId; + ownerId: StaffId; + humanCallCap: number; + workOrder: 'execution' | 'acceptance'; + card: Record; + }) => Promise<{ id: string }>; + /** 人类工具:立监听听人 */ + readonly listen: (input: { + taskId: TaskId; + eventType: 'data' | 'time' | 'human'; + keyFilter: Record; + deadline: string; + }) => Promise<{ id: string }>; + /** LLM 工具:经模型网关 */ + readonly generate: (input: { + model: string; + system?: string; + prompt: string; + outputSchema?: Record; + taskId: TaskId; + label: string; + }) => Promise<{ text: string; object?: unknown }>; +}; + +export type ToolBusContext = { + readonly taskId: TaskId; + readonly ownerId: StaffId; + readonly humanCallCap: number; + /** 活动声明的模型用途名(第一个)—— LLM 工具用它,活动不见厂商型号 */ + readonly model: string; +}; + +/** 本回合调人的痕:总线把它交回引擎,引擎据此把这一拍收成 awaiting */ +export type ToolBusTrace = { + /** 调人发出的卡(有值即本回合要等人) */ + askedCardId?: string; +}; + +/** + * JSON Schema → zod(仅译总线用得上的那一小撮:object/string/number/integer/ + * boolean/array/enum)。译不出的类型退化成 `z.unknown()` —— 宁可放宽, + * 也不假装校验过:真正的契约校验在缝里(`ToolInvoker.validate`),这里只为让模型会填。 + */ +function toZod(schema: Record | undefined): z.ZodTypeAny { + if (schema === undefined) return z.object({}).passthrough(); + const type = schema['type']; + const describe = (t: z.ZodTypeAny) => + typeof schema['description'] === 'string' ? t.describe(schema['description']) : t; + + if (Array.isArray(schema['enum'])) { + const values = (schema['enum'] as unknown[]).map(String); + return describe(values.length > 0 ? z.enum(values as [string, ...string[]]) : z.string()); + } + if (type === 'string') return describe(z.string()); + if (type === 'number') return describe(z.number()); + if (type === 'integer') return describe(z.number().int()); + if (type === 'boolean') return describe(z.boolean()); + if (type === 'array') { + const items = schema['items']; + return describe(z.array(toZod(typeof items === 'object' && items !== null ? (items as Record) : undefined))); + } + if (type === 'object') { + const props = schema['properties']; + if (typeof props !== 'object' || props === null) return describe(z.object({}).passthrough()); + const required = new Set(Array.isArray(schema['required']) ? (schema['required'] as string[]) : []); + const shape: Record = {}; + for (const [key, value] of Object.entries(props as Record)) { + const field = toZod(typeof value === 'object' && value !== null ? (value as Record) : undefined); + shape[key] = required.has(key) ? field : field.optional(); + } + return describe(z.object(shape)); + } + return describe(z.unknown()); +} + +/** LLM 五件的提示词:系统内化的能力,提示词也归系统 —— 活动不写、也改不了 */ +function llmPrompt(id: string, args: Record): { system: string; prompt: string } { + const j = (v: unknown) => JSON.stringify(v ?? null); + switch (id) { + case 'llm.extract': + return { + system: '你是抽取器。只从原文里抽,抽不到的字段留空 —— **不许编**。只回 JSON。', + prompt: `字段:${j(args['fields'])}\n提示:${String(args['hint'] ?? '无')}\n原文:\n${String(args['text'] ?? '')}\n\n回 {"values": {字段: 值}}`, + }; + case 'llm.classify': + return { + system: '你是归类器。只能从给定类目里选一个;判不了就回 "unknown"。只回 JSON。', + prompt: `类目:${j(args['labels'])}\n提示:${String(args['hint'] ?? '无')}\n内容:\n${String(args['text'] ?? '')}\n\n回 {"label": "...", "rationale": "一句话理由"}`, + }; + case 'llm.summarize': + return { + system: '你是摘要器。只压缩已有内容,不添事实、不作判断。只回 JSON。', + prompt: `重点:${String(args['focus'] ?? '无')}\n字数上限:${String(args['maxWords'] ?? 200)}\n原文:\n${String(args['text'] ?? '')}\n\n回 {"summary": "..."}`, + }; + case 'llm.judge': + return { + system: '你是裁断器。给出是/否与理由,并诚实给出把握度(0-1)。**你的结论只作参考,不代替人的放行裁决**。只回 JSON。', + prompt: `问题:${String(args['question'] ?? '')}\n判据:\n${String(args['basis'] ?? '')}\n\n回 {"verdict": true/false, "confidence": 0-1, "rationale": "理由"}`, + }; + default: + return { + system: '你是改写器。只改表达方式,**不添事实、不删事实**。只回 JSON。', + prompt: `要求:${String(args['instruction'] ?? '')}\n原文:\n${String(args['text'] ?? '')}\n\n回 {"text": "改写后"}`, + }; + } +} + +/** + * 把总线清单装配成 Mastra tools。 + * + * `trace` 是回传口:调人这件事在 Agent 眼里是「调了个工具」,在引擎眼里是 + * 「本回合要挂起等人」—— 工具执行时把卡号记进 trace,引擎读它收尾。 + */ +export function buildMastraTools( + bus: readonly BusTool[], + ports: ToolBusPorts, + context: ToolBusContext, + trace: ToolBusTrace, +): ToolsInput { + const out: ToolsInput = {}; + + for (const tool of bus) { + // Mastra 的 tool id 不收点号以外的怪字符,统一把点号换成双下划线,回调时换回来 + const key = tool.id.replace(/[^a-zA-Z0-9_]/g, '__'); + + out[key] = createTool({ + id: key, + description: tool.description, + inputSchema: toZod(tool.input) as never, + execute: async (inputData: unknown) => { + const args = (inputData ?? {}) as Record; + + if (tool.kind === 'human') { + const card = await ports.issueCard({ + taskId: context.taskId, + ownerId: context.ownerId, + humanCallCap: context.humanCallCap, + workOrder: 'execution', + card: args, + }); + await ports.listen({ + taskId: context.taskId, + eventType: 'human', + keyFilter: { cardId: card.id }, + deadline: 'P3D', + }); + trace.askedCardId = card.id; + return { asked: true, cardId: card.id }; + } + + if (tool.kind === 'llm') { + const { system, prompt } = llmPrompt(tool.id, args); + const result = await ports.generate({ + model: context.model, + system, + prompt, + ...(tool.output === undefined ? {} : { outputSchema: tool.output }), + taskId: context.taskId, + label: tool.id, + }); + return (result.object ?? { text: result.text }) as Record; + } + + /* + * 功能工具:**写类不当场落地**(OS 06「过程不落地」)—— + * 过程中只冻结入参登记为动作意向,放行那一刻由系统执行。 + * 骗 Agent 说「已执行」是最坏的选项:它会据此往下推,而世界上什么都没发生。 + */ + if (await ports.isWriteEffect(tool.id)) { + await ports.registerIntent({ taskId: context.taskId, tool: tool.id, input: args, label: tool.id }); + return { registered: true, note: '写类工具已登记为动作意向 —— 放行时才真正执行,现在世界上什么都没变' }; + } + + const result = await ports.invoke({ taskId: context.taskId, tool: tool.id, input: args }); + if (!result.ok) return { ok: false, error: result.error?.message ?? '工具调用失败' }; + return { ok: true, ...(result.output ?? {}) }; + }, + }); + } + + return out; +} diff --git a/apps/api/src/app/wiring/engines.ts b/apps/api/src/app/wiring/engines.ts index 5a7b558..c659ff0 100644 --- a/apps/api/src/app/wiring/engines.ts +++ b/apps/api/src/app/wiring/engines.ts @@ -9,6 +9,7 @@ import type { EventService } from '@modules/event'; import type { LedgerService } from '@modules/ledger'; import type { MemoryService } from '@modules/memory'; import type { ToolboxService, ToolInvoker } from '@modules/toolbox'; +import { compileToolBus } from '@modules/toolbox'; import type { HumanToolService } from '@modules/human-tool'; import { renderView } from '@modules/interaction'; import type { InteractionService } from '@modules/interaction'; @@ -33,6 +34,7 @@ import { evaluate as evalSfeel, evaluateCondition, evaluateUnaryTest } from '@sf import type { StaffId, TaskId } from '@contracts'; import { staffIdSchema } from '@contracts'; import { createAgentRunner } from '../agent-runner.ts'; +import { createMastraAgentRunner } from '../mastra-agent-runner.ts'; import type { Clock, IdGenerator } from '../runtime.ts'; export type EngineWiringDeps = { @@ -398,21 +400,93 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring { clock, }); + /* ── Agent 回路:单拍 or 开环(工具总线)────────────────────────── */ + + /** 活动声明的自定义模型名 —— 活动只见用途名,不见厂商型号 */ + const modelOf = async (taskId: TaskId) => { + const { activityId } = await taskContext.of(taskId); + const manifest = await deps.registry.manifestOf(activityId); + return manifest.declarations.models[0] ?? 'default'; + }; + const onAgentUsage = (taskId: TaskId, tokens: number) => + taskStore.addConsumption(taskId, { tokens }).then(() => undefined); + + /** + * 工具总线:**声明 × 目录**,编译期定死这一单能调什么(声明面在 toolbox/domain)。 + * 功能工具按活动白名单查目录;人类工具恒在(Harness 给的能力); + * LLM 五件仅当活动声明了模型用途名才给 —— 没声明模型却会问模型,是越权也无从归因。 + */ + const busOf = async (taskId: TaskId) => { + const { activityId } = await taskContext.of(taskId); + const manifest = await deps.registry.manifestOf(activityId); + const catalog = new Map( + (await deps.toolbox.list()).map((c) => [ + c.name, + { + name: c.name, + description: c.description, + input: c.input, + ...(c.output === undefined ? {} : { output: c.output }), + effect: c.effect === 'read' ? ('read' as const) : ('write' as const), + }, + ]), + ); + const report = compileToolBus({ + declaredTools: manifest.declarations.tools.map((t) => t.name), + catalog, + declaredModels: manifest.declarations.models, + }); + // 声明了却查无此工具 / 已停用:如实记痕,不静默 —— Agent 手上少了件东西,得看得见 + if (report.missing.length > 0 || report.disabled.length > 0) { + await memoryRecorder.append({ + taskId, + kind: 'observation', + title: `工具总线缺件:未装 ${report.missing.join('、') || '无'};已停用 ${report.disabled.join('、') || '无'}`, + } as never); + } + return report.tools; + }; + + /* + * 开环 or 单拍:`JCAI_AGENT_OPEN_LOOP=1` 时用 Mastra Agent 放开拍内工具循环。 + * 缺省仍是单拍版 —— 开环把「一拍调几次模型」交给了模型自己, + * 得有第一个真 loop 活动压着测过才好当缺省(见 debt M5-2)。 + */ + const agentRunner = + globalThis.process.env['JCAI_AGENT_OPEN_LOOP'] === '1' + ? createMastraAgentRunner({ + gateway: deps.modelGateway, + modelOf, + busOf, + onUsage: onAgentUsage, + contextOf: async (taskId) => { + const ctx = await taskContext.of(taskId); + return { taskId, ownerId: ctx.ownerId, humanCallCap: ctx.humanCallCap }; + }, + ports: { + invoke: async (input) => { + const { activityId } = await taskContext.of(input.taskId); + return toolGateway.invoke({ ...input, activityId }); + }, + isWriteEffect: (tool) => toolGateway.isWriteEffect(tool), + registerIntent: (input) => toolGateway.registerIntent(input), + issueCard: (input) => cards.issue(input), + listen: (input) => listeners.register(input), + generate: async (input) => { + const result = await deps.modelGateway.generate(input); + await onAgentUsage(input.taskId, result.usage.inputTokens + result.usage.outputTokens); + return { text: result.text, ...(result.object === undefined ? {} : { object: result.object }) }; + }, + }, + }) + : createAgentRunner({ gateway: deps.modelGateway, onUsage: onAgentUsage, modelOf }); + /* ── loop-engine ──────────────────────────────────────────────── */ const loop = createTurnRunner({ state: createLoopStateStore(db), sfeel, data: taskData, - agent: createAgentRunner({ - gateway: deps.modelGateway, - // loop 的每一回合都要问模型 —— 不计 token,预算熔断就永远不会响 - onUsage: (taskId, tokens) => taskStore.addConsumption(taskId, { tokens }).then(() => undefined), - modelOf: async (taskId) => { - const { activityId } = await taskContext.of(taskId); - const manifest = await deps.registry.manifestOf(activityId); - return manifest.declarations.models[0] ?? 'default'; - }, - }), + agent: agentRunner, tools: toolGateway, cards, listeners, diff --git a/apps/api/src/modules/llm/contract.ts b/apps/api/src/modules/llm/contract.ts index ceb0ca8..d8b7179 100644 --- a/apps/api/src/modules/llm/contract.ts +++ b/apps/api/src/modules/llm/contract.ts @@ -76,12 +76,27 @@ export type ModelResult = { readonly mode: GatewayMode; }; +/** 解好的模型端点(四元 + 明文密钥)—— app 层装配专用,见 ModelGateway.resolve */ +export type ResolvedEndpoint = { + readonly provider: LlmProvider; + readonly baseUrl: string; + readonly model: string; + readonly apiKey: string; +}; + /** * 模型网关 —— 活动基座六件里的「LLM 调用」。 * 活动只见自定义模型名;解析、凭证、录制回放全在此。 */ export type ModelGateway = { readonly mode: GatewayMode; + /** + * 解绑定:名 → 四元(含当场解出的密钥)—— **只给 app 层装配用**: + * Mastra Agent 那类需要真模型对象做 tool-calling 往返的场合, + * `generate` 的 text-in/text-out 抽象承载不了。 + * 密钥与 endpoint 仍不入 domain、不入包、不入留痕明文(OS 7.3 凭证隔离)。 + */ + resolve(modelName: string): Promise; generate(call: ModelCall): Promise; /** 换模式的网关 —— 回放审用 replay 模式重跑引擎(§7.3) */ withMode(mode: GatewayMode): ModelGateway; diff --git a/apps/api/src/modules/llm/index.ts b/apps/api/src/modules/llm/index.ts index 66d8c16..3dd20de 100644 --- a/apps/api/src/modules/llm/index.ts +++ b/apps/api/src/modules/llm/index.ts @@ -10,6 +10,7 @@ export type { ModelBinding, ModelCall, ModelGateway, + ResolvedEndpoint, ModelResult, ModelUsage, UpsertLlmInstance, diff --git a/apps/api/src/modules/llm/internal/usecase/model-gateway.ts b/apps/api/src/modules/llm/internal/usecase/model-gateway.ts index 920d903..b3213f0 100644 --- a/apps/api/src/modules/llm/internal/usecase/model-gateway.ts +++ b/apps/api/src/modules/llm/internal/usecase/model-gateway.ts @@ -26,6 +26,25 @@ export function createModelGateway(deps: ModelGatewayDeps): ModelGateway { const gateway: ModelGateway = { mode: deps.mode, + /** + * 解绑定:名 → 四元(密钥当场解出)。给 app 层装 Mastra Agent 那种 + * 需要真模型对象的场合(tool-calling 往返,`generate` 的 text-in/text-out 承载不了); + * `generate` 那条主路照旧全程在网关内部,录制回放不受影响。 + */ + async resolve(modelName) { + const binding = await deps.instances.findByName(modelName); + if (binding === undefined) throw new ModelNotBoundError(modelName, [{ field: 'name', message: '实例不存在' }]); + if (!binding.enabled) throw new ModelDisabledError(modelName); + const violations = validateBinding(binding); + if (violations.length > 0) throw new ModelNotBoundError(modelName, violations); + return { + provider: binding.provider, + baseUrl: binding.baseUrl, + model: binding.model, + apiKey: deps.secrets.open(binding.apiKeyCipher!), + }; + }, + async generate(call: ModelCall): Promise { const key = replayKey(call); diff --git a/apps/api/src/modules/loop-engine/contract.ts b/apps/api/src/modules/loop-engine/contract.ts index 81a9f4e..c2209af 100644 --- a/apps/api/src/modules/loop-engine/contract.ts +++ b/apps/api/src/modules/loop-engine/contract.ts @@ -70,7 +70,13 @@ export type AgentAction = /** 评估语义性前提(评估留痕,可回放可归因) */ | { readonly kind: 'judge'; readonly criterion: string; readonly satisfied: boolean; readonly rationale: string } /** 判定成果已齐,提交放行 */ - | { readonly kind: 'submit'; readonly rationale: string }; + | { readonly kind: 'submit'; readonly rationale: string } + /** + * 本回合**已在工具循环里调过人**:卡已发、监听已立(工具总线执行的)。 + * 引擎只收尾把这一拍置 awaiting —— 不能再发一张,否则负责人工位上堆两张同样的卡。 + * 开环模式(Mastra Agent 自主连环调工具)专用;单拍模式给不出这一型。 + */ + | { readonly kind: 'asked'; readonly cardId: string; readonly rationale: string }; export type TurnOutcome = { readonly runtime: CaseRuntime; diff --git a/apps/api/src/modules/loop-engine/internal/usecase/turn-runner.ts b/apps/api/src/modules/loop-engine/internal/usecase/turn-runner.ts index 40a81e5..6a9027c 100644 --- a/apps/api/src/modules/loop-engine/internal/usecase/turn-runner.ts +++ b/apps/api/src/modules/loop-engine/internal/usecase/turn-runner.ts @@ -190,6 +190,20 @@ export function createTurnRunner(deps: TurnRunnerDeps): LoopEngineService { return { runtime, status: 'awaiting' }; } + case 'asked': { + /* + * 开环模式:调人已由**工具总线**在拍内执行(发卡 + 立监听),引擎只收尾。 + * 再发一张就是重复调人 —— 工位上两张一模一样的卡,谁也不知道该答哪张。 + */ + await deps.memory.append({ + taskId, + kind: 'thought', + title: `本回合调人待回(卡 ${action.cardId})`, + detail: { rationale: action.rationale }, + }); + return { runtime, status: 'awaiting' }; + } + case 'submit': { // 终局唯放行:提交 = 发验收卡挂起等人裁决,不是自结(引擎不把案计划置为 Completed) return raiseAcceptance(taskId, runtime, action.rationale); diff --git a/apps/api/src/modules/toolbox/CONTRACT.md b/apps/api/src/modules/toolbox/CONTRACT.md index 4e258e1..51a9bfd 100644 --- a/apps/api/src/modules/toolbox/CONTRACT.md +++ b/apps/api/src/modules/toolbox/CONTRACT.md @@ -22,6 +22,13 @@ app(治理台 · 工具管理) 不变量: + - **工具总线是声明式的**(2026-07-28):Agent 能调什么由**活动声明 × 工具目录**在 + 编译期定死(`compileToolBus`),不由 Agent 临场想、也不由活动代码自己决定; + 声明了却查无此工具 / 已停用如实报,不静默给空壳。三路同一张清单: + `function`(功能工具,经工具调用一缝:白名单/录制回放/写类只登记意向)、 + `human`(**人类工具**,系统内化、零声明即得 —— 调人是 Harness 给的能力)、 + `llm`(**LLM 五件**:抽取/归类/摘要/裁断/改写,经模型网关一缝; + 仅当活动声明了模型用途名才上总线 —— 没声明却会问模型是越权,用量也无从归因) - **一切工具执行经 `ToolInvoker`** —— 绕过它,回放审就对它失明(§12.5#10) - `replay` 模式**绝不回退实调**:缺录即 `ToolReplayMissError` - **白名单在结构上拦截**:功能工具按活动白名单,纯工具按 `ownerActivityId` 私有作用域; diff --git a/apps/api/src/modules/toolbox/__tests__/tool-bus.test.ts b/apps/api/src/modules/toolbox/__tests__/tool-bus.test.ts new file mode 100644 index 0000000..22f2b04 --- /dev/null +++ b/apps/api/src/modules/toolbox/__tests__/tool-bus.test.ts @@ -0,0 +1,74 @@ +/** + * 工具总线的声明面 —— **Agent 能调什么由声明定死**,不由它临场想(domain 测试零 mock)。 + */ +import { describe, expect, it } from 'vitest'; +import { compileToolBus, HUMAN_TOOL, LLM_TOOLS } from '../internal/domain/tool-bus.ts'; +import type { CatalogEntry } from '../internal/domain/tool-bus.ts'; + +const entry = (over: Partial & { name: string }): CatalogEntry => ({ + description: '一件工具', + input: { type: 'object', properties: { pn: { type: 'string' } } }, + effect: 'read', + ...over, +}); + +const catalog = new Map([ + ['crm.history-price-read', entry({ name: 'crm.history-price-read' })], + ['mail.send', entry({ name: 'mail.send', effect: 'write' })], + ['old.tool', entry({ name: 'old.tool', enabled: false })], +]); + +describe('compileToolBus —— 声明 × 目录', () => { + it('只给声明过的功能工具;效应原样带出(写类下游不当场落地)', () => { + const report = compileToolBus({ + declaredTools: ['crm.history-price-read', 'mail.send'], + catalog, + declaredModels: [], + }); + const fn = report.tools.filter((t) => t.kind === 'function'); + expect(fn.map((t) => `${t.id}:${t.effect}`)).toEqual(['crm.history-price-read:read', 'mail.send:write']); + expect(report.missing).toEqual([]); + }); + + it('没声明的工具不在总线上 —— 白名单之外结构上调不到', () => { + const report = compileToolBus({ declaredTools: ['crm.history-price-read'], catalog, declaredModels: [] }); + expect(report.tools.some((t) => t.id === 'mail.send')).toBe(false); + }); + + it('声明了却查无此工具 / 已停用:如实报,不静默给一个空壳', () => { + const report = compileToolBus({ + declaredTools: ['crm.history-price-read', 'ghost.tool', 'old.tool'], + catalog, + declaredModels: [], + }); + expect(report.missing).toEqual(['ghost.tool']); + expect(report.disabled).toEqual(['old.tool']); + expect(report.tools.some((t) => t.id === 'ghost.tool' || t.id === 'old.tool')).toBe(false); + }); + + /* 人类工具是 Harness 给的能力,不是活动自带的本事 —— 每个活动天然可以调人 */ + it('人类工具恒在:一件工具都没声明也能调人', () => { + const report = compileToolBus({ declaredTools: [], catalog, declaredModels: [] }); + expect(report.tools).toHaveLength(1); + expect(report.tools[0]).toEqual(HUMAN_TOOL); + expect(report.tools[0]!.kind).toBe('human'); + }); + + /* 没声明模型的活动突然会「问模型」= 越权,且用量无从归因 */ + it('LLM 五件只在活动声明了模型用途名时才上总线', () => { + const without = compileToolBus({ declaredTools: [], catalog, declaredModels: [] }); + expect(without.tools.filter((t) => t.kind === 'llm')).toHaveLength(0); + + const with_ = compileToolBus({ declaredTools: [], catalog, declaredModels: ['quote-extractor'] }); + expect(with_.tools.filter((t) => t.kind === 'llm').map((t) => t.id)).toEqual(LLM_TOOLS.map((t) => t.id)); + expect(with_.tools.filter((t) => t.kind === 'llm')).toHaveLength(5); + }); + + it('LLM 五件都是读类、都有入参契约 —— 模型照它填参', () => { + for (const tool of LLM_TOOLS) { + expect(tool.effect).toBe('read'); + expect(tool.input['type']).toBe('object'); + expect(Array.isArray(tool.input['required'])).toBe(true); + } + }); +}); diff --git a/apps/api/src/modules/toolbox/index.ts b/apps/api/src/modules/toolbox/index.ts index dd60184..3c4a1ea 100644 --- a/apps/api/src/modules/toolbox/index.ts +++ b/apps/api/src/modules/toolbox/index.ts @@ -43,6 +43,9 @@ export type { ToolboxServiceDeps } from './internal/usecase/toolbox-service.ts'; export { createToolboxService } from './internal/usecase/toolbox-service.ts'; export { checkEvolution, dispositionOf, EFFECT_LEVEL_LABEL, EFFECT_LEVELS } from './internal/domain/tool-contract.ts'; +/* 工具总线的声明面(纯逻辑):声明 × 目录 → 一张清单;人类工具与 LLM 五件系统内化 */ +export type { BusTool, CatalogEntry, ToolBusInput, ToolBusReport } from './internal/domain/tool-bus.ts'; +export { compileToolBus, HUMAN_TOOL, LLM_TOOLS } from './internal/domain/tool-bus.ts'; export { auditPassed, staticAudit } from './internal/domain/registration-audit.ts'; export type { ToolHandler } from './internal/adapter/toolbox-store.ts'; diff --git a/apps/api/src/modules/toolbox/internal/domain/tool-bus.ts b/apps/api/src/modules/toolbox/internal/domain/tool-bus.ts new file mode 100644 index 0000000..dc8664e --- /dev/null +++ b/apps/api/src/modules/toolbox/internal/domain/tool-bus.ts @@ -0,0 +1,213 @@ +/** + * 工具总线的**声明面** —— 纯逻辑,零 IO、零框架(编码规范 §5.3 / §6.2)。 + * + * 「Agent 调用工具都是声明式的」:一个活动**能调什么**,不由 Agent 临场想、也不由 + * 活动代码自己决定 —— 由活动清单的 `declarations` 与工具目录在**编译期**定死。 + * 这里就是那次编译:声明 × 目录 → 一张总线清单(`BusTool[]`), + * 清单之外的调用在结构上不可能发生(白名单在 `ToolInvoker` 再把一次关)。 + * + * 三路工具,同一张清单、同一套形状: + * · `function` —— 功能工具:第一方 / 外部,经**工具调用一缝**(录制回放、白名单、 + * 写类先登记意向,放行时才落地); + * · `human` —— **人类工具**(系统内化,零声明即得):调人 = 发工单 + 立监听听人。 + * 它是三型行动里的「调人」,不是外部工具,不需要注册也不进白名单; + * · `llm` —— **LLM 工具**(系统内化,五件通用):抽取 / 归类 / 摘要 / 裁断 / 改写, + * 经**模型网关一缝**(录制回放、四元绑定)。活动只声明用途名,不见厂商型号。 + * + * 装配成具体可调用对象(Mastra `createTool`)是 app 层的事 —— 这里只出清单。 + */ + +/** 总线上的一件工具:形状与三路无关,调用路由靠 `kind` */ +export type BusTool = { + readonly id: string; + readonly description: string; + /** 入参契约(JSON Schema)—— 装配层据此生成 zod,模型据此填参 */ + readonly input: Record; + readonly output?: Record; + readonly kind: 'function' | 'human' | 'llm'; + /** + * 效应:`read` 当场调当场回;`write` **不当场落地** —— + * 过程中只登记动作意向,放行那一刻才由系统执行(OS 06「过程不落地」)。 + */ + readonly effect: 'read' | 'write'; +}; + +/** 目录里的一条工具契约(取自 toolbox,只用得上这几个字段) */ +export type CatalogEntry = { + readonly name: string; + readonly description: string; + readonly input: Record; + readonly output?: Record; + readonly effect: 'read' | 'write'; + readonly enabled?: boolean; +}; + +/** + * **人类工具**(系统内化):调人。 + * + * 「AI 对世界只有触达与等待两种姿势」—— 调人属于等待:发一张工单到负责人工位, + * 立一条监听听他的回传,本拍就此挂起。它不进工具目录、不需要白名单: + * 每个活动天然可以调人,这是 Harness 给的能力,不是活动自带的本事。 + */ +export const HUMAN_TOOL: BusTool = { + id: 'human.ask', + description: '调人:把一件事交到负责人工位上问他(发工单 + 立监听),本回合就此等待回传', + input: { + type: 'object', + required: ['title', 'ask'], + properties: { + title: { type: 'string', description: '工单标题:一句话说清要他做什么' }, + ask: { type: 'string', description: '问题正文:要他答什么、依据什么答' }, + basis: { + type: 'array', + description: '依据快照:给他看的事实(键值对),不要让人自己去翻', + items: { type: 'object', properties: { k: { type: 'string' }, v: { type: 'string' } } }, + }, + fields: { type: 'array', description: '要他填的字段名', items: { type: 'string' } }, + }, + }, + output: { + type: 'object', + properties: { asked: { type: 'boolean' }, cardId: { type: 'string' } }, + }, + kind: 'human', + effect: 'read', +}; + +/** + * **LLM 工具**(系统内化,五件通用):大模型驱动的通用能力,不是「一个模型实例」。 + * + * 每件都是**有契约的工具**:入参出参定死、经模型网关一缝(录制回放可重放)、 + * 用量计入任务预算。活动声明模型用途名(`declarations.models`),换档只改绑定。 + * 五件之外要更专的能力,写成功能工具进目录 —— 不在这儿加。 + */ +export const LLM_TOOLS: readonly BusTool[] = [ + { + id: 'llm.extract', + description: '抽取:从自由文本里按给定字段抽出结构化事实(抽不到的字段留空,不编)', + input: { + type: 'object', + required: ['text', 'fields'], + properties: { + text: { type: 'string', description: '原文' }, + fields: { type: 'array', items: { type: 'string' }, description: '要抽的字段名' }, + hint: { type: 'string', description: '可选:字段含义与格式提示' }, + }, + }, + output: { type: 'object', properties: { values: { type: 'object' } } }, + kind: 'llm', + effect: 'read', + }, + { + id: 'llm.classify', + description: '归类:把一段内容判进给定类目之一(类目必须穷举,判不了就回 unknown)', + input: { + type: 'object', + required: ['text', 'labels'], + properties: { + text: { type: 'string' }, + labels: { type: 'array', items: { type: 'string' }, description: '候选类目(穷举)' }, + hint: { type: 'string' }, + }, + }, + output: { type: 'object', properties: { label: { type: 'string' }, rationale: { type: 'string' } } }, + kind: 'llm', + effect: 'read', + }, + { + id: 'llm.summarize', + description: '摘要:把长文压成要点(叙述是视图不是事实 —— 结论不入事实库)', + input: { + type: 'object', + required: ['text'], + properties: { text: { type: 'string' }, maxWords: { type: 'integer' }, focus: { type: 'string' } }, + }, + output: { type: 'object', properties: { summary: { type: 'string' } } }, + kind: 'llm', + effect: 'read', + }, + { + id: 'llm.judge', + description: '裁断:对一个语义性判据给出是/否与理由(**只作参考**,不得代替人的放行裁决)', + input: { + type: 'object', + required: ['question', 'basis'], + properties: { + question: { type: 'string', description: '要判的问题(是非题)' }, + basis: { type: 'string', description: '判据材料' }, + }, + }, + output: { + type: 'object', + properties: { verdict: { type: 'boolean' }, confidence: { type: 'number' }, rationale: { type: 'string' } }, + }, + kind: 'llm', + effect: 'read', + }, + { + id: 'llm.rewrite', + description: '改写:按语气/格式要求重写一段文字(只改表达,不添事实)', + input: { + type: 'object', + required: ['text', 'instruction'], + properties: { text: { type: 'string' }, instruction: { type: 'string' } }, + }, + output: { type: 'object', properties: { text: { type: 'string' } } }, + kind: 'llm', + effect: 'read', + }, +]; + +export type ToolBusInput = { + /** 活动清单声明的功能工具白名单(`declarations.tools[].name`) */ + readonly declaredTools: readonly string[]; + /** 工具目录:名 → 契约 */ + readonly catalog: ReadonlyMap; + /** 活动声明了模型用途名才给 LLM 工具 —— 没声明模型的活动不该会「问模型」 */ + readonly declaredModels: readonly string[]; +}; + +export type ToolBusReport = { + readonly tools: readonly BusTool[]; + /** 声明了却在目录里查无此工具 / 已停用 —— 如实报,不静默吞 */ + readonly missing: readonly string[]; + readonly disabled: readonly string[]; +}; + +/** + * 编译总线清单:**声明是唯一入口**。 + * + * 功能工具按活动白名单逐条查目录(查不到 / 已停用如实报,不给它); + * 人类工具恒在(Harness 给的能力);LLM 五件仅当活动声明了模型用途名才给 —— + * 一个没声明模型的活动突然会「问模型」,那是越权,也让用量无从归因。 + */ +export function compileToolBus(input: ToolBusInput): ToolBusReport { + const tools: BusTool[] = []; + const missing: string[] = []; + const disabled: string[] = []; + + for (const name of input.declaredTools) { + const entry = input.catalog.get(name); + if (entry === undefined) { + missing.push(name); + continue; + } + if (entry.enabled === false) { + disabled.push(name); + continue; + } + tools.push({ + id: entry.name, + description: entry.description, + input: entry.input, + ...(entry.output === undefined ? {} : { output: entry.output }), + kind: 'function', + effect: entry.effect, + }); + } + + tools.push(HUMAN_TOOL); + if (input.declaredModels.length > 0) tools.push(...LLM_TOOLS); + + return { tools, missing, disabled }; +} diff --git a/docs/debt.md b/docs/debt.md index da12b08..20b3973 100644 --- a/docs/debt.md +++ b/docs/debt.md @@ -12,7 +12,7 @@ | M1-3 | ~~投递记录写入即止,尚无派发 worker~~ | 派发器已于 M2 落地(advisory lock 串行 + 消费幂等);消费者(任务 / 触发器)随 M4 / M5 注册 | M2 | 已清理 | | M2-1 | 派发器的消费者表为空 —— 投递只标记已送达 | 任务消费者属 task(M4),触发器消费者属 trigger(M5);投递链路本身已可测 | M4 / M5 | 进行中 | | M5-3 | 活动 .JS 产物是源码文本,未经 tsup 单文件 ESM 真编译 | 静态审扫描的正是产物文本(import 与全局引用),当前形态已可审;真编译在装载器落地时接入 | M6 前 | 进行中 | -| M5-2 | loop 的 Agent 回路直接经 `ModelGateway`,未用 Mastra `Agent` | 编码规范 §6.1 规定用 Mastra Agent;`AgentPort` 端口不变,换实现时 usecase 不动;当前实现仍过两缝(录制回放可见) | M6 前 | 进行中 | +| M5-2 | loop 的 Agent 回路有两个实现:单拍版(缺省,经 `ModelGateway`,两缝完整)与**开环版**(`JCAI_AGENT_OPEN_LOOP=1`:Mastra `Agent` + 工具总线,拍内自主连环调工具) | 端口 `AgentPort` 不变,usecase 未动。**开环的代价**:模型逐轮调用不经模型网关的录制回放(tool-calling 往返 `generate` 的 text-in/text-out 承载不了)—— 四元绑定与凭证隔离照旧走 `resolve`,**工具调用一缝完整**;要恢复逐轮录制须给 Mastra 供一个自实现的 AI SDK LanguageModel。开环待第一个真 loop 活动压测后再考虑转缺省 | 第一个真 loop 活动 | 进行中 | | M5-1 | `process` 未用 Mastra workflow 编译器 —— **运行时切面已立**(2026-07-28:`FlowRuntime` 端口 + 自持实现整体迁入 `internal/runtime/`,usecase 成薄壳,八例 E2E 为等价性护栏),编译器实现仍欠 | 编码规范 §6.1;接入路线已定(端口化+双实现,回边 reopen 先 spike);冲突清单见 process/CONTRACT.md | 编译器随 spike 结论落地 | 进行中(切面已立) | | M2-2 | pg-boss 已装未用 | 定时作业(监听时限扫描、周期触发器)随 M5 落地;当下派发器用 setInterval | M5 | 进行中 | | M5-4 | AND 并行没有声明机制 —— 网关废除后(2026-07-28)多出边一律异或,画不出并行分叉 | 分支=条件出边、汇合=多入边异或已够 MVP;真要并行时以「并行组」声明加回(对应 Mastra `.parallel` 结构块),与 M5-1 编译器同批设计 | 需要并行的第一条流 | 进行中 | diff --git a/eslint.config.js b/eslint.config.js index c0f962b..e164aa3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -21,6 +21,8 @@ export default tseslint.config( '.api-tmp/**', 'tools/depcruise-tiers.generated.cjs', 'docs/**', + // 验证性原型(spike):一次性的事实探针,跑完留证据即弃 —— 不进产线,也不受产线规矩约束 + 'spike/**', ], }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8afd3ab..a7bf782 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,7 +46,7 @@ importers: version: 8.65.0(eslint@9.39.5)(typescript@5.9.3) vitest: specifier: ^3.2.4 - version: 3.2.7(@types/node@22.20.1)(tsx@4.23.1)(yaml@2.9.0) + version: 3.2.7(@types/debug@4.1.13)(@types/node@22.20.1)(tsx@4.23.1)(yaml@2.9.0) activities/quote-alternative: {} @@ -68,6 +68,9 @@ importers: '@hono/node-server': specifier: ^2.0.12 version: 2.0.12(hono@4.12.32) + '@mastra/core': + specifier: ^1.53.0 + version: 1.53.0(@grpc/grpc-js@1.14.4)(ai@7.0.37(zod@4.4.3))(express@5.2.1)(zod@4.4.3) ai: specifier: ^7.0.37 version: 7.0.37(zod@4.4.3) @@ -119,12 +122,16 @@ importers: apps/api/src/modules/message: {} + apps/api/src/modules/minute: {} + apps/api/src/modules/org: {} apps/api/src/modules/process: {} apps/api/src/modules/release: {} + apps/api/src/modules/report: {} + apps/api/src/modules/skill-engine: {} apps/api/src/modules/task: {} @@ -187,6 +194,21 @@ importers: packages: + '@a2a-js/sdk@0.3.14': + resolution: {integrity: sha512-F6Ew1AtPzCLhTn8h9yiqTe7DiDf6XVrSnq9V1YqSl9eWqPm6anMveTiKdCSb/76cW0YiJc24rNaUrVezFFHbqQ==} + engines: {node: '>=18'} + peerDependencies: + '@bufbuild/protobuf': ^2.10.2 + '@grpc/grpc-js': ^1.11.0 + express: ^4.21.2 || ^5.1.0 + peerDependenciesMeta: + '@bufbuild/protobuf': + optional: true + '@grpc/grpc-js': + optional: true + express: + optional: true + '@ai-sdk/gateway@4.0.28': resolution: {integrity: sha512-ee9TsNO3mkgHDWmTmJ8Fvltr6PFh52zhrV2+FaKJY3F3iu7kWZi5tCRJCR1HVhhlpj6lHniUb28nLQdPHkA/1Q==} engines: {node: '>=22'} @@ -199,16 +221,58 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider-utils@2.2.8': + resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + + '@ai-sdk/provider-utils@3.0.30': + resolution: {integrity: sha512-NCJ9JKow5ENAgEZxzvEvF20thwDiH+hutvzmrUDbloRX0azpJHNst8+7pZIVryYhLM9wgpT5/ShTSjPTFhkxEQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@4.0.40': + resolution: {integrity: sha512-OL5IrpUm9Y8Dwy+w/vvFwPotS6m52O9W0op2oXgXdCROMJIBalBI0oro6OIBYkPxvm5Xg02GSkoQN25RlR0bnw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@5.0.11': + resolution: {integrity: sha512-7/96wE+ZsKB35iS9ASyllrE4Ym/EolXEB7AkuJ5FI++fmS85BVTAs77890C+1Z2jwHfBKjBQSBmsliOsAh0iFQ==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider-utils@5.0.12': resolution: {integrity: sha512-bbhlOgHeYwrIGheLkM6fhS8hVger8uFPmcOLg+kxc9EFh7y30XYorWhthlYAgpadO3SJhFZrIcEknN7qEqEVvA==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider@1.1.3': + resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} + engines: {node: '>=18'} + + '@ai-sdk/provider@2.0.3': + resolution: {integrity: sha512-h88OPkavHTiN9tMn2l5awAznGB0lXzjcLhgR1/rvjB2zlLprsNxbM2tt6OJsHUxduLC3klq0/eqaSf6fX5XVww==} + engines: {node: '>=18'} + + '@ai-sdk/provider@3.0.14': + resolution: {integrity: sha512-5X1k57JBJ4H7H1QjX7CnJYAB1I19r/trVZTMcSms7/kLNZ8RaU4Nt2agcwZzv82Hfx6Q7/TOLU7agAKeFfc8cA==} + engines: {node: '>=18'} + '@ai-sdk/provider@4.0.3': resolution: {integrity: sha512-e0CpNWJUY7OxAFAnCZkw+ri9QOHWwTs1tXP42782KFGCU07qt8NiXCrCVowyCB5dP2r5/Uls+g2oPd8kOJn9dw==} engines: {node: '>=22'} + '@ai-sdk/ui-utils@1.2.11': + resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} @@ -991,6 +1055,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/ttlcache@2.1.5': + resolution: {integrity: sha512-VwGZqqjAWPICTmxUZnbpEfO60LhPWzquik+bmyXGY7pYRn6diEvCI5i6Ca+J6o2y4vS73HrpuMTo2dOvUevH8w==} + engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1013,10 +1081,46 @@ packages: '@kwsites/file-exists@1.1.1': resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + + '@lukeed/uuid@2.0.1': + resolution: {integrity: sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==} + engines: {node: '>=8'} + + '@mastra/core@1.53.0': + resolution: {integrity: sha512-Q9dIpdGiCAAyX2dVSVIg5BRShsHPR17MsvEwowRf9IQyfw3DyP/h7UJEJ1vcY6cLjGm+AqLqRbof97TihW1WUA==} + engines: {node: '>=22.13.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + '@mastra/schema-compat@1.3.4': + resolution: {integrity: sha512-2ObUsd21KIVelQy+eKPxJvnMxtmKnWacsIkZovhEYjVcQX9OYTDQ+u4E4RboIJZvurJnFx++/ujQLFznUaEYMg==} + engines: {node: '>=22.13.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + '@modelcontextprotocol/sdk@1.30.0': + resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@posthog/core@1.45.1': + resolution: {integrity: sha512-tLtvzomavb2PPWdGYKsusyIzIeL2Px47v348Smibkay7sMy/83TyPk+Ptsp2NdeOgJsbuwSxWkR2+XA0aSCAaA==} + + '@posthog/types@1.398.0': + resolution: {integrity: sha512-sJMkl4k+u8yS/0fjHsKqE9xTdsAh30a2WvgChiptellnVoE0e8QJKFgqOMD2sk8FaEArPdeFklAhXvmENAt3Sg==} + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -1185,6 +1289,21 @@ packages: cpu: [x64] os: [win32] + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@sindresorhus/slugify@2.2.1': + resolution: {integrity: sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==} + engines: {node: '>=12'} + + '@sindresorhus/transliterate@1.6.0': + resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==} + engines: {node: '>=12'} + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -1238,6 +1357,9 @@ packages: '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -1253,6 +1375,12 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@18.19.130': resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} @@ -1279,6 +1407,9 @@ packages: '@types/ssh2@1.15.5': resolution: {integrity: sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@typescript-eslint/eslint-plugin@8.65.0': resolution: {integrity: sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1380,10 +1511,17 @@ packages: '@workflow/serde@4.1.0': resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} + '@workflow/serde@4.1.0-beta.2': + resolution: {integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-jsx-walk@2.0.0: resolution: {integrity: sha512-uuo6iJj4D4ygkdzd6jPtcxs8vZgDX9YFIkqczGImoypX2fQ4dVImmu3UzA4ynixCIMTrEOWW+95M2HuBaCEOVA==} @@ -1452,6 +1590,9 @@ packages: resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} engines: {node: '>= 14'} + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1476,6 +1617,9 @@ packages: react-native-b4a: optional: true + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1534,6 +1678,10 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + brace-expansion@1.1.16: resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==} @@ -1576,10 +1724,22 @@ packages: resolution: {integrity: sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==} engines: {node: '>=0.10.0'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1587,6 +1747,9 @@ packages: caniuse-lite@1.0.30001806: resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} @@ -1595,6 +1758,24 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + chat@4.35.0: + resolution: {integrity: sha512-IUbdgTBvgs/XYhKcpKGrpmZgcl8KcA5NZ+eOww+0rBdhPf+95INjcUauQTk5e48UI1V4PRg9stToPsT4vle07g==} + engines: {node: '>=20'} + peerDependencies: + ai: ^6.0.182 || ^7.0.0 + workflow: ^5.0.0-beta.35 + zod: ^3.0.0 || ^4.0.0 + peerDependenciesMeta: + ai: + optional: true + workflow: + optional: true + zod: + optional: true + check-error@2.1.3: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} @@ -1643,15 +1824,39 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} cookie-es@3.1.1: resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + cpu-features@0.0.10: resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} engines: {node: '>=10.0.0'} @@ -1669,6 +1874,10 @@ packages: resolution: {integrity: sha512-yJ/G1LVir6CnlkLI40CsampPLKl1SprGGlUagWtGJxewytRVYezv5xVyzzbT+Pvzx+VIRvZVF7/a0eEMTxdnTA==} engines: {node: '>=18'} + croner@10.0.1: + resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==} + engines: {node: '>=18.0'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1685,6 +1894,9 @@ packages: supports-color: optional: true + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -1692,11 +1904,22 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dependency-cruiser@16.10.4: resolution: {integrity: sha512-hrxVOjIm8idZ9ZVDGSyyG3SHiNcEUPhL6RTEmO/3wfQWLepH5pA3nuDMMrcJ1DkZztFA7xg3tk8OVO+MmwwH9w==} engines: {node: ^18.17||>=20} hasBin: true + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diagram-js@15.23.0: resolution: {integrity: sha512-cCgL+4Ep0xrLe6TtdvRVgo6bWYjUbrQg+ES/9rpltqmTD2YaPoC+NYcRsKYw/fDO+1RN0q16NzErP1svVZhNQg==} @@ -1720,6 +1943,10 @@ packages: resolution: {integrity: sha512-bs2yO68JDFOm6rKv8f0EnrM2cENduhRkpqOtt/s5l5JBA/eqGBZCzLPmdYoHtJ6utgLGgcBajFsEQbl12pT0lQ==} engines: {node: '>=20'} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + drizzle-kit@0.31.10: resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} hasBin: true @@ -1816,9 +2043,16 @@ packages: sqlite3: optional: true + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.396: resolution: {integrity: sha512-yHiw2Y3C3H9U6TMbOfoWK/BPreiOPXRfTWPBwQBoZG6/8TB6eOPnsy5oaRYuatR7Fw2SJ4kKforgufeo7fq0EQ==} @@ -1828,6 +2062,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -1835,6 +2073,10 @@ packages: resolution: {integrity: sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==} engines: {node: '>=10.13.0'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} @@ -1842,6 +2084,10 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} @@ -1866,10 +2112,17 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1900,6 +2153,11 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -1919,6 +2177,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -1934,10 +2196,35 @@ packages: resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} engines: {node: '>=18.0.0'} + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} + engines: {node: ^18.19.0 || >=20.5.0} + expect-type@1.4.0: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} + express-rate-limit@8.6.1: + resolution: {integrity: sha512-0D493aP61w0TJ2A0wy27riRsO7FMQ7FK+KUHOKCSfPvYo0R55aiC6emCVgFUeShH0fq0ICPVzNcgoS+BsbXQCA==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1953,6 +2240,9 @@ packages: fast-uri@3.1.4: resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1962,10 +2252,18 @@ packages: picomatch: optional: true + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1984,6 +2282,14 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -2003,10 +2309,22 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + get-port@5.1.1: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} engines: {node: '>=8'} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + get-tsconfig@4.14.0: resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} @@ -2031,13 +2349,25 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + hasown@2.0.4: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} @@ -2049,6 +2379,18 @@ packages: htm@3.1.1: resolution: {integrity: sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} + engines: {node: '>=18.18.0'} + + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2082,10 +2424,22 @@ packages: resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} engines: {node: '>=10.13.0'} + ip-address@10.3.1: + resolution: {integrity: sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-core-module@2.16.2: resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} engines: {node: '>= 0.4'} + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2102,14 +2456,33 @@ packages: resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} engines: {node: '>=18'} + is-network-error@1.3.2: + resolution: {integrity: sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==} + engines: {node: '>=16'} + is-path-inside@4.0.0: resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} engines: {node: '>=12'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -2123,16 +2496,26 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jose@6.2.4: + resolution: {integrity: sha512-N8acGzVsQy6M/fjFcxtysNc4Q379TcM5dM/qKkNtsHFji88yANnXTr7BLeP75iPnFwBfQzM/jg2BZ9+HZrHCZA==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + jpeg-js@0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@3.15.0: + resolution: {integrity: sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==} + hasBin: true + js-yaml@4.3.0: resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} hasBin: true @@ -2145,12 +2528,19 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-schema-to-zod@2.8.1: + resolution: {integrity: sha512-fRr1mHgZ7hboLKBUdR428gd9dIHUFGivUqOeiDcSmyXkNZCtB1uGaZLvsjZ4GaN5pwBIs+TGIOf6s+Rp5/R/zA==} + hasBin: true + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -2165,6 +2555,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -2204,12 +2598,19 @@ packages: long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -2220,10 +2621,150 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} + engines: {node: '>= 0.8'} + memoize@10.2.0: resolution: {integrity: sha512-DeC6b7QBrZsRs3Y02A6A7lQyzFbsQbqgjI6UW0GigGWV+u1s25TycMr0XHZE4cJce7rY/vyw2ctMQqfDkIhUEA==} engines: {node: '>=18'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -2284,6 +2825,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + node-releases@2.0.51: resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} engines: {node: '>=18'} @@ -2296,13 +2841,25 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + object-refs@0.4.0: resolution: {integrity: sha512-6kJqKWryKZmtte6QYvouas0/EIJKPI1/MMIuRsiBlNuhIMfqYTggzX2F1AJ2+cDs288xyi9GL7FyasHINR98BQ==} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -2318,6 +2875,14 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-map@7.0.6: + resolution: {integrity: sha512-I4Prw6ivkd6p8PiYR1tXASOAOBzIJwu0TB7fqaX0c/8c3QAehNYmX57EijyGGGBt3c/BIowGwV03RVBtXvHEVg==} + engines: {node: '>=18'} + + p-retry@7.1.1: + resolution: {integrity: sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==} + engines: {node: '>=20'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -2325,6 +2890,14 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2337,6 +2910,10 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -2344,6 +2921,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -2401,6 +2981,10 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -2442,6 +3026,15 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + posthog-node@5.46.1: + resolution: {integrity: sha512-WjCqExq44pBdyg9MSsH6UAE0tNZ88p4aIuVFicgqhjf2Fbws6IhS4ioYUa4aBrbUPS9EDRXtBTtF5DpP1ml8Pw==} + engines: {node: ^20.20.0 || >=22.22.0} + peerDependencies: + rxjs: ^7.0.0 + peerDependenciesMeta: + rxjs: + optional: true + preact@10.29.7: resolution: {integrity: sha512-DCHYrK/B10yUD3ZjLfhZ3WIE/9Vf9VFUODcRE2dRomTYDpJk6z6L9wecSfhfE6M9ZTHUdyQkoC46arIDhEV84Q==} peerDependencies: @@ -2454,6 +3047,10 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -2476,6 +3073,10 @@ packages: resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -2483,6 +3084,18 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} + engines: {node: '>=0.6'} + + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + react-dom@19.2.8: resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} peerDependencies: @@ -2522,6 +3135,18 @@ packages: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + remend@1.3.0: + resolution: {integrity: sha512-iIhggPkhW3hFImKtB10w0dz4EZbs28mV/dmbcYVonWEJ6UGHHpP+bFZnTh6GNWJONg5m+U56JrL+8IxZRdgWjw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -2550,11 +3175,19 @@ packages: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rollup@4.62.3: resolution: {integrity: sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -2570,6 +3203,13 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2579,6 +3219,10 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + serialize-error@13.0.1: resolution: {integrity: sha512-bBZaRwLH9PN5HbLCjPId4dP5bNGEtumcErgOX952IsvOhVPrm3/AeK1y0UHA/QaPG701eg0yEnOKsCOC6X/kaA==} engines: {node: '>=20'} @@ -2593,6 +3237,13 @@ packages: resolution: {integrity: sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA==} engines: {node: '>=10'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2601,6 +3252,22 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -2636,6 +3303,9 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + ssh-remote-port-forward@1.0.4: resolution: {integrity: sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ==} @@ -2646,6 +3316,10 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} @@ -2674,10 +3348,18 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -2768,10 +3450,20 @@ packages: resolution: {integrity: sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==} engines: {node: '>=14.14'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tokenx@1.6.0: + resolution: {integrity: sha512-CKTjk345ajvBAUp5xUI9a5KKN0zU0lBueVHQbCskH1Hp6WkUKsPW2qGCYNs0pxNyfzxfo+IIjdt2W4sMbw/qBw==} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -2824,6 +3516,10 @@ packages: resolution: {integrity: sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==} engines: {node: '>=20'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + typescript-eslint@8.65.0: resolution: {integrity: sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2849,6 +3545,29 @@ packages: resolution: {integrity: sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==} engines: {node: '>=22.19.0'} + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -2866,6 +3585,20 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} + hasBin: true + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -2969,10 +3702,25 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.21.1: + resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -2997,15 +3745,43 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors@2.2.0: + resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==} + engines: {node: '>=18'} + zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} + zod-from-json-schema@0.0.5: + resolution: {integrity: sha512-zYEoo86M1qpA1Pq6329oSyHLS785z/mTwfr9V1Xf/ZLhuuBGaMlDGu/pDVGVUe4H4oa1EFgWZT53DP0U3oT9CQ==} + + zod-from-json-schema@0.5.6: + resolution: {integrity: sha512-U33AJ7ZWS6y9XNSzMWcdy8hRAvZmWhTtpYJu0SXPT5AArbc9nq2ur7Magzmn5RF9KBV4b3FP0nCpmqqlfXlR9w==} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: + '@a2a-js/sdk@0.3.14(@grpc/grpc-js@1.14.4)(express@5.2.1)': + dependencies: + uuid: 11.1.1 + optionalDependencies: + '@grpc/grpc-js': 1.14.4 + express: 5.2.1 + '@ai-sdk/gateway@4.0.28(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.3 @@ -3019,6 +3795,35 @@ snapshots: '@ai-sdk/provider-utils': 5.0.12(zod@4.4.3) zod: 4.4.3 + '@ai-sdk/provider-utils@2.2.8(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 1.1.3 + nanoid: 3.3.16 + secure-json-parse: 2.7.0 + zod: 4.4.3 + + '@ai-sdk/provider-utils@3.0.30(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 2.0.3 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.1.0 + zod: 4.4.3 + + '@ai-sdk/provider-utils@4.0.40(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 3.0.14 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.1.0 + zod: 4.4.3 + + '@ai-sdk/provider-utils@5.0.11(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 4.0.3 + '@standard-schema/spec': 1.1.0 + '@workflow/serde': 4.1.0 + eventsource-parser: 3.1.0 + zod: 4.4.3 + '@ai-sdk/provider-utils@5.0.12(zod@4.4.3)': dependencies: '@ai-sdk/provider': 4.0.3 @@ -3027,10 +3832,29 @@ snapshots: eventsource-parser: 3.1.0 zod: 4.4.3 + '@ai-sdk/provider@1.1.3': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@2.0.3': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@3.0.14': + dependencies: + json-schema: 0.4.0 + '@ai-sdk/provider@4.0.3': dependencies: json-schema: 0.4.0 + '@ai-sdk/ui-utils@1.2.11(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@4.4.3) + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + '@babel/code-frame@7.29.7': dependencies: '@babel/helper-validator-identifier': 7.29.7 @@ -3558,6 +4382,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/ttlcache@2.1.5': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -3585,9 +4411,98 @@ snapshots: transitivePeerDependencies: - supports-color + '@lukeed/csprng@1.1.0': {} + + '@lukeed/uuid@2.0.1': + dependencies: + '@lukeed/csprng': 1.1.0 + + '@mastra/core@1.53.0(@grpc/grpc-js@1.14.4)(ai@7.0.37(zod@4.4.3))(express@5.2.1)(zod@4.4.3)': + dependencies: + '@a2a-js/sdk': 0.3.14(@grpc/grpc-js@1.14.4)(express@5.2.1) + '@ai-sdk/provider-utils-v5': '@ai-sdk/provider-utils@3.0.30(zod@4.4.3)' + '@ai-sdk/provider-utils-v6': '@ai-sdk/provider-utils@4.0.40(zod@4.4.3)' + '@ai-sdk/provider-utils-v7': '@ai-sdk/provider-utils@5.0.11(zod@4.4.3)' + '@ai-sdk/provider-v5': '@ai-sdk/provider@2.0.3' + '@ai-sdk/provider-v6': '@ai-sdk/provider@3.0.14' + '@ai-sdk/provider-v7': '@ai-sdk/provider@4.0.3' + '@ai-sdk/ui-utils-v5': '@ai-sdk/ui-utils@1.2.11(zod@4.4.3)' + '@isaacs/ttlcache': 2.1.5 + '@lukeed/uuid': 2.0.1 + '@mastra/schema-compat': 1.3.4(zod@4.4.3) + '@modelcontextprotocol/sdk': 1.30.0(zod@4.4.3) + '@sindresorhus/slugify': 2.2.1 + '@standard-schema/spec': 1.1.0 + ajv: 8.20.0 + chat: 4.35.0(ai@7.0.37(zod@4.4.3))(zod@4.4.3) + croner: 10.0.1 + dotenv: 17.4.2 + execa: 9.6.1 + fastq: 1.20.1 + gray-matter: 4.0.3 + ignore: 7.0.6 + jpeg-js: 0.4.4 + json-schema: 0.4.0 + lru-cache: 11.5.2 + p-map: 7.0.6 + p-retry: 7.1.1 + picomatch: 4.0.5 + posthog-node: 5.46.1 + tokenx: 1.6.0 + ws: 8.21.1 + xxhash-wasm: 1.1.0 + zod: 4.4.3 + transitivePeerDependencies: + - '@bufbuild/protobuf' + - '@cfworker/json-schema' + - '@grpc/grpc-js' + - ai + - bufferutil + - express + - rxjs + - supports-color + - utf-8-validate + - workflow + + '@mastra/schema-compat@1.3.4(zod@4.4.3)': + dependencies: + json-schema-to-zod: 2.8.1 + zod: 4.4.3 + zod-from-json-schema: 0.5.6 + zod-from-json-schema-v3: zod-from-json-schema@0.0.5 + zod-to-json-schema: 3.25.2(zod@4.4.3) + + '@modelcontextprotocol/sdk@1.30.0(zod@4.4.3)': + dependencies: + '@hono/node-server': 2.0.12(hono@4.12.32) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.6.1(express@5.2.1) + hono: 4.12.32 + jose: 6.2.4 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + '@pkgjs/parseargs@0.11.0': optional: true + '@posthog/core@1.45.1': + dependencies: + '@posthog/types': 1.398.0 + + '@posthog/types@1.398.0': {} + '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -3685,6 +4600,19 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.62.3': optional: true + '@sec-ant/readable-stream@0.4.1': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@sindresorhus/slugify@2.2.1': + dependencies: + '@sindresorhus/transliterate': 1.6.0 + escape-string-regexp: 5.0.0 + + '@sindresorhus/transliterate@1.6.0': + dependencies: + escape-string-regexp: 5.0.0 + '@standard-schema/spec@1.1.0': {} '@tanstack/history@1.162.0': {} @@ -3756,6 +4684,10 @@ snapshots: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + '@types/deep-eql@4.0.2': {} '@types/docker-modem@3.0.6': @@ -3773,6 +4705,12 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + '@types/node@18.19.130': dependencies: undici-types: 5.26.5 @@ -3808,6 +4746,8 @@ snapshots: dependencies: '@types/node': 18.19.130 + '@types/unist@3.0.3': {} + '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -3957,10 +4897,17 @@ snapshots: '@workflow/serde@4.1.0': {} + '@workflow/serde@4.1.0-beta.2': {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-jsx-walk@2.0.0: {} acorn-jsx@5.3.2(acorn@8.17.0): @@ -4038,6 +4985,10 @@ snapshots: - bare-buffer - react-native-b4a + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} asn1@0.2.6: @@ -4052,6 +5003,8 @@ snapshots: b4a@1.8.1: {} + bail@2.0.2: {} + balanced-match@1.0.2: {} balanced-match@4.0.4: {} @@ -4099,6 +5052,20 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + on-finished: 2.4.1 + qs: 6.15.3 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + brace-expansion@1.1.16: dependencies: balanced-match: 1.0.2 @@ -4144,12 +5111,26 @@ snapshots: byline@5.0.0: {} + bytes@3.1.2: {} + cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + callsites@3.1.0: {} caniuse-lite@1.0.30001806: {} + ccount@2.0.1: {} + chai@5.3.3: dependencies: assertion-error: 2.0.1 @@ -4163,6 +5144,23 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + character-entities@2.0.2: {} + + chat@4.35.0(ai@7.0.37(zod@4.4.3))(zod@4.4.3): + dependencies: + '@workflow/serde': 4.1.0-beta.2 + mdast-util-to-string: 4.0.0 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + remend: 1.3.0 + unified: 11.0.5 + optionalDependencies: + ai: 7.0.37(zod@4.4.3) + zod: 4.4.3 + transitivePeerDependencies: + - supports-color + check-error@2.1.3: {} chokidar@4.0.3: @@ -4203,12 +5201,27 @@ snapshots: consola@3.4.2: {} + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + convert-source-map@2.0.0: {} cookie-es@3.1.1: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cpu-features@0.0.10: dependencies: buildcheck: 0.0.7 @@ -4226,6 +5239,8 @@ snapshots: dependencies: luxon: 3.7.2 + croner@10.0.1: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -4238,10 +5253,16 @@ snapshots: dependencies: ms: 2.1.3 + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + deep-eql@5.0.2: {} deep-is@0.1.4: {} + depd@2.0.0: {} + dependency-cruiser@16.10.4: dependencies: acorn: 8.17.0 @@ -4267,6 +5288,12 @@ snapshots: tsconfig-paths-webpack-plugin: 4.2.0 watskeburt: 4.2.3 + dequal@2.0.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + diagram-js@15.23.0: dependencies: '@bpmn-io/diagram-js-ui': 0.2.4 @@ -4309,6 +5336,8 @@ snapshots: domify@3.0.0: {} + dotenv@17.4.2: {} + drizzle-kit@0.31.10: dependencies: '@drizzle-team/brocli': 0.10.2 @@ -4321,14 +5350,24 @@ snapshots: '@types/pg': 8.20.0 pg: 8.22.0 + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} + electron-to-chromium@1.5.396: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} + encodeurl@2.0.0: {} + end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -4338,10 +5377,16 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 + es-define-property@1.0.1: {} + es-errors@1.3.0: {} es-module-lexer@1.7.0: {} + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + esbuild@0.18.20: optionalDependencies: '@esbuild/android-arm': 0.18.20 @@ -4456,8 +5501,12 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -4514,6 +5563,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.17.0) eslint-visitor-keys: 4.2.1 + esprima@4.0.1: {} + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -4530,6 +5581,8 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + event-target-shim@5.0.1: {} events-universal@1.0.1: @@ -4542,8 +5595,74 @@ snapshots: eventsource-parser@3.1.0: {} + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.0 + + execa@9.6.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.2.0 + expect-type@1.4.0: {} + express-rate-limit@8.6.1(express@5.2.1): + dependencies: + debug: 4.4.3 + express: 5.2.1 + ip-address: 10.3.1 + transitivePeerDependencies: + - supports-color + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.3 + range-parser: 1.3.0 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend@3.0.2: {} + fast-deep-equal@3.1.3: {} fast-fifo@1.3.2: {} @@ -4554,14 +5673,33 @@ snapshots: fast-uri@3.1.4: {} + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: picomatch: 4.0.5 + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -4585,6 +5723,10 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + forwarded@0.2.0: {} + + fresh@2.0.0: {} + fs-constants@1.0.0: {} fsevents@2.3.3: @@ -4596,8 +5738,31 @@ snapshots: get-caller-file@2.0.5: {} + 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.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + get-port@5.1.1: {} + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -4623,10 +5788,21 @@ snapshots: globals@16.5.0: {} + gopd@1.2.0: {} + graceful-fs@4.2.11: {} + gray-matter@4.0.3: + dependencies: + js-yaml: 3.15.0 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + has-flag@4.0.0: {} + has-symbols@1.1.0: {} + hasown@2.0.4: dependencies: function-bind: 1.1.2 @@ -4635,6 +5811,20 @@ snapshots: htm@3.1.1: {} + 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 + + human-signals@8.0.1: {} + + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -4656,10 +5846,16 @@ snapshots: interpret@3.1.1: {} + ip-address@10.3.1: {} + + ipaddr.js@1.9.1: {} + is-core-module@2.16.2: dependencies: hasown: 2.0.4 + is-extendable@0.1.1: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -4673,10 +5869,20 @@ snapshots: global-directory: 4.0.1 is-path-inside: 4.0.0 + is-network-error@1.3.2: {} + is-path-inside@4.0.0: {} + is-plain-obj@4.1.0: {} + + is-promise@4.0.0: {} + is-stream@2.0.1: {} + is-stream@4.0.1: {} + + is-unicode-supported@2.1.0: {} + isarray@1.0.0: {} isbot@5.2.1: {} @@ -4689,12 +5895,21 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jose@6.2.4: {} + joycon@3.1.1: {} + jpeg-js@0.4.4: {} + js-tokens@4.0.0: {} js-tokens@9.0.1: {} + js-yaml@3.15.0: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + js-yaml@4.3.0: dependencies: argparse: 2.0.1 @@ -4703,10 +5918,14 @@ snapshots: json-buffer@3.0.1: {} + json-schema-to-zod@2.8.1: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -4717,6 +5936,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kind-of@6.0.3: {} + kleur@3.0.3: {} lazystream@1.0.1: @@ -4746,10 +5967,14 @@ snapshots: long@5.3.2: {} + longest-streak@3.1.0: {} + loupe@3.2.1: {} lru-cache@10.4.3: {} + lru-cache@11.5.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -4760,10 +5985,317 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + markdown-table@3.0.4: {} + + math-intrinsics@1.1.0: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + media-typer@1.1.1: {} + memoize@10.2.0: dependencies: mimic-function: 5.0.1 + merge-descriptors@2.0.0: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mimic-function@5.0.1: {} min-dash@5.1.0: {} @@ -4819,16 +6351,29 @@ snapshots: natural-compare@1.4.0: {} + negotiator@1.0.0: {} + node-releases@2.0.51: {} non-error@0.1.0: {} normalize-path@3.0.0: {} + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + object-assign@4.1.1: {} + object-inspect@1.13.4: {} + object-refs@0.4.0: {} + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -4850,18 +6395,30 @@ snapshots: dependencies: p-limit: 3.1.0 + p-map@7.0.6: {} + + p-retry@7.1.1: + dependencies: + is-network-error: 1.3.2 + package-json-from-dist@1.0.1: {} parent-module@1.0.1: dependencies: callsites: 3.1.0 + parse-ms@4.0.0: {} + + parseurl@1.3.3: {} + path-exists@4.0.0: {} path-intersection@4.1.0: {} path-key@3.1.1: {} + path-key@4.0.0: {} + path-parse@1.0.7: {} path-scurry@1.11.1: @@ -4869,6 +6426,8 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.3 + path-to-regexp@8.4.2: {} + pathe@2.0.3: {} pathval@2.0.1: {} @@ -4922,6 +6481,8 @@ snapshots: pirates@4.0.7: {} + pkce-challenge@5.0.1: {} + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -4952,10 +6513,18 @@ snapshots: dependencies: xtend: 4.0.2 + posthog-node@5.46.1: + dependencies: + '@posthog/core': 1.45.1 + preact@10.29.7: {} prelude-ls@1.2.1: {} + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + process-nextick-args@2.0.1: {} process@0.11.10: {} @@ -4992,6 +6561,11 @@ snapshots: '@types/node': 22.20.1 long: 5.3.2 + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -4999,6 +6573,20 @@ snapshots: punycode@2.3.1: {} + qs@6.15.3: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + + range-parser@1.3.0: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + react-dom@19.2.8(react@19.2.8): dependencies: react: 19.2.8 @@ -5044,6 +6632,34 @@ snapshots: regexp-tree@0.1.27: {} + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + remend@1.3.0: {} + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -5063,6 +6679,8 @@ snapshots: retry@0.12.0: {} + reusify@1.1.0: {} + rollup@4.62.3: dependencies: '@types/estree': 1.0.9 @@ -5094,6 +6712,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.62.3 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -5106,10 +6734,33 @@ snapshots: scheduler@0.27.0: {} + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + + secure-json-parse@2.7.0: {} + semver@6.3.1: {} semver@7.8.5: {} + 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.3.0 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + serialize-error@13.0.1: dependencies: non-error: 0.1.0 @@ -5121,12 +6772,51 @@ snapshots: seroval@1.5.6: {} + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} signal-exit@3.0.7: {} @@ -5150,6 +6840,8 @@ snapshots: split2@4.2.0: {} + sprintf-js@1.0.3: {} + ssh-remote-port-forward@1.0.4: dependencies: '@types/ssh2': 0.5.52 @@ -5165,6 +6857,8 @@ snapshots: stackback@0.0.2: {} + statuses@2.0.2: {} + std-env@3.10.0: {} streamx@2.28.0: @@ -5204,8 +6898,12 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-bom-string@1.0.0: {} + strip-bom@3.0.0: {} + strip-final-newline@4.0.0: {} + strip-json-comments@3.1.1: {} strip-literal@3.1.0: @@ -5335,8 +7033,14 @@ snapshots: tmp@0.2.7: {} + toidentifier@1.0.1: {} + + tokenx@1.6.0: {} + tree-kill@1.2.2: {} + trough@2.2.0: {} + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -5400,6 +7104,12 @@ snapshots: dependencies: tagged-tag: 1.0.0 + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.1 + mime-types: 3.0.2 + typescript-eslint@8.65.0(eslint@9.39.5)(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3) @@ -5421,6 +7131,39 @@ snapshots: undici@8.9.0: {} + unicorn-magic@0.3.0: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unpipe@1.0.0: {} + update-browserslist-db@1.2.3(browserslist@4.28.7): dependencies: browserslist: 4.28.7 @@ -5437,6 +7180,20 @@ snapshots: util-deprecate@1.0.2: {} + uuid@11.1.1: {} + + vary@1.1.2: {} + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + vite-node@3.2.4(@types/node@22.20.1)(tsx@4.23.1)(yaml@2.9.0): dependencies: cac: 6.7.14 @@ -5472,7 +7229,7 @@ snapshots: tsx: 4.23.1 yaml: 2.9.0 - vitest@3.2.7(@types/node@22.20.1)(tsx@4.23.1)(yaml@2.9.0): + vitest@3.2.7(@types/debug@4.1.13)(@types/node@22.20.1)(tsx@4.23.1)(yaml@2.9.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.7 @@ -5498,6 +7255,7 @@ snapshots: vite-node: 3.2.4(@types/node@22.20.1)(tsx@4.23.1)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: + '@types/debug': 4.1.13 '@types/node': 22.20.1 transitivePeerDependencies: - jiti @@ -5540,8 +7298,12 @@ snapshots: wrappy@1.0.2: {} + ws@8.21.1: {} + xtend@4.0.2: {} + xxhash-wasm@1.1.0: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -5562,10 +7324,28 @@ snapshots: yocto-queue@0.1.0: {} + yoctocolors@2.2.0: {} + zip-stream@6.0.1: dependencies: archiver-utils: 5.0.2 compress-commons: 6.0.2 readable-stream: 4.7.0 + zod-from-json-schema@0.0.5: + dependencies: + zod: 3.25.76 + + zod-from-json-schema@0.5.6: + dependencies: + zod: 4.4.3 + + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@3.25.76: {} + zod@4.4.3: {} + + zwitch@2.0.4: {} diff --git a/spike/mastra-reopen/package.json b/spike/mastra-reopen/package.json new file mode 100644 index 0000000..2caa9ea --- /dev/null +++ b/spike/mastra-reopen/package.json @@ -0,0 +1,21 @@ +{ + "name": "spike-mastra-reopen", + "private": true, + "version": "0.0.0", + "type": "module", + "description": "隔离验证原型:回边 reopen 在 Mastra workflow 里怎么表达。不属于主 workspace。", + "scripts": { + "route-a": "tsx src/route-a-dowhile.ts", + "route-b": "tsx src/route-b-external.ts", + "probe": "tsx src/probe.ts" + }, + "dependencies": { + "@mastra/core": "latest", + "zod": "^3.25.0" + }, + "devDependencies": { + "tsx": "^4.19.2", + "typescript": "^5.9.3", + "@types/node": "^22.10.2" + } +} diff --git a/spike/mastra-reopen/pnpm-lock.yaml b/spike/mastra-reopen/pnpm-lock.yaml new file mode 100644 index 0000000..8cdd09e --- /dev/null +++ b/spike/mastra-reopen/pnpm-lock.yaml @@ -0,0 +1,2333 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@mastra/core': + specifier: latest + version: 1.53.0(express@5.2.1)(zod@3.25.76) + zod: + specifier: ^3.25.0 + version: 3.25.76 + devDependencies: + '@types/node': + specifier: ^22.10.2 + version: 22.20.1 + tsx: + specifier: ^4.19.2 + version: 4.23.1 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +packages: + + '@a2a-js/sdk@0.3.14': + resolution: {integrity: sha512-F6Ew1AtPzCLhTn8h9yiqTe7DiDf6XVrSnq9V1YqSl9eWqPm6anMveTiKdCSb/76cW0YiJc24rNaUrVezFFHbqQ==} + engines: {node: '>=18'} + peerDependencies: + '@bufbuild/protobuf': ^2.10.2 + '@grpc/grpc-js': ^1.11.0 + express: ^4.21.2 || ^5.1.0 + peerDependenciesMeta: + '@bufbuild/protobuf': + optional: true + '@grpc/grpc-js': + optional: true + express: + optional: true + + '@ai-sdk/provider-utils@2.2.8': + resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + + '@ai-sdk/provider-utils@3.0.30': + resolution: {integrity: sha512-NCJ9JKow5ENAgEZxzvEvF20thwDiH+hutvzmrUDbloRX0azpJHNst8+7pZIVryYhLM9wgpT5/ShTSjPTFhkxEQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@4.0.40': + resolution: {integrity: sha512-OL5IrpUm9Y8Dwy+w/vvFwPotS6m52O9W0op2oXgXdCROMJIBalBI0oro6OIBYkPxvm5Xg02GSkoQN25RlR0bnw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@5.0.11': + resolution: {integrity: sha512-7/96wE+ZsKB35iS9ASyllrE4Ym/EolXEB7AkuJ5FI++fmS85BVTAs77890C+1Z2jwHfBKjBQSBmsliOsAh0iFQ==} + engines: {node: '>=22'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider@1.1.3': + resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} + engines: {node: '>=18'} + + '@ai-sdk/provider@2.0.3': + resolution: {integrity: sha512-h88OPkavHTiN9tMn2l5awAznGB0lXzjcLhgR1/rvjB2zlLprsNxbM2tt6OJsHUxduLC3klq0/eqaSf6fX5XVww==} + engines: {node: '>=18'} + + '@ai-sdk/provider@3.0.14': + resolution: {integrity: sha512-5X1k57JBJ4H7H1QjX7CnJYAB1I19r/trVZTMcSms7/kLNZ8RaU4Nt2agcwZzv82Hfx6Q7/TOLU7agAKeFfc8cA==} + engines: {node: '>=18'} + + '@ai-sdk/provider@4.0.3': + resolution: {integrity: sha512-e0CpNWJUY7OxAFAnCZkw+ri9QOHWwTs1tXP42782KFGCU07qt8NiXCrCVowyCB5dP2r5/Uls+g2oPd8kOJn9dw==} + engines: {node: '>=22'} + + '@ai-sdk/ui-utils@1.2.11': + resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@hono/node-server@2.0.12': + resolution: {integrity: sha512-eWpQYr67tqJLeaSUl0Q+TquuYfUdTibpOJlUMV2FfUP7+KqCC5TufnwnlXL6mobZBJbGAYRd7ZvEBDCbLInjhg==} + engines: {node: '>=20'} + peerDependencies: + hono: ^4 + + '@isaacs/ttlcache@2.1.5': + resolution: {integrity: sha512-VwGZqqjAWPICTmxUZnbpEfO60LhPWzquik+bmyXGY7pYRn6diEvCI5i6Ca+J6o2y4vS73HrpuMTo2dOvUevH8w==} + engines: {node: '>=12'} + + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + + '@lukeed/uuid@2.0.1': + resolution: {integrity: sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==} + engines: {node: '>=8'} + + '@mastra/core@1.53.0': + resolution: {integrity: sha512-Q9dIpdGiCAAyX2dVSVIg5BRShsHPR17MsvEwowRf9IQyfw3DyP/h7UJEJ1vcY6cLjGm+AqLqRbof97TihW1WUA==} + engines: {node: '>=22.13.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + '@mastra/schema-compat@1.3.4': + resolution: {integrity: sha512-2ObUsd21KIVelQy+eKPxJvnMxtmKnWacsIkZovhEYjVcQX9OYTDQ+u4E4RboIJZvurJnFx++/ujQLFznUaEYMg==} + engines: {node: '>=22.13.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + '@modelcontextprotocol/sdk@1.30.0': + resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@posthog/core@1.45.1': + resolution: {integrity: sha512-tLtvzomavb2PPWdGYKsusyIzIeL2Px47v348Smibkay7sMy/83TyPk+Ptsp2NdeOgJsbuwSxWkR2+XA0aSCAaA==} + + '@posthog/types@1.398.0': + resolution: {integrity: sha512-sJMkl4k+u8yS/0fjHsKqE9xTdsAh30a2WvgChiptellnVoE0e8QJKFgqOMD2sk8FaEArPdeFklAhXvmENAt3Sg==} + + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@sindresorhus/slugify@2.2.1': + resolution: {integrity: sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==} + engines: {node: '>=12'} + + '@sindresorhus/transliterate@1.6.0': + resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==} + engines: {node: '>=12'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@22.20.1': + resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@workflow/serde@4.1.0': + resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} + + '@workflow/serde@4.1.0-beta.2': + resolution: {integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + chat@4.35.0: + resolution: {integrity: sha512-IUbdgTBvgs/XYhKcpKGrpmZgcl8KcA5NZ+eOww+0rBdhPf+95INjcUauQTk5e48UI1V4PRg9stToPsT4vle07g==} + engines: {node: '>=20'} + peerDependencies: + ai: ^6.0.182 || ^7.0.0 + workflow: ^5.0.0-beta.35 + zod: ^3.0.0 || ^4.0.0 + peerDependenciesMeta: + ai: + optional: true + workflow: + optional: true + zod: + optional: true + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + croner@10.0.1: + resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==} + engines: {node: '>=18.0'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.1.0: + resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} + engines: {node: ^18.19.0 || >=20.5.0} + + express-rate-limit@8.6.1: + resolution: {integrity: sha512-0D493aP61w0TJ2A0wy27riRsO7FMQ7FK+KUHOKCSfPvYo0R55aiC6emCVgFUeShH0fq0ICPVzNcgoS+BsbXQCA==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.4: + resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hono@4.12.32: + resolution: {integrity: sha512-XcuyW9qE2kJn07PkecMOBd5Vq/hMy7mmGw+idz1yblbg9N17ijJODrvPkn7/dwL3Kulj8LcRJ69DLOWf91dRUg==} + engines: {node: '>=16.9.0'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} + engines: {node: '>=18.18.0'} + + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} + engines: {node: '>= 4'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ip-address@10.3.1: + resolution: {integrity: sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-network-error@1.3.2: + resolution: {integrity: sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==} + engines: {node: '>=16'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jose@6.2.4: + resolution: {integrity: sha512-N8acGzVsQy6M/fjFcxtysNc4Q379TcM5dM/qKkNtsHFji88yANnXTr7BLeP75iPnFwBfQzM/jg2BZ9+HZrHCZA==} + + jpeg-js@0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + + js-yaml@3.15.0: + resolution: {integrity: sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==} + hasBin: true + + json-schema-to-zod@2.8.1: + resolution: {integrity: sha512-fRr1mHgZ7hboLKBUdR428gd9dIHUFGivUqOeiDcSmyXkNZCtB1uGaZLvsjZ4GaN5pwBIs+TGIOf6s+Rp5/R/zA==} + hasBin: true + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + p-map@7.0.6: + resolution: {integrity: sha512-I4Prw6ivkd6p8PiYR1tXASOAOBzIJwu0TB7fqaX0c/8c3QAehNYmX57EijyGGGBt3c/BIowGwV03RVBtXvHEVg==} + engines: {node: '>=18'} + + p-retry@7.1.1: + resolution: {integrity: sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==} + engines: {node: '>=20'} + + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + posthog-node@5.46.1: + resolution: {integrity: sha512-WjCqExq44pBdyg9MSsH6UAE0tNZ88p4aIuVFicgqhjf2Fbws6IhS4ioYUa4aBrbUPS9EDRXtBTtF5DpP1ml8Pw==} + engines: {node: ^20.20.0 || >=22.22.0} + peerDependencies: + rxjs: ^7.0.0 + peerDependenciesMeta: + rxjs: + optional: true + + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} + engines: {node: '>=0.6'} + + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + remend@1.3.0: + resolution: {integrity: sha512-iIhggPkhW3hFImKtB10w0dz4EZbs28mV/dmbcYVonWEJ6UGHHpP+bFZnTh6GNWJONg5m+U56JrL+8IxZRdgWjw==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tokenx@1.6.0: + resolution: {integrity: sha512-CKTjk345ajvBAUp5xUI9a5KKN0zU0lBueVHQbCskH1Hp6WkUKsPW2qGCYNs0pxNyfzxfo+IIjdt2W4sMbw/qBw==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + tsx@4.23.1: + resolution: {integrity: sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} + hasBin: true + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.21.1: + resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + + yoctocolors@2.2.0: + resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==} + engines: {node: '>=18'} + + zod-from-json-schema@0.0.5: + resolution: {integrity: sha512-zYEoo86M1qpA1Pq6329oSyHLS785z/mTwfr9V1Xf/ZLhuuBGaMlDGu/pDVGVUe4H4oa1EFgWZT53DP0U3oT9CQ==} + + zod-from-json-schema@0.5.6: + resolution: {integrity: sha512-U33AJ7ZWS6y9XNSzMWcdy8hRAvZmWhTtpYJu0SXPT5AArbc9nq2ur7Magzmn5RF9KBV4b3FP0nCpmqqlfXlR9w==} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@a2a-js/sdk@0.3.14(express@5.2.1)': + dependencies: + uuid: 11.1.1 + optionalDependencies: + express: 5.2.1 + + '@ai-sdk/provider-utils@2.2.8(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 1.1.3 + nanoid: 3.3.16 + secure-json-parse: 2.7.0 + zod: 3.25.76 + + '@ai-sdk/provider-utils@3.0.30(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.3 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.1.0 + zod: 3.25.76 + + '@ai-sdk/provider-utils@4.0.40(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.14 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.1.0 + zod: 3.25.76 + + '@ai-sdk/provider-utils@5.0.11(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 4.0.3 + '@standard-schema/spec': 1.1.0 + '@workflow/serde': 4.1.0 + eventsource-parser: 3.1.0 + zod: 3.25.76 + + '@ai-sdk/provider@1.1.3': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@2.0.3': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@3.0.14': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@4.0.3': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/ui-utils@1.2.11(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + + '@esbuild/aix-ppc64@0.28.1': + optional: true + + '@esbuild/android-arm64@0.28.1': + optional: true + + '@esbuild/android-arm@0.28.1': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.28.1': + optional: true + + '@esbuild/darwin-x64@0.28.1': + optional: true + + '@esbuild/freebsd-arm64@0.28.1': + optional: true + + '@esbuild/freebsd-x64@0.28.1': + optional: true + + '@esbuild/linux-arm64@0.28.1': + optional: true + + '@esbuild/linux-arm@0.28.1': + optional: true + + '@esbuild/linux-ia32@0.28.1': + optional: true + + '@esbuild/linux-loong64@0.28.1': + optional: true + + '@esbuild/linux-mips64el@0.28.1': + optional: true + + '@esbuild/linux-ppc64@0.28.1': + optional: true + + '@esbuild/linux-riscv64@0.28.1': + optional: true + + '@esbuild/linux-s390x@0.28.1': + optional: true + + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + + '@hono/node-server@2.0.12(hono@4.12.32)': + dependencies: + hono: 4.12.32 + + '@isaacs/ttlcache@2.1.5': {} + + '@lukeed/csprng@1.1.0': {} + + '@lukeed/uuid@2.0.1': + dependencies: + '@lukeed/csprng': 1.1.0 + + '@mastra/core@1.53.0(express@5.2.1)(zod@3.25.76)': + dependencies: + '@a2a-js/sdk': 0.3.14(express@5.2.1) + '@ai-sdk/provider-utils-v5': '@ai-sdk/provider-utils@3.0.30(zod@3.25.76)' + '@ai-sdk/provider-utils-v6': '@ai-sdk/provider-utils@4.0.40(zod@3.25.76)' + '@ai-sdk/provider-utils-v7': '@ai-sdk/provider-utils@5.0.11(zod@3.25.76)' + '@ai-sdk/provider-v5': '@ai-sdk/provider@2.0.3' + '@ai-sdk/provider-v6': '@ai-sdk/provider@3.0.14' + '@ai-sdk/provider-v7': '@ai-sdk/provider@4.0.3' + '@ai-sdk/ui-utils-v5': '@ai-sdk/ui-utils@1.2.11(zod@3.25.76)' + '@isaacs/ttlcache': 2.1.5 + '@lukeed/uuid': 2.0.1 + '@mastra/schema-compat': 1.3.4(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.30.0(zod@3.25.76) + '@sindresorhus/slugify': 2.2.1 + '@standard-schema/spec': 1.1.0 + ajv: 8.20.0 + chat: 4.35.0(zod@3.25.76) + croner: 10.0.1 + dotenv: 17.4.2 + execa: 9.6.1 + fastq: 1.20.1 + gray-matter: 4.0.3 + ignore: 7.0.6 + jpeg-js: 0.4.4 + json-schema: 0.4.0 + lru-cache: 11.5.2 + p-map: 7.0.6 + p-retry: 7.1.1 + picomatch: 4.0.5 + posthog-node: 5.46.1 + tokenx: 1.6.0 + ws: 8.21.1 + xxhash-wasm: 1.1.0 + zod: 3.25.76 + transitivePeerDependencies: + - '@bufbuild/protobuf' + - '@cfworker/json-schema' + - '@grpc/grpc-js' + - ai + - bufferutil + - express + - rxjs + - supports-color + - utf-8-validate + - workflow + + '@mastra/schema-compat@1.3.4(zod@3.25.76)': + dependencies: + json-schema-to-zod: 2.8.1 + zod: 3.25.76 + zod-from-json-schema: 0.5.6 + zod-from-json-schema-v3: zod-from-json-schema@0.0.5 + zod-to-json-schema: 3.25.2(zod@3.25.76) + + '@modelcontextprotocol/sdk@1.30.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 2.0.12(hono@4.12.32) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.6.1(express@5.2.1) + hono: 4.12.32 + jose: 6.2.4 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@posthog/core@1.45.1': + dependencies: + '@posthog/types': 1.398.0 + + '@posthog/types@1.398.0': {} + + '@sec-ant/readable-stream@0.4.1': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@sindresorhus/slugify@2.2.1': + dependencies: + '@sindresorhus/transliterate': 1.6.0 + escape-string-regexp: 5.0.0 + + '@sindresorhus/transliterate@1.6.0': + dependencies: + escape-string-regexp: 5.0.0 + + '@standard-schema/spec@1.1.0': {} + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@22.20.1': + dependencies: + undici-types: 6.21.0 + + '@types/unist@3.0.3': {} + + '@workflow/serde@4.1.0': {} + + '@workflow/serde@4.1.0-beta.2': {} + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.4 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + bail@2.0.2: {} + + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + on-finished: 2.4.1 + qs: 6.15.3 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + ccount@2.0.1: {} + + character-entities@2.0.2: {} + + chat@4.35.0(zod@3.25.76): + dependencies: + '@workflow/serde': 4.1.0-beta.2 + mdast-util-to-string: 4.0.0 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + remend: 1.3.0 + unified: 11.0.5 + optionalDependencies: + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + croner@10.0.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + depd@2.0.0: {} + + dequal@2.0.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dotenv@17.4.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + + escape-html@1.0.3: {} + + escape-string-regexp@5.0.0: {} + + esprima@4.0.1: {} + + etag@1.8.1: {} + + eventsource-parser@3.1.0: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.0 + + execa@9.6.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.2.0 + + express-rate-limit@8.6.1(express@5.2.1): + dependencies: + debug: 4.4.3 + express: 5.2.1 + ip-address: 10.3.1 + transitivePeerDependencies: + - supports-color + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.3 + range-parser: 1.3.0 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.4: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + 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.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + + gopd@1.2.0: {} + + gray-matter@4.0.3: + dependencies: + js-yaml: 3.15.0 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + + has-symbols@1.1.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hono@4.12.32: {} + + 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 + + human-signals@8.0.1: {} + + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + + ignore@7.0.6: {} + + inherits@2.0.4: {} + + ip-address@10.3.1: {} + + ipaddr.js@1.9.1: {} + + is-extendable@0.1.1: {} + + is-network-error@1.3.2: {} + + is-plain-obj@4.1.0: {} + + is-promise@4.0.0: {} + + is-stream@4.0.1: {} + + is-unicode-supported@2.1.0: {} + + isexe@2.0.0: {} + + jose@6.2.4: {} + + jpeg-js@0.4.4: {} + + js-yaml@3.15.0: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + json-schema-to-zod@2.8.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + json-schema@0.4.0: {} + + kind-of@6.0.3: {} + + longest-streak@3.1.0: {} + + lru-cache@11.5.2: {} + + markdown-table@3.0.4: {} + + math-intrinsics@1.1.0: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + media-typer@1.1.1: {} + + merge-descriptors@2.0.0: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + ms@2.1.3: {} + + nanoid@3.3.16: {} + + negotiator@1.0.0: {} + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + p-map@7.0.6: {} + + p-retry@7.1.1: + dependencies: + is-network-error: 1.3.2 + + parse-ms@4.0.0: {} + + parseurl@1.3.3: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-to-regexp@8.4.2: {} + + picomatch@4.0.5: {} + + pkce-challenge@5.0.1: {} + + posthog-node@5.46.1: + dependencies: + '@posthog/core': 1.45.1 + + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + qs@6.15.3: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + + range-parser@1.3.0: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + remend@1.3.0: {} + + require-from-string@2.0.2: {} + + reusify@1.1.0: {} + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + safer-buffer@2.1.2: {} + + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + + secure-json-parse@2.7.0: {} + + 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.3.0 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@4.1.0: {} + + sprintf-js@1.0.3: {} + + statuses@2.0.2: {} + + strip-bom-string@1.0.0: {} + + strip-final-newline@4.0.0: {} + + toidentifier@1.0.1: {} + + tokenx@1.6.0: {} + + trough@2.2.0: {} + + tsx@4.23.1: + dependencies: + esbuild: 0.28.1 + optionalDependencies: + fsevents: 2.3.3 + + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.1 + mime-types: 3.0.2 + + typescript@5.9.3: {} + + undici-types@6.21.0: {} + + unicorn-magic@0.3.0: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unpipe@1.0.0: {} + + uuid@11.1.1: {} + + vary@1.1.2: {} + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrappy@1.0.2: {} + + ws@8.21.1: {} + + xxhash-wasm@1.1.0: {} + + yoctocolors@2.2.0: {} + + zod-from-json-schema@0.0.5: + dependencies: + zod: 3.25.76 + + zod-from-json-schema@0.5.6: + dependencies: + zod: 4.4.3 + + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} + + zod@4.4.3: {} + + zwitch@2.0.4: {} diff --git a/spike/mastra-reopen/src/ledger.ts b/spike/mastra-reopen/src/ledger.ts new file mode 100644 index 0000000..694f1d6 --- /dev/null +++ b/spike/mastra-reopen/src/ledger.ts @@ -0,0 +1,110 @@ +/** + * 模拟主工程的“实例/任务”台账。 + * + * 主工程语义:回边 reopen = 回到 A4 **重开一个新实例**(新 instance 号、新任务 ID, + * 旧实例留痕不动)。这里用一个进程内表来记账,用来验证「哪条路线能自然地拿到新实例号」。 + */ + +export type NodeId = 'A4' | 'A5' | 'A6'; + +export type InstanceRow = { + /** 实例号:同一节点上单调递增,A4#1 / A4#2 ... */ + instanceNo: number; + nodeId: NodeId; + /** 任务 ID:每个实例一个,全局唯一 */ + taskId: string; + /** 哪个 run 起的它(路线 B 会出现多个 runId) */ + runId: string; + /** 哪一轮循环起的它(路线 A 才有意义) */ + iteration: number; + /** 由哪条边重开(E10 / E12);首开为 null */ + reopenedBy: string | null; + status: 'open' | 'closed'; + outcome?: string; + openedAt: number; + closedAt?: number; +}; + +export class Ledger { + readonly rows: InstanceRow[] = []; + private seq = 0; + + openInstance(args: { + nodeId: NodeId; + runId: string; + iteration: number; + reopenedBy?: string | null; + }): InstanceRow { + const instanceNo = this.rows.filter((r) => r.nodeId === args.nodeId).length + 1; + const row: InstanceRow = { + instanceNo, + nodeId: args.nodeId, + taskId: `T-${args.nodeId}-${String(++this.seq).padStart(3, '0')}`, + runId: args.runId, + iteration: args.iteration, + reopenedBy: args.reopenedBy ?? null, + status: 'open', + openedAt: Date.now(), + }; + this.rows.push(row); + return row; + } + + closeTask(taskId: string, outcome: string): InstanceRow { + const row = this.rows.find((r) => r.taskId === taskId); + if (!row) throw new Error(`ledger: unknown taskId ${taskId}`); + row.status = 'closed'; + row.outcome = outcome; + row.closedAt = Date.now(); + return row; + } + + dump(title: string): void { + console.log(`\n ── 台账 ${title} ──`); + console.log( + ' ' + + ['节点', '实例', '任务ID', '轮次', '重开自', '状态', '结论', 'runId'].join('\t'), + ); + for (const r of this.rows) { + console.log( + ' ' + + [ + r.nodeId, + `#${r.instanceNo}`, + r.taskId, + `it=${r.iteration}`, + r.reopenedBy ?? '-', + r.status, + r.outcome ?? '-', + r.runId.slice(0, 8), + ].join('\t'), + ); + } + } +} + +/** 外部注入的“决策脚本”:模拟人在另一个调用链里点了按钮 */ +export type Decision = + | { node: 'A4'; price: number } + | { node: 'A5'; verdict: 'pass' | 'reject' } + | { node: 'A6'; outcome: 'won' | 'revise' }; + +export class DecisionScript { + private i = 0; + constructor(private readonly script: Decision[]) {} + next(expectNode: NodeId): Decision { + const d = this.script[this.i++]; + if (!d) throw new Error(`decision script exhausted at ${expectNode}`); + if (d.node !== expectNode) { + throw new Error(`decision script mismatch: expect ${expectNode}, got ${d.node}`); + } + return d; + } + get consumed(): number { + return this.i; + } +} + +export const log = (...args: unknown[]): void => console.log(...args); +export const banner = (s: string): void => + console.log(`\n${'='.repeat(78)}\n${s}\n${'='.repeat(78)}`); diff --git a/spike/mastra-reopen/src/probe-00-smoke.ts b/spike/mastra-reopen/src/probe-00-smoke.ts new file mode 100644 index 0000000..8958487 --- /dev/null +++ b/spike/mastra-reopen/src/probe-00-smoke.ts @@ -0,0 +1,46 @@ +/** 冒烟:确认 createWorkflow / suspend / resume / InMemoryStore 这套 API 在 1.53 上能跑 */ +import { Mastra } from '@mastra/core'; +import { InMemoryStore } from '@mastra/core/storage'; +import { createStep, createWorkflow, createWorkflowStateReader } from '@mastra/core/workflows'; +import { z } from 'zod'; + +const ask = createStep({ + id: 'ask', + inputSchema: z.object({ q: z.string() }), + outputSchema: z.object({ a: z.string() }), + resumeSchema: z.object({ a: z.string() }), + suspendSchema: z.object({ taskId: z.string() }), + execute: async ({ inputData, resumeData, suspend }) => { + console.log('[ask.execute] inputData=', inputData, 'resumeData=', resumeData); + if (!resumeData) return await suspend({ taskId: 'T-1' }, { resumeLabel: 'ask' }); + return { a: resumeData.a }; + }, +}); + +const wf = createWorkflow({ + id: 'smoke', + inputSchema: z.object({ q: z.string() }), + outputSchema: z.object({ a: z.string() }), +}) + .then(ask) + .commit(); + +const mastra = new Mastra({ + workflows: { smoke: wf }, + storage: new InMemoryStore(), + logger: false, +}); + +const run = await mastra.getWorkflow('smoke').createRun(); +const r1 = await run.start({ inputData: { q: 'hi' } }); +console.log('r1.status =', r1.status); +console.log('r1 =', JSON.stringify(r1, null, 2).slice(0, 1200)); + +const state = await mastra.getWorkflow('smoke').getWorkflowRunById(run.runId); +console.log('state.status =', state?.status); +const reader = createWorkflowStateReader(state!); +console.log('suspendedStep =', JSON.stringify(reader.getSuspendedStep(), null, 2)); +console.log('resumeLabels =', JSON.stringify(reader.getResumeLabels(), null, 2)); + +const r2 = await run.resume({ step: 'ask', resumeData: { a: '42' } }); +console.log('r2.status =', r2.status, 'result =', (r2 as { result?: unknown }).result); diff --git a/spike/mastra-reopen/src/probe-01-route-a-snapshot.ts b/spike/mastra-reopen/src/probe-01-route-a-snapshot.ts new file mode 100644 index 0000000..fa14864 --- /dev/null +++ b/spike/mastra-reopen/src/probe-01-route-a-snapshot.ts @@ -0,0 +1,131 @@ +/** + * 路线 A 深挖: + * a) 快照(WorkflowRunState)里循环轮次到底怎么表示? + * b) resume 能不能定位「第几轮的那个 step」?(label / forEachIndex / path) + * c) 重复 resume、跨轮 resume、run 结束后 resume 会怎样? + * + * 运行:SPIKE_NO_AUTORUN=1 tsx src/probe-01-route-a-snapshot.ts + */ +import { createWorkflowStateReader } from '@mastra/core/workflows'; +import { DecisionScript, Ledger, banner } from './ledger.js'; +import { mastraA, storeA, _internals } from './route-a-dowhile.js'; +import { resetTrace, t } from './trace.js'; + +_internals.setLedger(new Ledger()); +_internals.setScript(new DecisionScript([])); +resetTrace(); + +const wf = mastraA.getWorkflow('routeA'); +const rawSnap = async (runId: string) => + (await (storeA as any).stores.workflows.loadWorkflowSnapshot({ + workflowName: 'route-a', + runId, + })) as Record | null; + +banner('探针 A-1:跑到「第 2 轮 A4 挂起」,看快照'); + +const run = await wf.createRun(); +console.log('runId =', run.runId); + +let res = await run.start({ inputData: { quoteId: 'Q-probe' } }); +console.log('after start: status =', res.status); + +// 第 1 轮 A4 +res = await run.resume({ step: ['round-body', 'A4'], resumeData: { price: 100 } }); +// 第 1 轮 A5 → reject → 触发回边 E10 → 第 2 轮开始,A4 再次挂起 +res = await run.resume({ step: ['round-body', 'A5'], resumeData: { verdict: 'reject' } }); +console.log('after A5(reject): status =', res.status, 'suspended =', JSON.stringify((res as any).suspended)); + +const s2 = await rawSnap(run.runId); +console.log('\n── 原始快照 WorkflowRunState 的顶层键 ──'); +console.log(Object.keys(s2 ?? {})); +console.log('\nvalue =', JSON.stringify(s2?.value)); +console.log('activePaths =', JSON.stringify(s2?.activePaths)); +console.log('activeStepsPath=', JSON.stringify(s2?.activeStepsPath)); +console.log('suspendedPaths =', JSON.stringify(s2?.suspendedPaths)); +console.log('resumeLabels =', JSON.stringify(s2?.resumeLabels)); +console.log('stepExecutionPath =', JSON.stringify(s2?.stepExecutionPath)); +console.log('\ncontext 的键(= 快照里保存了哪些 step 的结果):'); +console.log(JSON.stringify(Object.keys(s2?.context ?? {}), null, 0)); +console.log('\ncontext["round-body.A4"] ='); +console.log(JSON.stringify(s2?.context?.['round-body.A4'], null, 2)); +console.log('\ncontext["round-body.A5"] ='); +console.log(JSON.stringify(s2?.context?.['round-body.A5'], null, 2)); +console.log('\ncontext["round-body"] (循环体本身) ='); +console.log(JSON.stringify(s2?.context?.['round-body'], null, 2)); + +banner('探针 A-2:resume 能不能指名「第 1 轮的 A4」?'); + +// 现在挂起的是「第 2 轮的 A4」。第 1 轮 A4 的 resumeLabel 是 A4-round-1。 +const reader = createWorkflowStateReader((await wf.getWorkflowRunById(run.runId))!); +console.log('当前 resumeLabels =', JSON.stringify(reader.getResumeLabels())); +console.log('getResumeLabel("A4-round-1") =', JSON.stringify(reader.getResumeLabel('A4-round-1'))); +console.log('getResumeLabel("A4-round-2") =', JSON.stringify(reader.getResumeLabel('A4-round-2'))); + +try { + const r = await run.resume({ label: 'A4-round-1', resumeData: { price: 111 } }); + console.log('resume(label=A4-round-1) → status =', r.status); + console.log(' 报错?', JSON.stringify((r as any).error ?? null)); +} catch (e) { + console.log('resume(label=A4-round-1) 抛异常:', (e as Error).message); +} + +banner('探针 A-3:forEachIndex 对 dowhile 有用吗?'); +try { + const r = await run.resume({ + step: ['round-body', 'A4'], + resumeData: { price: 222 }, + forEachIndex: 0, + }); + console.log('resume(step=round-body.A4, forEachIndex=0) → status =', r.status); + console.log(' error =', JSON.stringify((r as any).error ?? null)); + const snap = await rawSnap(run.runId); + console.log( + ' 快照里 A4 的 output.price =', + JSON.stringify(snap?.context?.['round-body.A4']?.output?.price), + ); +} catch (e) { + console.log('resume(forEachIndex=0) 抛异常:', (e as Error).message); +} + +banner('探针 A-4:对「已经推进过的 step」重复 resume'); +try { + const r = await run.resume({ step: ['round-body', 'A4'], resumeData: { price: 333 } }); + console.log('重复 resume A4 → status =', r.status, 'error =', JSON.stringify((r as any).error ?? null)); +} catch (e) { + console.log('重复 resume A4 抛异常:', (e as Error).message); +} + +banner('探针 A-5:resume 一个「没有挂起」的 step'); +try { + const r = await run.resume({ step: ['round-body', 'A6-sub', 'A6'], resumeData: { outcome: 'won' } }); + console.log('resume 未挂起的 A6 → status =', r.status, 'error =', JSON.stringify((r as any).error ?? null)); +} catch (e) { + console.log('resume 未挂起的 A6 抛异常:', (e as Error).message); +} + +banner('探针 A-6:把这一单跑完,再看终态快照能否回溯轮次'); +let guard = 0; +let cur = await wf.getWorkflowRunById(run.runId); +while (cur?.status === 'suspended' && guard++ < 8) { + const rd = createWorkflowStateReader(cur); + const sus = rd.getSuspendedStep()!; + const nodeId = (sus.suspendPayload as { nodeId: string }).nodeId; + const data = + nodeId === 'A4' ? { price: 77 } : nodeId === 'A5' ? { verdict: 'pass' } : { outcome: 'won' }; + t('[probe]', `resume ${nodeId} @ ${JSON.stringify(sus.path)}`, data); + await run.resume({ step: sus.path, resumeData: data }); + cur = await wf.getWorkflowRunById(run.runId); +} +console.log('最终 status =', cur?.status, 'result =', JSON.stringify(cur?.result)); + +const fin = await rawSnap(run.runId); +console.log('\n终态快照 context 的键:', JSON.stringify(Object.keys(fin?.context ?? {}))); +console.log('终态 context["round-body.A4"].suspendPayload =', JSON.stringify(fin?.context?.['round-body.A4']?.suspendPayload)); +console.log('终态 context["round-body.A4"].output =', JSON.stringify(fin?.context?.['round-body.A4']?.output)); +console.log('终态 context["round-body.A4"] 是数组吗? ', Array.isArray(fin?.context?.['round-body.A4'])); +console.log('终态 stepExecutionPath =', JSON.stringify(fin?.stepExecutionPath)); +console.log('\n第 1 轮的 A4(taskId=T-A4-001, price=100)还在快照里吗?→', + JSON.stringify(fin?.context?.['round-body.A4']).includes('T-A4-001') ? '在' : '不在(被覆盖)'); +console.log('\n台账(我们自己记的)里第 1 轮还在吗?'); +_internals.getLedger().dump('probe'); diff --git a/spike/mastra-reopen/src/probe-02-route-a-pitfalls.ts b/spike/mastra-reopen/src/probe-02-route-a-pitfalls.ts new file mode 100644 index 0000000..8f6f2a3 --- /dev/null +++ b/spike/mastra-reopen/src/probe-02-route-a-pitfalls.ts @@ -0,0 +1,117 @@ +/** + * 路线 A 的坑(每个坑一个全新的 run,避免互相污染): + * 1. dowhile 循环体的嵌套快照存在哪?循环第 2 轮会不会覆盖第 1 轮? + * 2. forEachIndex 能不能定位 dowhile 的第 N 轮? + * 3. resume 打错 step(或任务回调重复到达)会怎样? + * + * 运行:SPIKE_NO_AUTORUN=1 tsx src/probe-02-route-a-pitfalls.ts + */ +import { createWorkflowStateReader } from '@mastra/core/workflows'; +import { DecisionScript, Ledger, banner } from './ledger.js'; +import { mastraA, storeA, _internals } from './route-a-dowhile.js'; +import { resetTrace } from './trace.js'; + +_internals.setLedger(new Ledger()); +_internals.setScript(new DecisionScript([])); +resetTrace(); + +const wf = mastraA.getWorkflow('routeA'); +const snapOf = async (workflowName: string, runId: string) => + (await (storeA as any).stores.workflows.loadWorkflowSnapshot({ workflowName, runId })) as + | Record + | null; + +/** 开一个 run 并推进到「第 2 轮 A4 挂起」 */ +async function toRound2() { + const run = await wf.createRun(); + await run.start({ inputData: { quoteId: 'Q-pit' } }); + await run.resume({ step: ['round-body', 'A4'], resumeData: { price: 100 } }); + await run.resume({ step: ['round-body', 'A5'], resumeData: { verdict: 'reject' } }); + return run; +} + +banner('坑 1:循环体(嵌套 workflow)的快照存在哪?第 2 轮会不会盖掉第 1 轮?'); +{ + const run = await toRound2(); + const outer = await snapOf('route-a', run.runId); + const inner = await snapOf('round-body', run.runId); + console.log('外层快照 context 键 =', JSON.stringify(Object.keys(outer?.context ?? {}))); + console.log('外层 context["round-body"].metadata =', JSON.stringify(outer?.context?.['round-body']?.metadata)); + console.log('\n内层(workflowName="round-body", 同一个 runId)快照存在吗?', !!inner); + console.log('内层 context 键 =', JSON.stringify(Object.keys(inner?.context ?? {}))); + console.log('内层 A4.suspendPayload =', JSON.stringify(inner?.context?.['A4']?.suspendPayload)); + console.log('内层 A4.output =', JSON.stringify(inner?.context?.['A4']?.output)); + console.log('内层 A5.output =', JSON.stringify(inner?.context?.['A5']?.output)); + console.log( + '\n判定:第 1 轮的 A4(taskId=T-A4-001 / price=100)还在内层快照里吗?→', + JSON.stringify(inner?.context?.['A4']).includes('T-A4-001') ? '在' : '不在(已被第 2 轮覆盖)', + ); + const runs = await wf.listWorkflowRuns(); + console.log('listWorkflowRuns() 里能看到几条?', runs.total, JSON.stringify(runs.runs.map((r: any) => `${r.workflowName}/${r.runId.slice(0, 8)}`))); +} + +banner('坑 2:forEachIndex 能不能定位 dowhile 的第 N 轮?(此刻第 2 轮 A4 正挂起)'); +{ + const run = await toRound2(); + for (const idx of [0, 1]) { + const fresh = await wf.createRun({ runId: `${run.runId}-x${idx}` }); + void fresh; // 只是为了不复用同一个 run + } + try { + const r = await run.resume({ + step: ['round-body', 'A4'], + resumeData: { price: 999 }, + forEachIndex: 0, + }); + console.log('resume(step=[round-body,A4], forEachIndex=0) → status =', r.status); + console.log(' error =', JSON.stringify((r as any).error ?? null)); + const inner = await snapOf('round-body', run.runId); + console.log(' 内层 A4.output.price =', JSON.stringify(inner?.context?.['A4']?.output?.price)); + console.log(' → forEachIndex 被忽略了(打进的是「当前正挂起的那一轮」)'); + } catch (e) { + console.log('抛异常:', (e as Error).message); + } +} + +banner('坑 3:resume 打错 step(= 旧任务的回调迟到)会怎样?'); +{ + const run = await toRound2(); + const st = await wf.getWorkflowRunById(run.runId); + console.log('resume 之前 status =', st?.status, '挂起的是', + JSON.stringify(createWorkflowStateReader(st!).getSuspendedStep()?.path)); + let r; + try { + r = await run.resume({ step: ['round-body', 'A5'], resumeData: { verdict: 'pass' } }); + console.log('resume(错的 step=A5) → status =', r.status); + console.log(' error =', JSON.stringify((r as any).error ?? null)); + } catch (e) { + console.log('resume(错的 step=A5) 抛异常:', (e as Error).message); + } + const after = await wf.getWorkflowRunById(run.runId); + console.log(' 之后整个 run 的 status =', after?.status, ' ← 注意:run 被打成 failed 了'); + try { + const r2 = await run.resume({ step: ['round-body', 'A4'], resumeData: { price: 1 } }); + console.log(' 再补一次正确的 resume → status =', r2.status); + } catch (e) { + console.log(' 再补一次正确的 resume 抛异常:', (e as Error).message, ' ← 这一单救不回来了'); + } +} + +banner('坑 4:同一个任务回调重复到达(重复 resume 同一个 step)'); +{ + const run = await toRound2(); + const r1 = await run.resume({ step: ['round-body', 'A4'], resumeData: { price: 50 } }); + console.log('第一次 resume A4 → status =', r1.status, '(此时应轮到 A5 挂起)'); + try { + const r2 = await run.resume({ step: ['round-body', 'A4'], resumeData: { price: 50 } }); + console.log('第二次 resume A4 → status =', r2.status, 'error =', JSON.stringify((r2 as any).error ?? null)); + } catch (e) { + console.log('第二次 resume A4 抛异常:', (e as Error).message); + } + const after = await wf.getWorkflowRunById(run.runId); + console.log('之后 run 的 status =', after?.status); +} + +banner('坑 5:dowhile 的循环体输入/输出必须同构吗?'); +console.log('见 route-a-dowhile.ts:循环体 round-body 的 inputSchema 与 outputSchema 都是 RoundState。'); +console.log('把 outputSchema 改成别的形状时,TS 报错(dowhile 的 TStepInputSchema extends TPrevSchema 约束)。'); diff --git a/spike/mastra-reopen/src/probe-03-loop-snapshot-detail.ts b/spike/mastra-reopen/src/probe-03-loop-snapshot-detail.ts new file mode 100644 index 0000000..474f32f --- /dev/null +++ b/spike/mastra-reopen/src/probe-03-loop-snapshot-detail.ts @@ -0,0 +1,57 @@ +/** + * 精确定位:dowhile 每一轮的 step 记录,在快照里是「追加」还是「覆盖/重置」? + * 运行:SPIKE_NO_AUTORUN=1 tsx src/probe-03-loop-snapshot-detail.ts + */ +import { DecisionScript, Ledger, banner } from './ledger.js'; +import { mastraA, storeA, _internals } from './route-a-dowhile.js'; +import { resetTrace } from './trace.js'; + +_internals.setLedger(new Ledger()); +_internals.setScript(new DecisionScript([])); +resetTrace(); + +const wf = mastraA.getWorkflow('routeA'); +const snapOf = async (workflowName: string, runId: string) => + (await (storeA as any).stores.workflows.loadWorkflowSnapshot({ workflowName, runId })) as + | Record + | null; + +const run = await wf.createRun(); +const inner = async () => await snapOf('round-body', run.runId); +const dumpInner = async (tag: string) => { + const s = await inner(); + console.log(`\n[${tag}] 内层快照 context 的键 = ${JSON.stringify(Object.keys(s?.context ?? {}))}`); + for (const k of ['A4', 'A5', 'A6-sub']) { + const rec = s?.context?.[k]; + if (!rec) continue; + console.log( + ` ${k}: status=${rec.status} suspendPayload.taskId=${rec.suspendPayload?.taskId} output.price=${rec.output?.price} output.verdict=${rec.output?.verdict}`, + ); + } +}; + +banner('第 1 轮'); +await run.start({ inputData: { quoteId: 'Q-detail' } }); +await dumpInner('第1轮 A4 挂起'); +await run.resume({ step: ['round-body', 'A4'], resumeData: { price: 100 } }); +await dumpInner('第1轮 A4 已推进,A5 挂起'); +await run.resume({ step: ['round-body', 'A5'], resumeData: { verdict: 'reject' } }); + +banner('第 2 轮(E10 回边重开 A4)'); +await dumpInner('第2轮 A4 挂起'); +console.log('\n→ 第 1 轮的 A5(verdict=reject)记录还在内层快照里吗?', + (await inner())?.context?.['A5'] ? '在' : '不在(嵌套快照按轮重置了)'); +console.log('→ 第 1 轮的 A4(taskId=T-A4-001, price=100)记录还在吗?'); +console.log(' 当前 A4 记录全文 =', JSON.stringify((await inner())?.context?.['A4'], null, 2)); + +banner('跑完这一单,看终态'); +await run.resume({ step: ['round-body', 'A4'], resumeData: { price: 90 } }); +await run.resume({ step: ['round-body', 'A5'], resumeData: { verdict: 'pass' } }); +const fin = await run.resume({ step: ['round-body', 'A6-sub', 'A6'], resumeData: { outcome: 'won' } }); +console.log('最终 status =', fin.status, JSON.stringify((fin as any).result)); +await dumpInner('终态'); +const outer = await snapOf('route-a', run.runId); +console.log('\n外层 context["round-body"].metadata =', JSON.stringify(outer?.context?.['round-body']?.metadata)); +console.log('外层 context 键 =', JSON.stringify(Object.keys(outer?.context ?? {}))); +console.log('\n结论素材:整个 run 只有一份「A4 的记录」,内容是最后一轮的;第 1 轮的 A4/A5 记录不可回溯。'); +_internals.getLedger().dump('probe-03(我们自己记的台账则保留了每一轮)'); diff --git a/spike/mastra-reopen/src/probe-04-route-b-pitfalls.ts b/spike/mastra-reopen/src/probe-04-route-b-pitfalls.ts new file mode 100644 index 0000000..d880549 --- /dev/null +++ b/spike/mastra-reopen/src/probe-04-route-b-pitfalls.ts @@ -0,0 +1,144 @@ +/** + * 路线 B 的坑 + 一个额外候选(同 run 内 timeTravel): + * 1. 自定义 runId 撞车会怎样?(重开用确定性 runId 时的幂等性) + * 2. run 结束后再 resume / 重复 resume 会怎样? + * 3. 旧 run 的快照会不会被新 run 影响? + * 4. 回边目标如果不是图的入口节点,新 run 怎么从中间开始?—— 试 run.timeTravel() + * + * 运行:SPIKE_NO_AUTORUN=1 tsx src/probe-04-route-b-pitfalls.ts + */ +import { createWorkflowStateReader } from '@mastra/core/workflows'; +import { DecisionScript, Ledger, banner } from './ledger.js'; +import { mastraB, storeB, _internals } from './route-b-external.js'; +import { resetTrace } from './trace.js'; + +_internals.setLedger(new Ledger()); +_internals.setScript(new DecisionScript([])); +resetTrace(); + +const wf = mastraB.getWorkflow('routeB'); +const snapOf = async (workflowName: string, runId: string) => + (await (storeB as any).stores.workflows.loadWorkflowSnapshot({ workflowName, runId })) as + | Record + | null; + +const drive = async (run: any, steps: Array<[string[], any]>) => { + for (const [path, data] of steps) await run.resume({ step: path, resumeData: data }); +}; + +banner('坑 1:确定性 runId 撞车(重开时用 `${quoteId}-inst-N` 这种可读 ID)'); +{ + const runId = 'dup-run-1'; + const r1 = await wf.createRun({ runId }); + await r1.start({ inputData: { quoteId: 'Q1', instanceSeq: 1, reopenedBy: null, prevRunId: null } }); + console.log('第一次 createRun+start → status =', (await wf.getWorkflowRunById(runId))?.status); + const r2 = await wf.createRun({ runId }); + console.log('用同一个 runId 再 createRun → 没报错,拿到的是同一个 run?', r2.runId === runId); + const st = await wf.getWorkflowRunById(runId); + console.log(' 此时 status =', st?.status, ' 挂起的是', + JSON.stringify(createWorkflowStateReader(st!).getSuspendedStep()?.path)); + try { + const rr = await r2.start({ + inputData: { quoteId: 'Q1', instanceSeq: 99, reopenedBy: null, prevRunId: null }, + }); + console.log(' 对已挂起的 run 再 start() → status =', rr.status, 'error=', JSON.stringify((rr as any).error ?? null)); + const st2 = await wf.getWorkflowRunById(runId); + console.log(' A4.suspendPayload 变了吗?', JSON.stringify((st2?.steps as any)?.A4?.suspendPayload)); + } catch (e) { + console.log(' 对已挂起的 run 再 start() 抛异常:', (e as Error).message); + } +} + +banner('坑 2:run 已经 success 之后再 resume'); +{ + const runId = 'done-run-1'; + const run = await wf.createRun({ runId }); + await run.start({ inputData: { quoteId: 'Q2', instanceSeq: 1, reopenedBy: null, prevRunId: null } }); + await drive(run, [ + [['A4'], { price: 100 }], + [['A5'], { verdict: 'pass' }], + [['A6-sub', 'A6'], { outcome: 'won' }], + ]); + console.log('status =', (await wf.getWorkflowRunById(runId))?.status); + try { + const r = await run.resume({ step: ['A6-sub', 'A6'], resumeData: { outcome: 'won' } }); + console.log('已完成的 run 再 resume → status =', r.status, JSON.stringify((r as any).error ?? null)); + } catch (e) { + console.log('已完成的 run 再 resume 抛异常:', (e as Error).message); + } + console.log('之后 status 还是 =', (await wf.getWorkflowRunById(runId))?.status, ' ← 老 run 没被打坏'); +} + +banner('坑 3:重复 resume 同一个 step(任务回调重复到达)'); +{ + const runId = 'dupresume-1'; + const run = await wf.createRun({ runId }); + await run.start({ inputData: { quoteId: 'Q3', instanceSeq: 1, reopenedBy: null, prevRunId: null } }); + await run.resume({ step: ['A4'], resumeData: { price: 100 } }); + try { + const r = await run.resume({ step: ['A4'], resumeData: { price: 100 } }); + console.log('第二次 resume A4 → status =', r.status, 'error =', JSON.stringify((r as any).error ?? null)); + } catch (e) { + console.log('第二次 resume A4 抛异常:', (e as Error).message); + } + console.log('run 状态 =', (await wf.getWorkflowRunById(runId))?.status, ' ← 与路线 A 一样会被打成 failed'); +} + +banner('坑 4:回边目标不是入口节点时,新 run 能不能「从中间开始」?试 run.timeTravel()'); +{ + const runId = 'tt-1'; + const run = await wf.createRun({ runId }); + await run.start({ inputData: { quoteId: 'Q4', instanceSeq: 1, reopenedBy: null, prevRunId: null } }); + await run.resume({ step: ['A4'], resumeData: { price: 100 } }); + await run.resume({ step: ['A5'], resumeData: { verdict: 'reject' } }); + const st = await wf.getWorkflowRunById(runId); + console.log('E10 回边出口跑完,run status =', st?.status, 'result =', JSON.stringify(st?.result)); + + // 用 timeTravel 在同一个 run 里回到 A5(模拟「回边目标是中间节点」) + try { + const r = await run.timeTravel({ + step: 'A5', + inputData: { + quoteId: 'Q4', + instanceSeq: 2, + reopenedBy: 'E10', + prevRunId: null, + price: 100, + verdict: null, + finalOutcome: null, + }, + }); + console.log('timeTravel(step=A5) → status =', r.status); + const st2 = await wf.getWorkflowRunById(runId); + console.log(' A5.suspendPayload =', JSON.stringify((st2?.steps as any)?.A5?.suspendPayload)); + console.log(' A4 的记录还在吗? ', JSON.stringify((st2?.steps as any)?.A4?.output)); + console.log(' 第一次跑的 result 还在吗?', JSON.stringify(st2?.result)); + } catch (e) { + console.log('timeTravel 抛异常:', (e as Error).message); + } +} + +banner('坑 5:旧 run 的快照会不会被新 run 影响'); +{ + const q = 'Q5'; + const r1 = await wf.createRun({ runId: `${q}-inst-1`, resourceId: q }); + await r1.start({ inputData: { quoteId: q, instanceSeq: 1, reopenedBy: null, prevRunId: null } }); + await r1.resume({ step: ['A4'], resumeData: { price: 100 } }); + await r1.resume({ step: ['A5'], resumeData: { verdict: 'reject' } }); + + const r2 = await wf.createRun({ runId: `${q}-inst-2`, resourceId: q }); + await r2.start({ inputData: { quoteId: q, instanceSeq: 2, reopenedBy: 'E10', prevRunId: `${q}-inst-1` } }); + await r2.resume({ step: ['A4'], resumeData: { price: 90 } }); + await r2.resume({ step: ['A5'], resumeData: { verdict: 'pass' } }); + await r2.resume({ step: ['A6-sub', 'A6'], resumeData: { outcome: 'won' } }); + + for (const id of [`${q}-inst-1`, `${q}-inst-2`]) { + const s = await snapOf('route-b', id); + console.log( + `${id}: status=${s?.status} A4.taskId=${s?.context?.A4?.suspendPayload?.taskId} A4.price=${s?.context?.A4?.output?.price} result=${JSON.stringify(s?.result)}`, + ); + } + const runs = await wf.listWorkflowRuns({ resourceId: q }); + console.log('listWorkflowRuns({resourceId}) →', runs.total, JSON.stringify(runs.runs.map((r: any) => r.runId))); + _internals.getLedger().dump('probe-04'); +} diff --git a/spike/mastra-reopen/src/route-a-dowhile.ts b/spike/mastra-reopen/src/route-a-dowhile.ts new file mode 100644 index 0000000..c582fbb --- /dev/null +++ b/spike/mastra-reopen/src/route-a-dowhile.ts @@ -0,0 +1,379 @@ +/** + * 路线 A:.dowhile() 子图 + * + * 把「A4 → A5 (→ A6)」整体包成 dowhile 的循环体,循环条件 =「本轮发生了回跳」。 + * 拓扑(对齐种子 unified-quote): + * start → A4(定价,活动) → A5(审批) + * E11 A5 --verdict=pass--> A6(议价) + * E10 A5 --verdict=reject--> A4 (reopen) + * E13 A6 --outcome=won--> end + * E12 A6 --outcome=revise--> A4 (reopen) + * + * 每个活动/审批点都是:起任务 → suspend();终态由外部 run.resume() 送达。 + */ +import { Mastra } from '@mastra/core'; +import { RequestContext } from '@mastra/core/request-context'; +import { InMemoryStore } from '@mastra/core/storage'; +import { createStep, createWorkflow, createWorkflowStateReader } from '@mastra/core/workflows'; +import { z } from 'zod'; +import { banner, DecisionScript, Ledger, type Decision } from './ledger.js'; +import { resetTrace, t } from './trace.js'; + +/** 循环体的输入/输出必须同构 —— dowhile 把上一轮的输出直接当下一轮的输入 */ +const RoundState = z.object({ + round: z.number(), + reopen: z.boolean(), + reopenedBy: z.string().nullable(), + price: z.number().nullable(), + verdict: z.string().nullable(), + finalOutcome: z.string().nullable(), + a4TaskId: z.string().nullable(), +}); +type RoundState = z.infer; + +/** 每个场景一份新的 ledger / script,用模块级变量喂给 step(step 定义是静态的) */ +let ledger = new Ledger(); +let script = new DecisionScript([]); + +/* ------------------------------------------------------------------ 活动点 */ + +const a4 = createStep({ + id: 'A4', + description: '定价(活动点)', + inputSchema: RoundState, + outputSchema: RoundState, + resumeSchema: z.object({ price: z.number() }), + suspendSchema: z.object({ nodeId: z.string(), taskId: z.string(), instanceNo: z.number() }), + execute: async ({ inputData, resumeData, suspend, runId }) => { + t('A4.execute', `enter round=${inputData.round} resume=${!!resumeData}`); + if (!resumeData) { + const row = ledger.openInstance({ + nodeId: 'A4', + runId, + iteration: inputData.round, + reopenedBy: inputData.reopenedBy, + }); + t('A4.execute', `起任务 → suspend`, { instanceNo: row.instanceNo, taskId: row.taskId }); + return await suspend( + { nodeId: 'A4', taskId: row.taskId, instanceNo: row.instanceNo }, + { resumeLabel: `A4-round-${inputData.round}` }, + ); + } + const taskId = ledger.rows.filter((r) => r.nodeId === 'A4').at(-1)!.taskId; + ledger.closeTask(taskId, `price=${resumeData.price}`); + t('A4.execute', `任务终态到达 price=${resumeData.price}`); + return { ...inputData, price: resumeData.price, a4TaskId: taskId }; + }, +}); + +const a5 = createStep({ + id: 'A5', + description: '审批(审批点)', + inputSchema: RoundState, + outputSchema: RoundState, + resumeSchema: z.object({ verdict: z.enum(['pass', 'reject']) }), + suspendSchema: z.object({ nodeId: z.string(), taskId: z.string(), instanceNo: z.number() }), + execute: async ({ inputData, resumeData, suspend, runId }) => { + t('A5.execute', `enter round=${inputData.round} resume=${!!resumeData}`); + if (!resumeData) { + const row = ledger.openInstance({ nodeId: 'A5', runId, iteration: inputData.round }); + t('A5.execute', `起任务 → suspend`, { instanceNo: row.instanceNo, taskId: row.taskId }); + return await suspend( + { nodeId: 'A5', taskId: row.taskId, instanceNo: row.instanceNo }, + { resumeLabel: `A5-round-${inputData.round}` }, + ); + } + const taskId = ledger.rows.filter((r) => r.nodeId === 'A5').at(-1)!.taskId; + ledger.closeTask(taskId, resumeData.verdict); + t('A5.execute', `任务终态到达 verdict=${resumeData.verdict}`); + return { ...inputData, verdict: resumeData.verdict }; + }, +}); + +const a6 = createStep({ + id: 'A6', + description: '议价(活动点)', + inputSchema: RoundState, + outputSchema: RoundState, + resumeSchema: z.object({ outcome: z.enum(['won', 'revise']) }), + suspendSchema: z.object({ nodeId: z.string(), taskId: z.string(), instanceNo: z.number() }), + execute: async ({ inputData, resumeData, suspend, runId }) => { + t('A6.execute', `enter round=${inputData.round} resume=${!!resumeData}`); + if (!resumeData) { + const row = ledger.openInstance({ nodeId: 'A6', runId, iteration: inputData.round }); + t('A6.execute', `起任务 → suspend`, { instanceNo: row.instanceNo, taskId: row.taskId }); + return await suspend( + { nodeId: 'A6', taskId: row.taskId, instanceNo: row.instanceNo }, + { resumeLabel: `A6-round-${inputData.round}` }, + ); + } + const taskId = ledger.rows.filter((r) => r.nodeId === 'A6').at(-1)!.taskId; + ledger.closeTask(taskId, resumeData.outcome); + t('A6.execute', `任务终态到达 outcome=${resumeData.outcome}`); + return { ...inputData, finalOutcome: resumeData.outcome }; + }, +}); + +/* --------------------------------------------------------------- 边(出边) */ + +const e10Reopen = createStep({ + id: 'E10-reopen-A4', + description: 'A5 --verdict=reject--> A4 (reopen)', + inputSchema: RoundState, + outputSchema: RoundState, + execute: async ({ inputData }) => { + t('E10.execute', `回边命中,轮次 ${inputData.round} → ${inputData.round + 1}`); + return { ...inputData, round: inputData.round + 1, reopen: true, reopenedBy: 'E10' }; + }, +}); + +const e12Reopen = createStep({ + id: 'E12-reopen-A4', + description: 'A6 --outcome=revise--> A4 (reopen)', + inputSchema: RoundState, + outputSchema: RoundState, + execute: async ({ inputData }) => { + t('E12.execute', `回边命中,轮次 ${inputData.round} → ${inputData.round + 1}`); + return { ...inputData, round: inputData.round + 1, reopen: true, reopenedBy: 'E12' }; + }, +}); + +const e13End = createStep({ + id: 'E13-end', + description: 'A6 --outcome=won--> end', + inputSchema: RoundState, + outputSchema: RoundState, + execute: async ({ inputData }) => { + t('E13.execute', '成交,走向 end'); + return { ...inputData, reopen: false, reopenedBy: null }; + }, +}); + +/** + * branch 的输出是 { [每一条分支的 stepId]: output | undefined } —— 没命中的分支键也在,值是 + * undefined。所以收口步骤的 inputSchema 必须允许 undefined,并自己做 XOR 判定。 + */ +const pick = (id: string) => + createStep({ + id, + inputSchema: z.record(z.string(), RoundState.optional()), + outputSchema: RoundState, + execute: async ({ inputData }) => { + const allKeys = Object.keys(inputData); + const hit = allKeys.filter((k) => inputData[k] !== undefined); + t(`${id}.execute`, `branch 收口`, { '所有分支键': allKeys, '命中': hit }); + if (hit.length !== 1) throw new Error(`XOR 违约:命中 ${hit.length} 条出边`); + return inputData[hit[0]!]!; + }, + }); + +/* ------------------------------------------------------------ A6 子图 + 循环体 */ + +const a6Sub = createWorkflow({ + id: 'A6-sub', + inputSchema: RoundState, + outputSchema: RoundState, +}) + .then(a6) + .branch([ + [ + async ({ inputData, getStepResult, requestContext }) => { + t('cond(E13 won?)', 'evaluated', { + finalOutcome: inputData.finalOutcome, + '上一步输出可见': getStepResult(a6)?.finalOutcome ?? null, + 'requestContext.tenant': requestContext?.get?.('tenant') ?? null, + }); + return inputData.finalOutcome === 'won'; + }, + e13End, + ], + [ + async ({ inputData }) => { + t('cond(E12 revise?)', 'evaluated', { finalOutcome: inputData.finalOutcome }); + return inputData.finalOutcome === 'revise'; + }, + e12Reopen, + ], + ]) + .then(pick('pick-A6-out')) + .commit(); + +const roundBody = createWorkflow({ + id: 'round-body', + inputSchema: RoundState, + outputSchema: RoundState, +}) + .then(a4) + .then(a5) + .branch([ + [ + async ({ inputData, getStepResult, requestContext }) => { + t('cond(E11 pass?)', 'evaluated', { + verdict: inputData.verdict, + '上一步输出可见': getStepResult(a5)?.verdict ?? null, + 'requestContext.tenant': requestContext?.get?.('tenant') ?? null, + }); + return inputData.verdict === 'pass'; + }, + a6Sub, + ], + [ + async ({ inputData }) => { + t('cond(E10 reject?)', 'evaluated', { verdict: inputData.verdict }); + return inputData.verdict === 'reject'; + }, + e10Reopen, + ], + ]) + .then(pick('pick-A5-out')) + .commit(); + +const start = createStep({ + id: 'start', + inputSchema: z.object({ quoteId: z.string() }), + outputSchema: RoundState, + execute: async ({ inputData }) => { + t('start.execute', `起单 ${inputData.quoteId}`); + return { + round: 1, + reopen: false, + reopenedBy: null, + price: null, + verdict: null, + finalOutcome: null, + a4TaskId: null, + }; + }, +}); + +const end = createStep({ + id: 'end', + inputSchema: RoundState, + outputSchema: z.object({ rounds: z.number(), finalOutcome: z.string().nullable() }), + execute: async ({ inputData }) => { + t('end.execute', `收单 rounds=${inputData.round}`); + return { rounds: inputData.round, finalOutcome: inputData.finalOutcome }; + }, +}); + +export const routeA = createWorkflow({ + id: 'route-a', + inputSchema: z.object({ quoteId: z.string() }), + outputSchema: z.object({ rounds: z.number(), finalOutcome: z.string().nullable() }), +}) + .then(start) + .dowhile(roundBody, async ({ inputData, iterationCount }) => { + t('dowhile.condition', 'evaluated', { + iterationCount, + reopen: inputData.reopen, + round: inputData.round, + '继续循环?': inputData.reopen === true, + }); + return inputData.reopen === true; + }) + .then(end) + .commit(); + +export const storeA = new InMemoryStore(); +export const mastraA = new Mastra({ + workflows: { routeA }, + storage: storeA, + logger: false, +}); +const mastra = mastraA; + +/** 探针需要拿到 ledger/script 的控制权 */ +export const _internals = { + setLedger: (l: Ledger) => (ledger = l), + setScript: (s: DecisionScript) => (script = s), + getLedger: () => ledger, +}; + +/* ----------------------------------------------------------------- 驱动器 */ + +type NodeIdT = 'A4' | 'A5' | 'A6'; + +async function drive(scenario: string, decisions: Decision[]): Promise { + banner(`路线 A / 场景:${scenario}`); + resetTrace(); + ledger = new Ledger(); + script = new DecisionScript(decisions); + + const wf = mastra.getWorkflow('routeA'); + const run = await wf.createRun(); + console.log(` runId = ${run.runId}`); + + // 外部注入的上下文:必须是 RequestContext 实例(传普通对象会在持久化时炸,见 FINDINGS) + const rc = new RequestContext(); + rc.set('tenant', 'acme'); + + let res = await run.start({ + inputData: { quoteId: 'Q-2026-0001' }, + requestContext: rc as never, + }); + + let guard = 0; + while (res.status === 'suspended') { + if (++guard > 20) throw new Error('driver: too many suspends'); + const state = await wf.getWorkflowRunById(run.runId); + const reader = createWorkflowStateReader(state!); + const s = reader.getSuspendedStep(); + t('[driver]', 'getSuspendedStep()', { + stepId: s?.stepId, + path: s?.path, + executionPath: s?.executionPath, + suspendPayload: s?.suspendPayload, + resumeLabels: Object.keys(reader.getResumeLabels()), + }); + t('[driver]', 'result.suspended (来自 start/resume 的返回值)', res.suspended); + + const nodeId = (s!.suspendPayload as { nodeId: NodeIdT }).nodeId; + const d = script.next(nodeId); + const resumeData = + d.node === 'A4' + ? { price: d.price } + : d.node === 'A5' + ? { verdict: d.verdict } + : { outcome: d.outcome }; + t('[driver]', `外部推进 ${nodeId}`, resumeData); + res = await run.resume({ step: s!.path, resumeData }); + } + + console.log(`\n 最终 status = ${res.status}`); + if (res.status === 'success') console.log(' result =', res.result); + else console.log(' 非 success:', JSON.stringify(res).slice(0, 800)); + ledger.dump(scenario); + + // 跑完之后还能不能查到历史轮次? + const finalState = await wf.getWorkflowRunById(run.runId); + console.log('\n ── 终态快照 steps 的 key ──'); + console.log(' ' + JSON.stringify(Object.keys(finalState?.steps ?? {}))); + const a4Snap = finalState?.steps?.['round-body.A4'] ?? finalState?.steps?.['A4']; + console.log(' 快照里 A4 这一格是数组吗?', Array.isArray(a4Snap), '→', JSON.stringify(a4Snap)); +} + +// 被 probe 引入时不自动跑三个场景 +if (!process.env.SPIKE_NO_AUTORUN) { + await drive('① 一次过(A4→A5 pass→A6 won→end)', [ + { node: 'A4', price: 100 }, + { node: 'A5', verdict: 'pass' }, + { node: 'A6', outcome: 'won' }, + ]); + + await drive('② A5 驳回一次后再通过', [ + { node: 'A4', price: 100 }, + { node: 'A5', verdict: 'reject' }, + { node: 'A4', price: 90 }, + { node: 'A5', verdict: 'pass' }, + { node: 'A6', outcome: 'won' }, + ]); + + await drive('③ A6 revise 一次后再成交', [ + { node: 'A4', price: 100 }, + { node: 'A5', verdict: 'pass' }, + { node: 'A6', outcome: 'revise' }, + { node: 'A4', price: 80 }, + { node: 'A5', verdict: 'pass' }, + { node: 'A6', outcome: 'won' }, + ]); +} diff --git a/spike/mastra-reopen/src/route-b-external.ts b/spike/mastra-reopen/src/route-b-external.ts new file mode 100644 index 0000000..bae53d7 --- /dev/null +++ b/spike/mastra-reopen/src/route-b-external.ts @@ -0,0 +1,373 @@ +/** + * 路线 B:外部胶合(回跳 = 结束本 run,外部用同一份 workflow 定义新起一个 run) + * + * workflow 定义里 **没有循环**,就是一张 DAG: + * A4 → A5 --E11 pass--> A6 --E13 won--> end + * --E10 reject--> [回边出口] + * A6 --E12 revise--> [回边出口] + * 「回边出口」是一个终止步骤:它把 reopen 意图写进 workflow 的 result,run 正常 success 结束。 + * 外部胶合层看到 result.reopen 就 createRun 一个新 run,把重开载荷(重开边、实例号、上一个 runId) + * 当 inputData 传进去。run 之间用 runId 链 + resourceId 关联。 + */ +import { Mastra } from '@mastra/core'; +import { RequestContext } from '@mastra/core/request-context'; +import { InMemoryStore } from '@mastra/core/storage'; +import { createStep, createWorkflow, createWorkflowStateReader } from '@mastra/core/workflows'; +import { z } from 'zod'; +import { banner, DecisionScript, Ledger, type Decision } from './ledger.js'; +import { resetTrace, t } from './trace.js'; + +/** 一个 run = 一趟「A4 起,到 end 或到回边出口」 */ +const RunIn = z.object({ + quoteId: z.string(), + /** A4 的第几个实例(= 第几次重开 + 1),由外部胶合层递增后传进来 */ + instanceSeq: z.number(), + /** 由哪条回边重开;首开为 null */ + reopenedBy: z.string().nullable(), + /** 上一个 run 的 runId,形成链 */ + prevRunId: z.string().nullable(), +}); +type RunIn = z.infer; + +const Carry = RunIn.extend({ + price: z.number().nullable(), + verdict: z.string().nullable(), + finalOutcome: z.string().nullable(), +}); + +const RunOut = z.object({ + /** 本 run 是否以回跳结束 */ + reopen: z.boolean(), + /** 回跳边号 */ + reopenedBy: z.string().nullable(), + /** 回跳目标节点 */ + reopenTarget: z.string().nullable(), + finalOutcome: z.string().nullable(), + instanceSeq: z.number(), +}); + +let ledger = new Ledger(); +let script = new DecisionScript([]); + +/* ------------------------------------------------------------------ 活动点 */ + +const a4 = createStep({ + id: 'A4', + inputSchema: RunIn, + outputSchema: Carry, + resumeSchema: z.object({ price: z.number() }), + suspendSchema: z.object({ nodeId: z.string(), taskId: z.string(), instanceNo: z.number() }), + execute: async ({ inputData, resumeData, suspend, runId }) => { + t('A4.execute', `enter seq=${inputData.instanceSeq} resume=${!!resumeData}`); + if (!resumeData) { + const row = ledger.openInstance({ + nodeId: 'A4', + runId, + iteration: inputData.instanceSeq, + reopenedBy: inputData.reopenedBy, + }); + t('A4.execute', '起任务 → suspend', { instanceNo: row.instanceNo, taskId: row.taskId }); + return await suspend( + { nodeId: 'A4', taskId: row.taskId, instanceNo: row.instanceNo }, + { resumeLabel: 'A4' }, + ); + } + const taskId = ledger.rows.filter((r) => r.nodeId === 'A4').at(-1)!.taskId; + ledger.closeTask(taskId, `price=${resumeData.price}`); + t('A4.execute', `任务终态到达 price=${resumeData.price}`); + return { ...inputData, price: resumeData.price, verdict: null, finalOutcome: null }; + }, +}); + +const a5 = createStep({ + id: 'A5', + inputSchema: Carry, + outputSchema: Carry, + resumeSchema: z.object({ verdict: z.enum(['pass', 'reject']) }), + suspendSchema: z.object({ nodeId: z.string(), taskId: z.string(), instanceNo: z.number() }), + execute: async ({ inputData, resumeData, suspend, runId }) => { + t('A5.execute', `enter seq=${inputData.instanceSeq} resume=${!!resumeData}`); + if (!resumeData) { + const row = ledger.openInstance({ nodeId: 'A5', runId, iteration: inputData.instanceSeq }); + t('A5.execute', '起任务 → suspend', { instanceNo: row.instanceNo, taskId: row.taskId }); + return await suspend( + { nodeId: 'A5', taskId: row.taskId, instanceNo: row.instanceNo }, + { resumeLabel: 'A5' }, + ); + } + const taskId = ledger.rows.filter((r) => r.nodeId === 'A5').at(-1)!.taskId; + ledger.closeTask(taskId, resumeData.verdict); + t('A5.execute', `任务终态到达 verdict=${resumeData.verdict}`); + return { ...inputData, verdict: resumeData.verdict }; + }, +}); + +const a6 = createStep({ + id: 'A6', + inputSchema: Carry, + outputSchema: Carry, + resumeSchema: z.object({ outcome: z.enum(['won', 'revise']) }), + suspendSchema: z.object({ nodeId: z.string(), taskId: z.string(), instanceNo: z.number() }), + execute: async ({ inputData, resumeData, suspend, runId }) => { + t('A6.execute', `enter seq=${inputData.instanceSeq} resume=${!!resumeData}`); + if (!resumeData) { + const row = ledger.openInstance({ nodeId: 'A6', runId, iteration: inputData.instanceSeq }); + t('A6.execute', '起任务 → suspend', { instanceNo: row.instanceNo, taskId: row.taskId }); + return await suspend( + { nodeId: 'A6', taskId: row.taskId, instanceNo: row.instanceNo }, + { resumeLabel: 'A6' }, + ); + } + const taskId = ledger.rows.filter((r) => r.nodeId === 'A6').at(-1)!.taskId; + ledger.closeTask(taskId, resumeData.outcome); + t('A6.execute', `任务终态到达 outcome=${resumeData.outcome}`); + return { ...inputData, finalOutcome: resumeData.outcome }; + }, +}); + +/* ----------------------------------------------------- 出边(含两条回边出口) */ + +const reopenExit = (id: string, edge: string) => + createStep({ + id, + inputSchema: Carry, + outputSchema: RunOut, + execute: async ({ inputData }) => { + t(`${id}.execute`, `回边命中 → 本 run 到此为止,交给外部胶合层重开 A4`); + return { + reopen: true, + reopenedBy: edge, + reopenTarget: 'A4', + finalOutcome: inputData.finalOutcome, + instanceSeq: inputData.instanceSeq, + }; + }, + }); + +const e10Exit = reopenExit('E10-reopen-exit', 'E10'); +const e12Exit = reopenExit('E12-reopen-exit', 'E12'); + +const e13End = createStep({ + id: 'E13-end', + inputSchema: Carry, + outputSchema: RunOut, + execute: async ({ inputData }) => { + t('E13.execute', '成交,走向 end'); + return { + reopen: false, + reopenedBy: null, + reopenTarget: null, + finalOutcome: inputData.finalOutcome, + instanceSeq: inputData.instanceSeq, + }; + }, +}); + +const pick = (id: string) => + createStep({ + id, + inputSchema: z.record(z.string(), RunOut.optional()), + outputSchema: RunOut, + execute: async ({ inputData }) => { + const hit = Object.keys(inputData).filter((k) => inputData[k] !== undefined); + t(`${id}.execute`, 'branch 收口', { '所有分支键': Object.keys(inputData), '命中': hit }); + if (hit.length !== 1) throw new Error(`XOR 违约:命中 ${hit.length} 条出边`); + return inputData[hit[0]!]!; + }, + }); + +const a6Sub = createWorkflow({ id: 'A6-sub', inputSchema: Carry, outputSchema: RunOut }) + .then(a6) + .branch([ + [ + async ({ inputData, requestContext }) => { + t('cond(E13 won?)', 'evaluated', { + finalOutcome: inputData.finalOutcome, + 'requestContext.tenant': requestContext?.get?.('tenant') ?? null, + }); + return inputData.finalOutcome === 'won'; + }, + e13End, + ], + [ + async ({ inputData }) => { + t('cond(E12 revise?)', 'evaluated', { finalOutcome: inputData.finalOutcome }); + return inputData.finalOutcome === 'revise'; + }, + e12Exit, + ], + ]) + .then(pick('pick-A6-out')) + .commit(); + +export const routeB = createWorkflow({ + id: 'route-b', + inputSchema: RunIn, + outputSchema: RunOut, +}) + .then(a4) + .then(a5) + .branch([ + [ + async ({ inputData, requestContext }) => { + t('cond(E11 pass?)', 'evaluated', { + verdict: inputData.verdict, + 'requestContext.tenant': requestContext?.get?.('tenant') ?? null, + }); + return inputData.verdict === 'pass'; + }, + a6Sub, + ], + [ + async ({ inputData }) => { + t('cond(E10 reject?)', 'evaluated', { verdict: inputData.verdict }); + return inputData.verdict === 'reject'; + }, + e10Exit, + ], + ]) + .then(pick('pick-A5-out')) + .commit(); + +export const storeB = new InMemoryStore(); +export const mastraB = new Mastra({ + workflows: { routeB }, + storage: storeB, + logger: false, +}); +const mastra = mastraB; + +export const _internals = { + setLedger: (l: Ledger) => (ledger = l), + setScript: (s: DecisionScript) => (script = s), + getLedger: () => ledger, +}; + +/* ------------------------------------------------------- 外部胶合层(驱动器) */ + +type NodeIdT = 'A4' | 'A5' | 'A6'; + +/** run 链:外部胶合层自己维护的关联表(主工程里就是「实例表 + 边留痕」) */ +type ChainRow = { seq: number; runId: string; prevRunId: string | null; reopenedBy: string | null; endedAs: string }; + +async function drive(scenario: string, decisions: Decision[]): Promise { + banner(`路线 B / 场景:${scenario}`); + resetTrace(); + ledger = new Ledger(); + script = new DecisionScript(decisions); + + const wf = mastra.getWorkflow('routeB'); + const quoteId = `Q-${Math.random().toString(36).slice(2, 8)}`; + const chain: ChainRow[] = []; + + let input: RunIn = { quoteId, instanceSeq: 1, reopenedBy: null, prevRunId: null }; + let guard = 0; + + for (;;) { + if (++guard > 10) throw new Error('driver: too many reopens'); + + // 自己指定 runId —— 可读、可幂等、可与实例号一一对应 + const runId = `${quoteId}-inst-${input.instanceSeq}`; + const run = await wf.createRun({ runId, resourceId: quoteId }); + t('[glue]', `createRun`, { runId: run.runId, resourceId: quoteId, inputData: input }); + + const rc = new RequestContext(); + rc.set('tenant', 'acme'); + + let res = await run.start({ inputData: input, requestContext: rc as never }); + + let g2 = 0; + while (res.status === 'suspended') { + if (++g2 > 10) throw new Error('driver: too many suspends'); + const state = await wf.getWorkflowRunById(run.runId); + const reader = createWorkflowStateReader(state!); + const s = reader.getSuspendedStep(); + t('[glue]', 'getSuspendedStep()', { + stepId: s?.stepId, + path: s?.path, + suspendPayload: s?.suspendPayload, + resumeLabels: Object.keys(reader.getResumeLabels()), + }); + const nodeId = (s!.suspendPayload as { nodeId: NodeIdT }).nodeId; + const d = script.next(nodeId); + const resumeData = + d.node === 'A4' + ? { price: d.price } + : d.node === 'A5' + ? { verdict: d.verdict } + : { outcome: d.outcome }; + t('[glue]', `外部推进 ${nodeId}`, resumeData); + res = await run.resume({ step: s!.path, resumeData }); + } + + if (res.status !== 'success') { + console.log(' 非 success:', JSON.stringify(res).slice(0, 600)); + return; + } + const out = res.result; + chain.push({ + seq: input.instanceSeq, + runId: run.runId, + prevRunId: input.prevRunId, + reopenedBy: input.reopenedBy, + endedAs: out.reopen ? `reopen(${out.reopenedBy}) → ${out.reopenTarget}` : `end(${out.finalOutcome})`, + }); + + if (!out.reopen) { + t('[glue]', `run 结束:${JSON.stringify(out)} —— 流程完结`); + break; + } + t('[glue]', `run 结束:回跳 ${out.reopenedBy} → ${out.reopenTarget},新起一个 run`); + input = { + quoteId, + instanceSeq: input.instanceSeq + 1, + reopenedBy: out.reopenedBy, + prevRunId: run.runId, + }; + } + + console.log('\n ── run 链 ──'); + for (const c of chain) { + console.log( + ` seq=${c.seq}\trunId=${c.runId}\tprev=${c.prevRunId ?? '-'}\treopenedBy=${c.reopenedBy ?? '-'}\t${c.endedAs}`, + ); + } + ledger.dump(scenario); + + // 旧 run 留痕:流程都跑完了,还能不能查到第 1 个 run 的快照? + console.log('\n ── 历史 run 是否还查得到(旧实例留痕不动) ──'); + for (const c of chain) { + const st = await wf.getWorkflowRunById(c.runId); + const a4 = st?.steps?.['A4'] as { output?: { price?: number }; suspendPayload?: { taskId?: string } } | undefined; + console.log( + ` ${c.runId}: status=${st?.status} A4.taskId=${a4?.suspendPayload?.taskId} A4.price=${a4?.output?.price} result=${JSON.stringify(st?.result)}`, + ); + } + const runs = await wf.listWorkflowRuns({ resourceId: quoteId }); + console.log(` listWorkflowRuns({resourceId:'${quoteId}'}) → total=${runs.total}, runIds=${JSON.stringify(runs.runs.map((r) => r.runId))}`); +} + +if (!process.env.SPIKE_NO_AUTORUN) { + await drive('① 一次过(A4→A5 pass→A6 won→end)', [ + { node: 'A4', price: 100 }, + { node: 'A5', verdict: 'pass' }, + { node: 'A6', outcome: 'won' }, + ]); + + await drive('② A5 驳回一次后再通过', [ + { node: 'A4', price: 100 }, + { node: 'A5', verdict: 'reject' }, + { node: 'A4', price: 90 }, + { node: 'A5', verdict: 'pass' }, + { node: 'A6', outcome: 'won' }, + ]); + + await drive('③ A6 revise 一次后再成交', [ + { node: 'A4', price: 100 }, + { node: 'A5', verdict: 'pass' }, + { node: 'A6', outcome: 'revise' }, + { node: 'A4', price: 80 }, + { node: 'A5', verdict: 'pass' }, + { node: 'A6', outcome: 'won' }, + ]); +} diff --git a/spike/mastra-reopen/src/trace.ts b/spike/mastra-reopen/src/trace.ts new file mode 100644 index 0000000..8b642b2 --- /dev/null +++ b/spike/mastra-reopen/src/trace.ts @@ -0,0 +1,10 @@ +/** 带序号的轨迹打印,用来看「什么时候被调用了」 */ +let seq = 0; +export const resetTrace = (): void => { + seq = 0; +}; +export const t = (who: string, what: string, extra?: unknown): void => { + seq += 1; + const tail = extra === undefined ? '' : ` ${JSON.stringify(extra)}`; + console.log(` #${String(seq).padStart(2, '0')} ${who.padEnd(26)} ${what}${tail}`); +}; diff --git a/spike/mastra-reopen/tsconfig.json b/spike/mastra-reopen/tsconfig.json new file mode 100644 index 0000000..c41db61 --- /dev/null +++ b/spike/mastra-reopen/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": ["ES2023"], + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"] +}