778 lines
24 KiB
TypeScript
778 lines
24 KiB
TypeScript
import { Schema } from "effect";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
|
describe("run operation registry", () => {
|
|
afterEach(() => {
|
|
vi.resetModules();
|
|
vi.doUnmock("./rpcs.js");
|
|
});
|
|
|
|
it("registers capability calls with the exact CLI and interpreted fields", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta("workflow.capabilities.call");
|
|
if (operation === undefined) throw new Error("missing capability call operation");
|
|
|
|
expect(operation.idempotency).toBe("write");
|
|
expect(
|
|
operation.equivalentCli({
|
|
qualified_name: "local.example.echo",
|
|
payload: { text: "hello world" },
|
|
deployment_id: "demo.default",
|
|
}),
|
|
).toBe(
|
|
"uv run wf cap call local.example.echo --input '{\"text\":\"hello world\"}' --deployment demo.default",
|
|
);
|
|
expect(
|
|
operation.interpret({
|
|
qualified_name: "local.example.echo",
|
|
source_id: "local.example",
|
|
kind: "node_spec",
|
|
deployment_id: null,
|
|
outcome: "ok",
|
|
output: { text: "hello" },
|
|
diagnostics: [
|
|
{
|
|
bound_source: null,
|
|
code: "ok",
|
|
logical_ref: "local.example.echo",
|
|
message: "called",
|
|
repair_hint: null,
|
|
severity: "info",
|
|
},
|
|
],
|
|
}),
|
|
).toEqual({
|
|
qualifiedName: "local.example.echo",
|
|
sourceId: "local.example",
|
|
kind: "node_spec",
|
|
deploymentId: null,
|
|
outcome: "ok",
|
|
output: { text: "hello" },
|
|
diagnostics: [
|
|
{
|
|
boundSource: null,
|
|
code: "ok",
|
|
logicalRef: "local.example.echo",
|
|
message: "called",
|
|
repairHint: null,
|
|
severity: "info",
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it("preserves explicit null and empty contract replacement semantics", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta("workflow.draft_workspaces.set_contract");
|
|
if (operation === undefined) throw new Error("missing set contract operation");
|
|
|
|
const cli = operation.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 7,
|
|
input_schema: null,
|
|
outcomes: [],
|
|
});
|
|
|
|
expect(cli).toContain("input_schema=null (no equivalent CLI clear flag)");
|
|
expect(cli).toContain("outcomes=[] (no equivalent CLI clear flag)");
|
|
expect(cli).not.toContain("--outcome");
|
|
});
|
|
|
|
it("renders non-empty contract outcomes as repeated CLI flags", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta("workflow.draft_workspaces.set_contract");
|
|
if (operation === undefined) throw new Error("missing set contract operation");
|
|
|
|
expect(operation.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 7,
|
|
outcomes: ["ok", "cancelled"],
|
|
})).toContain("--outcome ok --outcome cancelled");
|
|
});
|
|
|
|
it("decodes start results with the start success schema", async () => {
|
|
vi.doMock("./rpcs.js", async () => {
|
|
const actual = await vi.importActual<typeof import("./rpcs.js")>(
|
|
"./rpcs.js",
|
|
);
|
|
return {
|
|
...actual,
|
|
WorkflowRunsStartResultSchema: Schema.Struct({
|
|
start_only: Schema.String,
|
|
next_actions: Schema.Struct({
|
|
can_continue: Schema.Boolean,
|
|
can_save_now: Schema.NullOr(Schema.Boolean),
|
|
recommended_next_tool: Schema.NullOr(Schema.String),
|
|
reason: Schema.String,
|
|
patch_examples: Schema.Array(Schema.Unknown),
|
|
warnings: Schema.Array(Schema.String),
|
|
}),
|
|
}),
|
|
};
|
|
});
|
|
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta("workflow.runs.start");
|
|
if (operation === undefined) throw new Error("missing start operation");
|
|
|
|
expect(() =>
|
|
operation.interpret({
|
|
start_only: "ok",
|
|
next_actions: {
|
|
can_continue: false,
|
|
can_save_now: null,
|
|
recommended_next_tool: null,
|
|
reason: "done",
|
|
patch_examples: [],
|
|
warnings: [],
|
|
},
|
|
}),
|
|
).not.toThrow();
|
|
});
|
|
|
|
it("decodes resume results with the resume success schema", async () => {
|
|
vi.doMock("./rpcs.js", async () => {
|
|
const actual = await vi.importActual<typeof import("./rpcs.js")>(
|
|
"./rpcs.js",
|
|
);
|
|
return {
|
|
...actual,
|
|
WorkflowRunsResumeResultSchema: Schema.Struct({
|
|
resume_only: Schema.String,
|
|
next_actions: Schema.Struct({
|
|
can_continue: Schema.Boolean,
|
|
can_save_now: Schema.NullOr(Schema.Boolean),
|
|
recommended_next_tool: Schema.NullOr(Schema.String),
|
|
reason: Schema.String,
|
|
patch_examples: Schema.Array(Schema.Unknown),
|
|
warnings: Schema.Array(Schema.String),
|
|
}),
|
|
}),
|
|
};
|
|
});
|
|
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta("workflow.runs.resume");
|
|
if (operation === undefined) throw new Error("missing resume operation");
|
|
|
|
expect(() =>
|
|
operation.interpret({
|
|
resume_only: "ok",
|
|
next_actions: {
|
|
can_continue: false,
|
|
can_save_now: null,
|
|
recommended_next_tool: null,
|
|
reason: "done",
|
|
patch_examples: [],
|
|
warnings: [],
|
|
},
|
|
}),
|
|
).not.toThrow();
|
|
});
|
|
|
|
it.each([
|
|
{
|
|
method: "workflow.draft_workspaces.create_empty" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
name: "console.demo",
|
|
title: "Console demo",
|
|
},
|
|
cli: "uv run wf draft create console.demo --name console.demo --title 'Console demo'",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 1,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: null,
|
|
step_count: 0,
|
|
route_count: 0,
|
|
steps: [],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.create_from_capability" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
capability_name: "local.example.echo",
|
|
name: "console.demo",
|
|
},
|
|
cli: "uv run wf draft create console.demo --capability local.example.echo --name console.demo",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 1,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
next_actions: {
|
|
can_continue: false,
|
|
can_save_now: true,
|
|
recommended_next_tool: null,
|
|
reason: "ready",
|
|
patch_examples: [],
|
|
warnings: [],
|
|
},
|
|
wrapper_hints: {
|
|
capability_name: "local.example.echo",
|
|
confidence: "high" as const,
|
|
declared_outcomes: ["ok"],
|
|
input_map: {},
|
|
input_schema: { type: "object" },
|
|
missing_decisions: [],
|
|
notes: [],
|
|
outcome_candidates: [],
|
|
outcome_policy: "preserve_declared" as const,
|
|
output_map: {},
|
|
output_schema: { type: "object" },
|
|
state_schema: { type: "object" },
|
|
suggested_wrapper_outcomes: ["ok"],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.add_step_from_capability" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
revision: 1,
|
|
step_id: "echo",
|
|
capability_name: "local.example.echo",
|
|
route_from_step: null,
|
|
route_from_outcome: "ok",
|
|
routes: { ok: "__end__" },
|
|
input_map: { "input.text": "text" },
|
|
bind_outputs: { text: "state.text" },
|
|
retry: 1,
|
|
timeout_seconds: 30,
|
|
},
|
|
cli: "uv run wf draft add capability console.demo --revision 1 --step echo --capability local.example.echo --route ok=__end__ --input input.text=text --bind-output text=state.text --retry 1 --timeout-seconds 30",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 2,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
draft: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
steps: { echo: { use: "local.example.echo" } },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.update_capability_step" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
revision: 2,
|
|
step_id: "echo",
|
|
update: { desc: "Echo text", retry: 2, timeout_seconds: 45 },
|
|
},
|
|
cli: "uv run wf draft update capability console.demo --revision 2 --step echo --description 'Echo text' --retry 2 --timeout-seconds 45",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 3,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
draft: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
steps: { echo: { use: "local.example.echo" } },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.set_route" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
revision: 3,
|
|
step_id: "echo",
|
|
outcome: "ok",
|
|
target: "__end__",
|
|
},
|
|
cli: "uv run wf draft set-route console.demo --revision 3 --step echo --outcome ok --to __end__",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 4,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
draft: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
steps: { echo: { use: "local.example.echo" } },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.set_contract" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
revision: 5,
|
|
outcomes: ["ok", "error"],
|
|
},
|
|
cli: "uv run wf draft set-contract console.demo --revision 5 --outcome ok --outcome error",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 6,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.set_start" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
revision: 6,
|
|
step_id: "echo",
|
|
},
|
|
cli: "uv run wf draft set-start console.demo --revision 6 --step echo",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 7,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.set_step_input_bindings" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
revision: 3,
|
|
step_id: "render",
|
|
bindings: [
|
|
{ path: "input.title", target: "report.title" },
|
|
{ target: "format", value: "markdown" },
|
|
],
|
|
},
|
|
cli: "uv run wf draft set-input console.demo --revision 3 --step render --map input.title=report.title --value 'format=\"markdown\"'",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 4,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
draft: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
steps: { echo: { use: "local.example.echo" } },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.set_step_output_bindings" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
revision: 4,
|
|
step_id: "render",
|
|
bindings: [{ source: "report", target: "state.report" }],
|
|
},
|
|
cli: "uv run wf draft set-output console.demo --revision 4 --step render --map report=state.report",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 5,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
draft: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
steps: { echo: { use: "local.example.echo" } },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.set_workflow_output_bindings" as const,
|
|
params: {
|
|
workspace_id: "console.demo",
|
|
revision: 7,
|
|
bindings: [
|
|
{ path: "state.report", target: "report" },
|
|
{ target: "format", value: "markdown" },
|
|
],
|
|
},
|
|
cli: "uv run wf draft set-workflow-output console.demo --revision 7 --map state.report=report --value 'format=\"markdown\"'",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 8,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
method: "workflow.draft_workspaces.validate" as const,
|
|
params: { workspace_id: "console.demo" },
|
|
cli: "uv run wf draft validate console.demo",
|
|
result: {
|
|
workspace_id: "console.demo",
|
|
revision: 4,
|
|
title: "Console demo",
|
|
status: "valid" as const,
|
|
diagnostics: [],
|
|
summary: {
|
|
name: "console.demo",
|
|
start: "echo",
|
|
step_count: 1,
|
|
route_count: 1,
|
|
steps: ["echo"],
|
|
},
|
|
},
|
|
},
|
|
])("registers and interprets $method", async (testCase) => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta(testCase.method);
|
|
if (operation === undefined) throw new Error(`missing ${testCase.method}`);
|
|
|
|
expect(operation.equivalentCli(testCase.params)).toBe(testCase.cli);
|
|
expect(operation.interpret(testCase.result)).toMatchObject({
|
|
workspaceId: "console.demo",
|
|
revision: testCase.result.revision,
|
|
title: "Console demo",
|
|
status: "valid",
|
|
summary: {
|
|
name: "console.demo",
|
|
start: testCase.result.summary.start,
|
|
stepCount: testCase.result.summary.step_count,
|
|
},
|
|
draft: "draft" in testCase.result ? testCase.result.draft : null,
|
|
});
|
|
});
|
|
|
|
it("renders clear metadata and representable canonical input bindings", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta(
|
|
"workflow.draft_workspaces.update_capability_step",
|
|
);
|
|
if (operation === undefined) throw new Error("missing update operation");
|
|
|
|
expect(
|
|
operation.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 2,
|
|
step_id: "echo",
|
|
update: {
|
|
input: [
|
|
{ path: "input.text", target: "text" },
|
|
{ target: "mode", value: { kind: "fast" } },
|
|
],
|
|
retry: null,
|
|
timeout_seconds: null,
|
|
},
|
|
}),
|
|
).toBe(
|
|
"uv run wf draft update capability console.demo --revision 2 --step echo --clear-retry --clear-timeout --input input.text=text --value 'mode={\"kind\":\"fast\"}'",
|
|
);
|
|
});
|
|
|
|
it("renders replacement binding clear flags and non-equivalent evidence", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const input = getOperationMeta(
|
|
"workflow.draft_workspaces.set_step_input_bindings",
|
|
);
|
|
const output = getOperationMeta(
|
|
"workflow.draft_workspaces.set_step_output_bindings",
|
|
);
|
|
if (input === undefined || output === undefined) {
|
|
throw new Error("missing focused binding operation");
|
|
}
|
|
|
|
expect(
|
|
input.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 3,
|
|
step_id: "render",
|
|
bindings: [],
|
|
}),
|
|
).toBe("uv run wf draft set-input console.demo --revision 3 --step render --clear");
|
|
expect(
|
|
output.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 4,
|
|
step_id: "render",
|
|
bindings: [],
|
|
}),
|
|
).toBe("uv run wf draft set-output console.demo --revision 4 --step render --clear");
|
|
expect(
|
|
input.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 3,
|
|
step_id: "render",
|
|
bindings: [
|
|
{
|
|
path: { root: "input", parts: ["title"] },
|
|
target: "report.title",
|
|
},
|
|
],
|
|
}),
|
|
).toContain(
|
|
"[non-equivalent: unavailable CLI representation for input_bindings (use --bindings-file)]",
|
|
);
|
|
});
|
|
|
|
it("shell-quotes complete route and binding map assignments", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta(
|
|
"workflow.draft_workspaces.add_step_from_capability",
|
|
);
|
|
if (operation === undefined) throw new Error("missing add operation");
|
|
|
|
expect(
|
|
operation.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 1,
|
|
step_id: "echo",
|
|
capability_name: "local.example.echo",
|
|
routes: { "when done": "state path" },
|
|
input_map: { "input value": "local target's" },
|
|
bind_outputs: { "output value": "state target" },
|
|
}),
|
|
).toBe(
|
|
"uv run wf draft add capability console.demo --revision 1 --step echo --capability local.example.echo --route 'when done=state path' --input 'input value=local target'\\''s' --bind-output 'output value=state target'",
|
|
);
|
|
});
|
|
|
|
it("renders path and value input bindings for add", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta(
|
|
"workflow.draft_workspaces.add_step_from_capability",
|
|
);
|
|
if (operation === undefined) throw new Error("missing add operation");
|
|
|
|
expect(
|
|
operation.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 1,
|
|
step_id: "echo",
|
|
capability_name: "local.example.echo",
|
|
input_bindings: [
|
|
{ path: "state.text", target: "text" },
|
|
{ target: "mode", value: { kind: "fast" } },
|
|
],
|
|
}),
|
|
).toBe(
|
|
"uv run wf draft add capability console.demo --revision 1 --step echo --capability local.example.echo --input state.text=text --value 'mode={\"kind\":\"fast\"}'",
|
|
);
|
|
});
|
|
|
|
it("registers authoring inspection as a read operation", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta(
|
|
"workflow.draft_workspaces.inspect_authoring_contract",
|
|
);
|
|
if (operation === undefined) throw new Error("missing authoring inspection");
|
|
|
|
expect(operation.idempotency).toBe("read");
|
|
expect(
|
|
operation.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 8,
|
|
selected_step_id: "render",
|
|
}),
|
|
).toBe(
|
|
"uv run wf draft inspect console.demo --include-draft [non-equivalent: unavailable CLI representation for revision, selected_step_id]",
|
|
);
|
|
expect(
|
|
operation.interpret({
|
|
workspace_id: "console.demo",
|
|
revision: 8,
|
|
selected_step_id: null,
|
|
readable_sources: [],
|
|
step_input_targets: [],
|
|
step_output_sources: [],
|
|
state_targets: [],
|
|
workflow_output_targets: [],
|
|
entry_steps: [],
|
|
workflow_outcomes: ["ok"],
|
|
warnings: [],
|
|
}),
|
|
).toMatchObject({
|
|
workspaceId: "console.demo",
|
|
selectedStepId: null,
|
|
workflowOutcomes: ["ok"],
|
|
});
|
|
});
|
|
|
|
it("does not flatten composite bindings into a fake inline CLI value", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta(
|
|
"workflow.draft_workspaces.set_step_input_bindings",
|
|
);
|
|
if (operation === undefined) throw new Error("missing set-input operation");
|
|
|
|
const cli = operation.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 3,
|
|
step_id: "concat",
|
|
bindings: [
|
|
{
|
|
target: "request",
|
|
expression: {
|
|
kind: "object",
|
|
fields: {
|
|
items: {
|
|
kind: "array",
|
|
items: [
|
|
{ kind: "path", path: "state.foo" },
|
|
{ kind: "literal", value: "wowcool" },
|
|
],
|
|
},
|
|
separator: { kind: "literal", value: " " },
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(cli).toContain(
|
|
"[non-equivalent: unavailable CLI representation for input_bindings (use --bindings-file)]",
|
|
);
|
|
expect(cli).not.toContain("--value");
|
|
});
|
|
|
|
it("explains unavailable inline schema and capability fields", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const createEmpty = getOperationMeta(
|
|
"workflow.draft_workspaces.create_empty",
|
|
);
|
|
const createFromCapability = getOperationMeta(
|
|
"workflow.draft_workspaces.create_from_capability",
|
|
);
|
|
if (createEmpty === undefined || createFromCapability === undefined) {
|
|
throw new Error("missing create operation");
|
|
}
|
|
|
|
const emptyCli = createEmpty.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
name: "console.demo",
|
|
input_schema: { type: "object" },
|
|
state_schema: { type: "object" },
|
|
output_schema: { type: "object" },
|
|
});
|
|
expect(emptyCli).toContain("uv run wf draft create console.demo --name console.demo");
|
|
expect(emptyCli).toContain("non-equivalent");
|
|
expect(emptyCli).toContain("input_schema");
|
|
expect(emptyCli).toContain("state_schema");
|
|
expect(emptyCli).toContain("output_schema");
|
|
|
|
const fromCapabilityCli = createFromCapability.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
capability_name: "local.example.echo",
|
|
input_schema: { type: "object" },
|
|
state_schema: { type: "object" },
|
|
output_schema: { type: "object" },
|
|
input: [{ path: "input.text", target: "text" }],
|
|
output: [{ source: "text", target: "state.text" }],
|
|
input_map: { "input.text": "text" },
|
|
output_map: { text: "state.text" },
|
|
error_message_source: "state.error",
|
|
});
|
|
expect(fromCapabilityCli).toContain("non-equivalent");
|
|
for (const field of [
|
|
"input_schema",
|
|
"state_schema",
|
|
"output_schema",
|
|
"input",
|
|
"output",
|
|
"input_map",
|
|
"output_map",
|
|
"error_message_source",
|
|
]) {
|
|
expect(fromCapabilityCli).toContain(field);
|
|
}
|
|
});
|
|
|
|
it("explains structural bindings that require a bindings file", async () => {
|
|
const { getOperationMeta } = await import("./method-registry.js");
|
|
const operation = getOperationMeta(
|
|
"workflow.draft_workspaces.add_step_from_capability",
|
|
);
|
|
if (operation === undefined) throw new Error("missing add operation");
|
|
|
|
const cli = operation.equivalentCli({
|
|
workspace_id: "console.demo",
|
|
revision: 1,
|
|
step_id: "echo",
|
|
capability_name: "local.example.echo",
|
|
input_bindings: [
|
|
{
|
|
path: { root: "state", parts: ["text"] },
|
|
target: { root: "local", parts: ["text"] },
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(cli).toContain("non-equivalent");
|
|
expect(cli).toContain("input_bindings");
|
|
expect(cli).toContain("--bindings-file");
|
|
});
|
|
});
|