@ai-agent-forge/plugin-test-runner 0.85.5 → 0.85.7

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/agent-forge.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "packageFormatVersion": 1,
3
3
  "id": "agent-forge.plugin.test-runner",
4
- "pluginVersion": "0.85.5",
4
+ "pluginVersion": "0.85.7",
5
5
  "apiVersion": "1",
6
6
  "minHostVersion": "0.84.4",
7
7
  "capabilityRefs": [
@@ -1 +1 @@
1
- {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAI3E,OAAO,KAAK,EAAE,mBAAmB,EAAmB,MAAM,YAAY,CAAC;AAiGvE,yEAAyE;AACzE,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,mBAAmB,GAAG,2BAA2B,CAsD7G","sourcesContent":["import type { CapabilityPluginSyncFactory } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport { projectTestRunResultV1, TEST_RUNNER_MAX_OPAQUE_REF_CHARS_V1 } from \"./node-adapter.ts\";\nimport type { TestRunnerAdapterV1, TestRunResultV1 } from \"./types.ts\";\n\nconst requestSchema = Type.Object(\n\t{\n\t\tworkspaceRef: Type.String({\n\t\t\tminLength: 1,\n\t\t\tmaxLength: TEST_RUNNER_MAX_OPAQUE_REF_CHARS_V1,\n\t\t\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n\t\t}),\n\t\tframework: Type.Union([\n\t\t\tType.Literal(\"vitest\"),\n\t\t\tType.Literal(\"jest\"),\n\t\t\tType.Literal(\"node-test\"),\n\t\t\tType.Literal(\"pytest\"),\n\t\t]),\n\t\ttarget: Type.String({ minLength: 1, maxLength: 1024, pattern: \"^[^\\\\u0000\\\\r\\\\n]+$\" }),\n\t\ttimeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: 120_000 })),\n\t\tmaxFailures: Type.Optional(Type.Integer({ minimum: 1, maximum: 1_000 })),\n\t},\n\t{ additionalProperties: false },\n);\nconst inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\tconst value = second === undefined ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(\"Test runner input must be an object\");\n\treturn value as Record<string, unknown>;\n}\n\nfunction invocation(\n\tfirst: unknown,\n\tsecond: unknown,\n): { readonly input: Record<string, unknown>; readonly operationId: string } {\n\tconst candidate = typeof first === \"string\" && first.trim() !== \"\" ? first : \"profile-runtime-tool-call\";\n\treturn {\n\t\tinput: objectInput(first, second),\n\t\toperationId: candidate.length <= 256 ? candidate : \"profile-runtime-tool-call\",\n\t};\n}\n\nfunction signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nfunction adapterFailure(operationId: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"adapter_failed\", message: \"Test runner adapter returned an invalid result\" },\n\t};\n}\n\nfunction invalidInput(operationId: string, message: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"invalid_input\", message },\n\t};\n}\n\nfunction cancelled(operationId: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"cancelled\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"cancelled\", message: \"Test run was cancelled\" },\n\t};\n}\n\nconst CANCELLATION_V1 = Symbol(\"test-runner-capability-cancelled\");\n\nfunction runWithCancellation(\n\trun: () => Promise<TestRunResultV1>,\n\tsignal: AbortSignal | undefined,\n): Promise<TestRunResultV1 | typeof CANCELLATION_V1> {\n\tif (signal === undefined) return run();\n\tlet onAbort!: () => void;\n\tconst cancellation = new Promise<typeof CANCELLATION_V1>((resolve) => {\n\t\tonAbort = () => resolve(CANCELLATION_V1);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n\tconst pending = run();\n\treturn Promise.race([pending, cancellation]).finally(() => signal.removeEventListener(\"abort\", onAbort));\n}\n\n/** Registers the bounded test operation only for a full-control host. */\nexport function createTestRunnerCapabilityFactoryV1(runtime: TestRunnerAdapterV1): CapabilityPluginSyncFactory {\n\treturn (api) => {\n\t\tif (api.host.mode === \"readonly\") return;\n\t\tapi.registerTool({\n\t\t\tname: \"test_run\",\n\t\t\tlabel: \"Run tests\",\n\t\t\tdescription: \"Run a host-resolved test target and return bounded structured test results\",\n\t\t\tparameters: inputSchema,\n\t\t\texecute: async (first: unknown, second?: unknown, third?: unknown) => {\n\t\t\t\tlet invocationResult: { readonly input: Record<string, unknown>; readonly operationId: string };\n\t\t\t\ttry {\n\t\t\t\t\tinvocationResult = invocation(first, second);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(\"profile-runtime-tool-call\", \"Test runner input must be an object\");\n\t\t\t\t}\n\t\t\t\tconst { input, operationId } = invocationResult;\n\t\t\t\tconst signal = signalFrom(third);\n\t\t\t\tif (signal?.aborted) return cancelled(operationId);\n\t\t\t\tlet requestInput: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tif (!Value.Check(inputSchema, input)) return invalidInput(operationId, \"Test runner request is invalid\");\n\t\t\t\t\trequestInput = objectInput(input.request, undefined);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(operationId, \"Test runner request is invalid\");\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await runWithCancellation(\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\truntime.run(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\t\t\toperationId,\n\t\t\t\t\t\t\t\t\tworkspaceRef: requestInput.workspaceRef as string,\n\t\t\t\t\t\t\t\t\tframework: requestInput.framework as \"vitest\" | \"jest\" | \"node-test\" | \"pytest\",\n\t\t\t\t\t\t\t\t\ttarget: requestInput.target as string,\n\t\t\t\t\t\t\t\t\t...(requestInput.timeoutMs === undefined\n\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t: { timeoutMs: requestInput.timeoutMs as number }),\n\t\t\t\t\t\t\t\t\t...(requestInput.maxFailures === undefined\n\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t: { maxFailures: requestInput.maxFailures as number }),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t);\n\t\t\t\t\tif (output === CANCELLATION_V1) return cancelled(operationId);\n\t\t\t\t\treturn projectTestRunResultV1(output, operationId) ?? adapterFailure(operationId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn adapterFailure(operationId);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n"]}
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAI3E,OAAO,KAAK,EAAE,mBAAmB,EAAmB,MAAM,YAAY,CAAC;AAqGvE,yEAAyE;AACzE,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,mBAAmB,GAAG,2BAA2B,CAsD7G","sourcesContent":["import type { CapabilityPluginSyncFactory } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport { projectTestRunResultV1, TEST_RUNNER_MAX_OPAQUE_REF_CHARS_V1 } from \"./node-adapter.ts\";\nimport type { TestRunnerAdapterV1, TestRunResultV1 } from \"./types.ts\";\n\nconst requestSchema = Type.Object(\n\t{\n\t\tworkspaceRef: Type.String({\n\t\t\tminLength: 1,\n\t\t\tmaxLength: TEST_RUNNER_MAX_OPAQUE_REF_CHARS_V1,\n\t\t\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n\t\t}),\n\t\tframework: Type.Union([\n\t\t\tType.Literal(\"vitest\"),\n\t\t\tType.Literal(\"jest\"),\n\t\t\tType.Literal(\"node-test\"),\n\t\t\tType.Literal(\"pytest\"),\n\t\t]),\n\t\ttarget: Type.String({ minLength: 1, maxLength: 1024, pattern: \"^[^\\\\u0000\\\\r\\\\n]+$\" }),\n\t\ttimeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: 120_000 })),\n\t\tmaxFailures: Type.Optional(Type.Integer({ minimum: 1, maximum: 1_000 })),\n\t},\n\t{ additionalProperties: false },\n);\nconst inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\t// Shape-based dual-convention read (aligned with subagent-delegate): the\n\t// runtime invoke face passes the input object first and the host\n\t// CapabilityToolContext second; the agent tool face passes the tool call\n\t// id (a string) first and the params object second.\n\tconst value = first !== null && typeof first === \"object\" && !Array.isArray(first) ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(\"Test runner input must be an object\");\n\treturn value as Record<string, unknown>;\n}\n\nfunction invocation(\n\tfirst: unknown,\n\tsecond: unknown,\n): { readonly input: Record<string, unknown>; readonly operationId: string } {\n\tconst candidate = typeof first === \"string\" && first.trim() !== \"\" ? first : \"profile-runtime-tool-call\";\n\treturn {\n\t\tinput: objectInput(first, second),\n\t\toperationId: candidate.length <= 256 ? candidate : \"profile-runtime-tool-call\",\n\t};\n}\n\nfunction signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nfunction adapterFailure(operationId: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"adapter_failed\", message: \"Test runner adapter returned an invalid result\" },\n\t};\n}\n\nfunction invalidInput(operationId: string, message: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"invalid_input\", message },\n\t};\n}\n\nfunction cancelled(operationId: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"cancelled\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"cancelled\", message: \"Test run was cancelled\" },\n\t};\n}\n\nconst CANCELLATION_V1 = Symbol(\"test-runner-capability-cancelled\");\n\nfunction runWithCancellation(\n\trun: () => Promise<TestRunResultV1>,\n\tsignal: AbortSignal | undefined,\n): Promise<TestRunResultV1 | typeof CANCELLATION_V1> {\n\tif (signal === undefined) return run();\n\tlet onAbort!: () => void;\n\tconst cancellation = new Promise<typeof CANCELLATION_V1>((resolve) => {\n\t\tonAbort = () => resolve(CANCELLATION_V1);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n\tconst pending = run();\n\treturn Promise.race([pending, cancellation]).finally(() => signal.removeEventListener(\"abort\", onAbort));\n}\n\n/** Registers the bounded test operation only for a full-control host. */\nexport function createTestRunnerCapabilityFactoryV1(runtime: TestRunnerAdapterV1): CapabilityPluginSyncFactory {\n\treturn (api) => {\n\t\tif (api.host.mode === \"readonly\") return;\n\t\tapi.registerTool({\n\t\t\tname: \"test_run\",\n\t\t\tlabel: \"Run tests\",\n\t\t\tdescription: \"Run a host-resolved test target and return bounded structured test results\",\n\t\t\tparameters: inputSchema,\n\t\t\texecute: async (first: unknown, second?: unknown, third?: unknown) => {\n\t\t\t\tlet invocationResult: { readonly input: Record<string, unknown>; readonly operationId: string };\n\t\t\t\ttry {\n\t\t\t\t\tinvocationResult = invocation(first, second);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(\"profile-runtime-tool-call\", \"Test runner input must be an object\");\n\t\t\t\t}\n\t\t\t\tconst { input, operationId } = invocationResult;\n\t\t\t\tconst signal = signalFrom(third);\n\t\t\t\tif (signal?.aborted) return cancelled(operationId);\n\t\t\t\tlet requestInput: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tif (!Value.Check(inputSchema, input)) return invalidInput(operationId, \"Test runner request is invalid\");\n\t\t\t\t\trequestInput = objectInput(input.request, undefined);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(operationId, \"Test runner request is invalid\");\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await runWithCancellation(\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\truntime.run(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\t\t\toperationId,\n\t\t\t\t\t\t\t\t\tworkspaceRef: requestInput.workspaceRef as string,\n\t\t\t\t\t\t\t\t\tframework: requestInput.framework as \"vitest\" | \"jest\" | \"node-test\" | \"pytest\",\n\t\t\t\t\t\t\t\t\ttarget: requestInput.target as string,\n\t\t\t\t\t\t\t\t\t...(requestInput.timeoutMs === undefined\n\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t: { timeoutMs: requestInput.timeoutMs as number }),\n\t\t\t\t\t\t\t\t\t...(requestInput.maxFailures === undefined\n\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t: { maxFailures: requestInput.maxFailures as number }),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t);\n\t\t\t\t\tif (output === CANCELLATION_V1) return cancelled(operationId);\n\t\t\t\t\treturn projectTestRunResultV1(output, operationId) ?? adapterFailure(operationId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn adapterFailure(operationId);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n"]}
@@ -19,7 +19,11 @@ const requestSchema = Type.Object({
19
19
  }, { additionalProperties: false });
20
20
  const inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });
21
21
  function objectInput(first, second) {
22
- const value = second === undefined ? first : second;
22
+ // Shape-based dual-convention read (aligned with subagent-delegate): the
23
+ // runtime invoke face passes the input object first and the host
24
+ // CapabilityToolContext second; the agent tool face passes the tool call
25
+ // id (a string) first and the params object second.
26
+ const value = first !== null && typeof first === "object" && !Array.isArray(first) ? first : second;
23
27
  if (value === null || typeof value !== "object" || Array.isArray(value))
24
28
  throw new Error("Test runner input must be an object");
25
29
  return value;
@@ -1 +1 @@
1
- {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CapabilityPluginSyncFactory } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport { projectTestRunResultV1, TEST_RUNNER_MAX_OPAQUE_REF_CHARS_V1 } from \"./node-adapter.ts\";\nimport type { TestRunnerAdapterV1, TestRunResultV1 } from \"./types.ts\";\n\nconst requestSchema = Type.Object(\n\t{\n\t\tworkspaceRef: Type.String({\n\t\t\tminLength: 1,\n\t\t\tmaxLength: TEST_RUNNER_MAX_OPAQUE_REF_CHARS_V1,\n\t\t\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n\t\t}),\n\t\tframework: Type.Union([\n\t\t\tType.Literal(\"vitest\"),\n\t\t\tType.Literal(\"jest\"),\n\t\t\tType.Literal(\"node-test\"),\n\t\t\tType.Literal(\"pytest\"),\n\t\t]),\n\t\ttarget: Type.String({ minLength: 1, maxLength: 1024, pattern: \"^[^\\\\u0000\\\\r\\\\n]+$\" }),\n\t\ttimeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: 120_000 })),\n\t\tmaxFailures: Type.Optional(Type.Integer({ minimum: 1, maximum: 1_000 })),\n\t},\n\t{ additionalProperties: false },\n);\nconst inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\tconst value = second === undefined ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(\"Test runner input must be an object\");\n\treturn value as Record<string, unknown>;\n}\n\nfunction invocation(\n\tfirst: unknown,\n\tsecond: unknown,\n): { readonly input: Record<string, unknown>; readonly operationId: string } {\n\tconst candidate = typeof first === \"string\" && first.trim() !== \"\" ? first : \"profile-runtime-tool-call\";\n\treturn {\n\t\tinput: objectInput(first, second),\n\t\toperationId: candidate.length <= 256 ? candidate : \"profile-runtime-tool-call\",\n\t};\n}\n\nfunction signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nfunction adapterFailure(operationId: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"adapter_failed\", message: \"Test runner adapter returned an invalid result\" },\n\t};\n}\n\nfunction invalidInput(operationId: string, message: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"invalid_input\", message },\n\t};\n}\n\nfunction cancelled(operationId: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"cancelled\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"cancelled\", message: \"Test run was cancelled\" },\n\t};\n}\n\nconst CANCELLATION_V1 = Symbol(\"test-runner-capability-cancelled\");\n\nfunction runWithCancellation(\n\trun: () => Promise<TestRunResultV1>,\n\tsignal: AbortSignal | undefined,\n): Promise<TestRunResultV1 | typeof CANCELLATION_V1> {\n\tif (signal === undefined) return run();\n\tlet onAbort!: () => void;\n\tconst cancellation = new Promise<typeof CANCELLATION_V1>((resolve) => {\n\t\tonAbort = () => resolve(CANCELLATION_V1);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n\tconst pending = run();\n\treturn Promise.race([pending, cancellation]).finally(() => signal.removeEventListener(\"abort\", onAbort));\n}\n\n/** Registers the bounded test operation only for a full-control host. */\nexport function createTestRunnerCapabilityFactoryV1(runtime: TestRunnerAdapterV1): CapabilityPluginSyncFactory {\n\treturn (api) => {\n\t\tif (api.host.mode === \"readonly\") return;\n\t\tapi.registerTool({\n\t\t\tname: \"test_run\",\n\t\t\tlabel: \"Run tests\",\n\t\t\tdescription: \"Run a host-resolved test target and return bounded structured test results\",\n\t\t\tparameters: inputSchema,\n\t\t\texecute: async (first: unknown, second?: unknown, third?: unknown) => {\n\t\t\t\tlet invocationResult: { readonly input: Record<string, unknown>; readonly operationId: string };\n\t\t\t\ttry {\n\t\t\t\t\tinvocationResult = invocation(first, second);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(\"profile-runtime-tool-call\", \"Test runner input must be an object\");\n\t\t\t\t}\n\t\t\t\tconst { input, operationId } = invocationResult;\n\t\t\t\tconst signal = signalFrom(third);\n\t\t\t\tif (signal?.aborted) return cancelled(operationId);\n\t\t\t\tlet requestInput: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tif (!Value.Check(inputSchema, input)) return invalidInput(operationId, \"Test runner request is invalid\");\n\t\t\t\t\trequestInput = objectInput(input.request, undefined);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(operationId, \"Test runner request is invalid\");\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await runWithCancellation(\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\truntime.run(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\t\t\toperationId,\n\t\t\t\t\t\t\t\t\tworkspaceRef: requestInput.workspaceRef as string,\n\t\t\t\t\t\t\t\t\tframework: requestInput.framework as \"vitest\" | \"jest\" | \"node-test\" | \"pytest\",\n\t\t\t\t\t\t\t\t\ttarget: requestInput.target as string,\n\t\t\t\t\t\t\t\t\t...(requestInput.timeoutMs === undefined\n\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t: { timeoutMs: requestInput.timeoutMs as number }),\n\t\t\t\t\t\t\t\t\t...(requestInput.maxFailures === undefined\n\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t: { maxFailures: requestInput.maxFailures as number }),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t);\n\t\t\t\t\tif (output === CANCELLATION_V1) return cancelled(operationId);\n\t\t\t\t\treturn projectTestRunResultV1(output, operationId) ?? adapterFailure(operationId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn adapterFailure(operationId);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n"]}
1
+ {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CapabilityPluginSyncFactory } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport { projectTestRunResultV1, TEST_RUNNER_MAX_OPAQUE_REF_CHARS_V1 } from \"./node-adapter.ts\";\nimport type { TestRunnerAdapterV1, TestRunResultV1 } from \"./types.ts\";\n\nconst requestSchema = Type.Object(\n\t{\n\t\tworkspaceRef: Type.String({\n\t\t\tminLength: 1,\n\t\t\tmaxLength: TEST_RUNNER_MAX_OPAQUE_REF_CHARS_V1,\n\t\t\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n\t\t}),\n\t\tframework: Type.Union([\n\t\t\tType.Literal(\"vitest\"),\n\t\t\tType.Literal(\"jest\"),\n\t\t\tType.Literal(\"node-test\"),\n\t\t\tType.Literal(\"pytest\"),\n\t\t]),\n\t\ttarget: Type.String({ minLength: 1, maxLength: 1024, pattern: \"^[^\\\\u0000\\\\r\\\\n]+$\" }),\n\t\ttimeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: 120_000 })),\n\t\tmaxFailures: Type.Optional(Type.Integer({ minimum: 1, maximum: 1_000 })),\n\t},\n\t{ additionalProperties: false },\n);\nconst inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\t// Shape-based dual-convention read (aligned with subagent-delegate): the\n\t// runtime invoke face passes the input object first and the host\n\t// CapabilityToolContext second; the agent tool face passes the tool call\n\t// id (a string) first and the params object second.\n\tconst value = first !== null && typeof first === \"object\" && !Array.isArray(first) ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(\"Test runner input must be an object\");\n\treturn value as Record<string, unknown>;\n}\n\nfunction invocation(\n\tfirst: unknown,\n\tsecond: unknown,\n): { readonly input: Record<string, unknown>; readonly operationId: string } {\n\tconst candidate = typeof first === \"string\" && first.trim() !== \"\" ? first : \"profile-runtime-tool-call\";\n\treturn {\n\t\tinput: objectInput(first, second),\n\t\toperationId: candidate.length <= 256 ? candidate : \"profile-runtime-tool-call\",\n\t};\n}\n\nfunction signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nfunction adapterFailure(operationId: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"adapter_failed\", message: \"Test runner adapter returned an invalid result\" },\n\t};\n}\n\nfunction invalidInput(operationId: string, message: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"failed\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"invalid_input\", message },\n\t};\n}\n\nfunction cancelled(operationId: string): TestRunResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"cancelled\",\n\t\tsummary: { total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 },\n\t\tfailures: [],\n\t\tfailuresTruncated: false,\n\t\terror: { version: 1, code: \"cancelled\", message: \"Test run was cancelled\" },\n\t};\n}\n\nconst CANCELLATION_V1 = Symbol(\"test-runner-capability-cancelled\");\n\nfunction runWithCancellation(\n\trun: () => Promise<TestRunResultV1>,\n\tsignal: AbortSignal | undefined,\n): Promise<TestRunResultV1 | typeof CANCELLATION_V1> {\n\tif (signal === undefined) return run();\n\tlet onAbort!: () => void;\n\tconst cancellation = new Promise<typeof CANCELLATION_V1>((resolve) => {\n\t\tonAbort = () => resolve(CANCELLATION_V1);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n\tconst pending = run();\n\treturn Promise.race([pending, cancellation]).finally(() => signal.removeEventListener(\"abort\", onAbort));\n}\n\n/** Registers the bounded test operation only for a full-control host. */\nexport function createTestRunnerCapabilityFactoryV1(runtime: TestRunnerAdapterV1): CapabilityPluginSyncFactory {\n\treturn (api) => {\n\t\tif (api.host.mode === \"readonly\") return;\n\t\tapi.registerTool({\n\t\t\tname: \"test_run\",\n\t\t\tlabel: \"Run tests\",\n\t\t\tdescription: \"Run a host-resolved test target and return bounded structured test results\",\n\t\t\tparameters: inputSchema,\n\t\t\texecute: async (first: unknown, second?: unknown, third?: unknown) => {\n\t\t\t\tlet invocationResult: { readonly input: Record<string, unknown>; readonly operationId: string };\n\t\t\t\ttry {\n\t\t\t\t\tinvocationResult = invocation(first, second);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(\"profile-runtime-tool-call\", \"Test runner input must be an object\");\n\t\t\t\t}\n\t\t\t\tconst { input, operationId } = invocationResult;\n\t\t\t\tconst signal = signalFrom(third);\n\t\t\t\tif (signal?.aborted) return cancelled(operationId);\n\t\t\t\tlet requestInput: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tif (!Value.Check(inputSchema, input)) return invalidInput(operationId, \"Test runner request is invalid\");\n\t\t\t\t\trequestInput = objectInput(input.request, undefined);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(operationId, \"Test runner request is invalid\");\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await runWithCancellation(\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\truntime.run(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\t\t\toperationId,\n\t\t\t\t\t\t\t\t\tworkspaceRef: requestInput.workspaceRef as string,\n\t\t\t\t\t\t\t\t\tframework: requestInput.framework as \"vitest\" | \"jest\" | \"node-test\" | \"pytest\",\n\t\t\t\t\t\t\t\t\ttarget: requestInput.target as string,\n\t\t\t\t\t\t\t\t\t...(requestInput.timeoutMs === undefined\n\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t: { timeoutMs: requestInput.timeoutMs as number }),\n\t\t\t\t\t\t\t\t\t...(requestInput.maxFailures === undefined\n\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t: { maxFailures: requestInput.maxFailures as number }),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t);\n\t\t\t\t\tif (output === CANCELLATION_V1) return cancelled(operationId);\n\t\t\t\t\treturn projectTestRunResultV1(output, operationId) ?? adapterFailure(operationId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn adapterFailure(operationId);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-agent-forge/plugin-test-runner",
3
- "version": "0.85.5",
3
+ "version": "0.85.7",
4
4
  "description": "Test runner capability plugin for Agent Forge (full-control test_run tool over vitest/jest/node-test/pytest)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -44,11 +44,11 @@
44
44
  "node": ">=22.19.0"
45
45
  },
46
46
  "dependencies": {
47
- "@agent-forge/plugin-sdk": "^0.85.5",
47
+ "@agent-forge/plugin-sdk": "^0.85.7",
48
48
  "typebox": "1.3.27"
49
49
  },
50
50
  "devDependencies": {
51
- "@agent-forge/agent-forge": "^0.85.5",
51
+ "@agent-forge/agent-forge": "^0.85.7",
52
52
  "shx": "0.4.0",
53
53
  "vitest": "4.1.9"
54
54
  }
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "agent-forge.plugin.test-runner",
3
- "version": "0.85.5",
3
+ "version": "0.85.7",
4
4
  "apiVersion": "1-draft",
5
5
  "entry": "./dist/entry.js",
6
6
  "hostVersion": ">=0.84.4",