@bpmnkit/cli 0.0.35 → 0.0.37

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
@@ -103,10 +103,12 @@ casen instances list --state active
103
103
  | [`@bpmnkit/plugins`](https://www.npmjs.com/package/@bpmnkit/plugins) | 22 composable canvas plugins |
104
104
  | [`@bpmnkit/api`](https://www.npmjs.com/package/@bpmnkit/api) | Camunda 8 REST API TypeScript client |
105
105
  | [`@bpmnkit/ascii`](https://www.npmjs.com/package/@bpmnkit/ascii) | Render BPMN diagrams as Unicode ASCII art |
106
+ | [`@bpmnkit/docspack`](https://www.npmjs.com/package/@bpmnkit/docspack) | BPMN Kit docs as an offline docspack package for AI agents |
106
107
  | [`@bpmnkit/ui`](https://www.npmjs.com/package/@bpmnkit/ui) | Shared design tokens and UI components |
107
108
  | [`@bpmnkit/profiles`](https://www.npmjs.com/package/@bpmnkit/profiles) | Shared auth, profile storage, and client factories for CLI & proxy |
108
109
  | [`@bpmnkit/operate`](https://www.npmjs.com/package/@bpmnkit/operate) | Monitoring & operations frontend for Camunda clusters |
109
110
  | [`@bpmnkit/connector-gen`](https://www.npmjs.com/package/@bpmnkit/connector-gen) | Generate connector templates from OpenAPI specs |
111
+ | [`@bpmnkit/connectors`](https://www.npmjs.com/package/@bpmnkit/connectors) | Camunda 8 OOTB connector catalog and deterministic template application |
110
112
  | [`@bpmnkit/proxy`](https://www.npmjs.com/package/@bpmnkit/proxy) | Local AI bridge and Camunda API proxy server |
111
113
  | [`@bpmnkit/patterns`](https://www.npmjs.com/package/@bpmnkit/patterns) | Domain process patterns for BPMNKit AIKit |
112
114
  | [`@bpmnkit/reebe-wasm`](https://www.npmjs.com/package/@bpmnkit/reebe-wasm) | WebAssembly BPMN engine for browser simulation |
@@ -1,5 +1,84 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { resolve } from "node:path";
3
+ import { getTemplate, listConnectors, searchConnectors } from "@bpmnkit/connectors";
4
+ const searchCmd = {
5
+ name: "search",
6
+ description: "Search the bundled Camunda 8 out-of-the-box connector catalog (Slack, HTTP, AWS, AI Agent, …)",
7
+ args: [
8
+ { name: "query", description: 'Search terms, e.g. "slack" or "send email"', required: true },
9
+ ],
10
+ examples: [{ description: "Find the Slack connector", command: "casen connector search slack" }],
11
+ async run(ctx) {
12
+ const query = ctx.positional.join(" ");
13
+ const results = searchConnectors(query);
14
+ if (results.length === 0) {
15
+ ctx.output.info(`No connectors matched "${query}". Try 'casen connector list' to browse all.`);
16
+ return;
17
+ }
18
+ ctx.output.printList({ items: results }, [
19
+ { key: "id", header: "TEMPLATE ID", maxWidth: 48 },
20
+ { key: "direction", header: "DIRECTION", maxWidth: 18 },
21
+ { key: "taskType", header: "TASK TYPE", maxWidth: 32 },
22
+ { key: "description", header: "DESCRIPTION", maxWidth: 50 },
23
+ ]);
24
+ },
25
+ };
26
+ const listCatalogCmd = {
27
+ name: "list",
28
+ description: "List all bundled Camunda 8 out-of-the-box connector templates",
29
+ async run(ctx) {
30
+ ctx.output.printList({ items: listConnectors() }, [
31
+ { key: "id", header: "TEMPLATE ID", maxWidth: 48 },
32
+ { key: "direction", header: "DIRECTION", maxWidth: 18 },
33
+ { key: "taskType", header: "TASK TYPE", maxWidth: 32 },
34
+ ]);
35
+ },
36
+ };
37
+ const showCmd = {
38
+ name: "show",
39
+ description: "Show a connector template's required/optional input keys",
40
+ args: [
41
+ {
42
+ name: "templateId",
43
+ description: "Template id, e.g. io.camunda.connectors.Slack.v1",
44
+ required: true,
45
+ },
46
+ ],
47
+ examples: [
48
+ {
49
+ description: "Show the Slack connector's inputs",
50
+ command: "casen connector show io.camunda.connectors.Slack.v1",
51
+ },
52
+ ],
53
+ async run(ctx) {
54
+ const templateId = ctx.positional[0];
55
+ if (!templateId)
56
+ throw new Error("Missing required argument: <templateId>");
57
+ const summary = searchConnectors(templateId).find((s) => s.id === templateId) ??
58
+ listConnectors().find((s) => s.id === templateId);
59
+ if (!summary || !getTemplate(templateId)) {
60
+ throw new Error(`Unknown connector template "${templateId}". Use 'casen connector search <query>' to find one.`);
61
+ }
62
+ ctx.output.info(`${summary.name} (${summary.id})`);
63
+ if (summary.taskType)
64
+ ctx.output.info(`Task type: ${summary.taskType}`);
65
+ ctx.output.info(`Direction: ${summary.direction}`);
66
+ if (summary.description)
67
+ ctx.output.info(summary.description);
68
+ if (summary.requiredInputs.length > 0) {
69
+ ctx.output.info("\nRequired inputs:");
70
+ for (const i of summary.requiredInputs) {
71
+ ctx.output.info(` ${i.key}${i.isSecret ? " (secret)" : ""} — ${i.label}`);
72
+ }
73
+ }
74
+ if (summary.optionalInputs.length > 0) {
75
+ ctx.output.info("\nOptional inputs:");
76
+ for (const i of summary.optionalInputs) {
77
+ ctx.output.info(` ${i.key}${i.isSecret ? " (secret)" : ""} — ${i.label}`);
78
+ }
79
+ }
80
+ },
81
+ };
3
82
  export const connectorGroup = {
4
83
  name: "connector",
5
84
  description: "Generate Camunda REST connector element templates from OpenAPI specs",
@@ -167,6 +246,9 @@ export const connectorGroup = {
167
246
  ]);
168
247
  },
169
248
  },
249
+ searchCmd,
250
+ listCatalogCmd,
251
+ showCmd,
170
252
  ],
171
253
  };
172
254
  //# sourceMappingURL=connector.js.map
@@ -0,0 +1,70 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { basename, resolve } from "node:path";
3
+ import { getActiveProfile, getAuthHeader } from "@bpmnkit/profiles";
4
+ const ZEEBE_ADDRESS = (process.env.ZEEBE_ADDRESS ?? "http://localhost:26500").replace(/\/$/, "");
5
+ const deployCmd = {
6
+ name: "deploy",
7
+ description: "Deploy a BPMN (or DMN/form) file to local Reebe or the active Camunda 8 profile",
8
+ args: [{ name: "file", description: "Path to the resource file", required: true }],
9
+ flags: [
10
+ {
11
+ name: "target",
12
+ description: 'Deployment target: "local" (Reebe, via ZEEBE_ADDRESS) or "camunda8" (active profile)',
13
+ type: "string",
14
+ default: "local",
15
+ enum: ["local", "camunda8"],
16
+ },
17
+ ],
18
+ examples: [
19
+ { description: "Deploy to local Reebe", command: "casen deploy deploy order-process.bpmn" },
20
+ {
21
+ description: "Deploy to Camunda 8",
22
+ command: "casen deploy deploy order-process.bpmn --target camunda8",
23
+ },
24
+ ],
25
+ async run(ctx) {
26
+ const filePath = ctx.positional[0];
27
+ if (!filePath)
28
+ throw new Error("Missing required argument: <file>");
29
+ const absPath = resolve(filePath);
30
+ const content = await readFile(absPath, "utf-8").catch(() => {
31
+ throw new Error(`Cannot read file: ${absPath}`);
32
+ });
33
+ const formData = new FormData();
34
+ formData.append("resources[]", new Blob([content], { type: "application/octet-stream" }), basename(absPath));
35
+ const target = typeof ctx.flags.target === "string" ? ctx.flags.target : "local";
36
+ if (target === "camunda8") {
37
+ const profile = getActiveProfile();
38
+ if (!profile?.config.baseUrl) {
39
+ throw new Error("No active Camunda 8 profile. Run: casen profile create");
40
+ }
41
+ const authHeader = await getAuthHeader(profile.config);
42
+ const baseUrl = profile.config.baseUrl.replace(/\/$/, "");
43
+ const res = await fetch(`${baseUrl}/v2/deployments`, {
44
+ method: "POST",
45
+ headers: { authorization: authHeader },
46
+ body: formData,
47
+ });
48
+ if (!res.ok)
49
+ throw new Error(`Camunda 8 deploy failed: ${res.status} ${await res.text()}`);
50
+ ctx.output.print({ success: true, target: "camunda8", result: await res.json() });
51
+ return;
52
+ }
53
+ let res;
54
+ try {
55
+ res = await fetch(`${ZEEBE_ADDRESS}/v2/deployments`, { method: "POST", body: formData });
56
+ }
57
+ catch (err) {
58
+ throw new Error(`Cannot reach Reebe at ${ZEEBE_ADDRESS}. Start it with: casen reebe start\n${String(err)}`);
59
+ }
60
+ if (!res.ok)
61
+ throw new Error(`Local deploy failed: ${res.status} ${await res.text()}`);
62
+ ctx.output.print({ success: true, target: "local", result: await res.json() });
63
+ },
64
+ };
65
+ export const deployGroup = {
66
+ name: "deploy",
67
+ description: "Deploy BPMN/DMN/form resources to local Reebe or Camunda 8",
68
+ commands: [deployCmd],
69
+ };
70
+ //# sourceMappingURL=deploy.js.map
@@ -4,8 +4,11 @@ import { askGroup } from "./ask.js";
4
4
  import { getDmnReqsXmlCmd, getDmnXmlCmd, getStartFormCmd, getUserTaskFormCmd, getXmlCmd, renderBpmnCmd, } from "./bpmn.js";
5
5
  import { completionGroup } from "./completion.js";
6
6
  import { connectorGroup } from "./connector.js";
7
+ import { deployGroup } from "./deploy.js";
7
8
  import { generateGroup } from "./generate.js";
8
9
  import { lintGroup } from "./lint.js";
10
+ import { patternGroup } from "./pattern.js";
11
+ import { planGroup } from "./plan.js";
9
12
  import { pluginGroup } from "./plugin.js";
10
13
  import { profileGroup } from "./profile.js";
11
14
  import { proxyGroup } from "./proxy.js";
@@ -14,6 +17,7 @@ import { computeRelations } from "./relations.js";
14
17
  import { settingsGroup } from "./settings.js";
15
18
  import { skillsGroup } from "./skills.js";
16
19
  import { storyGroup } from "./story.js";
20
+ import { synthGroup } from "./synth.js";
17
21
  import { testGroup } from "./test.js";
18
22
  import { viewGroup } from "./view.js";
19
23
  import { workerStartCmd } from "./worker-start.js";
@@ -57,13 +61,17 @@ const workerGroup = {
57
61
  /** Pinned groups shown above the separator in the main TUI menu. */
58
62
  export const pinnedGroups = [
59
63
  askGroup,
64
+ deployGroup,
60
65
  generateGroup,
61
66
  lintGroup,
67
+ patternGroup,
68
+ planGroup,
62
69
  proxyGroup,
63
70
  reebeGroup,
64
71
  skillsGroup,
65
72
  storyGroup,
66
73
  settingsGroup,
74
+ synthGroup,
67
75
  testGroup,
68
76
  viewGroup,
69
77
  workerGroup,
@@ -1,5 +1,17 @@
1
1
  import { readFile, writeFile } from "node:fs/promises";
2
+ import { applyConnectorTemplate } from "@bpmnkit/connectors";
2
3
  import { Bpmn, compactify, optimize } from "@bpmnkit/core";
4
+ /** Resolves a connector template's missing required keys via @bpmnkit/connectors, for the `connector/*` lint rule. */
5
+ export function resolveConnectorRequirements(templateId, boundKeys) {
6
+ const values = Object.fromEntries(boundKeys.map((k) => [k, "x"]));
7
+ const result = applyConnectorTemplate(templateId, values);
8
+ // Only "missing-required" problems mean something is actually unset — an "unknown-key"
9
+ // problem here just means a bound key doesn't match propertyKey()'s lookup key (e.g. a
10
+ // property whose `id` differs from its zeebe:input binding name), not a missing value.
11
+ return result.problems
12
+ .filter((p) => p.kind === "missing-required" && p.key !== undefined)
13
+ .map((p) => p.key);
14
+ }
3
15
  const SEVERITY_SYMBOL = {
4
16
  error: "✖",
5
17
  warning: "⚠",
@@ -16,6 +28,11 @@ const lintCmd = {
16
28
  description: "Comma-separated categories to run (default: all)",
17
29
  type: "string",
18
30
  },
31
+ {
32
+ name: "profile",
33
+ description: 'Lint profile. "deploy" runs every category and shows only error-severity findings — the deploy-readiness gate.',
34
+ type: "string",
35
+ },
19
36
  {
20
37
  name: "format",
21
38
  description: "Output format: text (default) or json",
@@ -27,6 +44,13 @@ const lintCmd = {
27
44
  type: "boolean",
28
45
  },
29
46
  ],
47
+ examples: [
48
+ { description: "Lint a file", command: "casen lint lint order-process.bpmn" },
49
+ {
50
+ description: "Deploy-readiness gate (errors only)",
51
+ command: "casen lint lint order-process.bpmn --profile deploy",
52
+ },
53
+ ],
30
54
  async run(ctx) {
31
55
  const filePath = ctx.positional[0];
32
56
  if (!filePath)
@@ -37,8 +61,14 @@ const lintCmd = {
37
61
  const categories = typeof categoriesFlag === "string" && categoriesFlag.length > 0
38
62
  ? categoriesFlag.split(",").map((s) => s.trim())
39
63
  : undefined;
40
- const report = optimize(defs, categories !== undefined ? { categories } : undefined);
41
- const { findings } = report;
64
+ const deployProfile = ctx.flags.profile === "deploy";
65
+ const report = optimize(defs, {
66
+ ...(categories !== undefined ? { categories } : {}),
67
+ resolveConnectorRequirements,
68
+ });
69
+ const findings = deployProfile
70
+ ? report.findings.filter((f) => f.severity === "error")
71
+ : report.findings;
42
72
  // --fix: apply all auto-fixable findings and write back
43
73
  if (ctx.flags.fix) {
44
74
  const fixable = findings.filter((f) => f.applyFix);
@@ -67,10 +97,10 @@ const lintCmd = {
67
97
  const elIds = f.elementIds.length > 0 ? ` [${f.elementIds.join(", ")}]` : "";
68
98
  ctx.output.info(`${symbol} [${f.category}]${elIds} ${f.message}`);
69
99
  }
70
- const { total, bySeverity } = report.summary;
71
- const errorCount = bySeverity.error ?? 0;
72
- const warnCount = bySeverity.warning ?? 0;
73
- const infoCount = bySeverity.info ?? 0;
100
+ const total = findings.length;
101
+ const errorCount = findings.filter((f) => f.severity === "error").length;
102
+ const warnCount = findings.filter((f) => f.severity === "warning").length;
103
+ const infoCount = findings.filter((f) => f.severity === "info").length;
74
104
  ctx.output.info(`\n${total} finding${total !== 1 ? "s" : ""}: ${errorCount} error${errorCount !== 1 ? "s" : ""}, ${warnCount} warning${warnCount !== 1 ? "s" : ""}, ${infoCount} info`);
75
105
  if (errorCount > 0) {
76
106
  throw new Error(`Lint failed with ${errorCount} error${errorCount !== 1 ? "s" : ""}`);
@@ -0,0 +1,55 @@
1
+ import { ALL_PATTERNS, findPattern } from "@bpmnkit/patterns";
2
+ const listCmd = {
3
+ name: "list",
4
+ description: "List the built-in domain process patterns",
5
+ examples: [{ description: "List all patterns", command: "casen pattern list" }],
6
+ async run(ctx) {
7
+ ctx.output.print(ALL_PATTERNS.map((p) => ({
8
+ id: p.id,
9
+ name: p.name,
10
+ description: p.description,
11
+ keywords: p.keywords,
12
+ })));
13
+ },
14
+ };
15
+ const getCmd = {
16
+ name: "get",
17
+ description: "Show a domain pattern's full context: readme, worker specs, and variations",
18
+ args: [
19
+ {
20
+ name: "query",
21
+ description: "Pattern id (e.g. invoice-approval) or a free-text description to match",
22
+ required: true,
23
+ },
24
+ ],
25
+ examples: [
26
+ { description: "By id", command: "casen pattern get invoice-approval" },
27
+ { description: "By description", command: 'casen pattern get "employee onboarding"' },
28
+ ],
29
+ async run(ctx) {
30
+ const query = ctx.positional.join(" ");
31
+ if (!query)
32
+ throw new Error("Missing required argument: <query>");
33
+ const pattern = findPattern(query);
34
+ if (!pattern) {
35
+ ctx.output.info(`No pattern matched "${query}". Run \`casen pattern list\` to see all patterns.`);
36
+ return;
37
+ }
38
+ ctx.output.print({
39
+ id: pattern.id,
40
+ name: pattern.name,
41
+ description: pattern.description,
42
+ readme: pattern.readme,
43
+ workers: pattern.workers,
44
+ variations: pattern.variations,
45
+ note: "`template` is a rough structural reference in an older compact-diagram shape, not a ProcessPlan — use the readme/workers as context when writing your own plan, don't paste the template in as-is.",
46
+ template: pattern.template,
47
+ });
48
+ },
49
+ };
50
+ export const patternGroup = {
51
+ name: "pattern",
52
+ description: "Look up built-in domain process patterns for AI-driven process generation",
53
+ commands: [listCmd, getCmd],
54
+ };
55
+ //# sourceMappingURL=pattern.js.map
@@ -0,0 +1,70 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { Bpmn, extractPlan } from "@bpmnkit/core";
4
+ const extractCmd = {
5
+ name: "extract",
6
+ description: "Lift an existing .bpmn file back into ProcessPlan JSON form",
7
+ args: [{ name: "file", description: "Path to the .bpmn file", required: true }],
8
+ flags: [
9
+ {
10
+ name: "output",
11
+ short: "o",
12
+ description: "Output .json file path (default: <file>.plan.json)",
13
+ type: "string",
14
+ },
15
+ ],
16
+ examples: [{ description: "Extract a plan", command: "casen plan extract order-process.bpmn" }],
17
+ async run(ctx) {
18
+ const filePath = ctx.positional[0];
19
+ if (!filePath)
20
+ throw new Error("Missing required argument: <file>");
21
+ const xml = await readFile(resolve(filePath), "utf-8");
22
+ const defs = Bpmn.parse(xml);
23
+ const { plan, unsupported } = extractPlan(defs);
24
+ const outputPath = resolve(typeof ctx.flags.output === "string"
25
+ ? ctx.flags.output
26
+ : `${filePath.replace(/\.bpmn$/, "")}.plan.json`);
27
+ await writeFile(outputPath, `${JSON.stringify(plan, null, "\t")}\n`, "utf-8");
28
+ ctx.output.ok(`Wrote ${outputPath}`);
29
+ if (unsupported.length > 0) {
30
+ ctx.output.info(`\n${unsupported.length} element(s) could not be lifted — left out of the plan, not guessed at:`);
31
+ for (const u of unsupported)
32
+ ctx.output.info(` [${u.id}] (${u.type}) ${u.reason}`);
33
+ }
34
+ },
35
+ };
36
+ export const PLAN_SCHEMA_SUMMARY = `ProcessPlan (version 1)
37
+ {
38
+ "version": 1,
39
+ "process": { "id": string, "name"?: string, "versionTag"?: string },
40
+ "inputs"?: [{ "name": string, "type": string, "required"?: boolean, "description"?: string }],
41
+ "steps": PlanStep[],
42
+ "tests"?: PlanScenario[]
43
+ }
44
+
45
+ PlanStep.kind: "start" | "connector" | "serviceTask" | "userTask" | "businessRuleTask" |
46
+ "scriptTask" | "sendTask" | "receiveTask" | "callActivity" | "aiAgent" | "gateway" |
47
+ "subProcess" | "wait" | "end" | "raw"
48
+
49
+ Every step: { id?, name?, documentation?, errorBoundary?: { errorCode, steps }, timerBoundary?: {...} }
50
+ FEEL convention: a leading "=" makes a string a FEEL expression; without it, the value is literal.
51
+
52
+ steps[0] must be kind "start". "gateway" steps carry { gatewayType, branches: [{ condition?, default?, steps }] }.
53
+ "connector"/"aiAgent" tool steps reference a bundled Camunda template via { template, values } —
54
+ see \`casen connector search <query>\` / \`casen connector show <templateId>\` for available templates
55
+ and their required/optional input keys.
56
+
57
+ Full type definitions: packages/core/src/plan/types.ts in the bpmnkit monorepo.`;
58
+ const schemaCmd = {
59
+ name: "schema",
60
+ description: "Print the ProcessPlan format reference",
61
+ async run(ctx) {
62
+ ctx.output.info(PLAN_SCHEMA_SUMMARY);
63
+ },
64
+ };
65
+ export const planGroup = {
66
+ name: "plan",
67
+ description: "ProcessPlan authoring — extract an existing process, or print the plan format reference",
68
+ commands: [extractCmd, schemaCmd],
69
+ };
70
+ //# sourceMappingURL=plan.js.map
@@ -4,7 +4,8 @@ import { fileURLToPath } from "node:url";
4
4
  /**
5
5
  * Install BPMNKit AIKit skills into `.claude/commands/` in the current project.
6
6
  * Skills are markdown prompt files that Claude Code executes as slash commands:
7
- * /design, /implement, /review, /test, /deploy
7
+ * /implement, /review, /test, /deploy
8
+ * Lightweight, CLI-only versions of the full plugin's skill set — see aikit.md.
8
9
  *
9
10
  * Also installs aikit.md into .claude/ as a shared tool reference.
10
11
  */
@@ -84,7 +85,10 @@ const skillsInstallCmd = {
84
85
  ctx.output.info(` /${name}`);
85
86
  }
86
87
  ctx.output.info("");
87
- ctx.output.info("Make sure the BPMNKit AIKit MCP server is configured in .claude/mcp.json");
88
+ ctx.output.info("These commands drive `casen` directly — no MCP server or proxy needed. " +
89
+ "For the full skill set (implement/extend/agent/connect/review/test/deploy + generated " +
90
+ "reference docs), install the Claude Code plugin instead: " +
91
+ "/plugin marketplace add github:bpmnkit/monorepo && /plugin install bpmnkit");
88
92
  },
89
93
  };
90
94
  export const skillsGroup = {
@@ -0,0 +1,103 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { applyConnectorTemplate } from "@bpmnkit/connectors";
4
+ import { Bpmn, compilePlan, mergePlan, slugify, uniqueId } from "@bpmnkit/core";
5
+ async function readPlan(path) {
6
+ const text = await readFile(resolve(path), "utf-8");
7
+ return JSON.parse(text);
8
+ }
9
+ /** Convert plan-embedded test scenarios to the `.bpmn.tests.json` shape consumed by `casen test`. */
10
+ export function toScenarioSidecar(tests) {
11
+ const taken = new Set();
12
+ return tests.map((t) => {
13
+ const id = uniqueId(slugify(t.name), taken);
14
+ const mocks = Object.fromEntries(Object.entries(t.mocks ?? {}).map(([jobType, mock]) => [
15
+ jobType,
16
+ "error" in mock
17
+ ? {
18
+ error: mock.error.message
19
+ ? `${mock.error.code}: ${mock.error.message}`
20
+ : mock.error.code,
21
+ }
22
+ : { outputs: mock.outputs },
23
+ ]));
24
+ return { id, name: t.name, inputs: t.inputs, mocks, expect: t.expect };
25
+ });
26
+ }
27
+ const synthCmd = {
28
+ name: "synth",
29
+ description: "Compile a ProcessPlan JSON file into deployable, laid-out BPMN XML",
30
+ args: [{ name: "plan", description: "Path to the ProcessPlan JSON file", required: true }],
31
+ flags: [
32
+ {
33
+ name: "output",
34
+ short: "o",
35
+ description: "Output .bpmn file path (default: <plan>.bpmn)",
36
+ type: "string",
37
+ },
38
+ {
39
+ name: "merge",
40
+ description: "Merge into an existing .bpmn file instead of creating a new one",
41
+ type: "string",
42
+ },
43
+ {
44
+ name: "json",
45
+ description: "Print the result (problems + xml) as JSON instead of writing a file",
46
+ type: "boolean",
47
+ },
48
+ ],
49
+ examples: [
50
+ { description: "Compile a plan to BPMN", command: "casen synth order-process.plan.json" },
51
+ {
52
+ description: "Extend an existing process",
53
+ command: "casen synth delta.plan.json --merge order-process.bpmn",
54
+ },
55
+ ],
56
+ async run(ctx) {
57
+ const planPath = ctx.positional[0];
58
+ if (!planPath)
59
+ throw new Error("Missing required argument: <plan>");
60
+ const plan = await readPlan(planPath);
61
+ const mergeTarget = typeof ctx.flags.merge === "string" ? ctx.flags.merge : undefined;
62
+ const result = mergeTarget
63
+ ? mergePlan(Bpmn.parse(await readFile(resolve(mergeTarget), "utf-8")), plan, {
64
+ resolveConnector: applyConnectorTemplate,
65
+ })
66
+ : compilePlan(plan, { resolveConnector: applyConnectorTemplate });
67
+ if (ctx.flags.json) {
68
+ ctx.output.print(result);
69
+ if (!result.xml)
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+ if (result.problems.length > 0) {
74
+ for (const p of result.problems)
75
+ ctx.output.info(`✖ [${p.path}] ${p.message}`);
76
+ }
77
+ if (!result.xml) {
78
+ throw new Error(`Compilation failed with ${result.problems.length} problem(s) — see above`);
79
+ }
80
+ const outputPath = resolve(typeof ctx.flags.output === "string"
81
+ ? ctx.flags.output
82
+ : (mergeTarget ?? planPath.replace(/\.json$/, ".bpmn")));
83
+ await writeFile(outputPath, result.xml, "utf-8");
84
+ if (plan.tests && plan.tests.length > 0) {
85
+ const sidecarPath = `${outputPath}.tests.json`;
86
+ await writeFile(sidecarPath, JSON.stringify(toScenarioSidecar(plan.tests), null, 2), "utf-8");
87
+ ctx.output.info(`Wrote ${sidecarPath} (${plan.tests.length} scenario(s) — run: casen test ${outputPath})`);
88
+ }
89
+ if (result.problems.length > 0) {
90
+ ctx.output.info(`\nWrote ${outputPath} with ${result.problems.length} problem(s) above.`);
91
+ process.exitCode = 1;
92
+ }
93
+ else {
94
+ ctx.output.ok(`Wrote ${outputPath}`);
95
+ }
96
+ },
97
+ };
98
+ export const synthGroup = {
99
+ name: "synth",
100
+ description: "Compile a ProcessPlan into deployable BPMN — the deterministic AI-generation pipeline",
101
+ commands: [synthCmd],
102
+ };
103
+ //# sourceMappingURL=synth.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bpmnkit/cli",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
4
4
  "description": "Command-line interface for Camunda 8 — deploy, manage, and monitor processes from the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,13 +16,15 @@
16
16
  "node": ">=20"
17
17
  },
18
18
  "dependencies": {
19
- "@bpmnkit/api": "0.0.19",
20
- "@bpmnkit/ascii": "0.0.28",
21
- "@bpmnkit/connector-gen": "0.0.14",
22
- "@bpmnkit/core": "0.1.0",
23
- "@bpmnkit/engine": "0.1.28",
24
- "@bpmnkit/profiles": "0.0.17",
25
- "@bpmnkit/proxy": "0.0.31"
19
+ "@bpmnkit/api": "0.0.20",
20
+ "@bpmnkit/ascii": "0.0.30",
21
+ "@bpmnkit/connector-gen": "0.0.15",
22
+ "@bpmnkit/connectors": "0.0.2",
23
+ "@bpmnkit/core": "0.1.2",
24
+ "@bpmnkit/engine": "0.1.30",
25
+ "@bpmnkit/patterns": "0.0.5",
26
+ "@bpmnkit/profiles": "0.0.18",
27
+ "@bpmnkit/proxy": "0.0.33"
26
28
  },
27
29
  "publishConfig": {
28
30
  "access": "public"
package/skills/aikit.md CHANGED
@@ -1,267 +1,46 @@
1
- # BPMNKit AIKit Tool Reference
1
+ # BPMNKit — Reference
2
2
 
3
- This file is installed to `.claude/aikit.md` by `casen skills install`.
4
- The skill files (`/design`, `/implement`, etc.) reference it with `@.claude/aikit.md`.
3
+ This file is installed to `.claude/aikit.md` by `casen skills install`. The skill files (`/implement`, `/review`, `/test`, `/deploy`) reference it with `@.claude/aikit.md`.
5
4
 
6
- ---
7
-
8
- ## MCP server
9
-
10
- All tools are exposed by the `bpmnkit-aikit` MCP server configured in `.claude/mcp.json`.
11
- Tool names follow the pattern `mcp__bpmnkit-aikit__<tool_name>`.
12
-
13
- ---
14
-
15
- ## BPMN tools
16
-
17
- ### `bpmn_create`
18
-
19
- Generate a new BPMN process from a natural language description.
20
-
21
- - Automatically loads a matching domain pattern for context before calling the AI.
22
- - Writes the `.bpmn` file to disk.
23
-
24
- **Parameters**
25
- | Name | Required | Description |
26
- |---|---|---|
27
- | `description` | yes | Natural language description of the process. Include actors, decision points, and expected outcomes. The richer the description, the better the diagram. |
28
- | `outputDir` | no | Directory to write the file (default: current working directory). |
29
-
30
- **Returns** `{ path: string, patternMatched: string | null }`
31
-
32
- **Good description example:**
33
- > "Invoice approval process with a clerk review step, automatic approval under €500, manager approval for higher amounts, and email notification on rejection."
34
-
35
- ---
36
-
37
- ### `bpmn_read`
38
-
39
- Read a BPMN file and return its compact JSON representation.
40
-
41
- **Parameters**
42
- | Name | Required | Description |
43
- |---|---|---|
44
- | `path` | yes | Path to the `.bpmn` file. |
45
-
46
- **Returns** Compact JSON with shape:
47
- ```json
48
- {
49
- "id": "process-id",
50
- "processes": [{
51
- "id": "...", "name": "...",
52
- "elements": [
53
- { "type": "startEvent", "id": "...", "name": "..." },
54
- { "type": "serviceTask", "id": "...", "name": "...", "jobType": "com.example:do-thing:1" },
55
- { "type": "userTask", "id": "...", "name": "...", "formId": "approve-form" },
56
- { "type": "businessRuleTask", "id": "...", "name": "...", "decisionId": "credit-check" },
57
- { "type": "exclusiveGateway", "id": "...", "name": "..." },
58
- { "type": "endEvent", "id": "...", "name": "..." }
59
- ]
60
- }]
61
- }
62
- ```
63
-
64
- Use `jobType` to identify service tasks for worker scaffolding. Use `formId` / `decisionId` to know which tasks need forms/DMN tables.
65
-
66
- ---
67
-
68
- ### `bpmn_update`
69
-
70
- Update an existing BPMN by describing the change in natural language.
71
-
72
- **Parameters**
73
- | Name | Required | Description |
74
- |---|---|---|
75
- | `path` | yes | Path to the `.bpmn` file. |
76
- | `instruction` | yes | What to change, e.g. "Add an error boundary event on the payment task that routes to a manual review lane." |
77
-
78
- **Returns** `{ path: string, updated: true }`
79
-
80
- ---
81
-
82
- ### `bpmn_validate`
83
-
84
- Validate a BPMN file using the BPMNKit pattern advisor.
85
-
86
- **Parameters**
87
- | Name | Required | Description |
88
- |---|---|---|
89
- | `path` | yes | Path to the `.bpmn` file. |
90
-
91
- **Returns**
92
- ```json
93
- {
94
- "summary": { "total": 3, "errors": 1, "warnings": 1, "info": 1, "autoFixable": 2 },
95
- "findings": [
96
- {
97
- "severity": "error" | "warning" | "info",
98
- "category": "string",
99
- "message": "string",
100
- "suggestion": "string",
101
- "elementIds": ["..."],
102
- "autoFixable": true
103
- }
104
- ]
105
- }
106
- ```
107
-
108
- Errors block deployment. Warnings and info are advisory.
109
-
110
- ---
111
-
112
- ### `bpmn_deploy`
113
-
114
- Deploy a BPMN process to a running engine.
115
-
116
- **Parameters**
117
- | Name | Required | Description |
118
- |---|---|---|
119
- | `path` | yes | Path to the `.bpmn` file. |
120
- | `target` | yes | `"local"` — local reebe instance (uses `ZEEBE_ADDRESS`). `"camunda8"` — active Camunda 8 profile (set with `casen profile create`). |
121
-
122
- **Returns** `{ success: true, target: string, result: object }`
123
-
124
- ---
125
-
126
- ### `bpmn_simulate`
127
-
128
- Structural analysis: validation findings + worker coverage check.
129
-
130
- > **Note:** Phase 1 only — structural analysis. Full process execution simulation is planned for a future phase.
5
+ These are lightweight, CLI-only slash commands. For the full skill set — `/bpmnkit:implement`, `/bpmnkit:extend`, `/bpmnkit:agent`, `/bpmnkit:connect`, plus generated reference docs (`plan-format.md`, `connectors.md`, `agentic.md`, `feel.md`) — install the Claude Code plugin instead:
131
6
 
132
- **Parameters**
133
- | Name | Required | Description |
134
- |---|---|---|
135
- | `path` | yes | Path to the `.bpmn` file. |
136
-
137
- **Returns**
138
- ```json
139
- {
140
- "validation": { "errors": 0, "findings": [] },
141
- "workerCoverage": {
142
- "total": 3,
143
- "covered": 2,
144
- "missing": ["com.example:send-invoice:1"]
145
- }
146
- }
7
+ ```sh
8
+ /plugin marketplace add github:bpmnkit/monorepo
9
+ /plugin install bpmnkit
147
10
  ```
148
11
 
149
12
  ---
150
13
 
151
- ### `bpmn_run_history`
152
-
153
- Query recent process executions from the local proxy.
154
-
155
- **Parameters**
156
- | Name | Required | Description |
157
- |---|---|---|
158
- | `processId` | no | Filter by process definition ID. |
159
-
160
- **Returns** `{ runs: [...] }` — up to 20 recent executions.
161
-
162
- ---
163
-
164
- ## Worker tools
165
-
166
- ### `worker_list`
167
-
168
- List all available workers: built-in BPMNKit workers and any scaffolded workers found in `./workers/`.
169
-
170
- **Parameters** none
171
-
172
- **Returns** `{ workers: [{ jobType, name, description, ... }], total: number }`
173
-
174
- ---
175
-
176
- ### `worker_scaffold`
177
-
178
- Scaffold a TypeScript worker for a Zeebe job type. Generates `index.ts`, `package.json`, `tsconfig.json`, `README.md` in `./workers/<slug>/`.
179
-
180
- **Parameters**
181
- | Name | Required | Description |
182
- |---|---|---|
183
- | `jobType` | yes | Zeebe job type string, e.g. `com.example:send-invoice:1`. |
184
- | `description` | no | What this worker does. |
185
- | `inputs` | no | Object mapping input variable names to type descriptions, e.g. `{ "invoiceId": "string", "amount": "number" }`. |
186
- | `outputs` | no | Object mapping output variable names to type descriptions. |
187
-
188
- **Returns** `{ path: string, files: [...], jobType: string, note: string }`
189
-
190
- After scaffolding: `cd workers/<slug> && npm install && npm start`. Edit `index.ts` to implement `handle()`.
191
-
192
- ---
193
-
194
- ## Form & DMN tools
195
-
196
- ### `form_create`
197
-
198
- Generate Camunda form JSON for all `userTask` elements in a BPMN that have a `formId`. Writes one `.form` file per task.
14
+ ## The pipeline
199
15
 
200
- **Parameters**
201
- | Name | Required | Description |
202
- |---|---|---|
203
- | `bpmnPath` | yes | Path to the `.bpmn` file. |
204
- | `outputDir` | no | Where to write form files (default: same directory as the BPMN). |
16
+ Every process is authored as a `ProcessPlan` JSON file, never hand-written BPMN XML:
205
17
 
206
- **Returns**
207
- ```json
208
- {
209
- "forms": [
210
- { "taskId": "...", "taskName": "...", "formId": "...", "path": "path/to/form-id.form" }
211
- ]
212
- }
213
18
  ```
214
-
215
- Returns `{ "forms": [] }` if no user tasks with `formId` are found.
216
-
217
- ---
218
-
219
- ### `dmn_create`
220
-
221
- Generate DMN decision table XML for all `businessRuleTask` elements in a BPMN that have a `decisionId`. Writes one `.dmn` file per task.
222
-
223
- **Parameters**
224
- | Name | Required | Description |
225
- |---|---|---|
226
- | `bpmnPath` | yes | Path to the `.bpmn` file. |
227
- | `outputDir` | no | Where to write DMN files (default: same directory as the BPMN). |
228
-
229
- **Returns**
230
- ```json
231
- {
232
- "decisions": [
233
- { "taskId": "...", "taskName": "...", "decisionId": "...", "path": "path/to/decision-id.dmn" }
234
- ]
235
- }
19
+ <name>.plan.json → casen synth → <name>.bpmn (+ <name>.bpmn.tests.json if plan.tests is set)
236
20
  ```
237
21
 
238
- Returns `{ "decisions": [] }` if no business rule tasks with `decisionId` are found.
239
-
240
- ---
241
-
242
- ## Pattern tools
243
-
244
- ### `pattern_list`
245
-
246
- List all available domain process patterns.
247
-
248
- **Parameters** none
249
-
250
- **Returns** `{ patterns: [{ id, name, description, keywords }], total: number }`
251
-
252
- Call this at the start of any skill to check whether a domain pattern applies. Match by comparing keywords against the user's request.
253
-
254
- ---
255
-
256
- ### `pattern_get`
257
-
258
- Get the full content of a domain pattern: readme, worker specs, variations, and a compact BPMN template.
259
-
260
- **Parameters**
261
- | Name | Required | Description |
262
- |---|---|---|
263
- | `domain` | yes | Pattern id (e.g. `"invoice-approval"`) or free-text query (e.g. `"employee onboarding"`). |
264
-
265
- **Returns** `{ id, name, description, keywords, readme, workers, variations, template }`
266
-
267
- Pass `pattern.readme` and `pattern.workers` as additional context in the `description` parameter of `bpmn_create`.
22
+ `casen plan schema` prints the full `ProcessPlan` format reference. `casen plan extract <file>.bpmn` lifts an existing process back into plan form (for `/extend`-style changes).
23
+
24
+ ## Key commands
25
+
26
+ | Command | Does |
27
+ |---|---|
28
+ | `casen plan schema` | Print the `ProcessPlan` JSON format reference |
29
+ | `casen plan extract <file>.bpmn` | Lift an existing process into `<file>.plan.json` |
30
+ | `casen synth <plan>.json --output <file>.bpmn` | Compile a plan to laid-out, deployable BPMN |
31
+ | `casen synth <plan>.json --merge <file>.bpmn --output <file>.bpmn` | Compile a delta plan and merge it into an existing process |
32
+ | `casen connector search "<query>"` | Find a Camunda connector template by name/keyword |
33
+ | `casen connector show <template-id>` | Required/optional input keys, task type, direction |
34
+ | `casen lint lint <file>.bpmn` | Full static analysis (all categories) |
35
+ | `casen lint lint <file>.bpmn --profile deploy` | Deploy-readiness gate — errors only |
36
+ | `casen lint lint <file>.bpmn --fix` | Apply auto-fixable findings, write back |
37
+ | `casen test <file>.bpmn` | Run scenarios from `<file>.bpmn.tests.json` |
38
+ | `casen deploy deploy <file>.bpmn [--target camunda8]` | Deploy to local Reebe (default) or Camunda 8 |
39
+ | `casen worker start` | Start every scaffolded worker in `./workers/` |
40
+
41
+ ## Conventions
42
+
43
+ - A value starting with `=` is a FEEL expression; without it, it's a literal string.
44
+ - Secrets always use the `{{secrets.NAME}}` placeholder — never a literal credential.
45
+ - Every plan step's `id`/`name` should follow Camunda naming conventions ("Verb Object" tasks, "Object + past participle" start events, "?" gateway questions) — see the full plugin's `references/modeling-style.md` for the complete list.
46
+ - Worker stubs use `@bpmnkit/worker-client`'s `createWorkerClient({ workerName }).poll(jobType)` API, written to `workers/<slug>/index.ts`.
package/skills/deploy.md CHANGED
@@ -1,33 +1,36 @@
1
1
  ---
2
- description: Deploy a BPMN process to local reebe or Camunda 8
2
+ description: Gate a BPMN process on deploy-readiness, then deploy it to local Reebe or Camunda 8.
3
3
  ---
4
4
 
5
5
  @.claude/aikit.md
6
6
 
7
- Deploy the BPMN process at the given path.
7
+ Deploy the BPMN process: $ARGUMENTS
8
8
 
9
- ## File to deploy
9
+ Extract the `.bpmn` filename (find the single `.bpmn` in cwd, or ask, if not given) and destination (`--local` default, or `--camunda`).
10
10
 
11
- $ARGUMENTS
11
+ ## Step 1 — Gate on deploy-readiness
12
12
 
13
- ---
13
+ ```sh
14
+ casen lint lint <file>.bpmn --profile deploy
15
+ ```
16
+
17
+ If this reports any errors, stop and fix them first (or run `/review`) — do not deploy with deploy-profile errors.
18
+
19
+ ## Step 2 — Deploy
20
+
21
+ ```sh
22
+ casen deploy deploy <file>.bpmn # local Reebe
23
+ casen deploy deploy <file>.bpmn --target camunda8 # active Camunda 8 profile
24
+ ```
14
25
 
15
- 1. Call `mcp__bpmnkit-aikit__bpmn_validate` on the file to check for errors before deploying.
16
- - If there are errors, show them and ask: **"Fix errors first or deploy anyway?"**
17
- - If warnings only: show them but proceed.
26
+ Local deploy unreachable → tell the user to run `casen reebe start --port 26500` first, then retry. Camunda 8 deploy with no active profile → tell the user to run `casen profile create <name> --base-url <url> --auth-type bearer --token <token>` then `casen profile use <name>`, then retry.
18
27
 
19
- 2. Ask: **"Deploy to local reebe or Camunda 8?"**
28
+ ## Step 3 Verify and summarize
20
29
 
21
- 3. Call `mcp__bpmnkit-aikit__bpmn_deploy` with the chosen target:
22
- - `"local"` deploys to the local reebe instance at ZEEBE_ADDRESS
23
- - `"camunda8"` — deploys using the active casen profile (run `casen profile create` if not set up)
30
+ ```sh
31
+ casen process-definition list --output json
32
+ ```
24
33
 
25
- 4. Report the result:
26
- - On success: "Deployed successfully. Process ID: <id>"
27
- - On failure: show the error and suggest a fix (profile not set up, reebe not running, etc.)
34
+ Report: `Deployed: <process-id> version: <N> target: <local|camunda8>`.
28
35
 
29
- 5. If any scaffolded workers exist in ./workers/, remind:
30
- ```
31
- Don't forget to start your workers:
32
- casen worker start
33
- ```
36
+ If any scaffolded workers exist in `./workers/`, remind: `casen worker start`. Remind about any `{{secrets.NAME}}` the process references — they must be provisioned in the target engine's secret store.
@@ -1,10 +1,10 @@
1
1
  ---
2
- description: Implement a BPMN process end-to-end from a natural language description
2
+ description: Implement a BPMN process end-to-end from a natural language description — plan, compile, test, deploy.
3
3
  ---
4
4
 
5
5
  @.claude/aikit.md
6
6
 
7
- You are implementing a BPMN process end-to-end using BPMNKit AIKit tools. Work through these steps in order.
7
+ You are implementing a BPMN process using `casen`. You never write BPMN XML by hand — every process is authored as a `ProcessPlan` JSON file and compiled with `casen synth`.
8
8
 
9
9
  ## Request
10
10
 
@@ -12,82 +12,48 @@ $ARGUMENTS
12
12
 
13
13
  ---
14
14
 
15
- ## Step 1 — Check for a domain pattern
15
+ ## Step 1 — Resolve external interactions
16
16
 
17
- Call `mcp__bpmnkit-aikit__pattern_list` to see available domain patterns.
18
- If any pattern keywords match the request, call `mcp__bpmnkit-aikit__pattern_get` to load the full pattern as context for the next step.
17
+ For each external system the process touches (Slack, email, HTTP, etc.): `casen connector search "<system>"` then `casen connector show <template-id>` for its required inputs. No match → use a plain `jobType` step (a worker gets scaffolded in Step 5).
19
18
 
20
- ---
21
-
22
- ## Step 2 — Plan: Create the BPMN
23
-
24
- Spawn a subagent with this task:
19
+ ## Step 2 — Write the plan
25
20
 
26
- > Using the MCP tool `mcp__bpmnkit-aikit__bpmn_create`, generate a BPMN process for: **$ARGUMENTS**
27
- >
28
- > If a domain pattern was loaded in Step 1, pass its readme and worker specs as additional context in the description parameter.
29
- >
30
- > Return the file path of the generated BPMN.
31
-
32
- ---
21
+ Write `<slug>.plan.json` per `casen plan schema`. Name elements clearly (see `.claude/aikit.md`'s naming conventions).
33
22
 
34
- ## Step 3 — Implement: Wire workers
35
-
36
- Spawn a subagent with this task:
37
-
38
- > You are implementing workers for a BPMN process.
39
- >
40
- > 1. Call `mcp__bpmnkit-aikit__worker_list` to get the catalog of available workers.
41
- > 2. Call `mcp__bpmnkit-aikit__bpmn_read` on the BPMN file from Step 2 to find all service task job types.
42
- > 3. For each service task job type:
43
- > - If a built-in or previously scaffolded worker matches: note it as "reused"
44
- > - If no match exists: call `mcp__bpmnkit-aikit__worker_scaffold` with the job type, a description, and expected inputs/outputs derived from the BPMN context
45
- > 4. Return: a list of `{ jobType, status: "reused" | "scaffolded", workerPath? }` for each service task
46
-
47
- ---
23
+ ## Step 3 — Compile
48
24
 
49
- ## Step 4 — Review: Validate the BPMN
50
-
51
- Spawn a subagent with this task:
25
+ ```sh
26
+ casen synth <slug>.plan.json --output <slug>.bpmn
27
+ ```
52
28
 
53
- > Call `mcp__bpmnkit-aikit__bpmn_validate` on the BPMN file from Step 2.
54
- > Identify any errors that block deployment and any warnings worth noting.
55
- > Return: `{ errors: [...], warnings: [...] }`
29
+ Fix any reported problems in the plan (never the XML) and re-run — bounded to 2 retries before asking the user.
56
30
 
57
- ---
31
+ ## Step 4 — Test
58
32
 
59
- ## Step 5 Test: Check coverage
33
+ Add a `tests` array to the plan covering the happy path and every branch/boundary, re-synth (writes `<slug>.bpmn.tests.json`), then:
60
34
 
61
- Spawn a subagent with this task:
35
+ ```sh
36
+ casen test <slug>.bpmn
37
+ ```
62
38
 
63
- > Call `mcp__bpmnkit-aikit__bpmn_simulate` on the BPMN file from Step 2 with an empty scenarios array.
64
- > Return: worker coverage report (total service tasks, covered, missing)
39
+ ## Step 5 Scaffold workers
65
40
 
66
- ---
41
+ For every job-type step with no existing worker, write `workers/<slug>/index.ts` using `@bpmnkit/worker-client`'s `createWorkerClient({ workerName }).poll(jobType)` API.
67
42
 
68
43
  ## Step 6 — Present summary and ask to deploy
69
44
 
70
- Collect all results and present a summary:
71
-
72
45
  ```
73
46
  BPMN file: <path>
74
- Pattern used: <id or "none">
75
-
76
- Workers:
77
- ✓ reused: <list>
78
- + scaffolded: <list with paths>
79
-
80
- Validation:
81
- Errors: <count> — <list if any>
82
- Warnings: <count> — <list if any>
83
47
 
84
- Worker coverage: <covered>/<total> service tasks
48
+ Connectors used: <list, with required secrets — never their values>
49
+ Workers: reused <list> / scaffolded <list with paths>
50
+ Tests: X/Y passed
85
51
 
86
52
  Scaffolded workers require: npm install && npm start (in each workers/<name>/ directory)
87
53
  ```
88
54
 
89
- Then ask: **"Deploy to local reebe, deploy to Camunda 8, or skip deployment?"**
55
+ Then ask: **"Deploy to local Reebe, deploy to Camunda 8, or skip?"**
90
56
 
91
- - If "local": call `mcp__bpmnkit-aikit__bpmn_deploy` with `target: "local"`
92
- - If "camunda8": call `mcp__bpmnkit-aikit__bpmn_deploy` with `target: "camunda8"`
93
- - If "skip": done
57
+ - local: `casen lint lint <slug>.bpmn --profile deploy` (must be zero errors) then `casen deploy deploy <slug>.bpmn`
58
+ - camunda8: same lint gate, then `casen deploy deploy <slug>.bpmn --target camunda8`
59
+ - skip: done
package/skills/review.md CHANGED
@@ -1,35 +1,41 @@
1
1
  ---
2
- description: Review a BPMN file and report findings with severity and fix suggestions
2
+ description: Review a BPMN file and report findings with severity and an explicit deploy-ready verdict.
3
3
  ---
4
4
 
5
5
  @.claude/aikit.md
6
6
 
7
- Review the BPMN file at the given path using BPMNKit's pattern advisor.
7
+ Review the BPMN file: $ARGUMENTS
8
8
 
9
- ## File to review
9
+ If no file is given, find the single `.bpmn` in cwd or ask.
10
10
 
11
- $ARGUMENTS
11
+ ## Step 1 — Run both profiles
12
12
 
13
- ---
13
+ ```sh
14
+ casen lint lint <file>.bpmn --profile deploy --format json
15
+ casen lint lint <file>.bpmn --format json
16
+ ```
14
17
 
15
- 1. Call `mcp__bpmnkit-aikit__bpmn_validate` on the path above.
18
+ ## Step 2 Present findings grouped by severity
16
19
 
17
- 2. Present findings grouped by severity:
20
+ **Errors** (must fix before deploy)
21
+ - `[element-id]` `[category]` message. Fix: suggestion, if present.
18
22
 
19
- **Errors** (block deployment or indicate broken process flow)
20
- - For each error: element IDs, message, suggested fix
23
+ **Warnings** (should fix)
24
+ - ...
21
25
 
22
- **Warnings** (best-practice violations, missing patterns)
23
- - For each warning: element IDs, message, suggested fix
26
+ **Info** (consider)
27
+ - ...
24
28
 
25
- **Info** (improvement suggestions)
26
- - For each info item: message
29
+ ## Step 3 — Offer auto-fix
27
30
 
28
- 3. Show a summary:
29
- ```
30
- Total: <n> findings — <errors> errors, <warnings> warnings, <info> info
31
- Auto-fixable: <n>
31
+ If there are any findings, offer:
32
+
33
+ ```sh
34
+ casen lint lint <file>.bpmn --fix
32
35
  ```
33
36
 
34
- 4. If there are auto-fixable findings, ask: **"Apply auto-fixes?"**
35
- If yes, call `mcp__bpmnkit-aikit__bpmn_update` with instruction: "Apply all auto-fixable pattern advisor suggestions"
37
+ Re-run Step 1 afterward to confirm.
38
+
39
+ ## Step 4 — Explicit verdict
40
+
41
+ End with: **"Deploy-ready: yes"** (zero errors from the deploy profile) or **"Deploy-ready: no — N error(s)"**.
package/skills/test.md CHANGED
@@ -1,38 +1,36 @@
1
1
  ---
2
- description: Analyse a BPMN process check worker coverage and validation findings
2
+ description: Run scenario tests on a BPMN process file and report path coverage.
3
3
  ---
4
4
 
5
5
  @.claude/aikit.md
6
6
 
7
- Analyse the BPMN process at the given path.
7
+ Run scenario tests: $ARGUMENTS
8
8
 
9
- ## File to test
9
+ If no file is given, find the single `.bpmn` in cwd or ask.
10
10
 
11
- $ARGUMENTS
11
+ ## Step 1 — Ensure scenarios exist
12
12
 
13
- ---
13
+ Look for `<file>.bpmn.tests.json` (written automatically by `casen synth` from a plan's `tests` array). If missing: `casen plan extract <file>.bpmn`, add a `tests` array covering the happy path and every branch/boundary, then `casen synth <plan>.json --merge <file>.bpmn` to regenerate it — or hand-write the sidecar directly (array of `{ id, name, inputs?, mocks?, expect? }`).
14
14
 
15
- 1. Call `mcp__bpmnkit-aikit__bpmn_read` to understand the process structure (elements, service tasks, gateways, event types).
15
+ ## Step 2 Run
16
16
 
17
- 2. Call `mcp__bpmnkit-aikit__bpmn_simulate` with the path and an empty scenarios array to get worker coverage and validation analysis.
17
+ ```sh
18
+ casen test <file>.bpmn
19
+ ```
18
20
 
19
- 3. Call `mcp__bpmnkit-aikit__worker_list` to show the full worker catalog.
21
+ ## Step 3 Report
20
22
 
21
- 4. Present the results:
23
+ ```
24
+ | Scenario | Result | Details |
25
+ |----------|--------|---------|
26
+ | happy-path | ✓ PASS | (Nms) |
27
+ | error-path | ✗ FAIL | field: expected X, got Y |
28
+ ```
22
29
 
23
- **Process structure**
24
- - Pools / participants
25
- - Service tasks and their job types
26
- - Decision gateways and branch conditions
27
- - Event types (timer, message, error, escalation)
30
+ ## Step 4 — Coverage
28
31
 
29
- **Worker coverage**
30
- - ✓ Covered job types (matched to built-in or scaffolded workers)
31
- - ✗ Missing job types (no worker found — scaffold with worker_scaffold)
32
+ Cross-reference gateway branches and error/timer boundaries against which scenarios exercise them; report anything uncovered.
32
33
 
33
- **Validation findings**
34
- - Errors and warnings from the pattern advisor
34
+ ## Step 5 — Summary
35
35
 
36
- **Suggested test scenarios** (derived from the BPMN structure)
37
- - Happy path: <describe the main success path>
38
- - Edge cases: <describe key branches, timeouts, error conditions>
36
+ "X/Y scenarios passed. N branch(es)/boundary(ies) uncovered."
package/skills/design.md DELETED
@@ -1,87 +0,0 @@
1
- ---
2
- description: Design a BPMN process — flow, forms, and decision tables. No workers, no deployment.
3
- ---
4
-
5
- @.claude/aikit.md
6
-
7
- You are designing a BPMN process using BPMNKit AIKit tools. Work through these steps in order.
8
-
9
- ## Request
10
-
11
- $ARGUMENTS
12
-
13
- ---
14
-
15
- ## Step 1 — Check for a domain pattern
16
-
17
- Call `mcp__bpmnkit-aikit__pattern_list` to see available domain patterns.
18
- If any pattern keywords match the request, call `mcp__bpmnkit-aikit__pattern_get` to load the full pattern as context.
19
-
20
- ---
21
-
22
- ## Step 2 — Create the BPMN
23
-
24
- Spawn a subagent with this task:
25
-
26
- > Using `mcp__bpmnkit-aikit__bpmn_create`, generate a BPMN process for: **$ARGUMENTS**
27
- >
28
- > If a pattern was loaded in Step 1, pass its readme and worker specs as context in the description parameter.
29
- >
30
- > Return the file path of the generated BPMN.
31
-
32
- ---
33
-
34
- ## Step 3 — Generate forms
35
-
36
- Spawn a subagent with this task:
37
-
38
- > Call `mcp__bpmnkit-aikit__form_create` with the BPMN path from Step 2.
39
- >
40
- > Return: list of `{ taskId, formId, path }` for each form created, or an empty list if no user tasks with formId were found.
41
-
42
- ---
43
-
44
- ## Step 4 — Generate DMN tables
45
-
46
- Spawn a subagent with this task:
47
-
48
- > Call `mcp__bpmnkit-aikit__dmn_create` with the BPMN path from Step 2.
49
- >
50
- > Return: list of `{ taskId, decisionId, path }` for each DMN file created, or an empty list if no business rule tasks with decisionId were found.
51
-
52
- ---
53
-
54
- ## Step 5 — Validate
55
-
56
- Spawn a subagent with this task:
57
-
58
- > Call `mcp__bpmnkit-aikit__bpmn_validate` on the BPMN file from Step 2.
59
- >
60
- > Return: `{ errors: [...], warnings: [...] }`
61
-
62
- ---
63
-
64
- ## Step 6 — Present design summary
65
-
66
- Collect all results and present:
67
-
68
- ```
69
- BPMN: <path>
70
- Pattern: <id or "none">
71
-
72
- Forms (<count>):
73
- <formId> → <path>
74
- (or "none" if empty)
75
-
76
- DMN tables (<count>):
77
- <decisionId> → <path>
78
- (or "none" if empty)
79
-
80
- Validation:
81
- Errors: <count> — <list if any>
82
- Warnings: <count> — <list if any>
83
- ```
84
-
85
- Then say: **"Use `/implement` to add workers, or `/deploy` when ready."**
86
-
87
- Do NOT offer to deploy.