@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.
- package/dist/browser.d.ts +11 -5
- package/dist/browser.js +11 -11
- package/dist/claude.d.ts +20 -0
- package/dist/claude.js +139 -9
- package/dist/cli/config.d.ts +22 -0
- package/dist/cli/config.js +56 -9
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.js +56 -57
- package/dist/cli/marketplace.js +35 -9
- package/dist/cli/publish.d.ts +10 -0
- package/dist/cli/publish.js +22 -14
- package/dist/executor.js +104 -43
- package/dist/loader.d.ts +40 -0
- package/dist/loader.js +73 -0
- package/dist/mcp-catalog.d.ts +47 -0
- package/dist/mcp-catalog.js +304 -0
- package/dist/mcp.d.ts +6 -9
- package/dist/mcp.js +24 -314
- package/dist/requires.d.ts +7 -0
- package/dist/requires.js +34 -0
- package/dist/retry.d.ts +23 -0
- package/dist/retry.js +72 -0
- package/dist/schema.d.ts +667 -80
- package/dist/schema.js +144 -5
- package/dist/skills/custom-loader.d.ts +40 -0
- package/dist/skills/custom-loader.js +107 -32
- package/dist/skills/index.d.ts +13 -1
- package/dist/skills/index.js +12 -3
- package/dist/studio.js +4 -1
- package/dist/templates.d.ts +29 -8
- package/dist/templates.js +30 -20
- package/dist/testing.d.ts +7 -0
- package/dist/testing.js +7 -0
- package/dist/types.d.ts +76 -0
- package/dist/verify.d.ts +1 -0
- package/dist/verify.js +43 -5
- package/package.json +8 -4
- package/dist/__tests__/cascade.test.d.ts +0 -11
- package/dist/__tests__/cascade.test.js +0 -449
- package/dist/__tests__/claude.test.d.ts +0 -1
- package/dist/__tests__/claude.test.js +0 -427
- package/dist/__tests__/custom-loader.test.d.ts +0 -1
- package/dist/__tests__/custom-loader.test.js +0 -116
- package/dist/__tests__/executor.test.d.ts +0 -1
- package/dist/__tests__/executor.test.js +0 -736
- package/dist/__tests__/integration/datadog.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/datadog.integration.test.js +0 -23
- package/dist/__tests__/integration/e2e-workflow.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/e2e-workflow.integration.test.js +0 -75
- package/dist/__tests__/integration/github.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/github.integration.test.js +0 -37
- package/dist/__tests__/integration/harness.d.ts +0 -24
- package/dist/__tests__/integration/harness.js +0 -34
- package/dist/__tests__/integration/linear.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/linear.integration.test.js +0 -15
- package/dist/__tests__/integration/sentry.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/sentry.integration.test.js +0 -20
- package/dist/__tests__/integration/slack.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/slack.integration.test.js +0 -22
- package/dist/__tests__/integration/sources.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/sources.integration.test.js +0 -123
- package/dist/__tests__/publish.test.d.ts +0 -1
- package/dist/__tests__/publish.test.js +0 -180
- package/dist/__tests__/schema.test.d.ts +0 -1
- package/dist/__tests__/schema.test.js +0 -526
- package/dist/__tests__/skill-config-integration.test.d.ts +0 -1
- package/dist/__tests__/skill-config-integration.test.js +0 -204
- package/dist/__tests__/skills-index.test.d.ts +0 -1
- package/dist/__tests__/skills-index.test.js +0 -119
- package/dist/__tests__/skills.test.d.ts +0 -1
- package/dist/__tests__/skills.test.js +0 -565
- package/dist/__tests__/spec-conformance.test.d.ts +0 -18
- package/dist/__tests__/spec-conformance.test.js +0 -1074
- package/dist/__tests__/studio.test.d.ts +0 -1
- package/dist/__tests__/studio.test.js +0 -403
- package/dist/__tests__/templates.test.d.ts +0 -1
- package/dist/__tests__/templates.test.js +0 -49
- package/dist/__tests__/testing.test.d.ts +0 -1
- package/dist/__tests__/testing.test.js +0 -224
- package/dist/__tests__/verify.test.d.ts +0 -1
- package/dist/__tests__/verify.test.js +0 -517
- package/dist/__tests__/version-consistency.test.d.ts +0 -1
- package/dist/__tests__/version-consistency.test.js +0 -312
- package/dist/__tests__/workflow-builder.test.d.ts +0 -1
- package/dist/__tests__/workflow-builder.test.js +0 -110
- package/dist/__tests__/workflow-yaml.test.d.ts +0 -1
- package/dist/__tests__/workflow-yaml.test.js +0 -201
- package/dist/cli/__tests__/diagram.test.d.ts +0 -1
- package/dist/cli/__tests__/diagram.test.js +0 -225
- package/dist/cli/__tests__/report-cloud.test.d.ts +0 -1
- package/dist/cli/__tests__/report-cloud.test.js +0 -165
- package/dist/cli/__tests__/upgrade.test.d.ts +0 -1
- package/dist/cli/__tests__/upgrade.test.js +0 -317
- package/dist/cli/__tests__/version-check.test.d.ts +0 -1
- package/dist/cli/__tests__/version-check.test.js +0 -209
- package/dist/cli/config.test.d.ts +0 -1
- package/dist/cli/config.test.js +0 -200
- package/dist/cli/credentials.test.d.ts +0 -1
- package/dist/cli/credentials.test.js +0 -172
- package/dist/cli/e2e.test.d.ts +0 -1
- package/dist/cli/e2e.test.js +0 -690
- package/dist/cli/marketplace.test.d.ts +0 -1
- package/dist/cli/marketplace.test.js +0 -355
- package/dist/cli/new.test.d.ts +0 -1
- package/dist/cli/new.test.js +0 -1043
- package/dist/cli/output.test.d.ts +0 -1
- package/dist/cli/output.test.js +0 -180
- package/dist/cli/publish.test.d.ts +0 -1
- package/dist/cli/publish.test.js +0 -610
- package/dist/cli/renderer.test.d.ts +0 -1
- package/dist/cli/renderer.test.js +0 -302
- package/dist/executor.test.d.ts +0 -1
- package/dist/executor.test.js +0 -603
- package/dist/mcp.test.d.ts +0 -1
- package/dist/mcp.test.js +0 -735
- package/dist/mermaid.test.d.ts +0 -1
- package/dist/mermaid.test.js +0 -256
- package/dist/sources.test.d.ts +0 -1
- package/dist/sources.test.js +0 -265
- package/dist/sources.validation.test.d.ts +0 -12
- package/dist/sources.validation.test.js +0 -380
- package/dist/workflow-builder.test.d.ts +0 -1
- package/dist/workflow-builder.test.js +0 -117
package/dist/templates.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Template loading for
|
|
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
|
|
10
|
-
*
|
|
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
|
-
|
|
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,
|
|
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",
|
|
75
|
+
const resolved = await resolveSource(source.trim(), "template", buildCtx(opts));
|
|
72
76
|
return resolved.content;
|
|
73
77
|
}
|
|
74
78
|
catch (err) {
|
|
75
|
-
|
|
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,
|
|
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,
|
|
85
|
-
loadTemplate(config.prTemplate, DEFAULT_PR_TEMPLATE,
|
|
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,
|
|
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 =
|
|
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
|
-
|
|
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
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
|
|
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 (
|
|
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.
|
|
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 {};
|