@silkweave/core 2.6.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -121,5 +121,5 @@ type AdapterFactory<T = void> = (options: T) => AdapterGenerator
121
121
  - [`@silkweave/mcp`](https://www.npmjs.com/package/@silkweave/mcp) - MCP stdio and HTTP adapters
122
122
  - [`@silkweave/fastify`](https://www.npmjs.com/package/@silkweave/fastify) - Fastify REST adapter
123
123
  - [`@silkweave/cli`](https://www.npmjs.com/package/@silkweave/cli) - CLI adapter
124
- - [`@silkweave/vercel`](https://www.npmjs.com/package/@silkweave/vercel) - Vercel serverless adapter
124
+ - [`@silkweave/edge`](https://www.npmjs.com/package/@silkweave/edge) - Web-Standard edge/serverless adapter (Cloudflare Workers, Vercel, Bun, Deno)
125
125
  - [`@silkweave/typegen`](https://www.npmjs.com/package/@silkweave/typegen) - Build-time type generation
package/build/index.d.mts CHANGED
@@ -116,6 +116,13 @@ interface SilkweaveOptions {
116
116
  name: string;
117
117
  description: string;
118
118
  version: string;
119
+ /**
120
+ * Run the dev-time action linter on `start()` (warns about missing/short tool
121
+ * descriptions and undescribed input params - mistakes that degrade agent
122
+ * tool-use). Warnings go to stderr via `console.warn`. Default `true`; set
123
+ * `false` to silence in production.
124
+ */
125
+ lint?: boolean;
119
126
  }
120
127
  interface Adapter {
121
128
  context: SilkweaveContext;
@@ -186,6 +193,64 @@ interface ActionInputSources {
186
193
  */
187
194
  declare function resolveActionInput(action: Action, sources: ActionInputSources): Record<string, unknown>;
188
195
  //#endregion
196
+ //#region src/util/lint.d.ts
197
+ type ActionLintCode = 'missing-description' | 'short-description' | 'undescribed-params' | 'some-undescribed-params';
198
+ interface ActionLintWarning {
199
+ action: string;
200
+ code: ActionLintCode;
201
+ message: string;
202
+ }
203
+ /**
204
+ * Static checks for agent-hostile action definitions - the cheap mistakes that
205
+ * quietly degrade tool-use: a missing or throwaway description (the model reads
206
+ * it to decide when to call the tool) and undescribed input parameters (the
207
+ * model guesses what to pass). Pure + side-effect-free; `reportActionLint` wires
208
+ * it to a warn sink, and `silkweave().start()` runs it automatically.
209
+ */
210
+ declare function lintActions(actions: Action[]): ActionLintWarning[];
211
+ /**
212
+ * Run `lintActions` and emit each warning through `warn` (default `console.warn`,
213
+ * which goes to stderr - safe even for the stdio MCP transport). Returns the
214
+ * warnings so callers can also inspect or suppress them.
215
+ */
216
+ declare function reportActionLint(actions: Action[], warn?: (message: string) => void): ActionLintWarning[];
217
+ //#endregion
218
+ //#region src/util/logger.d.ts
219
+ interface MessageOptions {
220
+ message: string;
221
+ }
222
+ interface ProgressOptions {
223
+ progress: number;
224
+ total?: number;
225
+ message?: string;
226
+ }
227
+ declare const LogLevels: readonly ["error", "debug", "info", "notice", "warning", "critical", "alert", "emergency"];
228
+ type LogLevel = typeof LogLevels[number];
229
+ type LogFn = (data: unknown) => void;
230
+ interface Logger extends Record<LogLevel, LogFn> {
231
+ progress: (options: ProgressOptions) => void;
232
+ }
233
+ interface CreateLoggerOptions {
234
+ name?: string;
235
+ /** Minimum severity to write to `stream`. Defaults to `'debug'` (everything). */
236
+ level?: LogLevel;
237
+ /**
238
+ * Destination stream for structured log lines, or `false` to discard them.
239
+ * Defaults to `process.stdout`. The `onLog` callback always fires regardless
240
+ * of this setting - the stream is just the diagnostic sink.
241
+ */
242
+ stream?: NodeJS.WritableStream | false;
243
+ onLog?: (level: LogLevel, data: unknown) => void;
244
+ onProgress?: (options: ProgressOptions) => void;
245
+ }
246
+ declare function createLogger(options?: CreateLoggerOptions): Logger;
247
+ declare function buildLogLevels(fn: (level: LogLevel, data: unknown) => void): Record<LogLevel, LogFn>;
248
+ /**
249
+ * Human-readable `console`-backed logger for terminal contexts. Strings are
250
+ * written verbatim; objects are JSON-stringified. Zero dependencies.
251
+ */
252
+ declare function createConsoleLogger(): Logger;
253
+ //#endregion
189
254
  //#region src/util/streaming.d.ts
190
255
  /**
191
256
  * Drive a streaming action's async generator. Calls `onChunk` once per yielded
@@ -208,5 +273,5 @@ interface UnwrapResult {
208
273
  }
209
274
  declare function unwrap(type: z.ZodTypeAny, result?: UnwrapResult): [z.ZodTypeAny, UnwrapResult];
210
275
  //#endregion
211
- export { Action, ActionInputSources, ActionKind, ActionRun, ActionStreamRun, Adapter, AdapterFactory, AdapterGenerator, HttpMethod, NonStreamingActionInput, Silkweave, SilkweaveContext, SilkweaveError, type SilkweaveOptions, StreamingActionInput, UnwrapResult, actionMethod, badRequest, createAction, createContext, forbidden, internal, isStreamingAction, methodHasBody, notFound, pathParamNames, resolveActionInput, runStreamingAction, silkweave, unwrap, validateActionRouting };
276
+ export { Action, ActionInputSources, ActionKind, ActionLintCode, ActionLintWarning, ActionRun, ActionStreamRun, Adapter, AdapterFactory, AdapterGenerator, CreateLoggerOptions, HttpMethod, LogFn, LogLevel, LogLevels, Logger, MessageOptions, NonStreamingActionInput, ProgressOptions, Silkweave, SilkweaveContext, SilkweaveError, type SilkweaveOptions, StreamingActionInput, UnwrapResult, actionMethod, badRequest, buildLogLevels, createAction, createConsoleLogger, createContext, createLogger, forbidden, internal, isStreamingAction, lintActions, methodHasBody, notFound, pathParamNames, reportActionLint, resolveActionInput, runStreamingAction, silkweave, unwrap, validateActionRouting };
212
277
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/util/context.ts","../src/util/action.ts","../src/util/adapter.ts","../src/lib/silkweave.ts","../src/util/error.ts","../src/util/http.ts","../src/util/streaming.ts","../src/util/zod.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/util/context.ts","../src/util/action.ts","../src/util/adapter.ts","../src/lib/silkweave.ts","../src/util/error.ts","../src/util/http.ts","../src/util/lint.ts","../src/util/logger.ts","../src/util/streaming.ts","../src/util/zod.ts"],"mappings":"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"}
package/build/index.mjs CHANGED
@@ -28,6 +28,82 @@ function createContext(store = {}) {
28
28
  };
29
29
  }
30
30
  //#endregion
31
+ //#region src/util/zod.ts
32
+ function unwrap(type, result = {}) {
33
+ if (type instanceof z.ZodOptional) {
34
+ result.isOptional = true;
35
+ return unwrap(type.unwrap(), result);
36
+ } else if (type instanceof z.ZodNullable) {
37
+ result.isNullable = true;
38
+ return unwrap(type.unwrap(), result);
39
+ } else if (type instanceof z.ZodReadonly) {
40
+ result.isReadOnly = true;
41
+ return unwrap(type.def.innerType, result);
42
+ } else if (type instanceof z.ZodDefault) {
43
+ result.defaultValue = typeof type.def.defaultValue === "function" ? type.def.defaultValue() : type.def.defaultValue;
44
+ return unwrap(type.unwrap(), result);
45
+ } else return [type, result];
46
+ }
47
+ //#endregion
48
+ //#region src/util/lint.ts
49
+ /** A description shorter than this reads as a placeholder to an agent picking a tool. */
50
+ const MIN_DESCRIPTION_LENGTH = 12;
51
+ /** A field's `.describe()` text, looking through optional/default/nullable/readonly wrappers. */
52
+ function describedText(field) {
53
+ if (field.description) return field.description;
54
+ const [base] = unwrap(field);
55
+ return base.description;
56
+ }
57
+ /**
58
+ * Static checks for agent-hostile action definitions - the cheap mistakes that
59
+ * quietly degrade tool-use: a missing or throwaway description (the model reads
60
+ * it to decide when to call the tool) and undescribed input parameters (the
61
+ * model guesses what to pass). Pure + side-effect-free; `reportActionLint` wires
62
+ * it to a warn sink, and `silkweave().start()` runs it automatically.
63
+ */
64
+ function lintActions(actions) {
65
+ const warnings = [];
66
+ for (const action of actions) {
67
+ const description = action.description?.trim() ?? "";
68
+ if (!description) warnings.push({
69
+ action: action.name,
70
+ code: "missing-description",
71
+ message: `Action "${action.name}" has no description - MCP clients show it to the model to decide when to call the tool. Add a clear, specific sentence.`
72
+ });
73
+ else if (description.length < MIN_DESCRIPTION_LENGTH) warnings.push({
74
+ action: action.name,
75
+ code: "short-description",
76
+ message: `Action "${action.name}" description is very short ("${description}"). A fuller sentence helps agents choose the right tool.`
77
+ });
78
+ const shape = action.input?.shape ?? {};
79
+ const params = Object.keys(shape);
80
+ const undescribed = params.filter((name) => !describedText(shape[name]));
81
+ if (params.length > 0 && undescribed.length === params.length) warnings.push({
82
+ action: action.name,
83
+ code: "undescribed-params",
84
+ message: `Action "${action.name}" has no described input parameters (${params.join(", ")}). Add .describe() to each field so agents pass correct values.`
85
+ });
86
+ else if (undescribed.length > 0) warnings.push({
87
+ action: action.name,
88
+ code: "some-undescribed-params",
89
+ message: `Action "${action.name}" input fields lack descriptions: ${undescribed.join(", ")}. Add .describe() for better agent tool-use.`
90
+ });
91
+ }
92
+ return warnings;
93
+ }
94
+ /**
95
+ * Run `lintActions` and emit each warning through `warn` (default `console.warn`,
96
+ * which goes to stderr - safe even for the stdio MCP transport). Returns the
97
+ * warnings so callers can also inspect or suppress them.
98
+ */
99
+ function reportActionLint(actions, warn = (message) => {
100
+ console.warn(message);
101
+ }) {
102
+ const warnings = lintActions(actions);
103
+ for (const warning of warnings) warn(`[silkweave] ${warning.message}`);
104
+ return warnings;
105
+ }
106
+ //#endregion
31
107
  //#region src/lib/silkweave.ts
32
108
  function silkweave(options) {
33
109
  const adapters = [];
@@ -51,6 +127,7 @@ function silkweave(options) {
51
127
  return builder;
52
128
  },
53
129
  start: async () => {
130
+ if (options.lint !== false) reportActionLint(actions);
54
131
  await Promise.all(adapters.map((adapter) => {
55
132
  const filtered = adapter.allActions ? actions : actions.filter((action) => {
56
133
  if (!action.isEnabled) return true;
@@ -99,23 +176,6 @@ function internal(message = "Internal error") {
99
176
  return new SilkweaveError(message, "internal", 500);
100
177
  }
101
178
  //#endregion
102
- //#region src/util/zod.ts
103
- function unwrap(type, result = {}) {
104
- if (type instanceof z.ZodOptional) {
105
- result.isOptional = true;
106
- return unwrap(type.unwrap(), result);
107
- } else if (type instanceof z.ZodNullable) {
108
- result.isNullable = true;
109
- return unwrap(type.unwrap(), result);
110
- } else if (type instanceof z.ZodReadonly) {
111
- result.isReadOnly = true;
112
- return unwrap(type.def.innerType, result);
113
- } else if (type instanceof z.ZodDefault) {
114
- result.defaultValue = typeof type.def.defaultValue === "function" ? type.def.defaultValue() : type.def.defaultValue;
115
- return unwrap(type.unwrap(), result);
116
- } else return [type, result];
117
- }
118
- //#endregion
119
179
  //#region src/util/http.ts
120
180
  const PATH_PARAM_RE = /:([A-Za-z0-9_]+)/g;
121
181
  /**
@@ -206,6 +266,95 @@ function resolveActionInput(action, sources) {
206
266
  return merged;
207
267
  }
208
268
  //#endregion
269
+ //#region src/util/logger.ts
270
+ const LogLevels = [
271
+ "error",
272
+ "debug",
273
+ "info",
274
+ "notice",
275
+ "warning",
276
+ "critical",
277
+ "alert",
278
+ "emergency"
279
+ ];
280
+ const LEVEL_SEVERITY = {
281
+ debug: 10,
282
+ info: 20,
283
+ notice: 30,
284
+ warning: 40,
285
+ error: 50,
286
+ critical: 60,
287
+ alert: 70,
288
+ emergency: 80
289
+ };
290
+ function createLogger(options = {}) {
291
+ const { name, level = "debug", stream, onLog, onProgress } = options;
292
+ const target = stream === false ? void 0 : stream ?? process.stdout;
293
+ const threshold = LEVEL_SEVERITY[level] ?? LEVEL_SEVERITY.debug;
294
+ const write = (logLevel, data) => {
295
+ if (target && LEVEL_SEVERITY[logLevel] >= threshold) {
296
+ const line = typeof data === "object" && data !== null ? {
297
+ level: logLevel,
298
+ time: Date.now(),
299
+ name,
300
+ ...data
301
+ } : {
302
+ level: logLevel,
303
+ time: Date.now(),
304
+ name,
305
+ msg: data
306
+ };
307
+ target.write(`${JSON.stringify(line)}\n`);
308
+ }
309
+ };
310
+ return {
311
+ ...Object.fromEntries(LogLevels.map((logLevel) => {
312
+ return [logLevel, (data) => {
313
+ write(logLevel, data);
314
+ onLog?.(logLevel, data);
315
+ }];
316
+ })),
317
+ progress: (progressOptions) => {
318
+ if (onProgress) onProgress(progressOptions);
319
+ else write("info", { ...progressOptions });
320
+ }
321
+ };
322
+ }
323
+ function buildLogLevels(fn) {
324
+ return Object.fromEntries(LogLevels.map((level) => [level, (data) => {
325
+ fn(level, data);
326
+ }]));
327
+ }
328
+ const CONSOLE_LEVEL_MAP = {
329
+ debug: "log",
330
+ info: "info",
331
+ notice: "info",
332
+ warning: "warn",
333
+ error: "error",
334
+ critical: "error",
335
+ alert: "error",
336
+ emergency: "error"
337
+ };
338
+ /**
339
+ * Human-readable `console`-backed logger for terminal contexts. Strings are
340
+ * written verbatim; objects are JSON-stringified. Zero dependencies.
341
+ */
342
+ function createConsoleLogger() {
343
+ const toString = (value) => typeof value === "string" ? value : JSON.stringify(value);
344
+ return {
345
+ ...buildLogLevels((level, data) => {
346
+ console[CONSOLE_LEVEL_MAP[level]](toString(data));
347
+ }),
348
+ progress: ({ progress, total, message }) => {
349
+ console.info(toString({
350
+ progress,
351
+ total,
352
+ message
353
+ }));
354
+ }
355
+ };
356
+ }
357
+ //#endregion
209
358
  //#region src/util/streaming.ts
210
359
  /**
211
360
  * Drive a streaming action's async generator. Calls `onChunk` once per yielded
@@ -231,6 +380,6 @@ async function runStreamingAction(action, input, context, onChunk) {
231
380
  return chunks;
232
381
  }
233
382
  //#endregion
234
- export { SilkweaveError, actionMethod, badRequest, createAction, createContext, forbidden, internal, isStreamingAction, methodHasBody, notFound, pathParamNames, resolveActionInput, runStreamingAction, silkweave, unwrap, validateActionRouting };
383
+ export { LogLevels, SilkweaveError, actionMethod, badRequest, buildLogLevels, createAction, createConsoleLogger, createContext, createLogger, forbidden, internal, isStreamingAction, lintActions, methodHasBody, notFound, pathParamNames, reportActionLint, resolveActionInput, runStreamingAction, silkweave, unwrap, validateActionRouting };
235
384
 
236
385
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/util/context.ts","../src/lib/silkweave.ts","../src/util/action.ts","../src/util/error.ts","../src/util/zod.ts","../src/util/http.ts","../src/util/streaming.ts"],"sourcesContent":["export interface SilkweaveContext {\n keys: () => string[]\n has: (key: string) => boolean\n get: <T>(key: string) => T\n getOptional: <T>(key: string) => T | undefined\n set: <T>(key: string, value: T) => void\n fork: (store?: Record<string, unknown>) => SilkweaveContext\n}\n\nexport function createContext(store: Record<string, unknown> = {}): SilkweaveContext {\n return {\n keys: () => {\n return Object.keys(store)\n },\n has: (key: string): boolean => {\n return store[key] != null\n },\n get: <T>(key: string): T => {\n const value = store[key]\n if (value == null) { throw new Error(`Invalid context key: ${key}`) }\n return value as T\n },\n getOptional: <T>(key: string): T | undefined => {\n return store[key] as T | undefined\n },\n set: <T>(key: string, value: T) => {\n store[key] = value\n },\n fork: (value?: Record<string, unknown>) => {\n return createContext({ ...store, ...value })\n }\n }\n}\n","import { Action } from '../util/action.js'\nimport { Adapter, AdapterGenerator, SilkweaveOptions } from '../util/adapter.js'\nimport { createContext } from '../util/context.js'\n\nexport type { SilkweaveOptions } from '../util/adapter.js'\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface Silkweave<Actions extends Record<string, Action> = {}> {\n set: <T>(key: string, value: T) => Silkweave<Actions>\n adapter: (generator: AdapterGenerator) => Silkweave<Actions>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n action: <A extends Action<any, any, string, any>>(\n action: A\n ) => Silkweave<Actions & Record<A['name'], A>>\n actions: <Arr extends readonly Action[]>(\n actions: Arr\n ) => Silkweave<Actions & { [K in Arr[number] as K['name']]: K }>\n start: () => Promise<Silkweave<Actions>>\n}\n\nexport function silkweave(options: SilkweaveOptions): Silkweave {\n const adapters: Adapter[] = []\n const actions: Action[] = []\n const context = createContext()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const builder: Silkweave<any> = {\n set: (key, value) => {\n context.set(key, value)\n return builder\n },\n adapter: (generator) => {\n adapters.push(generator(options, context))\n return builder\n },\n action: (value) => {\n actions.push(value)\n return builder\n },\n actions: (values) => {\n actions.push(...values)\n return builder\n },\n start: async () => {\n await Promise.all(adapters.map((adapter) => {\n const filtered = adapter.allActions\n ? actions\n : actions.filter((action) => {\n if (!action.isEnabled) { return true }\n return action.isEnabled(adapter.context)\n })\n return adapter.start(filtered)\n }))\n return builder\n }\n }\n return builder\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { type CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport z from 'zod/v4'\nimport { SilkweaveContext } from './context.js'\n\nexport type ActionKind = 'query' | 'mutation'\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'\n\nexport type ActionRun<I, O> = (input: I, context: SilkweaveContext) => Promise<O>\nexport type ActionStreamRun<I, C> = (input: I, context: SilkweaveContext) => AsyncGenerator<C, void, void>\n\nexport interface Action<\n I extends object = any,\n O extends object = any,\n N extends string = string,\n K extends ActionKind = ActionKind,\n C = any\n> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }\n /**\n * Schema for individual chunks yielded by a streaming `run`. Required when\n * `run` is an async generator; adapters detect streaming actions by checking\n * `isStreamingAction(action)` at runtime, but type-aware tooling (inferRouter,\n * typegen) uses the presence of this field.\n */\n chunk?: z.ZodType<C>\n kind?: K\n /**\n * HTTP verb for REST-style adapters (fastify, nestjs `rest`). Defaults to\n * `POST`, or `GET` when `kind` is `'query'`. An explicit `method` always wins.\n */\n method?: HttpMethod\n /**\n * Route path for REST-style adapters. May contain `:param` placeholders\n * (e.g. `'spaces/:spaceId/users'`); each placeholder must be a key of the\n * input schema and is resolved from the URL path at runtime. When unset, the\n * adapter derives the path from `name`.\n */\n path?: string\n /**\n * Input fields sourced from the URL query string instead of the request body\n * (e.g. `['offset', 'limit']`). Each must be a key of the input schema; their\n * required/optional status is validated by the input schema as usual.\n */\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n /**\n * Default MCP result disposition for this action - `'json'` formats the\n * response with `jsonToolResult` (compact JSON text), `'smart'` (the default\n * when unset) uses `smartToolResult` (inlines small payloads, offloads large\n * ones to an embedded resource). This is only a default: a client that sends\n * `_meta.disposition` on the tool call always wins. Ignored by non-MCP\n * adapters.\n */\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionRun<I, O> | ActionStreamRun<I, C>\n toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport interface NonStreamingActionInput<I extends object, O extends object, N extends string, K extends ActionKind> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }\n kind?: K\n method?: HttpMethod\n path?: string\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionRun<I, O>\n toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport interface StreamingActionInput<I extends object, C, N extends string, K extends ActionKind> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n chunk: z.ZodType<C>\n kind?: K\n method?: HttpMethod\n path?: string\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionStreamRun<I, C>\n toolResult?: (response: C[], context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport function createAction<\n I extends object,\n C,\n N extends string,\n K extends ActionKind = 'mutation'\n>(action: StreamingActionInput<I, C, N, K>): StreamingActionInput<I, C, N, K>\nexport function createAction<\n I extends object,\n O extends object,\n N extends string,\n K extends ActionKind = 'mutation'\n>(action: NonStreamingActionInput<I, O, N, K>): NonStreamingActionInput<I, O, N, K>\nexport function createAction(action: Action): Action {\n return action\n}\n\n/**\n * Returns `true` when `action.run` is an async generator function (declared\n * with `async function*`). Adapters use this to switch between buffered\n * request/response and streaming chunk delivery.\n */\nexport function isStreamingAction(action: Action): boolean {\n return action.run?.constructor?.name === 'AsyncGeneratorFunction'\n}\n","export class SilkweaveError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode = 500\n ) {\n super(message)\n this.name = 'SilkweaveError'\n }\n}\n\nexport function notFound(message = 'Not found') {\n return new SilkweaveError(message, 'not_found', 404)\n}\n\nexport function badRequest(message = 'Bad request') {\n return new SilkweaveError(message, 'bad_request', 400)\n}\n\nexport function forbidden(message = 'Forbidden') {\n return new SilkweaveError(message, 'forbidden', 403)\n}\n\nexport function internal(message = 'Internal error') {\n return new SilkweaveError(message, 'internal', 500)\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from 'zod/v4'\n\nexport interface UnwrapResult {\n defaultValue?: any\n isOptional?: boolean\n isNullable?: boolean\n isReadOnly?: boolean\n}\n\nexport function unwrap(\n type: z.ZodTypeAny,\n result: UnwrapResult = {}\n): [z.ZodTypeAny, UnwrapResult] {\n if (type instanceof z.ZodOptional) {\n result.isOptional = true\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodNullable) {\n result.isNullable = true\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodReadonly) {\n result.isReadOnly = true\n return unwrap(type.def.innerType as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodDefault) {\n result.defaultValue = typeof type.def.defaultValue === 'function'\n ? type.def.defaultValue()\n : type.def.defaultValue\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else {\n return [type, result]\n }\n}\n","import type z from 'zod/v4'\nimport { type Action, type HttpMethod } from './action.js'\nimport { SilkweaveError } from './error.js'\nimport { unwrap } from './zod.js'\n\nconst PATH_PARAM_RE = /:([A-Za-z0-9_]+)/g\n\n/**\n * Resolve the HTTP verb for an action. An explicit `method` always wins;\n * otherwise `kind: 'query'` maps to `GET` and everything else to `POST`.\n */\nexport function actionMethod(action: Pick<Action, 'method' | 'kind'>): HttpMethod {\n if (action.method) { return action.method }\n return action.kind === 'query' ? 'GET' : 'POST'\n}\n\n/** Whether a request with this method carries a body (everything except GET). */\nexport function methodHasBody(method: HttpMethod): boolean {\n return method !== 'GET'\n}\n\n/** Extract the `:param` placeholder names from a route path template. */\nexport function pathParamNames(path: string | undefined): string[] {\n if (!path) { return [] }\n return [...path.matchAll(PATH_PARAM_RE)].map((match) => match[1])\n}\n\n/**\n * Assert that every `:param` in `action.path` and every `queryParams` entry is a\n * field of the input schema. Throws a `SilkweaveError` at registration time so\n * misconfigured routing fails fast instead of silently dropping values.\n */\nexport function validateActionRouting(action: Action): void {\n const shape = action.input.shape\n for (const param of pathParamNames(action.path)) {\n if (!(param in shape)) {\n throw new SilkweaveError(\n `Action \"${action.name}\" path \"${action.path}\" references \":${param}\" but the input schema has no \"${param}\" field`,\n 'invalid_action_routing'\n )\n }\n }\n for (const key of action.queryParams ?? []) {\n if (!(String(key) in shape)) {\n throw new SilkweaveError(\n `Action \"${action.name}\" lists query param \"${String(key)}\" but the input schema has no such field`,\n 'invalid_action_routing'\n )\n }\n }\n}\n\n/**\n * Coerce a raw string (from the URL path or query string) to the primitive the\n * field's schema expects. Non-string values pass through untouched (REST\n * frameworks like Fastify may have already coerced via JSON Schema), and a\n * failed coercion returns the original value so Zod surfaces a proper error.\n */\nfunction coerceScalar(field: z.ZodTypeAny | undefined, value: unknown): unknown {\n if (!field || typeof value !== 'string') { return value }\n const [base] = unwrap(field)\n const type = (base as { def?: { type?: string } }).def?.type\n if (type === 'number') {\n const num = Number(value)\n return value.trim() === '' || Number.isNaN(num) ? value : num\n }\n if (type === 'boolean') {\n if (value === 'true') { return true }\n if (value === 'false') { return false }\n return value\n }\n if (type === 'bigint') {\n try { return BigInt(value) } catch { return value }\n }\n return value\n}\n\nexport interface ActionInputSources {\n /** Path parameters keyed by `:param` name (e.g. Express/Fastify `req.params`). */\n params?: Record<string, string | undefined>\n /** Parsed query string (string values, or arrays/coerced values from a framework). */\n query?: Record<string, unknown>\n /** Parsed request body (already-typed JSON for body methods). */\n body?: unknown\n}\n\n/**\n * Merge an action's path params, query params, and body into a single input\n * object honouring its `method`/`path`/`queryParams` routing config:\n *\n * - body fields form the base layer (only for body-carrying methods),\n * - declared query params override (on bodyless GET requests every input field\n * that is not a path param is read from the query string),\n * - path params override last.\n *\n * String values from the path/query are coerced to the primitive their schema\n * expects. The result is not validated here - callers pass it to\n * `action.input.parse()` (or let a framework validate it).\n */\nexport function resolveActionInput(action: Action, sources: ActionInputSources): Record<string, unknown> {\n const shape = action.input.shape\n const method = actionMethod(action)\n const hasBody = methodHasBody(method)\n const params = sources.params ?? {}\n const query = sources.query ?? {}\n const pathParams = new Set(pathParamNames(action.path))\n const queryKeys = new Set((action.queryParams ?? []).map(String))\n\n const merged: Record<string, unknown> = {}\n\n if (hasBody && sources.body && typeof sources.body === 'object') {\n Object.assign(merged, sources.body as Record<string, unknown>)\n }\n\n for (const [key, raw] of Object.entries(query)) {\n if (raw === undefined) { continue }\n const declared = hasBody ? queryKeys.has(key) : (key in shape && !pathParams.has(key))\n if (!declared) { continue }\n merged[key] = Array.isArray(raw) ? raw : coerceScalar(shape[key], raw)\n }\n\n for (const key of pathParams) {\n const raw = params[key]\n if (raw === undefined) { continue }\n merged[key] = coerceScalar(shape[key], raw)\n }\n\n return merged\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Action, ActionStreamRun, isStreamingAction } from './action.js'\nimport { SilkweaveContext } from './context.js'\n\n/**\n * Drive a streaming action's async generator. Calls `onChunk` once per yielded\n * value and awaits it before pulling the next value from the generator - this\n * is what wires transport-level backpressure (SSE drain, stdout flush, tRPC\n * subscription consumer) back to the action.\n *\n * Returns the buffered array of all chunks. Use this for non-streaming\n * adapters or when a client has opted out of streaming (e.g. no MCP\n * `progressToken`). Pass `onChunk` to also emit each chunk on the wire.\n */\nexport async function runStreamingAction<C>(\n action: Action<any, any, string, any, C>,\n input: object,\n context: SilkweaveContext,\n onChunk?: (chunk: C, index: number) => void | Promise<void>\n): Promise<C[]> {\n if (!isStreamingAction(action)) {\n throw new Error(`Action ${action.name} is not a streaming action`)\n }\n const run = action.run as ActionStreamRun<object, C>\n const iter = run(input, context)\n const chunks: C[] = []\n let index = 0\n for await (const chunk of iter) {\n chunks.push(chunk)\n if (onChunk) { await onChunk(chunk, index) }\n index += 1\n }\n return chunks\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/util/context.ts","../src/util/zod.ts","../src/util/lint.ts","../src/lib/silkweave.ts","../src/util/action.ts","../src/util/error.ts","../src/util/http.ts","../src/util/logger.ts","../src/util/streaming.ts"],"sourcesContent":["export interface SilkweaveContext {\n keys: () => string[]\n has: (key: string) => boolean\n get: <T>(key: string) => T\n getOptional: <T>(key: string) => T | undefined\n set: <T>(key: string, value: T) => void\n fork: (store?: Record<string, unknown>) => SilkweaveContext\n}\n\nexport function createContext(store: Record<string, unknown> = {}): SilkweaveContext {\n return {\n keys: () => {\n return Object.keys(store)\n },\n has: (key: string): boolean => {\n return store[key] != null\n },\n get: <T>(key: string): T => {\n const value = store[key]\n if (value == null) { throw new Error(`Invalid context key: ${key}`) }\n return value as T\n },\n getOptional: <T>(key: string): T | undefined => {\n return store[key] as T | undefined\n },\n set: <T>(key: string, value: T) => {\n store[key] = value\n },\n fork: (value?: Record<string, unknown>) => {\n return createContext({ ...store, ...value })\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from 'zod/v4'\n\nexport interface UnwrapResult {\n defaultValue?: any\n isOptional?: boolean\n isNullable?: boolean\n isReadOnly?: boolean\n}\n\nexport function unwrap(\n type: z.ZodTypeAny,\n result: UnwrapResult = {}\n): [z.ZodTypeAny, UnwrapResult] {\n if (type instanceof z.ZodOptional) {\n result.isOptional = true\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodNullable) {\n result.isNullable = true\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodReadonly) {\n result.isReadOnly = true\n return unwrap(type.def.innerType as z.ZodTypeAny, result)\n } else if (type instanceof z.ZodDefault) {\n result.defaultValue = typeof type.def.defaultValue === 'function'\n ? type.def.defaultValue()\n : type.def.defaultValue\n return unwrap(type.unwrap() as z.ZodTypeAny, result)\n } else {\n return [type, result]\n }\n}\n","import { z } from 'zod/v4'\nimport { Action } from './action.js'\nimport { unwrap } from './zod.js'\n\nexport type ActionLintCode =\n | 'missing-description'\n | 'short-description'\n | 'undescribed-params'\n | 'some-undescribed-params'\n\nexport interface ActionLintWarning {\n action: string\n code: ActionLintCode\n message: string\n}\n\n/** A description shorter than this reads as a placeholder to an agent picking a tool. */\nconst MIN_DESCRIPTION_LENGTH = 12\n\n/** A field's `.describe()` text, looking through optional/default/nullable/readonly wrappers. */\nfunction describedText(field: z.ZodTypeAny): string | undefined {\n if (field.description) { return field.description }\n const [base] = unwrap(field)\n return base.description\n}\n\n/**\n * Static checks for agent-hostile action definitions - the cheap mistakes that\n * quietly degrade tool-use: a missing or throwaway description (the model reads\n * it to decide when to call the tool) and undescribed input parameters (the\n * model guesses what to pass). Pure + side-effect-free; `reportActionLint` wires\n * it to a warn sink, and `silkweave().start()` runs it automatically.\n */\nexport function lintActions(actions: Action[]): ActionLintWarning[] {\n const warnings: ActionLintWarning[] = []\n for (const action of actions) {\n const description = action.description?.trim() ?? ''\n if (!description) {\n warnings.push({\n action: action.name,\n code: 'missing-description',\n message: `Action \"${action.name}\" has no description - MCP clients show it to the model to decide when to call the tool. Add a clear, specific sentence.`\n })\n } else if (description.length < MIN_DESCRIPTION_LENGTH) {\n warnings.push({\n action: action.name,\n code: 'short-description',\n message: `Action \"${action.name}\" description is very short (\"${description}\"). A fuller sentence helps agents choose the right tool.`\n })\n }\n\n const shape = action.input?.shape ?? {}\n const params = Object.keys(shape)\n const undescribed = params.filter((name) => !describedText(shape[name]))\n if (params.length > 0 && undescribed.length === params.length) {\n warnings.push({\n action: action.name,\n code: 'undescribed-params',\n message: `Action \"${action.name}\" has no described input parameters (${params.join(', ')}). Add .describe() to each field so agents pass correct values.`\n })\n } else if (undescribed.length > 0) {\n warnings.push({\n action: action.name,\n code: 'some-undescribed-params',\n message: `Action \"${action.name}\" input fields lack descriptions: ${undescribed.join(', ')}. Add .describe() for better agent tool-use.`\n })\n }\n }\n return warnings\n}\n\n/**\n * Run `lintActions` and emit each warning through `warn` (default `console.warn`,\n * which goes to stderr - safe even for the stdio MCP transport). Returns the\n * warnings so callers can also inspect or suppress them.\n */\nexport function reportActionLint(\n actions: Action[],\n warn: (message: string) => void = (message) => { console.warn(message) }\n): ActionLintWarning[] {\n const warnings = lintActions(actions)\n for (const warning of warnings) {\n warn(`[silkweave] ${warning.message}`)\n }\n return warnings\n}\n","import { Action } from '../util/action.js'\nimport { Adapter, AdapterGenerator, SilkweaveOptions } from '../util/adapter.js'\nimport { createContext } from '../util/context.js'\nimport { reportActionLint } from '../util/lint.js'\n\nexport type { SilkweaveOptions } from '../util/adapter.js'\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface Silkweave<Actions extends Record<string, Action> = {}> {\n set: <T>(key: string, value: T) => Silkweave<Actions>\n adapter: (generator: AdapterGenerator) => Silkweave<Actions>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n action: <A extends Action<any, any, string, any>>(\n action: A\n ) => Silkweave<Actions & Record<A['name'], A>>\n actions: <Arr extends readonly Action[]>(\n actions: Arr\n ) => Silkweave<Actions & { [K in Arr[number] as K['name']]: K }>\n start: () => Promise<Silkweave<Actions>>\n}\n\nexport function silkweave(options: SilkweaveOptions): Silkweave {\n const adapters: Adapter[] = []\n const actions: Action[] = []\n const context = createContext()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const builder: Silkweave<any> = {\n set: (key, value) => {\n context.set(key, value)\n return builder\n },\n adapter: (generator) => {\n adapters.push(generator(options, context))\n return builder\n },\n action: (value) => {\n actions.push(value)\n return builder\n },\n actions: (values) => {\n actions.push(...values)\n return builder\n },\n start: async () => {\n if (options.lint !== false) { reportActionLint(actions) }\n await Promise.all(adapters.map((adapter) => {\n const filtered = adapter.allActions\n ? actions\n : actions.filter((action) => {\n if (!action.isEnabled) { return true }\n return action.isEnabled(adapter.context)\n })\n return adapter.start(filtered)\n }))\n return builder\n }\n }\n return builder\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { type CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport z from 'zod/v4'\nimport { SilkweaveContext } from './context.js'\n\nexport type ActionKind = 'query' | 'mutation'\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'\n\nexport type ActionRun<I, O> = (input: I, context: SilkweaveContext) => Promise<O>\nexport type ActionStreamRun<I, C> = (input: I, context: SilkweaveContext) => AsyncGenerator<C, void, void>\n\nexport interface Action<\n I extends object = any,\n O extends object = any,\n N extends string = string,\n K extends ActionKind = ActionKind,\n C = any\n> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }\n /**\n * Schema for individual chunks yielded by a streaming `run`. Required when\n * `run` is an async generator; adapters detect streaming actions by checking\n * `isStreamingAction(action)` at runtime, but type-aware tooling (inferRouter,\n * typegen) uses the presence of this field.\n */\n chunk?: z.ZodType<C>\n kind?: K\n /**\n * HTTP verb for REST-style adapters (fastify, nestjs `rest`). Defaults to\n * `POST`, or `GET` when `kind` is `'query'`. An explicit `method` always wins.\n */\n method?: HttpMethod\n /**\n * Route path for REST-style adapters. May contain `:param` placeholders\n * (e.g. `'spaces/:spaceId/users'`); each placeholder must be a key of the\n * input schema and is resolved from the URL path at runtime. When unset, the\n * adapter derives the path from `name`.\n */\n path?: string\n /**\n * Input fields sourced from the URL query string instead of the request body\n * (e.g. `['offset', 'limit']`). Each must be a key of the input schema; their\n * required/optional status is validated by the input schema as usual.\n */\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n /**\n * Default MCP result disposition for this action - `'json'` formats the\n * response with `jsonToolResult` (compact JSON text), `'smart'` (the default\n * when unset) uses `smartToolResult` (inlines small payloads, offloads large\n * ones to an embedded resource). This is only a default: a client that sends\n * `_meta.disposition` on the tool call always wins. Ignored by non-MCP\n * adapters.\n */\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionRun<I, O> | ActionStreamRun<I, C>\n toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport interface NonStreamingActionInput<I extends object, O extends object, N extends string, K extends ActionKind> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n output?: z.ZodType<O> & { shape: Record<string, z.ZodTypeAny> }\n kind?: K\n method?: HttpMethod\n path?: string\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionRun<I, O>\n toolResult?: (response: O, context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport interface StreamingActionInput<I extends object, C, N extends string, K extends ActionKind> {\n name: N\n description: string\n input: z.ZodType<I> & { shape: Record<string, z.ZodTypeAny> }\n chunk: z.ZodType<C>\n kind?: K\n method?: HttpMethod\n path?: string\n queryParams?: (keyof I)[]\n args?: (keyof I)[]\n disposition?: 'json' | 'smart'\n isEnabled?: (context: SilkweaveContext) => boolean\n run: ActionStreamRun<I, C>\n toolResult?: (response: C[], context: SilkweaveContext) => CallToolResult | undefined\n}\n\nexport function createAction<\n I extends object,\n C,\n N extends string,\n K extends ActionKind = 'mutation'\n>(action: StreamingActionInput<I, C, N, K>): StreamingActionInput<I, C, N, K>\nexport function createAction<\n I extends object,\n O extends object,\n N extends string,\n K extends ActionKind = 'mutation'\n>(action: NonStreamingActionInput<I, O, N, K>): NonStreamingActionInput<I, O, N, K>\nexport function createAction(action: Action): Action {\n return action\n}\n\n/**\n * Returns `true` when `action.run` is an async generator function (declared\n * with `async function*`). Adapters use this to switch between buffered\n * request/response and streaming chunk delivery.\n */\nexport function isStreamingAction(action: Action): boolean {\n return action.run?.constructor?.name === 'AsyncGeneratorFunction'\n}\n","export class SilkweaveError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly statusCode = 500\n ) {\n super(message)\n this.name = 'SilkweaveError'\n }\n}\n\nexport function notFound(message = 'Not found') {\n return new SilkweaveError(message, 'not_found', 404)\n}\n\nexport function badRequest(message = 'Bad request') {\n return new SilkweaveError(message, 'bad_request', 400)\n}\n\nexport function forbidden(message = 'Forbidden') {\n return new SilkweaveError(message, 'forbidden', 403)\n}\n\nexport function internal(message = 'Internal error') {\n return new SilkweaveError(message, 'internal', 500)\n}\n","import type z from 'zod/v4'\nimport { type Action, type HttpMethod } from './action.js'\nimport { SilkweaveError } from './error.js'\nimport { unwrap } from './zod.js'\n\nconst PATH_PARAM_RE = /:([A-Za-z0-9_]+)/g\n\n/**\n * Resolve the HTTP verb for an action. An explicit `method` always wins;\n * otherwise `kind: 'query'` maps to `GET` and everything else to `POST`.\n */\nexport function actionMethod(action: Pick<Action, 'method' | 'kind'>): HttpMethod {\n if (action.method) { return action.method }\n return action.kind === 'query' ? 'GET' : 'POST'\n}\n\n/** Whether a request with this method carries a body (everything except GET). */\nexport function methodHasBody(method: HttpMethod): boolean {\n return method !== 'GET'\n}\n\n/** Extract the `:param` placeholder names from a route path template. */\nexport function pathParamNames(path: string | undefined): string[] {\n if (!path) { return [] }\n return [...path.matchAll(PATH_PARAM_RE)].map((match) => match[1])\n}\n\n/**\n * Assert that every `:param` in `action.path` and every `queryParams` entry is a\n * field of the input schema. Throws a `SilkweaveError` at registration time so\n * misconfigured routing fails fast instead of silently dropping values.\n */\nexport function validateActionRouting(action: Action): void {\n const shape = action.input.shape\n for (const param of pathParamNames(action.path)) {\n if (!(param in shape)) {\n throw new SilkweaveError(\n `Action \"${action.name}\" path \"${action.path}\" references \":${param}\" but the input schema has no \"${param}\" field`,\n 'invalid_action_routing'\n )\n }\n }\n for (const key of action.queryParams ?? []) {\n if (!(String(key) in shape)) {\n throw new SilkweaveError(\n `Action \"${action.name}\" lists query param \"${String(key)}\" but the input schema has no such field`,\n 'invalid_action_routing'\n )\n }\n }\n}\n\n/**\n * Coerce a raw string (from the URL path or query string) to the primitive the\n * field's schema expects. Non-string values pass through untouched (REST\n * frameworks like Fastify may have already coerced via JSON Schema), and a\n * failed coercion returns the original value so Zod surfaces a proper error.\n */\nfunction coerceScalar(field: z.ZodTypeAny | undefined, value: unknown): unknown {\n if (!field || typeof value !== 'string') { return value }\n const [base] = unwrap(field)\n const type = (base as { def?: { type?: string } }).def?.type\n if (type === 'number') {\n const num = Number(value)\n return value.trim() === '' || Number.isNaN(num) ? value : num\n }\n if (type === 'boolean') {\n if (value === 'true') { return true }\n if (value === 'false') { return false }\n return value\n }\n if (type === 'bigint') {\n try { return BigInt(value) } catch { return value }\n }\n return value\n}\n\nexport interface ActionInputSources {\n /** Path parameters keyed by `:param` name (e.g. Express/Fastify `req.params`). */\n params?: Record<string, string | undefined>\n /** Parsed query string (string values, or arrays/coerced values from a framework). */\n query?: Record<string, unknown>\n /** Parsed request body (already-typed JSON for body methods). */\n body?: unknown\n}\n\n/**\n * Merge an action's path params, query params, and body into a single input\n * object honouring its `method`/`path`/`queryParams` routing config:\n *\n * - body fields form the base layer (only for body-carrying methods),\n * - declared query params override (on bodyless GET requests every input field\n * that is not a path param is read from the query string),\n * - path params override last.\n *\n * String values from the path/query are coerced to the primitive their schema\n * expects. The result is not validated here - callers pass it to\n * `action.input.parse()` (or let a framework validate it).\n */\nexport function resolveActionInput(action: Action, sources: ActionInputSources): Record<string, unknown> {\n const shape = action.input.shape\n const method = actionMethod(action)\n const hasBody = methodHasBody(method)\n const params = sources.params ?? {}\n const query = sources.query ?? {}\n const pathParams = new Set(pathParamNames(action.path))\n const queryKeys = new Set((action.queryParams ?? []).map(String))\n\n const merged: Record<string, unknown> = {}\n\n if (hasBody && sources.body && typeof sources.body === 'object') {\n Object.assign(merged, sources.body as Record<string, unknown>)\n }\n\n for (const [key, raw] of Object.entries(query)) {\n if (raw === undefined) { continue }\n const declared = hasBody ? queryKeys.has(key) : (key in shape && !pathParams.has(key))\n if (!declared) { continue }\n merged[key] = Array.isArray(raw) ? raw : coerceScalar(shape[key], raw)\n }\n\n for (const key of pathParams) {\n const raw = params[key]\n if (raw === undefined) { continue }\n merged[key] = coerceScalar(shape[key], raw)\n }\n\n return merged\n}\n","export interface MessageOptions {\n message: string\n}\n\nexport interface ProgressOptions {\n progress: number\n total?: number\n message?: string\n}\n\nconst LogLevels = ['error', 'debug', 'info', 'notice', 'warning', 'critical', 'alert', 'emergency'] as const\n\nexport type LogLevel = typeof LogLevels[number]\n\nexport type LogFn = (data: unknown) => void\n\nexport interface Logger extends Record<LogLevel, LogFn> {\n progress: (options: ProgressOptions) => void\n}\n\nexport { LogLevels }\n\n// Severity ordering (lowest number = most verbose) used to gate writes by the\n// configured `level` threshold. Mirrors syslog-style precedence so a `level` of\n// e.g. `'warning'` suppresses `info`/`notice`/`debug`.\nconst LEVEL_SEVERITY: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n notice: 30,\n warning: 40,\n error: 50,\n critical: 60,\n alert: 70,\n emergency: 80\n}\n\nexport interface CreateLoggerOptions {\n name?: string\n /** Minimum severity to write to `stream`. Defaults to `'debug'` (everything). */\n level?: LogLevel\n /**\n * Destination stream for structured log lines, or `false` to discard them.\n * Defaults to `process.stdout`. The `onLog` callback always fires regardless\n * of this setting - the stream is just the diagnostic sink.\n */\n stream?: NodeJS.WritableStream | false\n onLog?: (level: LogLevel, data: unknown) => void\n onProgress?: (options: ProgressOptions) => void\n}\n\nexport function createLogger(options: CreateLoggerOptions = {}): Logger {\n const { name, level = 'debug', stream, onLog, onProgress } = options\n\n const target = stream === false ? undefined : stream ?? process.stdout\n const threshold = LEVEL_SEVERITY[level] ?? LEVEL_SEVERITY.debug\n\n const write = (logLevel: LogLevel, data: unknown) => {\n if (target && LEVEL_SEVERITY[logLevel] >= threshold) {\n const line = typeof data === 'object' && data !== null\n ? { level: logLevel, time: Date.now(), name, ...data }\n : { level: logLevel, time: Date.now(), name, msg: data }\n target.write(`${JSON.stringify(line)}\\n`)\n }\n }\n\n const logLevels = Object.fromEntries(LogLevels.map((logLevel) => {\n return [logLevel, (data: unknown) => {\n write(logLevel, data)\n onLog?.(logLevel, data)\n }]\n })) as Record<LogLevel, LogFn>\n\n return {\n ...logLevels,\n progress: (progressOptions) => {\n if (onProgress) {\n onProgress(progressOptions)\n } else {\n write('info', { ...progressOptions })\n }\n }\n }\n}\n\nexport function buildLogLevels(fn: (level: LogLevel, data: unknown) => void): Record<LogLevel, LogFn> {\n return Object.fromEntries(LogLevels.map((level) => [level, (data: unknown) => { fn(level, data) }])) as Record<LogLevel, LogFn>\n}\n\n// Maps each syslog level onto a `console` method for a human-readable terminal\n// logger. Used by the `cli` adapter and the MCP `cliProxy` client - a\n// zero-dependency replacement for a terminal-UI logging library.\nconst CONSOLE_LEVEL_MAP: Record<LogLevel, 'log' | 'info' | 'warn' | 'error'> = {\n debug: 'log',\n info: 'info',\n notice: 'info',\n warning: 'warn',\n error: 'error',\n critical: 'error',\n alert: 'error',\n emergency: 'error'\n}\n\n/**\n * Human-readable `console`-backed logger for terminal contexts. Strings are\n * written verbatim; objects are JSON-stringified. Zero dependencies.\n */\nexport function createConsoleLogger(): Logger {\n const toString = (value: unknown) => typeof value === 'string' ? value : JSON.stringify(value)\n return {\n ...buildLogLevels((level, data) => {\n console[CONSOLE_LEVEL_MAP[level]](toString(data))\n }),\n progress: ({ progress, total, message }) => {\n console.info(toString({ progress, total, message }))\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Action, ActionStreamRun, isStreamingAction } from './action.js'\nimport { SilkweaveContext } from './context.js'\n\n/**\n * Drive a streaming action's async generator. Calls `onChunk` once per yielded\n * value and awaits it before pulling the next value from the generator - this\n * is what wires transport-level backpressure (SSE drain, stdout flush, tRPC\n * subscription consumer) back to the action.\n *\n * Returns the buffered array of all chunks. Use this for non-streaming\n * adapters or when a client has opted out of streaming (e.g. no MCP\n * `progressToken`). Pass `onChunk` to also emit each chunk on the wire.\n */\nexport async function runStreamingAction<C>(\n action: Action<any, any, string, any, C>,\n input: object,\n context: SilkweaveContext,\n onChunk?: (chunk: C, index: number) => void | Promise<void>\n): Promise<C[]> {\n if (!isStreamingAction(action)) {\n throw new Error(`Action ${action.name} is not a streaming action`)\n }\n const run = action.run as ActionStreamRun<object, C>\n const iter = run(input, context)\n const chunks: C[] = []\n let index = 0\n for await (const chunk of iter) {\n chunks.push(chunk)\n if (onChunk) { await onChunk(chunk, index) }\n index += 1\n }\n return chunks\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silkweave/core",
3
- "version": "2.6.1",
3
+ "version": "3.1.0",
4
4
  "description": "Silkweave Core",
5
5
  "license": "MIT",
6
6
  "homepage": "https://www.silkweave.dev",
@@ -42,6 +42,7 @@
42
42
  "tsx": "^4.21.0",
43
43
  "typescript": "^5.9.3",
44
44
  "typescript-eslint": "^8.56.1",
45
+ "vitest": "^4.1.9",
45
46
  "zod": "^3.25.0"
46
47
  },
47
48
  "scripts": {
@@ -50,6 +51,7 @@
50
51
  "watch": "tsdown --watch",
51
52
  "typecheck": "tsc --noEmit",
52
53
  "lint": "eslint",
53
- "check": "pnpm lint && pnpm typecheck"
54
+ "check": "pnpm lint && pnpm typecheck",
55
+ "test": "vitest run"
54
56
  }
55
57
  }