@sweny-ai/core 0.1.76 → 0.1.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/dist/browser.d.ts +11 -5
  2. package/dist/browser.js +11 -11
  3. package/dist/claude.d.ts +20 -0
  4. package/dist/claude.js +139 -9
  5. package/dist/cli/config.d.ts +22 -0
  6. package/dist/cli/config.js +56 -9
  7. package/dist/cli/main.d.ts +1 -1
  8. package/dist/cli/main.js +56 -57
  9. package/dist/cli/marketplace.js +35 -9
  10. package/dist/cli/publish.d.ts +10 -0
  11. package/dist/cli/publish.js +22 -14
  12. package/dist/executor.js +104 -43
  13. package/dist/loader.d.ts +40 -0
  14. package/dist/loader.js +73 -0
  15. package/dist/mcp-catalog.d.ts +47 -0
  16. package/dist/mcp-catalog.js +304 -0
  17. package/dist/mcp.d.ts +6 -9
  18. package/dist/mcp.js +24 -314
  19. package/dist/requires.d.ts +7 -0
  20. package/dist/requires.js +34 -0
  21. package/dist/retry.d.ts +23 -0
  22. package/dist/retry.js +72 -0
  23. package/dist/schema.d.ts +667 -80
  24. package/dist/schema.js +144 -5
  25. package/dist/skills/custom-loader.d.ts +40 -0
  26. package/dist/skills/custom-loader.js +107 -32
  27. package/dist/skills/index.d.ts +13 -1
  28. package/dist/skills/index.js +12 -3
  29. package/dist/studio.js +4 -1
  30. package/dist/templates.d.ts +29 -8
  31. package/dist/templates.js +30 -20
  32. package/dist/testing.d.ts +7 -0
  33. package/dist/testing.js +7 -0
  34. package/dist/types.d.ts +76 -0
  35. package/dist/verify.d.ts +1 -0
  36. package/dist/verify.js +43 -5
  37. package/package.json +8 -4
  38. package/dist/__tests__/cascade.test.d.ts +0 -11
  39. package/dist/__tests__/cascade.test.js +0 -449
  40. package/dist/__tests__/claude.test.d.ts +0 -1
  41. package/dist/__tests__/claude.test.js +0 -427
  42. package/dist/__tests__/custom-loader.test.d.ts +0 -1
  43. package/dist/__tests__/custom-loader.test.js +0 -116
  44. package/dist/__tests__/executor.test.d.ts +0 -1
  45. package/dist/__tests__/executor.test.js +0 -736
  46. package/dist/__tests__/integration/datadog.integration.test.d.ts +0 -1
  47. package/dist/__tests__/integration/datadog.integration.test.js +0 -23
  48. package/dist/__tests__/integration/e2e-workflow.integration.test.d.ts +0 -1
  49. package/dist/__tests__/integration/e2e-workflow.integration.test.js +0 -75
  50. package/dist/__tests__/integration/github.integration.test.d.ts +0 -1
  51. package/dist/__tests__/integration/github.integration.test.js +0 -37
  52. package/dist/__tests__/integration/harness.d.ts +0 -24
  53. package/dist/__tests__/integration/harness.js +0 -34
  54. package/dist/__tests__/integration/linear.integration.test.d.ts +0 -1
  55. package/dist/__tests__/integration/linear.integration.test.js +0 -15
  56. package/dist/__tests__/integration/sentry.integration.test.d.ts +0 -1
  57. package/dist/__tests__/integration/sentry.integration.test.js +0 -20
  58. package/dist/__tests__/integration/slack.integration.test.d.ts +0 -1
  59. package/dist/__tests__/integration/slack.integration.test.js +0 -22
  60. package/dist/__tests__/integration/sources.integration.test.d.ts +0 -1
  61. package/dist/__tests__/integration/sources.integration.test.js +0 -123
  62. package/dist/__tests__/publish.test.d.ts +0 -1
  63. package/dist/__tests__/publish.test.js +0 -180
  64. package/dist/__tests__/schema.test.d.ts +0 -1
  65. package/dist/__tests__/schema.test.js +0 -526
  66. package/dist/__tests__/skill-config-integration.test.d.ts +0 -1
  67. package/dist/__tests__/skill-config-integration.test.js +0 -204
  68. package/dist/__tests__/skills-index.test.d.ts +0 -1
  69. package/dist/__tests__/skills-index.test.js +0 -119
  70. package/dist/__tests__/skills.test.d.ts +0 -1
  71. package/dist/__tests__/skills.test.js +0 -565
  72. package/dist/__tests__/spec-conformance.test.d.ts +0 -18
  73. package/dist/__tests__/spec-conformance.test.js +0 -1074
  74. package/dist/__tests__/studio.test.d.ts +0 -1
  75. package/dist/__tests__/studio.test.js +0 -403
  76. package/dist/__tests__/templates.test.d.ts +0 -1
  77. package/dist/__tests__/templates.test.js +0 -49
  78. package/dist/__tests__/testing.test.d.ts +0 -1
  79. package/dist/__tests__/testing.test.js +0 -224
  80. package/dist/__tests__/verify.test.d.ts +0 -1
  81. package/dist/__tests__/verify.test.js +0 -517
  82. package/dist/__tests__/version-consistency.test.d.ts +0 -1
  83. package/dist/__tests__/version-consistency.test.js +0 -312
  84. package/dist/__tests__/workflow-builder.test.d.ts +0 -1
  85. package/dist/__tests__/workflow-builder.test.js +0 -110
  86. package/dist/__tests__/workflow-yaml.test.d.ts +0 -1
  87. package/dist/__tests__/workflow-yaml.test.js +0 -201
  88. package/dist/cli/__tests__/diagram.test.d.ts +0 -1
  89. package/dist/cli/__tests__/diagram.test.js +0 -225
  90. package/dist/cli/__tests__/report-cloud.test.d.ts +0 -1
  91. package/dist/cli/__tests__/report-cloud.test.js +0 -165
  92. package/dist/cli/__tests__/upgrade.test.d.ts +0 -1
  93. package/dist/cli/__tests__/upgrade.test.js +0 -317
  94. package/dist/cli/__tests__/version-check.test.d.ts +0 -1
  95. package/dist/cli/__tests__/version-check.test.js +0 -209
  96. package/dist/cli/config.test.d.ts +0 -1
  97. package/dist/cli/config.test.js +0 -200
  98. package/dist/cli/credentials.test.d.ts +0 -1
  99. package/dist/cli/credentials.test.js +0 -172
  100. package/dist/cli/e2e.test.d.ts +0 -1
  101. package/dist/cli/e2e.test.js +0 -690
  102. package/dist/cli/marketplace.test.d.ts +0 -1
  103. package/dist/cli/marketplace.test.js +0 -355
  104. package/dist/cli/new.test.d.ts +0 -1
  105. package/dist/cli/new.test.js +0 -1043
  106. package/dist/cli/output.test.d.ts +0 -1
  107. package/dist/cli/output.test.js +0 -180
  108. package/dist/cli/publish.test.d.ts +0 -1
  109. package/dist/cli/publish.test.js +0 -610
  110. package/dist/cli/renderer.test.d.ts +0 -1
  111. package/dist/cli/renderer.test.js +0 -302
  112. package/dist/executor.test.d.ts +0 -1
  113. package/dist/executor.test.js +0 -603
  114. package/dist/mcp.test.d.ts +0 -1
  115. package/dist/mcp.test.js +0 -735
  116. package/dist/mermaid.test.d.ts +0 -1
  117. package/dist/mermaid.test.js +0 -256
  118. package/dist/sources.test.d.ts +0 -1
  119. package/dist/sources.test.js +0 -265
  120. package/dist/sources.validation.test.d.ts +0 -12
  121. package/dist/sources.validation.test.js +0 -380
  122. package/dist/workflow-builder.test.d.ts +0 -1
  123. package/dist/workflow-builder.test.js +0 -117
package/dist/templates.js CHANGED
@@ -1,13 +1,15 @@
1
1
  /**
2
- * Template loading for issues and PRs.
2
+ * Template + rules/context loading for the CLI.
3
3
  *
4
- * Templates can come from:
4
+ * Templates and additional-context documents can come from:
5
5
  * 1. Local file path (relative to repo root)
6
6
  * 2. URL (fetched at runtime)
7
- * 3. Built-in defaults
7
+ * 3. Built-in defaults / inline text
8
8
  *
9
- * Delegates to sources.ts for actual resolution; this module provides
10
- * backwards-compatible wrappers with fallback semantics.
9
+ * Delegates to source-resolver.ts for the actual fetch. Fix #16: both
10
+ * `loadTemplate` and `loadAdditionalContext` now honor `offline` and
11
+ * `fetchAuth` the same way the executor's per-node Sources do, so CLI-level
12
+ * rules/context stay consistent with everything the executor touches later.
11
13
  */
12
14
  import * as path from "node:path";
13
15
  import { classifySource } from "./sources.js";
@@ -50,39 +52,43 @@ export const DEFAULT_PR_TEMPLATE = `## Summary
50
52
  ## Related Issues
51
53
  Fixes #
52
54
  `;
53
- /** Default resolution context used by template helpers. */
54
- function defaultCtx(cwd) {
55
+ function buildCtx(options) {
55
56
  return {
56
- cwd,
57
- env: process.env,
58
- authConfig: {},
59
- offline: false,
57
+ cwd: options.cwd ?? process.cwd(),
58
+ env: options.env ?? process.env,
59
+ authConfig: options.fetchAuth ?? {},
60
+ offline: options.offline ?? false,
60
61
  logger: consoleLogger,
61
62
  };
62
63
  }
63
64
  /**
64
65
  * Load a template from a file path or URL.
65
66
  * Returns the default if source is empty or loading fails.
67
+ *
68
+ * Accepts the legacy `cwd?: string` signature for backward compat.
66
69
  */
67
- export async function loadTemplate(source, fallback, cwd = process.cwd()) {
70
+ export async function loadTemplate(source, fallback, options = {}) {
68
71
  if (!source || source.trim() === "")
69
72
  return fallback;
73
+ const opts = typeof options === "string" ? { cwd: options } : options;
70
74
  try {
71
- const resolved = await resolveSource(source.trim(), "template", defaultCtx(cwd));
75
+ const resolved = await resolveSource(source.trim(), "template", buildCtx(opts));
72
76
  return resolved.content;
73
77
  }
74
78
  catch (err) {
75
- console.warn(`[templates] Failed to load template: ${err.message}, using default`);
79
+ const msg = err instanceof Error ? err.message : String(err);
80
+ console.warn(`[templates] Failed to load template: ${msg}, using default`);
76
81
  return fallback;
77
82
  }
78
83
  }
79
84
  /**
80
85
  * Resolve issue and PR templates from config.
81
86
  */
82
- export async function resolveTemplates(config, cwd) {
87
+ export async function resolveTemplates(config, options = {}) {
88
+ const opts = typeof options === "string" ? { cwd: options } : options;
83
89
  const [issueTemplate, prTemplate] = await Promise.all([
84
- loadTemplate(config.issueTemplate, DEFAULT_ISSUE_TEMPLATE, cwd),
85
- loadTemplate(config.prTemplate, DEFAULT_PR_TEMPLATE, cwd),
90
+ loadTemplate(config.issueTemplate, DEFAULT_ISSUE_TEMPLATE, opts),
91
+ loadTemplate(config.prTemplate, DEFAULT_PR_TEMPLATE, opts),
86
92
  ]);
87
93
  return { issueTemplate, prTemplate };
88
94
  }
@@ -91,12 +97,15 @@ export async function resolveTemplates(config, cwd) {
91
97
  * Each source is resolved eagerly (including URLs) and wrapped with a header.
92
98
  * Returns { resolved, urls } — resolved text for all sources; urls is kept
93
99
  * for API compat but will be empty since URLs now resolve eagerly.
100
+ *
101
+ * Accepts the legacy `cwd?: string` signature for backward compat.
94
102
  */
95
- export async function loadAdditionalContext(sources, cwd = process.cwd()) {
103
+ export async function loadAdditionalContext(sources, options = {}) {
96
104
  if (sources.length === 0)
97
105
  return { resolved: "", urls: [] };
106
+ const opts = typeof options === "string" ? { cwd: options } : options;
98
107
  const parts = [];
99
- const ctx = defaultCtx(cwd);
108
+ const ctx = buildCtx(opts);
100
109
  for (const source of sources) {
101
110
  const trimmed = source.trim();
102
111
  if (!trimmed)
@@ -114,7 +123,8 @@ export async function loadAdditionalContext(sources, cwd = process.cwd()) {
114
123
  }
115
124
  }
116
125
  catch (err) {
117
- console.warn(`[templates] Failed to load context source: ${err.message}`);
126
+ const msg = err instanceof Error ? err.message : String(err);
127
+ console.warn(`[templates] Failed to load context source: ${msg}`);
118
128
  }
119
129
  }
120
130
  }
package/dist/testing.d.ts CHANGED
@@ -38,6 +38,8 @@ export interface MockClaudeOptions {
38
38
  routes?: Record<string, string>;
39
39
  /** Workflow definition — enables instruction-based node matching (required for branching workflows) */
40
40
  workflow?: Workflow;
41
+ /** Scripted handler for `ask()` calls. */
42
+ ask?: (instruction: string, context: Record<string, unknown>) => string;
41
43
  }
42
44
  /**
43
45
  * A mock Claude client that follows a script.
@@ -51,6 +53,7 @@ export declare class MockClaude implements Claude {
51
53
  private responses;
52
54
  private routes;
53
55
  private instructionMap;
56
+ private askFn?;
54
57
  constructor(opts: MockClaudeOptions);
55
58
  /** Returns the order in which nodes were executed */
56
59
  get executedNodes(): string[];
@@ -68,6 +71,10 @@ export declare class MockClaude implements Claude {
68
71
  description: string;
69
72
  }[];
70
73
  }): Promise<string>;
74
+ ask(opts: {
75
+ instruction: string;
76
+ context: Record<string, unknown>;
77
+ }): Promise<string>;
71
78
  /**
72
79
  * Identify which node is being executed.
73
80
  *
package/dist/testing.js CHANGED
@@ -32,9 +32,11 @@ export class MockClaude {
32
32
  responses;
33
33
  routes;
34
34
  instructionMap; // instruction text → node ID
35
+ askFn;
35
36
  constructor(opts) {
36
37
  this.responses = opts.responses;
37
38
  this.routes = opts.routes ?? {};
39
+ this.askFn = opts.ask;
38
40
  // Build reverse map: instruction → node ID (for accurate matching in branching workflows)
39
41
  this.instructionMap = new Map();
40
42
  if (opts.workflow) {
@@ -98,6 +100,11 @@ export class MockClaude {
98
100
  // Default: first choice
99
101
  return opts.choices[0].id;
100
102
  }
103
+ async ask(opts) {
104
+ if (this.askFn)
105
+ return this.askFn(opts.instruction, opts.context);
106
+ return "";
107
+ }
101
108
  /**
102
109
  * Identify which node is being executed.
103
110
  *
package/dist/types.d.ts CHANGED
@@ -73,6 +73,50 @@ export interface NodeVerify {
73
73
  /** Each assertion must hold against `result.data`. */
74
74
  output_matches?: OutputMatch[];
75
75
  }
76
+ /**
77
+ * Machine-checked pre-condition for a node.
78
+ *
79
+ * Evaluated by the executor BEFORE the LLM runs. If any declared check fails,
80
+ * the node is marked `failed` (or `skipped` when `on_fail: "skip"`) and the
81
+ * LLM is never invoked.
82
+ *
83
+ * Path roots resolve against the cross-node context map:
84
+ * { input: <runtime input>, [priorNodeId]: <data of prior node>, ... }
85
+ *
86
+ * Reuses the same path grammar as `verify` (dotted segments, `[*]` wildcard,
87
+ * optional `all:`/`any:` prefix).
88
+ */
89
+ export interface NodeRequires {
90
+ /** Listed paths must be present and non-null in the context map. */
91
+ output_required?: string[];
92
+ /** Each assertion must hold against the context map. */
93
+ output_matches?: OutputMatch[];
94
+ /** Action when checks fail. Default: "fail". */
95
+ on_fail?: "fail" | "skip";
96
+ }
97
+ /**
98
+ * Node-local retry on verify failure.
99
+ *
100
+ * Re-runs the LLM up to `max` additional times, prepending feedback derived
101
+ * from the verify failure. Triggered ONLY by verify failure — not by tool/API
102
+ * errors and not by `requires` failure.
103
+ *
104
+ * `instruction` shapes the feedback preamble:
105
+ * - omitted → default "## Previous attempt failed verification..."
106
+ * - string → static text + verify error
107
+ * - { auto: true } → LLM-generated diagnosis from default reflection prompt
108
+ * - { reflect: s } → LLM-generated diagnosis from author-provided prompt
109
+ */
110
+ export interface NodeRetry {
111
+ /** Maximum number of retry attempts after the initial run. Must be ≥ 1. */
112
+ max: number;
113
+ /** Preamble shape — see interface docs. */
114
+ instruction?: string | {
115
+ auto: true;
116
+ } | {
117
+ reflect: string;
118
+ };
119
+ }
76
120
  /**
77
121
  * A single output assertion. Exactly one of `equals | in | matches` must be set.
78
122
  *
@@ -106,6 +150,10 @@ export interface Node {
106
150
  context?: NodeSources;
107
151
  /** Machine-checked post-conditions. Enforced by the executor after the LLM finishes. */
108
152
  verify?: NodeVerify;
153
+ /** Machine-checked pre-conditions. Enforced by the executor before the LLM runs. */
154
+ requires?: NodeRequires;
155
+ /** Node-local retry on verify failure (with optional autonomous reflection). */
156
+ retry?: NodeRetry;
109
157
  }
110
158
  /** An edge connecting two nodes */
111
159
  export interface Edge {
@@ -153,6 +201,18 @@ export interface ToolCall {
153
201
  tool: string;
154
202
  input: unknown;
155
203
  output?: unknown;
204
+ /**
205
+ * Authoritative outcome of the tool invocation.
206
+ *
207
+ * When present, this is the source of truth for `verify` checks — the
208
+ * output-shape heuristic is a legacy fallback only. Set by the Claude
209
+ * runtime on tool completion: "success" when the tool returned normally,
210
+ * "error" when it threw or the MCP server returned is_error=true.
211
+ *
212
+ * Absent status indicates a legacy or hand-constructed ToolCall — verify
213
+ * falls back to inspecting `output` for an `error` key.
214
+ */
215
+ status?: "success" | "error";
156
216
  }
157
217
  export type ExecutionEvent = {
158
218
  type: "workflow:start";
@@ -182,6 +242,12 @@ export type ExecutionEvent = {
182
242
  type: "node:progress";
183
243
  node: string;
184
244
  message: string;
245
+ } | {
246
+ type: "node:retry";
247
+ node: string;
248
+ attempt: number;
249
+ reason: string;
250
+ preamble: string;
185
251
  } | {
186
252
  type: "route";
187
253
  from: string;
@@ -200,6 +266,8 @@ export interface TraceStep {
200
266
  status: "success" | "failed" | "skipped";
201
267
  /** 1-based iteration count (2 = second time this node ran) */
202
268
  iteration: number;
269
+ /** 0-indexed retry attempt for this iteration. Absent when no retry fired. */
270
+ retryAttempt?: number;
203
271
  }
204
272
  /** A routing decision between nodes */
205
273
  export interface TraceEdge {
@@ -245,6 +313,14 @@ export interface Claude {
245
313
  description: string;
246
314
  }[];
247
315
  }): Promise<string>;
316
+ /**
317
+ * Single-completion free-text query. No tools, no output schema.
318
+ * Used by the executor to generate retry strategies in autonomous reflection mode.
319
+ */
320
+ ask(opts: {
321
+ instruction: string;
322
+ context: Record<string, unknown>;
323
+ }): Promise<string>;
248
324
  }
249
325
  export interface McpServerConfig {
250
326
  type?: "stdio" | "http";
package/dist/verify.d.ts CHANGED
@@ -8,6 +8,7 @@ export type Resolution = {
8
8
  reason: string;
9
9
  };
10
10
  export declare function resolvePath(data: unknown, path: string): Resolution;
11
+ export declare function isErrorOutput(output: unknown): boolean;
11
12
  export declare function checkAnyToolCalled(required: string[], toolCalls: ToolCall[]): string | null;
12
13
  export declare function checkAllToolsCalled(required: string[], toolCalls: ToolCall[]): string | null;
13
14
  export declare function checkNoToolCalled(forbidden: string[], toolCalls: ToolCall[]): string | null;
package/dist/verify.js CHANGED
@@ -69,19 +69,35 @@ export function resolvePath(data, path) {
69
69
  }
70
70
  return { ok: true, mode: parsed.mode, values: current };
71
71
  }
72
- // A tool call "succeeded" when its output does not carry a non-null `error` field.
73
- // `{ error: null }` and `{ error: false }` are treated as success — many real
74
- // tools include the key with a null sentinel.
75
- function isErrorOutput(output) {
72
+ // Legacy output-shape heuristic: a tool call "succeeded" when its output
73
+ // does not carry a non-null `error` field. Kept as a fallback for ToolCall
74
+ // records that predate the explicit `status` field (hand-constructed in
75
+ // tests, older runtimes). The Claude runtime now sets `status` directly.
76
+ export function isErrorOutput(output) {
76
77
  if (!output || typeof output !== "object")
77
78
  return false;
78
79
  const err = output.error;
79
80
  return err !== undefined && err !== null && err !== false;
80
81
  }
82
+ /**
83
+ * A tool call is considered successful when:
84
+ * - explicit `status === "success"`, OR
85
+ * - no explicit status AND output does not look like an error.
86
+ *
87
+ * `status` is authoritative. It's the only signal we have for external MCP
88
+ * tools whose structured output isn't exposed to the workflow runtime.
89
+ */
90
+ function didSucceed(c) {
91
+ if (c.status === "error")
92
+ return false;
93
+ if (c.status === "success")
94
+ return true;
95
+ return !isErrorOutput(c.output);
96
+ }
81
97
  function succeededTools(toolCalls) {
82
98
  const names = new Set();
83
99
  for (const c of toolCalls) {
84
- if (!isErrorOutput(c.output))
100
+ if (didSucceed(c))
85
101
  names.add(c.tool);
86
102
  }
87
103
  return names;
@@ -180,8 +196,30 @@ export function checkOutputRequired(paths, data) {
180
196
  return null;
181
197
  return `output_required: ${failures.join("; ")}`;
182
198
  }
199
+ /**
200
+ * Cap on `verify.output_matches[].matches` source length.
201
+ *
202
+ * `matches` is user-supplied through workflow YAML, including marketplace
203
+ * workflows. A pathological pattern like `(a+)+$` causes exponential
204
+ * backtracking in V8's regex engine. Capping the source length is a cheap,
205
+ * useful defense — well-formed verify regexes are tens of characters at
206
+ * most. Patterns longer than this are almost always either generated junk
207
+ * or a deliberate ReDoS attempt; either way, refusing to compile is safer
208
+ * than executing them.
209
+ *
210
+ * Caveat: length alone does NOT prevent all ReDoS — a 12-char pattern like
211
+ * `(a+)+$` is still catastrophic against the right input. Future work:
212
+ * gate compilation through `safe-regex` or use the `re2` engine for
213
+ * marketplace inputs. The cap closes the obvious abuse surface without
214
+ * adding a runtime dep right now.
215
+ */
216
+ const MAX_REGEX_SOURCE_LENGTH = 1000;
183
217
  function compileMatch(m) {
184
218
  if (m.matches !== undefined) {
219
+ if (m.matches.length > MAX_REGEX_SOURCE_LENGTH) {
220
+ throw new Error(`regex source exceeds ${MAX_REGEX_SOURCE_LENGTH} characters (got ${m.matches.length}); ` +
221
+ `tighten the pattern to avoid catastrophic-backtracking risk`);
222
+ }
185
223
  // Throws synchronously if the regex source is invalid; surfaced as a
186
224
  // verify failure rather than a crash because the executor catches.
187
225
  return { match: m, regex: new RegExp(m.matches) };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sweny-ai/core",
3
- "version": "0.1.76",
3
+ "version": "0.1.78",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sweny": "./dist/cli/main.js"
@@ -46,10 +46,11 @@
46
46
  "dist"
47
47
  ],
48
48
  "scripts": {
49
- "build": "rm -rf dist && tsc && cp src/workflows/*.yml dist/workflows/ && node scripts/build-workflow-browser.mjs",
49
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && cp src/workflows/*.yml dist/workflows/ && node scripts/build-workflow-browser.mjs && node scripts/write-public-schema.mjs",
50
50
  "typecheck": "tsc --noEmit",
51
- "test": "vitest run --exclude 'src/__tests__/integration/**'",
52
- "test:integration": "vitest run --config vitest.integration.config.ts"
51
+ "test": "vitest run --exclude 'src/__tests__/integration/**' --exclude 'dist/**'",
52
+ "test:integration": "vitest run --config vitest.integration.config.ts",
53
+ "check:schema-drift": "node scripts/write-public-schema.mjs && git diff --exit-code -- ../../spec/public/schemas/workflow.json"
53
54
  },
54
55
  "dependencies": {
55
56
  "@anthropic-ai/claude-agent-sdk": "^0.2.114",
@@ -61,6 +62,9 @@
61
62
  },
62
63
  "devDependencies": {
63
64
  "@anthropic-ai/claude-code": "^2.1.114",
65
+ "ajv": "^8.18.0",
66
+ "esbuild": "^0.28.0",
67
+ "prettier": "^3.8.3",
64
68
  "vitest": "^4.1.4"
65
69
  },
66
70
  "publishConfig": {
@@ -1,11 +0,0 @@
1
- /**
2
- * Rules / Context Cascade + max_turns Tests
3
- *
4
- * Covers the spec sections:
5
- * - Workflow > Rules & Context
6
- * - Workflow > Runtime Input (rules/context)
7
- * - Nodes > Max Turns Semantics
8
- * - Nodes > Rules & Context (cascade + `only` flag)
9
- * - Nodes > Input Augmentation (assembly order)
10
- */
11
- export {};