toolcraft 0.0.231 → 0.0.233

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.
Files changed (180) hide show
  1. package/composition.json +3 -3
  2. package/dist/applied-default.d.ts +3 -0
  3. package/dist/applied-default.js +16 -0
  4. package/dist/cli.js +508 -204
  5. package/dist/composition.json +3 -3
  6. package/dist/discriminator.d.ts +9 -0
  7. package/dist/discriminator.js +32 -0
  8. package/dist/error-report.d.ts +2 -18
  9. package/dist/error-report.js +12 -14
  10. package/dist/http.js +8 -1
  11. package/dist/human-in-loop/gate.js +6 -0
  12. package/dist/index.compile-check.js +22 -5
  13. package/dist/index.d.ts +12 -5
  14. package/dist/index.js +50 -0
  15. package/dist/json-schema-converter.d.ts +14 -6
  16. package/dist/json-schema-converter.js +150 -20
  17. package/dist/mcp-proxy-metadata.d.ts +2 -0
  18. package/dist/mcp-proxy-metadata.js +13 -0
  19. package/dist/mcp-proxy.d.ts +1 -0
  20. package/dist/mcp-proxy.js +65 -47
  21. package/dist/mcp-result.d.ts +3 -0
  22. package/dist/mcp-result.js +10 -0
  23. package/dist/mcp.js +211 -153
  24. package/dist/redaction.js +26 -17
  25. package/dist/renderer.js +40 -29
  26. package/dist/schema-member-names.d.ts +2 -0
  27. package/dist/schema-member-names.js +39 -0
  28. package/dist/schema-scope.d.ts +1 -0
  29. package/dist/schema-scope.js +29 -16
  30. package/dist/schema.d.ts +1 -1
  31. package/dist/sdk.d.ts +2 -1
  32. package/dist/sdk.js +164 -50
  33. package/dist/stream.js +24 -23
  34. package/dist/testing/diagnostic-value.d.ts +1 -0
  35. package/dist/testing/diagnostic-value.js +57 -0
  36. package/dist/testing/fakes.js +2 -1
  37. package/dist/testing/harness.js +1 -0
  38. package/dist/testing/memory-fs.js +42 -1
  39. package/dist/testing/parity.js +50 -6
  40. package/dist/union-validation.d.ts +5 -0
  41. package/dist/union-validation.js +36 -0
  42. package/node_modules/@poe-code/process-runner/dist/types.d.ts +2 -0
  43. package/node_modules/mcp-oauth-server/dist/index.js +47 -6
  44. package/node_modules/tiny-http-mcp-server/dist/cli.js +14 -2
  45. package/node_modules/tiny-http-mcp-server/dist/composition.json +1 -1
  46. package/node_modules/tiny-http-mcp-server/dist/http-server.d.ts +7 -5
  47. package/node_modules/tiny-http-mcp-server/dist/http-server.js +3 -11
  48. package/node_modules/tiny-http-mcp-server/dist/http-transport.d.ts +6 -1
  49. package/node_modules/tiny-http-mcp-server/dist/http-transport.js +196 -15
  50. package/node_modules/tiny-http-mcp-server/dist/index.d.ts +2 -2
  51. package/node_modules/tiny-http-mcp-server/dist/modern-headers.d.ts +3 -0
  52. package/node_modules/tiny-http-mcp-server/dist/modern-headers.js +35 -0
  53. package/node_modules/tiny-http-mcp-server/dist/parse-body.d.ts +1 -0
  54. package/node_modules/tiny-http-mcp-server/dist/parse-body.js +9 -5
  55. package/node_modules/tiny-http-mcp-server/dist/test-support.js +17 -0
  56. package/node_modules/tiny-http-mcp-server/dist/testing.d.ts +1 -1
  57. package/node_modules/tiny-http-mcp-server/dist/testing.js +3 -2
  58. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +21 -4
  59. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.d.ts +1 -1
  60. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js +14 -6
  61. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-fetch.d.ts +1 -0
  62. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-fetch.js +8 -0
  63. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-response.d.ts +1 -0
  64. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-response.js +50 -0
  65. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.d.ts +2 -0
  66. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.js +2 -0
  67. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/server/jwks-token-verifier.js +21 -3
  68. package/node_modules/tiny-http-mcp-server/package.json +1 -1
  69. package/node_modules/tiny-mcp-client/README.md +1 -0
  70. package/node_modules/tiny-mcp-client/dist/index.d.ts +178 -101
  71. package/node_modules/tiny-mcp-client/dist/index.js +4696 -291
  72. package/node_modules/tiny-mcp-client/package.json +2 -1
  73. package/node_modules/tiny-stdio-mcp-server/dist/base64.d.ts +1 -0
  74. package/node_modules/tiny-stdio-mcp-server/dist/base64.js +5 -0
  75. package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
  76. package/node_modules/tiny-stdio-mcp-server/dist/content/audio.d.ts +3 -0
  77. package/node_modules/tiny-stdio-mcp-server/dist/content/convert.d.ts +5 -1
  78. package/node_modules/tiny-stdio-mcp-server/dist/content/convert.js +41 -6
  79. package/node_modules/tiny-stdio-mcp-server/dist/content/file.d.ts +5 -0
  80. package/node_modules/tiny-stdio-mcp-server/dist/content/image.d.ts +3 -0
  81. package/node_modules/tiny-stdio-mcp-server/dist/headers.d.ts +10 -0
  82. package/node_modules/tiny-stdio-mcp-server/dist/headers.js +180 -0
  83. package/node_modules/tiny-stdio-mcp-server/dist/index.d.ts +5 -5
  84. package/node_modules/tiny-stdio-mcp-server/dist/index.js +1 -1
  85. package/node_modules/tiny-stdio-mcp-server/dist/input-request-schema.d.ts +220 -0
  86. package/node_modules/tiny-stdio-mcp-server/dist/input-request-schema.js +1995 -0
  87. package/node_modules/tiny-stdio-mcp-server/dist/jsonrpc.d.ts +1 -0
  88. package/node_modules/tiny-stdio-mcp-server/dist/jsonrpc.js +38 -25
  89. package/node_modules/tiny-stdio-mcp-server/dist/metadata.d.ts +2 -0
  90. package/node_modules/tiny-stdio-mcp-server/dist/metadata.js +37 -0
  91. package/node_modules/tiny-stdio-mcp-server/dist/protocol-validation.d.ts +4 -0
  92. package/node_modules/tiny-stdio-mcp-server/dist/protocol-validation.js +53 -0
  93. package/node_modules/tiny-stdio-mcp-server/dist/protocol.d.ts +17 -0
  94. package/node_modules/tiny-stdio-mcp-server/dist/protocol.js +228 -0
  95. package/node_modules/tiny-stdio-mcp-server/dist/request-cancellation.d.ts +1 -0
  96. package/node_modules/tiny-stdio-mcp-server/dist/request-cancellation.js +18 -0
  97. package/node_modules/tiny-stdio-mcp-server/dist/sampling-messages.d.ts +18 -0
  98. package/node_modules/tiny-stdio-mcp-server/dist/sampling-messages.js +34 -0
  99. package/node_modules/tiny-stdio-mcp-server/dist/schema.d.ts +4 -1
  100. package/node_modules/tiny-stdio-mcp-server/dist/server.d.ts +9 -4
  101. package/node_modules/tiny-stdio-mcp-server/dist/server.js +334 -135
  102. package/node_modules/tiny-stdio-mcp-server/dist/stdio-input.d.ts +3 -0
  103. package/node_modules/tiny-stdio-mcp-server/dist/stdio-input.js +50 -28
  104. package/node_modules/tiny-stdio-mcp-server/dist/subscriptions.d.ts +11 -0
  105. package/node_modules/tiny-stdio-mcp-server/dist/subscriptions.js +128 -0
  106. package/node_modules/tiny-stdio-mcp-server/dist/types.d.ts +58 -18
  107. package/node_modules/tiny-stdio-mcp-server/dist/types.js +2 -1
  108. package/node_modules/tiny-stdio-mcp-server/dist/uri.d.ts +1 -0
  109. package/node_modules/tiny-stdio-mcp-server/dist/uri.js +41 -0
  110. package/node_modules/tiny-stdio-mcp-server/package.json +8 -0
  111. package/node_modules/toolcraft-design/dist/command-registry.d.ts +11 -0
  112. package/node_modules/toolcraft-design/dist/command-registry.js +24 -0
  113. package/node_modules/toolcraft-design/dist/dashboard/ansi.d.ts +2 -0
  114. package/node_modules/toolcraft-design/dist/dashboard/ansi.js +81 -27
  115. package/node_modules/toolcraft-design/dist/dashboard/buffer.js +39 -25
  116. package/node_modules/toolcraft-design/dist/dashboard/components/border.js +6 -5
  117. package/node_modules/toolcraft-design/dist/dashboard/components/footer.js +26 -21
  118. package/node_modules/toolcraft-design/dist/dashboard/components/output-pane.d.ts +1 -1
  119. package/node_modules/toolcraft-design/dist/dashboard/components/output-pane.js +12 -6
  120. package/node_modules/toolcraft-design/dist/dashboard/components/stats-pane.d.ts +2 -1
  121. package/node_modules/toolcraft-design/dist/dashboard/components/stats-pane.js +51 -10
  122. package/node_modules/toolcraft-design/dist/dashboard/dashboard.d.ts +4 -0
  123. package/node_modules/toolcraft-design/dist/dashboard/dashboard.js +77 -4
  124. package/node_modules/toolcraft-design/dist/dashboard/index.d.ts +2 -0
  125. package/node_modules/toolcraft-design/dist/dashboard/index.js +2 -0
  126. package/node_modules/toolcraft-design/dist/dashboard/keymap.js +26 -6
  127. package/node_modules/toolcraft-design/dist/dashboard/layout.d.ts +1 -0
  128. package/node_modules/toolcraft-design/dist/dashboard/layout.js +19 -3
  129. package/node_modules/toolcraft-design/dist/dashboard/line-buffer.d.ts +9 -0
  130. package/node_modules/toolcraft-design/dist/dashboard/line-buffer.js +63 -0
  131. package/node_modules/toolcraft-design/dist/dashboard/output-preview.d.ts +9 -0
  132. package/node_modules/toolcraft-design/dist/dashboard/output-preview.js +70 -0
  133. package/node_modules/toolcraft-design/dist/dashboard/snapshot.js +3 -1
  134. package/node_modules/toolcraft-design/dist/dashboard/store.js +9 -3
  135. package/node_modules/toolcraft-design/dist/dashboard/terminal-strings.d.ts +6 -0
  136. package/node_modules/toolcraft-design/dist/dashboard/terminal-strings.js +108 -0
  137. package/node_modules/toolcraft-design/dist/dashboard/terminal-width.js +3 -1
  138. package/node_modules/toolcraft-design/dist/dashboard/terminal.js +11 -1
  139. package/node_modules/toolcraft-design/dist/dashboard/testing/pipeline-scenario.d.ts +1 -0
  140. package/node_modules/toolcraft-design/dist/dashboard/testing/pipeline-scenario.js +126 -0
  141. package/node_modules/toolcraft-design/dist/dashboard/types.d.ts +3 -1
  142. package/node_modules/toolcraft-design/dist/event-groups.d.ts +19 -0
  143. package/node_modules/toolcraft-design/dist/event-groups.js +49 -0
  144. package/node_modules/toolcraft-design/dist/index.d.ts +6 -1
  145. package/node_modules/toolcraft-design/dist/index.js +5 -1
  146. package/node_modules/toolcraft-design/dist/inline-notice.d.ts +14 -0
  147. package/node_modules/toolcraft-design/dist/inline-notice.js +28 -0
  148. package/node_modules/toolcraft-design/dist/metric.d.ts +8 -0
  149. package/node_modules/toolcraft-design/dist/metric.js +21 -0
  150. package/node_modules/toolcraft-design/dist/overlay-manager.d.ts +6 -0
  151. package/node_modules/toolcraft-design/dist/overlay-manager.js +10 -0
  152. package/node_modules/toolcraft-design/dist/primitives.d.ts +12 -0
  153. package/node_modules/toolcraft-design/dist/primitives.js +7 -0
  154. package/node_modules/toolcraft-design/dist/progress-group.d.ts +7 -0
  155. package/node_modules/toolcraft-design/dist/progress-group.js +10 -0
  156. package/node_modules/toolcraft-design/dist/render-performance.d.ts +33 -0
  157. package/node_modules/toolcraft-design/dist/render-performance.js +71 -0
  158. package/node_modules/toolcraft-design/dist/task-tree.d.ts +22 -0
  159. package/node_modules/toolcraft-design/dist/task-tree.js +79 -0
  160. package/node_modules/toolcraft-design/dist/viewport.d.ts +18 -0
  161. package/node_modules/toolcraft-design/dist/viewport.js +56 -0
  162. package/node_modules/toolcraft-schema/dist/clone-default.d.ts +1 -0
  163. package/node_modules/toolcraft-schema/dist/clone-default.js +26 -0
  164. package/node_modules/toolcraft-schema/dist/index.compile-check.js +1 -0
  165. package/node_modules/toolcraft-schema/dist/index.d.ts +18 -9
  166. package/node_modules/toolcraft-schema/dist/index.js +46 -8
  167. package/node_modules/toolcraft-schema/dist/json-schema/compiler.d.ts +1 -0
  168. package/node_modules/toolcraft-schema/dist/json-schema/compiler.js +6 -0
  169. package/node_modules/toolcraft-schema/dist/json-schema/evaluate.js +6 -3
  170. package/node_modules/toolcraft-schema/dist/json-schema/normalize-nullability.d.ts +1 -0
  171. package/node_modules/toolcraft-schema/dist/json-schema/normalize-nullability.js +69 -0
  172. package/node_modules/toolcraft-schema/dist/json-schema/types.d.ts +1 -0
  173. package/node_modules/toolcraft-schema/dist/json.d.ts +4 -1
  174. package/node_modules/toolcraft-schema/dist/json.js +57 -1
  175. package/node_modules/toolcraft-schema/dist/native-json-schema.d.ts +10 -0
  176. package/node_modules/toolcraft-schema/dist/native-json-schema.js +11 -0
  177. package/node_modules/toolcraft-schema/dist/validate.d.ts +5 -1
  178. package/node_modules/toolcraft-schema/dist/validate.js +61 -47
  179. package/node_modules/toolcraft-schema/package.json +1 -1
  180. package/package.json +6 -3
@@ -98,7 +98,7 @@
98
98
  },
99
99
  {
100
100
  "name": "tiny-http-mcp-server",
101
- "version": "0.1.17",
101
+ "version": "0.1.18",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.231",
116
+ "version": "0.0.233",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.231",
126
+ "version": "0.0.233",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -0,0 +1,9 @@
1
+ import { type AnySchema, type ObjectSchema } from "toolcraft-schema";
2
+ import type { ValidationError } from "./validation-errors.js";
3
+ export declare function resolveDiscriminatedBranch(schema: Extract<AnySchema, {
4
+ kind: "oneOf";
5
+ }>, value: unknown, discriminatorKey: string, label: string, errors: ValidationError[]): {
6
+ discriminator: string;
7
+ branch: ObjectSchema<any>;
8
+ value: Record<string, unknown>;
9
+ } | undefined;
@@ -0,0 +1,32 @@
1
+ import { isPlainRecord } from "toolcraft-schema";
2
+ export function resolveDiscriminatedBranch(schema, value, discriminatorKey, label, errors) {
3
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
4
+ errors.push({ path: label, message: `Invalid value for "${label}". Expected an object.` });
5
+ return undefined;
6
+ }
7
+ const record = value;
8
+ const fieldLabel = label.length === 0 ? discriminatorKey : `${label}.${discriminatorKey}`;
9
+ const branchNames = Object.keys(schema.branches);
10
+ const expected = branchNames.length === 0
11
+ ? "No branches are available."
12
+ : `Expected one of: ${branchNames.join(", ")}.`;
13
+ if (!Object.hasOwn(record, discriminatorKey)) {
14
+ errors.push({ path: fieldLabel, message: `Missing discriminator "${fieldLabel}". ${expected}` });
15
+ return undefined;
16
+ }
17
+ if (!isPlainRecord(record)) {
18
+ errors.push({ path: label, message: `Invalid value for "${label}". Expected an object, got non-plain object.` });
19
+ return undefined;
20
+ }
21
+ const discriminator = record[discriminatorKey];
22
+ if (typeof discriminator !== "string" || !Object.hasOwn(schema.branches, discriminator)) {
23
+ const received = typeof discriminator === "string"
24
+ ? JSON.stringify(discriminator)
25
+ : discriminator === null ? "null" : typeof discriminator;
26
+ errors.push({ path: fieldLabel, message: `Invalid discriminator "${fieldLabel}": ${received}. ${expected}` });
27
+ return undefined;
28
+ }
29
+ const { [discriminatorKey]: ignoredDiscriminator, ...branchValue } = record;
30
+ void ignoredDiscriminator;
31
+ return { discriminator, branch: schema.branches[discriminator], value: branchValue };
32
+ }
@@ -1,4 +1,5 @@
1
1
  import type { Command } from "./index.js";
2
+ import { isHttpErrorLike } from "./api-error-summary.js";
2
3
  export type ErrorReportsOption = boolean | {
3
4
  dir?: string;
4
5
  };
@@ -23,23 +24,6 @@ export interface ErrorReportRenderResult {
23
24
  content: string;
24
25
  redactedKeys: string[];
25
26
  }
26
- interface HttpErrorLike {
27
- name: "HttpError";
28
- message: string;
29
- request: {
30
- method: string;
31
- url: string;
32
- headers: Record<string, string>;
33
- body?: unknown;
34
- };
35
- response: {
36
- status: number;
37
- statusText: string;
38
- headers: Record<string, string>;
39
- body: unknown;
40
- };
41
- }
42
- declare function hasHttpContext(error: unknown): error is HttpErrorLike;
43
27
  /**
44
28
  * Renders the exact redacted content used by `writeErrorReport` without checking report enablement
45
29
  * or writing to the filesystem. `redactedKeys` lists every environment variable declared by the
@@ -47,4 +31,4 @@ declare function hasHttpContext(error: unknown): error is HttpErrorLike;
47
31
  */
48
32
  export declare function renderErrorReport(context: ErrorReportRenderContext): ErrorReportRenderResult;
49
33
  export declare function writeErrorReport(context: ErrorReportContext): Promise<ErrorReportResult | undefined>;
50
- export { hasHttpContext };
34
+ export { isHttpErrorLike as hasHttpContext };
@@ -6,7 +6,8 @@ import { CommanderError } from "commander";
6
6
  import { ApprovalDeclinedError } from "./human-in-loop/types.js";
7
7
  import { findPackageMetadata } from "./package-metadata.js";
8
8
  import { findProjectRoot } from "./project-root.js";
9
- import { isSensitiveName, redactHttpBody, redactHttpHeaderValue } from "./redaction.js";
9
+ import { isSensitiveName, redactHttpBody, redactHttpHeaderValue, redactSecretLikeFields } from "./redaction.js";
10
+ import { isHttpErrorLike } from "./api-error-summary.js";
10
11
  import { UserError } from "./user-error.js";
11
12
  const ERROR_REPORTS_ENV = "TOOLCRAFT_ERROR_REPORTS";
12
13
  function isPlainObject(value) {
@@ -18,12 +19,6 @@ function unwrapOptional(schema) {
18
19
  }
19
20
  return schema;
20
21
  }
21
- function hasHttpContext(error) {
22
- return (error instanceof Error &&
23
- error.name === "HttpError" &&
24
- isPlainObject(error.request) &&
25
- isPlainObject(error.response));
26
- }
27
22
  function isSkippedError(error) {
28
23
  if (error instanceof ApprovalDeclinedError) {
29
24
  return true;
@@ -32,7 +27,7 @@ function isSkippedError(error) {
32
27
  (error.code === "commander.helpDisplayed" || error.code === "commander.version")) {
33
28
  return true;
34
29
  }
35
- return error instanceof UserError && error.cause === undefined && !hasHttpContext(error);
30
+ return error instanceof UserError && error.cause === undefined && !isHttpErrorLike(error);
36
31
  }
37
32
  function reportsEnabled(option, env) {
38
33
  if (env[ERROR_REPORTS_ENV] === "1") {
@@ -274,9 +269,6 @@ function redactStructuredErrorField(name, value, redactString) {
274
269
  if (redactedHeaderValue !== value) {
275
270
  return redactedHeaderValue;
276
271
  }
277
- if (isSensitiveName(name)) {
278
- return "<redacted>";
279
- }
280
272
  return redactString(value);
281
273
  }
282
274
  if (Array.isArray(value)) {
@@ -297,7 +289,7 @@ function ownStructuredFields(error, redactString) {
297
289
  continue;
298
290
  }
299
291
  Object.defineProperty(fields, key, {
300
- value: redactStructuredErrorField(key, error[key], redactString),
292
+ value: redactStructuredErrorField(key, redactSecretLikeFields(error[key], key), redactString),
301
293
  enumerable: true,
302
294
  configurable: true,
303
295
  writable: true
@@ -307,10 +299,16 @@ function ownStructuredFields(error, redactString) {
307
299
  }
308
300
  function formatStackChain(error, redactString) {
309
301
  const lines = [];
302
+ const seen = new Set();
310
303
  let current = error;
311
304
  let index = 0;
312
305
  while (current !== undefined) {
313
306
  if (current instanceof Error) {
307
+ if (seen.has(current)) {
308
+ lines.push("Caused by: [Circular]");
309
+ break;
310
+ }
311
+ seen.add(current);
314
312
  const stack = current.stack ?? String(current);
315
313
  lines.push(redactString(index === 0 ? stack : `Caused by: ${stack}`));
316
314
  current = current.cause;
@@ -405,7 +403,7 @@ function buildReport(context) {
405
403
  "Stack",
406
404
  formatStackChain(error, redactString)
407
405
  ];
408
- if (hasHttpContext(error)) {
406
+ if (isHttpErrorLike(error)) {
409
407
  lines.push("", "HTTP Transcript", formatHttpTranscript(error, redactString));
410
408
  }
411
409
  return `${lines.join("\n")}\n`;
@@ -440,4 +438,4 @@ export async function writeErrorReport(context) {
440
438
  displayPath: relativeDisplayPath(projectRoot, absolutePath)
441
439
  };
442
440
  }
443
- export { hasHttpContext };
441
+ export { isHttpErrorLike as hasHttpContext };
package/dist/http.js CHANGED
@@ -46,19 +46,24 @@ function createTransportOptions(options, serverOptions) {
46
46
  return {
47
47
  ...serverOptions,
48
48
  toolCallTimeoutMs: options.toolCallTimeoutMs,
49
- sessionIdGenerator: options.sessionIdGenerator,
49
+ ...(Object.prototype.hasOwnProperty.call(options, "sessionIdGenerator")
50
+ ? { sessionIdGenerator: options.sessionIdGenerator }
51
+ : {}),
50
52
  enableJsonResponse: options.enableJsonResponse,
51
53
  allowedOrigins: options.allowedOrigins,
52
54
  allowedHosts: options.allowedHosts,
53
55
  maxRequestBytes: options.maxRequestBytes,
56
+ maxResponseBytes: options.maxResponseBytes,
54
57
  maxBatchSize: options.maxBatchSize,
55
58
  maxSessions: options.maxSessions,
59
+ maxSessionsPerSubject: options.maxSessionsPerSubject,
56
60
  sessionTtlMs: options.sessionTtlMs,
57
61
  maxStreamsPerSession: options.maxStreamsPerSession,
58
62
  maxStreamBufferBytes: options.maxStreamBufferBytes,
59
63
  maxSseEventHistory: options.maxSseEventHistory,
60
64
  sseKeepAliveMs: options.sseKeepAliveMs,
61
65
  maxConcurrentToolCalls: options.maxConcurrentToolCalls,
66
+ maxQueuedToolCalls: options.maxQueuedToolCalls,
62
67
  sessionStore: options.sessionStore,
63
68
  requestIdGenerator: options.requestIdGenerator,
64
69
  observability: options.observability,
@@ -111,6 +116,8 @@ export async function createHTTPMCPServer(roots, options) {
111
116
  }
112
117
  let server;
113
118
  await createMCPServerForTransport(roots, resolvedOptions, {
119
+ supportsStreaming: !Object.prototype.hasOwnProperty.call(resolvedOptions, "sessionIdGenerator") ||
120
+ resolvedOptions.sessionIdGenerator !== undefined,
114
121
  createServer(serverOptions) {
115
122
  server = createHttpServer(createTransportOptions(resolvedOptions, serverOptions));
116
123
  return server;
@@ -3,6 +3,7 @@ import { spawnApprovalRunner } from "./spawn.js";
3
3
  import { ApprovalDeclinedError } from "./types.js";
4
4
  import { assertApprovalPlanHash, createApprovalPlan, formatApprovalMessage } from "./plan-hash.js";
5
5
  export async function invokeWithHumanInLoop(node, ctx, runtimeOptions, commandPath, options = {}) {
6
+ ctx.signal?.throwIfAborted();
6
7
  if (!node.humanInLoop) {
7
8
  return node.handler(ctx);
8
9
  }
@@ -14,11 +15,13 @@ export async function invokeWithHumanInLoop(node, ctx, runtimeOptions, commandPa
14
15
  const approvalPlan = node.humanInLoop.plan === undefined
15
16
  ? undefined
16
17
  : createApprovalPlan(await node.humanInLoop.plan(planContext));
18
+ ctx.signal?.throwIfAborted();
17
19
  const message = approvalPlan === undefined
18
20
  ? baseMessage
19
21
  : formatApprovalMessage(baseMessage, approvalPlan);
20
22
  if (node.humanInLoop.mode === "async") {
21
23
  const { tasks } = await ensureApprovalList(runtimeOptions);
24
+ ctx.signal?.throwIfAborted();
22
25
  const { approvalId, pending } = await (options.enqueueApproval ?? enqueueApproval)({
23
26
  tasks,
24
27
  payload: {
@@ -30,6 +33,7 @@ export async function invokeWithHumanInLoop(node, ctx, runtimeOptions, commandPa
30
33
  declineInputPrompt: node.humanInLoop.declineInputPrompt
31
34
  }
32
35
  });
36
+ ctx.signal?.throwIfAborted();
33
37
  if (options.spawnRunner !== false) {
34
38
  spawnApprovalRunner(approvalId, runtimeOptions);
35
39
  }
@@ -39,6 +43,7 @@ export async function invokeWithHumanInLoop(node, ctx, runtimeOptions, commandPa
39
43
  message,
40
44
  declineInputPrompt: node.humanInLoop.declineInputPrompt
41
45
  });
46
+ ctx.signal?.throwIfAborted();
42
47
  if (result.outcome === "declined") {
43
48
  throw new ApprovalDeclinedError({
44
49
  reason: result.reason,
@@ -47,6 +52,7 @@ export async function invokeWithHumanInLoop(node, ctx, runtimeOptions, commandPa
47
52
  }
48
53
  if (approvalPlan !== undefined && node.humanInLoop.plan !== undefined) {
49
54
  const executionPlan = createApprovalPlan(await node.humanInLoop.plan(planContext));
55
+ ctx.signal?.throwIfAborted();
50
56
  assertApprovalPlanHash(approvalPlan.hash, executionPlan.hash);
51
57
  }
52
58
  return node.handler(ctx);
@@ -1,6 +1,24 @@
1
1
  import { S } from "toolcraft-schema";
2
- import { defineCommand, defineGroup } from "./index.js";
2
+ import { asMCPResult, cloneCommandNode, defineCommand, defineGroup } from "./index.js";
3
3
  import { createFileChangeRenderers } from "./file-change-renderer.js";
4
+ import { validate as validateSchema } from "./schema.js";
5
+ const ignoredValidationOptions = { defaults: "none" };
6
+ const ignoredWithoutDefaults = validateSchema(S.Object({ count: S.Optional(S.Number({ default: 2 })) }), {}, ignoredValidationOptions);
7
+ const ignoredMCPResult = asMCPResult({
8
+ content: [{ type: "text", text: "upstream message" }],
9
+ structuredContent: { id: "one" },
10
+ _meta: { trace: "request" }
11
+ });
12
+ const ignoredMCPResultCommand = defineCommand({
13
+ name: "upstream",
14
+ params: S.Object({}),
15
+ handler: () => ignoredMCPResult,
16
+ render: { json: (result) => ({ id: result.structuredContent.id, trace: result._meta.trace }) }
17
+ });
18
+ const ignoredClonedCommand = cloneCommandNode(ignoredMCPResultCommand);
19
+ const ignoredExtendedCommand = { ...ignoredMCPResultCommand, extraRuntimeState: 1 };
20
+ const ignoredClonedDefinition = cloneCommandNode(ignoredExtendedCommand);
21
+ const ignoredScopeOverrideClone = cloneCommandNode(ignoredMCPResultCommand, ["cli"]);
4
22
  const ignoredScope = ["cli", "sdk"];
5
23
  const ignoredSecrets = {
6
24
  apiKey: { env: "API_KEY" },
@@ -54,11 +72,10 @@ defineCommand({
54
72
  handler: async () => [],
55
73
  });
56
74
  defineCommand({
57
- name: "invalid-scalar-mapped-result",
75
+ name: "scalar-mapped-result",
58
76
  params: S.Object({}),
59
- result: S.Object({ data: S.Array(S.String()) }),
60
- // @ts-expect-error MCP structured results must have an object root
61
- mcpResult: () => "invalid",
77
+ result: S.String(),
78
+ mcpResult: () => "ready",
62
79
  handler: async () => [],
63
80
  });
64
81
  const ignoredGroup = defineGroup({
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ type ScopeInput = readonly Scope[] | undefined;
15
15
  type HumanInLoopMode = "sync" | "async";
16
16
  type HumanInLoopModeInput = HumanInLoopMode | null | undefined;
17
17
  export type Scope = ScopeValue;
18
+ export type MCPResultValue = Record<string, unknown> | readonly unknown[] | string | number | boolean | null;
18
19
  type ResolveOwnHumanInLoopMode<TValue> = TValue extends {
19
20
  mode: infer TMode extends HumanInLoopMode;
20
21
  } ? TMode : TValue extends null ? null : undefined;
@@ -74,6 +75,7 @@ export type GroupCheckContext<TServices extends object = EmptyServices> = TServi
74
75
  fs: HandlerFs;
75
76
  env: HandlerEnv;
76
77
  diagnostics: RuntimeLogger;
78
+ signal?: AbortSignal;
77
79
  progress(message: string): void;
78
80
  };
79
81
  export type CommandCheckContext<TParamsSchema extends ObjectSchema<any> = AnyObjectSchema, TSecrets extends SecretDeclarations | undefined = undefined, TServices extends object = EmptyServices> = TServices & {
@@ -122,8 +124,8 @@ export interface CommandConfig<TServices extends object, TParamsSchema extends O
122
124
  aliases?: string[];
123
125
  positional?: string[];
124
126
  params: TParamsSchema;
125
- result?: ObjectSchema<any>;
126
- mcpResult?: (result: TResult) => Record<string, unknown>;
127
+ result?: AnySchema;
128
+ mcpResult?: (result: TResult) => MCPResultValue;
127
129
  secrets?: TSecrets;
128
130
  scope?: Scope[];
129
131
  confirm?: boolean;
@@ -157,8 +159,8 @@ export interface Command<TServices extends object = EmptyServices, TParamsSchema
157
159
  aliases: string[];
158
160
  positional: string[];
159
161
  params: TParamsSchema;
160
- result?: ObjectSchema<any>;
161
- mcpResult?: (result: TResult) => Record<string, unknown>;
162
+ result?: AnySchema;
163
+ mcpResult?: (result: TResult) => MCPResultValue;
162
164
  stream?: StreamDefinition<any>;
163
165
  secrets: SecretDeclarations;
164
166
  scope: Scope[];
@@ -236,6 +238,9 @@ export declare function defineGroup<TServices extends object = EmptyServices, TN
236
238
  scope?: TOwnScope;
237
239
  humanInLoop?: TOwnHumanInLoop;
238
240
  }): Group<TServices> & TypedGroupMetadata<TServices, TName, TChildren, TOwnScope, ResolveOwnHumanInLoopMode<TOwnHumanInLoop>>;
241
+ export type ClonedCommandNode<TNode extends CommandNode<any>> = TNode extends Command<infer TServices, infer TParams, infer TSecrets, infer TResult> ? Command<TServices, TParams, TSecrets, TResult> & Pick<TNode, Extract<keyof TNode, "__agentKitCommandTypeInfo">> : TNode extends Group<infer TServices> ? Group<TServices> & Pick<TNode, Extract<keyof TNode, "__agentKitGroupTypeInfo">> : never;
242
+ export declare function cloneCommandNode<TNode extends CommandNode<any>>(node: TNode): ClonedCommandNode<TNode>;
243
+ export declare function cloneCommandNode<TServices extends object>(node: CommandNode<TServices>, scopeOverride: Scope[]): CommandNode<TServices>;
239
244
  export declare function getCommandSourcePath(command: Command<any, any, any, any>): string | undefined;
240
245
  export declare function hasMcpProxyConfig(group: Group<any>): boolean;
241
246
  export { S, toJsonSchema } from "./schema.js";
@@ -244,10 +249,12 @@ export type { HttpErrorRequest, HttpErrorResponse } from "./http-errors.js";
244
249
  export { ApprovalDeclinedError, ToolcraftBugError, UserError, isUserError };
245
250
  export { suggest } from "./suggest.js";
246
251
  export { createRuntimeLogger, isLogLevel, shouldEmitDiagnostic } from "./runtime-logging.js";
252
+ export { isSensitiveName, redactHttpBody } from "./redaction.js";
247
253
  export { findPackageMetadata, packageMetadata } from "./package-metadata.js";
254
+ export { asMCPResult } from "./mcp-result.js";
248
255
  export type { PackageMetadata } from "./package-metadata.js";
249
256
  export type { FileChangeRendererOptions, FileChangeResult } from "./file-change-renderer.js";
250
257
  export type { FileChange, FileChangeDisplayMode, FileChangeKind } from "toolcraft-design";
251
258
  export type { DiagnosticLogEvent, LogLevel, RuntimeLogger, RuntimeLoggerInput } from "./runtime-logging.js";
252
- export type { AnySchema, ArraySchema, BooleanSchema, CliMissingParameterChoice, CliMissingParameterContext, CliMissingParameterResolution, CliOutputMode, CliSchemaOptions, EnumSchema, JsonSchema, JsonSchemaDocument, JsonSchemaDocumentOptions, JsonValue, JsonValueSchema, NumberSchema, ObjectSchema, OneOfSchema, OptionalSchema, RecordSchema, SchemaBase, Static, StringSchema, UnionSchema, ValidationIssue, ValidationResult } from "./schema.js";
259
+ export type { AnySchema, ArraySchema, BooleanSchema, CliMissingParameterChoice, CliMissingParameterContext, CliMissingParameterResolution, CliOutputMode, CliSchemaOptions, EnumSchema, JsonSchema, JsonSchemaDocument, JsonSchemaDocumentOptions, JsonValue, JsonValueSchema, NumberSchema, ObjectSchema, OneOfSchema, OptionalSchema, RecordSchema, SchemaBase, Static, StringSchema, UnionSchema, ValidationIssue, ValidationOptions, ValidationResult } from "./schema.js";
253
260
  export type { HumanInLoopConfig, HumanInLoopPending, HumanInLoopRuntime };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { ApprovalDeclinedError } from "./human-in-loop/types.js";
3
3
  import { mergeHumanInLoopFromGroup, validateHumanInLoopOnDefine } from "./human-in-loop/config.js";
4
4
  import { ToolcraftBugError, UserError, isUserError } from "./user-error.js";
5
5
  import { suggest } from "./suggest.js";
6
+ import { isProxyNode } from "./mcp-proxy-metadata.js";
6
7
  export { createManagedStream } from "./stream.js";
7
8
  const commandConfigSymbol = Symbol("toolcraft.command.config");
8
9
  const groupConfigSymbol = Symbol("toolcraft.group.config");
@@ -502,6 +503,53 @@ export function defineGroup(config) {
502
503
  requires: undefined
503
504
  });
504
505
  }
506
+ export function cloneCommandNode(node, scopeOverride) {
507
+ function rebuildNode(current, root, withinProxy) {
508
+ const description = current.kind === "command"
509
+ ? commandConfigSymbol.description
510
+ : groupConfigSymbol.description;
511
+ const symbol = Object.getOwnPropertySymbols(current).find((candidate) => candidate.description === description);
512
+ const config = symbol === undefined ? undefined : Reflect.get(current, symbol);
513
+ const inherited = root || config === undefined ? current : config;
514
+ const metadata = {
515
+ scope: scopeOverride ?? inherited.scope,
516
+ humanInLoop: inherited.humanInLoop,
517
+ secrets: inherited.secrets,
518
+ requires: inherited.requires
519
+ };
520
+ if (current.kind === "command") {
521
+ const base = createBaseCommand({ ...current, ...metadata });
522
+ if (config !== undefined) {
523
+ getInternalCommandConfig(base).sourcePath = config.sourcePath;
524
+ }
525
+ base.stream = current.stream === undefined ? undefined : { ...current.stream };
526
+ return base;
527
+ }
528
+ const groupConfig = config;
529
+ const proxyChildren = withinProxy || groupConfig?.mcp !== undefined;
530
+ const sourceChildren = current.children.filter((child) => !proxyChildren || !isProxyNode(child));
531
+ const children = sourceChildren.map((child) => rebuildNode(child, false, proxyChildren));
532
+ const defaultIndex = current.default === undefined ? -1 : sourceChildren.indexOf(current.default);
533
+ if (current.default !== undefined && defaultIndex === -1) {
534
+ throw new ToolcraftBugError(`Default command "${current.default.name}" must be listed in children.`);
535
+ }
536
+ return createBaseGroup({
537
+ ...current,
538
+ ...metadata,
539
+ mcp: groupConfig?.mcp,
540
+ tools: groupConfig?.tools,
541
+ rename: groupConfig?.rename,
542
+ children,
543
+ default: defaultIndex === -1 ? undefined : children[defaultIndex]
544
+ });
545
+ }
546
+ return materializeNode(rebuildNode(node, true, false), {
547
+ scope: undefined,
548
+ humanInLoop: undefined,
549
+ secrets: {},
550
+ requires: undefined
551
+ });
552
+ }
505
553
  export function getCommandSourcePath(command) {
506
554
  return command[commandSourcePathSymbol];
507
555
  }
@@ -521,4 +569,6 @@ export { AuthenticationError, BadRequestError, ClientError, ConflictError, HttpE
521
569
  export { ApprovalDeclinedError, ToolcraftBugError, UserError, isUserError };
522
570
  export { suggest } from "./suggest.js";
523
571
  export { createRuntimeLogger, isLogLevel, shouldEmitDiagnostic } from "./runtime-logging.js";
572
+ export { isSensitiveName, redactHttpBody } from "./redaction.js";
524
573
  export { findPackageMetadata, packageMetadata } from "./package-metadata.js";
574
+ export { asMCPResult } from "./mcp-result.js";
@@ -1,20 +1,28 @@
1
1
  import type { AnySchema } from "toolcraft-schema";
2
2
  type JsonSchemaType = "string" | "number" | "integer" | "boolean" | "array" | "object" | "null";
3
+ type JsonSchemaNode = JsonSchema | boolean;
3
4
  export interface JsonSchema {
4
- $defs?: Record<string, JsonSchema>;
5
+ [keyword: string]: unknown;
6
+ $defs?: Record<string, JsonSchemaNode>;
5
7
  $ref?: string;
6
8
  additionalProperties?: boolean | JsonSchema;
7
- allOf?: readonly JsonSchema[];
8
- anyOf?: readonly JsonSchema[];
9
+ allOf?: readonly JsonSchemaNode[];
10
+ anyOf?: readonly JsonSchemaNode[];
9
11
  const?: unknown;
10
12
  default?: unknown;
11
13
  description?: string;
12
14
  enum?: readonly unknown[];
13
- items?: JsonSchema;
15
+ items?: JsonSchemaNode | readonly JsonSchemaNode[];
16
+ minLength?: number;
17
+ maxLength?: number;
18
+ minimum?: number;
19
+ maximum?: number;
20
+ minItems?: number;
21
+ maxItems?: number;
14
22
  nullable?: boolean;
15
- oneOf?: readonly JsonSchema[];
23
+ oneOf?: readonly JsonSchemaNode[];
16
24
  pattern?: string;
17
- properties?: Record<string, JsonSchema>;
25
+ properties?: Record<string, JsonSchemaNode>;
18
26
  required?: readonly string[];
19
27
  type?: JsonSchemaType | readonly JsonSchemaType[];
20
28
  }