@sweny-ai/core 0.1.132 → 0.1.134
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/claude.d.ts +3 -230
- package/dist/claude.js +3 -1049
- package/dist/cli/comment-output.d.ts +29 -0
- package/dist/cli/comment-output.js +82 -0
- package/dist/cli/e2e.js +2 -2
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +21 -6
- package/dist/cli/new.js +3 -3
- package/dist/cli/run-history.d.ts +5 -0
- package/dist/cli/run-history.js +2 -0
- package/dist/cli/run-output.d.ts +7 -0
- package/dist/cli/run-output.js +12 -3
- package/dist/eval/index.js +7 -4
- package/dist/executor.d.ts +11 -2
- package/dist/executor.js +7 -1
- package/dist/harness/capabilities.d.ts +7 -0
- package/dist/harness/capabilities.js +17 -0
- package/dist/harness/claude-code.d.ts +228 -0
- package/dist/harness/claude-code.js +1020 -0
- package/dist/harness/compat.d.ts +18 -0
- package/dist/harness/compat.js +62 -0
- package/dist/harness/index.d.ts +17 -0
- package/dist/harness/index.js +24 -0
- package/dist/harness/policy.d.ts +8 -0
- package/dist/harness/policy.js +33 -0
- package/dist/harness/prompts.d.ts +59 -0
- package/dist/harness/prompts.js +107 -0
- package/dist/harness/types.d.ts +111 -0
- package/dist/harness/types.js +11 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.js +7 -5
- package/dist/testing.d.ts +23 -5
- package/dist/testing.js +29 -1
- package/dist/types.d.ts +14 -0
- package/package.json +1 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR billboard: the markdown a CI runner posts as one sticky comment on a
|
|
3
|
+
* pull request. Pure and runner-agnostic; the CLI writes it with
|
|
4
|
+
* `--comment-file`, and any runner (the GitHub Action, GitLab, a script) posts it.
|
|
5
|
+
*
|
|
6
|
+
* METADATA ONLY. Node names, statuses, counts, and durations. Never prompts,
|
|
7
|
+
* tool inputs, node outputs, errors, or model prose.
|
|
8
|
+
*/
|
|
9
|
+
import type { ExecutionTrace, NodeResult, Workflow } from "../types.js";
|
|
10
|
+
import { type RunSummary } from "./run-output.js";
|
|
11
|
+
export declare const RUN_COMMENT_FOOTER = "Run with [SWEny](https://sweny.ai): `npx @sweny-ai/core new`";
|
|
12
|
+
export interface RunCommentOptions {
|
|
13
|
+
trace?: ExecutionTrace;
|
|
14
|
+
/** Per-node wall-clock duration in ms, keyed by node id. Missing entries render as "-". */
|
|
15
|
+
durationsMs?: Record<string, number>;
|
|
16
|
+
}
|
|
17
|
+
/** Hidden marker the poster searches for to update the comment in place. */
|
|
18
|
+
export declare function runCommentMarker(workflowId: string): string;
|
|
19
|
+
export declare function formatRunComment(workflow: Workflow, results: Map<string, NodeResult>, summary: RunSummary, opts?: RunCommentOptions): string;
|
|
20
|
+
/**
|
|
21
|
+
* Minimal comment for a run that crashed before producing node results: no DAG
|
|
22
|
+
* and no error text (thrown messages can embed model prose). Replaces any stale
|
|
23
|
+
* success comment for the same workflow.
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatCrashComment(workflow: Workflow, summary: RunSummary): string;
|
|
26
|
+
/** Write the comment markdown to `file`. Never throws; returns true only when written. */
|
|
27
|
+
export declare function writeRunComment(file: string, workflow: Workflow, results: Map<string, NodeResult>, summary: RunSummary, opts?: RunCommentOptions & {
|
|
28
|
+
crashed?: boolean;
|
|
29
|
+
}): boolean;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR billboard: the markdown a CI runner posts as one sticky comment on a
|
|
3
|
+
* pull request. Pure and runner-agnostic; the CLI writes it with
|
|
4
|
+
* `--comment-file`, and any runner (the GitHub Action, GitLab, a script) posts it.
|
|
5
|
+
*
|
|
6
|
+
* METADATA ONLY. Node names, statuses, counts, and durations. Never prompts,
|
|
7
|
+
* tool inputs, node outputs, errors, or model prose.
|
|
8
|
+
*/
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { toMermaidBlock } from "../mermaid.js";
|
|
12
|
+
import { STEP_SUMMARY_CLASS_DEFS, formatReceipt, formatReceiptDuration, nodeStates, } from "./run-output.js";
|
|
13
|
+
export const RUN_COMMENT_FOOTER = "Run with [SWEny](https://sweny.ai): `npx @sweny-ai/core new`";
|
|
14
|
+
/** Hidden marker the poster searches for to update the comment in place. */
|
|
15
|
+
export function runCommentMarker(workflowId) {
|
|
16
|
+
const safe = workflowId.replace(/[^A-Za-z0-9._-]+/g, "_").replace(/-{2,}/g, "-") || "workflow";
|
|
17
|
+
return `<!-- sweny-run-comment:${safe} -->`;
|
|
18
|
+
}
|
|
19
|
+
/** Table-cell-safe text: no pipes, newlines, or backticks. */
|
|
20
|
+
function cell(text) {
|
|
21
|
+
return text.replace(/\s+/g, " ").replace(/\|/g, "\\|").replace(/`/g, "'").trim();
|
|
22
|
+
}
|
|
23
|
+
const STATUS_LABEL = { success: "✅ success", failed: "❌ failed", skipped: "⏭️ skipped" };
|
|
24
|
+
export function formatRunComment(workflow, results, summary, opts = {}) {
|
|
25
|
+
const state = nodeStates(results);
|
|
26
|
+
const rows = [...results].map(([id, r]) => {
|
|
27
|
+
const name = cell(workflow.nodes[id]?.name ?? id);
|
|
28
|
+
const ms = opts.durationsMs?.[id];
|
|
29
|
+
const dur = typeof ms === "number" && Number.isFinite(ms) ? formatReceiptDuration(ms) : "-";
|
|
30
|
+
return `| ${name} | ${STATUS_LABEL[r.status]} | ${dur} |`;
|
|
31
|
+
});
|
|
32
|
+
return [
|
|
33
|
+
runCommentMarker(workflow.id),
|
|
34
|
+
`## ${summary.ok ? "✅" : "❌"} ${cell(workflow.name)}`,
|
|
35
|
+
"",
|
|
36
|
+
`\`${formatReceipt(summary)}\``,
|
|
37
|
+
"",
|
|
38
|
+
toMermaidBlock(workflow, { state, trace: opts.trace, classDefs: STEP_SUMMARY_CLASS_DEFS }),
|
|
39
|
+
"",
|
|
40
|
+
"<details>",
|
|
41
|
+
"<summary>Nodes</summary>",
|
|
42
|
+
"",
|
|
43
|
+
"| Node | Status | Duration |",
|
|
44
|
+
"| --- | --- | --- |",
|
|
45
|
+
...rows,
|
|
46
|
+
"",
|
|
47
|
+
"</details>",
|
|
48
|
+
"",
|
|
49
|
+
`<sub>${RUN_COMMENT_FOOTER}</sub>`,
|
|
50
|
+
"",
|
|
51
|
+
].join("\n");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Minimal comment for a run that crashed before producing node results: no DAG
|
|
55
|
+
* and no error text (thrown messages can embed model prose). Replaces any stale
|
|
56
|
+
* success comment for the same workflow.
|
|
57
|
+
*/
|
|
58
|
+
export function formatCrashComment(workflow, summary) {
|
|
59
|
+
return [
|
|
60
|
+
runCommentMarker(workflow.id),
|
|
61
|
+
`## ❌ ${cell(workflow.name)}`,
|
|
62
|
+
"",
|
|
63
|
+
`\`${formatReceipt(summary)} · crashed\``,
|
|
64
|
+
"",
|
|
65
|
+
"The run stopped before finishing. See the job log for details.",
|
|
66
|
+
"",
|
|
67
|
+
`<sub>${RUN_COMMENT_FOOTER}</sub>`,
|
|
68
|
+
"",
|
|
69
|
+
].join("\n");
|
|
70
|
+
}
|
|
71
|
+
/** Write the comment markdown to `file`. Never throws; returns true only when written. */
|
|
72
|
+
export function writeRunComment(file, workflow, results, summary, opts = {}) {
|
|
73
|
+
try {
|
|
74
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
75
|
+
fs.writeFileSync(file, opts.crashed ? formatCrashComment(workflow, summary) : formatRunComment(workflow, results, summary, opts));
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
process.stderr.write(` ⚠ could not write comment file: ${err instanceof Error ? err.message : err}\n`);
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
package/dist/cli/e2e.js
CHANGED
|
@@ -10,7 +10,7 @@ import * as p from "@clack/prompts";
|
|
|
10
10
|
import chalk from "chalk";
|
|
11
11
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
12
12
|
import { execute } from "../executor.js";
|
|
13
|
-
import {
|
|
13
|
+
import { createHarness } from "../harness/index.js";
|
|
14
14
|
import { createSkillMap } from "../skills/index.js";
|
|
15
15
|
import { configuredSkills } from "../skills/custom-loader.js";
|
|
16
16
|
import { consoleLogger } from "../types.js";
|
|
@@ -906,7 +906,7 @@ export async function runE2eRun(options) {
|
|
|
906
906
|
}
|
|
907
907
|
// Build skills + Claude client
|
|
908
908
|
const skills = createSkillMap(configuredSkills(process.env, cwd));
|
|
909
|
-
const claude =
|
|
909
|
+
const claude = createHarness("claude-code", {
|
|
910
910
|
maxTurns: 80,
|
|
911
911
|
cwd,
|
|
912
912
|
logger: consoleLogger,
|
package/dist/cli/main.d.ts
CHANGED
package/dist/cli/main.js
CHANGED
|
@@ -9,7 +9,7 @@ import chalk from "chalk";
|
|
|
9
9
|
import { execute } from "../executor.js";
|
|
10
10
|
import { triageWorkflow, implementWorkflow, seedContentWorkflow } from "../workflows/index.js";
|
|
11
11
|
import { consoleLogger } from "../types.js";
|
|
12
|
-
import {
|
|
12
|
+
import { createHarness } from "../harness/index.js";
|
|
13
13
|
import { builtinSkills, createSkillMap, validateWorkflowSkills } from "../skills/index.js";
|
|
14
14
|
import { formatMissingSkillLines, skillEnvWarnings } from "./skill-env.js";
|
|
15
15
|
import { configuredSkills, configuredSkillsWithDiagnostics } from "../skills/custom-loader.js";
|
|
@@ -32,6 +32,7 @@ import { registerRunsCommand } from "./runs.js";
|
|
|
32
32
|
import { runE2eRun, runWithWallClockBudget, DEFAULT_WORKFLOW_TIMEOUT_MS } from "./e2e.js";
|
|
33
33
|
import { createVerboseToolObserver } from "./verbose-observer.js";
|
|
34
34
|
import { createRunLogger, renderReceiptLine, summarizeRun, writeStepSummary, WORKFLOW_RUN_DESCRIPTION, WORKFLOW_RUN_OPTIONS, } from "./run-output.js";
|
|
35
|
+
import { writeRunComment } from "./comment-output.js";
|
|
35
36
|
import { registerTriageCommand, registerImplementCommand, parseCliInputs, validateInputs, validateWarnings, parsePositiveInt, } from "./config.js";
|
|
36
37
|
import { c, formatBanner, getStepDetails, formatStepLine, formatDagResultHuman, formatDagResultMarkdown, formatResultJson, formatValidationErrors, formatCrashError, formatCheckResults, } from "./output.js";
|
|
37
38
|
import { checkProviderConnectivity, detectClaudeCodeLogin, discoverWorkflowSkillIds, validateCheckInputs, } from "./check.js";
|
|
@@ -202,7 +203,7 @@ triageCmd.action(async (options) => {
|
|
|
202
203
|
const skills = createSkillMap(triageSkillDiscovery.skills);
|
|
203
204
|
const mcpAutoConfig = buildMcpAutoConfig(config);
|
|
204
205
|
const mcpServers = buildAutoMcpServers(mcpAutoConfig);
|
|
205
|
-
const claude =
|
|
206
|
+
const claude = createHarness("claude-code", {
|
|
206
207
|
maxTurns: config.maxInvestigateTurns || 50,
|
|
207
208
|
cwd: process.cwd(),
|
|
208
209
|
logger: consoleLogger,
|
|
@@ -512,7 +513,7 @@ implementCmd.action(async (issueId, options) => {
|
|
|
512
513
|
const skills = createSkillMap(implementSkillDiscovery.skills);
|
|
513
514
|
const mcpAutoConfig = buildMcpAutoConfig(config);
|
|
514
515
|
const mcpServers = buildAutoMcpServers(mcpAutoConfig);
|
|
515
|
-
const claude =
|
|
516
|
+
const claude = createHarness("claude-code", {
|
|
516
517
|
maxTurns: config.maxImplementTurns || 40,
|
|
517
518
|
cwd: process.cwd(),
|
|
518
519
|
logger: consoleLogger,
|
|
@@ -756,7 +757,7 @@ export async function workflowRunAction(file, options) {
|
|
|
756
757
|
});
|
|
757
758
|
// Raw [info]/[debug] lines are verbose-only; warnings are rendered (#383).
|
|
758
759
|
const runLogger = createRunLogger({ verbose: Boolean(options.verbose), tty: isTTY });
|
|
759
|
-
const claude =
|
|
760
|
+
const claude = createHarness("claude-code", {
|
|
760
761
|
maxTurns: config.maxInvestigateTurns || 50,
|
|
761
762
|
cwd: process.cwd(),
|
|
762
763
|
logger: runLogger,
|
|
@@ -948,6 +949,14 @@ export async function workflowRunAction(file, options) {
|
|
|
948
949
|
catch {
|
|
949
950
|
// silent
|
|
950
951
|
}
|
|
952
|
+
// PR billboard markdown (metadata only). Written before any early exit so
|
|
953
|
+
// --json runs and failed runs still get a comment.
|
|
954
|
+
if (options.commentFile) {
|
|
955
|
+
writeRunComment(options.commentFile, workflow, results, summarizeRun(results, wfDurationMs), {
|
|
956
|
+
trace,
|
|
957
|
+
durationsMs: Object.fromEntries(nodeTimer.durations),
|
|
958
|
+
});
|
|
959
|
+
}
|
|
951
960
|
if (isJson) {
|
|
952
961
|
process.stdout.write(JSON.stringify(Object.fromEntries(results), null, 2) + "\n");
|
|
953
962
|
process.exit(wfHasFailed ? 1 : 0);
|
|
@@ -986,6 +995,12 @@ export async function workflowRunAction(file, options) {
|
|
|
986
995
|
runLogger.flush();
|
|
987
996
|
recordHistory(nodeTimer.lastResults, undefined, true);
|
|
988
997
|
console.error(` ${renderReceiptLine(summarizeRun(new Map(), Date.now() - runStart, true), isTTY)}\n`);
|
|
998
|
+
// A crash must not leave a stale success comment behind.
|
|
999
|
+
if (options.commentFile) {
|
|
1000
|
+
writeRunComment(options.commentFile, workflow, new Map(), summarizeRun(new Map(), Date.now() - runStart, true), {
|
|
1001
|
+
crashed: true,
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
989
1004
|
// Finalize the cloud run as failed (covers thrown errors, incl.
|
|
990
1005
|
// RouteEvaluationError). Without this a crashed workflow run stays
|
|
991
1006
|
// "running" in cloud forever.
|
|
@@ -1086,7 +1101,7 @@ workflowCmd
|
|
|
1086
1101
|
console.warn("\x1B[33m ⚠ `sweny workflow create` is deprecated. Use `sweny new` instead.\x1B[0m\n");
|
|
1087
1102
|
}
|
|
1088
1103
|
const skills = configuredSkills();
|
|
1089
|
-
const claude =
|
|
1104
|
+
const claude = createHarness("claude-code", {
|
|
1090
1105
|
maxTurns: 3,
|
|
1091
1106
|
cwd: process.cwd(),
|
|
1092
1107
|
logger: consoleLogger,
|
|
@@ -1153,7 +1168,7 @@ workflowCmd
|
|
|
1153
1168
|
return;
|
|
1154
1169
|
}
|
|
1155
1170
|
const skills = configuredSkills();
|
|
1156
|
-
const claude =
|
|
1171
|
+
const claude = createHarness("claude-code", {
|
|
1157
1172
|
maxTurns: 3,
|
|
1158
1173
|
cwd: process.cwd(),
|
|
1159
1174
|
logger: consoleLogger,
|
package/dist/cli/new.js
CHANGED
|
@@ -14,7 +14,7 @@ import chalk from "chalk";
|
|
|
14
14
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
15
15
|
import { WORKFLOW_TEMPLATES } from "./templates.js";
|
|
16
16
|
import { buildWorkflow, refineWorkflow } from "../workflow-builder.js";
|
|
17
|
-
import {
|
|
17
|
+
import { createHarness } from "../harness/index.js";
|
|
18
18
|
import { consoleLogger } from "../types.js";
|
|
19
19
|
import { configuredSkills } from "../skills/custom-loader.js";
|
|
20
20
|
import { builtinSkills } from "../skills/index.js";
|
|
@@ -541,7 +541,7 @@ export async function runNew(options) {
|
|
|
541
541
|
const { installMarketplaceWorkflow } = await import("./marketplace.js");
|
|
542
542
|
const allSkills = configuredSkills(process.env, cwd);
|
|
543
543
|
const hasAgent = !!process.env.ANTHROPIC_API_KEY;
|
|
544
|
-
const claude = hasAgent ?
|
|
544
|
+
const claude = hasAgent ? createHarness("claude-code", { maxTurns: 3, cwd, logger: consoleLogger }) : null;
|
|
545
545
|
if (!options.skipIntro)
|
|
546
546
|
p.intro(`Installing ${options.marketplaceId} from marketplace`);
|
|
547
547
|
// Pre-compute source-control from git-remote (same method as the wizard path).
|
|
@@ -833,7 +833,7 @@ async function runCustomWorkflowBuilder(skills) {
|
|
|
833
833
|
});
|
|
834
834
|
if (p.isCancel(description))
|
|
835
835
|
return null;
|
|
836
|
-
const claude =
|
|
836
|
+
const claude = createHarness("claude-code", {
|
|
837
837
|
maxTurns: 3,
|
|
838
838
|
cwd: process.cwd(),
|
|
839
839
|
logger: consoleLogger,
|
|
@@ -48,6 +48,11 @@ export interface RunRecord {
|
|
|
48
48
|
to: string;
|
|
49
49
|
}>;
|
|
50
50
|
totals: RunTotals;
|
|
51
|
+
/** Harness that ran the nodes (id + version). Absent for runs with no harness-tagged result. */
|
|
52
|
+
harness?: {
|
|
53
|
+
id: string;
|
|
54
|
+
version: string;
|
|
55
|
+
};
|
|
51
56
|
}
|
|
52
57
|
/** sha256 (hex) of the workflow as canonical JSON: keys sorted, undefined dropped. */
|
|
53
58
|
export declare function hashWorkflow(workflow: Workflow): string;
|
package/dist/cli/run-history.js
CHANGED
|
@@ -91,6 +91,7 @@ export function buildRunRecord(i) {
|
|
|
91
91
|
retries: retries.get(id) ?? 0,
|
|
92
92
|
};
|
|
93
93
|
});
|
|
94
|
+
const harness = [...i.results.values()].find((r) => r.harness)?.harness;
|
|
94
95
|
return {
|
|
95
96
|
schema_version: RUN_HISTORY_SCHEMA_VERSION,
|
|
96
97
|
run_id: i.runId,
|
|
@@ -109,6 +110,7 @@ export function buildRunRecord(i) {
|
|
|
109
110
|
tokens: summary.tokens ?? null,
|
|
110
111
|
cost_usd: summary.costUsd ?? null,
|
|
111
112
|
},
|
|
113
|
+
...(harness ? { harness: { id: harness.id, version: harness.version } } : {}),
|
|
112
114
|
};
|
|
113
115
|
}
|
|
114
116
|
// ── Write, prune, read ──────────────────────────────────────────
|
package/dist/cli/run-output.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* model prose: only counts, durations, token totals, and cost.
|
|
7
7
|
*/
|
|
8
8
|
import { type ExecutionTrace, type Logger, type NodeResult, type Workflow } from "../types.js";
|
|
9
|
+
import { type NodeStatus } from "../mermaid.js";
|
|
9
10
|
export interface RunSummary {
|
|
10
11
|
ok: boolean;
|
|
11
12
|
nodesOk: number;
|
|
@@ -31,6 +32,12 @@ export declare function formatCost(usd: number): string;
|
|
|
31
32
|
export declare function formatReceipt(s: RunSummary): string;
|
|
32
33
|
/** Receipt for a terminal: colored only when `color` is true. */
|
|
33
34
|
export declare function renderReceiptLine(s: RunSummary, color: boolean): string;
|
|
35
|
+
/** Brand blue (blue-600 / blue-700), not indigo. Applied to successful nodes. */
|
|
36
|
+
export declare const STEP_SUMMARY_CLASS_DEFS: {
|
|
37
|
+
readonly success: "fill:#2563eb,stroke:#1d4ed8,color:#fff,stroke-width:2px";
|
|
38
|
+
};
|
|
39
|
+
/** Per-node Mermaid status from run results. */
|
|
40
|
+
export declare function nodeStates(results: Map<string, NodeResult>): Record<string, NodeStatus>;
|
|
34
41
|
/** Markdown for `$GITHUB_STEP_SUMMARY`: receipt + status-colored Mermaid DAG. */
|
|
35
42
|
export declare function formatStepSummary(workflow: Workflow, results: Map<string, NodeResult>, summary: RunSummary, trace?: ExecutionTrace): string;
|
|
36
43
|
/**
|
package/dist/cli/run-output.js
CHANGED
|
@@ -94,15 +94,20 @@ export function renderReceiptLine(s, color) {
|
|
|
94
94
|
}
|
|
95
95
|
// ── Step summary ────────────────────────────────────────────────
|
|
96
96
|
/** Brand blue (blue-600 / blue-700), not indigo. Applied to successful nodes. */
|
|
97
|
-
const STEP_SUMMARY_CLASS_DEFS = {
|
|
97
|
+
export const STEP_SUMMARY_CLASS_DEFS = {
|
|
98
98
|
success: "fill:#2563eb,stroke:#1d4ed8,color:#fff,stroke-width:2px",
|
|
99
99
|
};
|
|
100
|
-
/**
|
|
101
|
-
export function
|
|
100
|
+
/** Per-node Mermaid status from run results. */
|
|
101
|
+
export function nodeStates(results) {
|
|
102
102
|
const state = {};
|
|
103
103
|
for (const [id, r] of results) {
|
|
104
104
|
state[id] = r.status === "success" ? "success" : r.status === "failed" ? "failed" : "skipped";
|
|
105
105
|
}
|
|
106
|
+
return state;
|
|
107
|
+
}
|
|
108
|
+
/** Markdown for `$GITHUB_STEP_SUMMARY`: receipt + status-colored Mermaid DAG. */
|
|
109
|
+
export function formatStepSummary(workflow, results, summary, trace) {
|
|
110
|
+
const state = nodeStates(results);
|
|
106
111
|
return [
|
|
107
112
|
`## ${summary.ok ? "✅" : "❌"} ${workflow.name}`,
|
|
108
113
|
"",
|
|
@@ -185,5 +190,9 @@ export const WORKFLOW_RUN_OPTIONS = [
|
|
|
185
190
|
"Show raw log lines and each tool call's input and output inline (human-readable, truncated). Use --stream for full untruncated NDJSON.",
|
|
186
191
|
],
|
|
187
192
|
["--mermaid", "Output a Mermaid diagram with execution state after run"],
|
|
193
|
+
[
|
|
194
|
+
"--comment-file <path>",
|
|
195
|
+
"Write a PR-comment markdown (run receipt, status-colored DAG, per-node table; metadata only) to <path> so any CI can post it",
|
|
196
|
+
],
|
|
188
197
|
["--input <json>", "JSON string of input data to pass to the workflow"],
|
|
189
198
|
];
|
package/dist/eval/index.js
CHANGED
|
@@ -8,7 +8,10 @@ import { evaluateFunctionRule } from "./function.js";
|
|
|
8
8
|
import { evaluateJudge } from "./judge.js";
|
|
9
9
|
/** Reasoning cap, matching the spec's ~500-character ceiling. */
|
|
10
10
|
const MAX_REASONING_LENGTH = 500;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Judge model when neither evaluator, node, workflow nor the harness names one.
|
|
13
|
+
* Harnesses declare their own via `defaultJudgeModel` (Claude Code: this value).
|
|
14
|
+
*/
|
|
12
15
|
const DEFAULT_JUDGE_MODEL = "claude-haiku-4-5";
|
|
13
16
|
function capReasoning(reasoning) {
|
|
14
17
|
if (!reasoning)
|
|
@@ -17,8 +20,8 @@ function capReasoning(reasoning) {
|
|
|
17
20
|
return reasoning;
|
|
18
21
|
return reasoning.slice(0, MAX_REASONING_LENGTH - 1) + "…";
|
|
19
22
|
}
|
|
20
|
-
function resolveJudgeModel(evaluator, node, workflow) {
|
|
21
|
-
return evaluator.model ?? node?.judge_model ?? workflow?.judge_model ?? DEFAULT_JUDGE_MODEL;
|
|
23
|
+
function resolveJudgeModel(evaluator, node, workflow, harnessDefault) {
|
|
24
|
+
return evaluator.model ?? node?.judge_model ?? workflow?.judge_model ?? harnessDefault ?? DEFAULT_JUDGE_MODEL;
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
27
|
* Run every declared evaluator against the node's result and return one
|
|
@@ -56,7 +59,7 @@ export async function evaluateAll(evaluators, result, opts = {}) {
|
|
|
56
59
|
if (!opts.claude) {
|
|
57
60
|
throw new Error(`evaluator '${e.name}' is kind: judge but no Claude client was provided to evaluateAll`);
|
|
58
61
|
}
|
|
59
|
-
const model = resolveJudgeModel(e, opts.node, opts.workflow);
|
|
62
|
+
const model = resolveJudgeModel(e, opts.node, opts.workflow, opts.claude.defaultJudgeModel);
|
|
60
63
|
const verdict = await evaluateJudge(e, result, opts.claude, { model });
|
|
61
64
|
out.push({
|
|
62
65
|
name: e.name,
|
package/dist/executor.d.ts
CHANGED
|
@@ -13,13 +13,22 @@
|
|
|
13
13
|
* This replaces ~8k lines of engine + recipe step code.
|
|
14
14
|
*/
|
|
15
15
|
import type { Workflow, Skill, Tool, Claude, Observer, Logger, ExecutionResult } from "./types.js";
|
|
16
|
+
import type { AgentHarness } from "./harness/types.js";
|
|
16
17
|
export interface ExecuteOptions {
|
|
17
18
|
/** Registered skills (id → Skill) */
|
|
18
19
|
skills: Map<string, Skill>;
|
|
19
20
|
/** Config values — env vars + explicit overrides */
|
|
20
21
|
config?: Record<string, string>;
|
|
21
|
-
/**
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The agent harness that runs nodes (`createHarness("claude-code")`).
|
|
24
|
+
* Required unless the deprecated `claude` option is given.
|
|
25
|
+
*/
|
|
26
|
+
harness?: AgentHarness;
|
|
27
|
+
/**
|
|
28
|
+
* Claude client.
|
|
29
|
+
* @deprecated Pass `harness`. Still accepted (see `claudeCompat()`); when both are set, `harness` wins.
|
|
30
|
+
*/
|
|
31
|
+
claude?: Claude;
|
|
23
32
|
/** Event observer for streaming/logging */
|
|
24
33
|
observer?: Observer;
|
|
25
34
|
/** Logger */
|
package/dist/executor.js
CHANGED
|
@@ -22,6 +22,7 @@ import { buildToolAliases } from "./skills/index.js";
|
|
|
22
22
|
import { validateWorkflow } from "./schema.js";
|
|
23
23
|
import { resolveAgentAccess } from "./agent-env.js";
|
|
24
24
|
import { fenceUntrusted } from "./untrusted.js";
|
|
25
|
+
import { asClaude } from "./harness/compat.js";
|
|
25
26
|
/**
|
|
26
27
|
* Default workflow-level step budget. Counts total node executions across the
|
|
27
28
|
* whole run (loop iterations included). Generous enough for legitimate deep
|
|
@@ -47,7 +48,12 @@ function throwIfAborted(signal) {
|
|
|
47
48
|
* - `trace`: full ordered execution trace including loops and routing decisions
|
|
48
49
|
*/
|
|
49
50
|
export async function execute(workflow, input, options) {
|
|
50
|
-
const {
|
|
51
|
+
const { observer, signal, timeoutMs } = options;
|
|
52
|
+
// `harness` is the seam; a legacy `claude` object is used as-is (what `asClaude(claudeCompat(claude))` yields).
|
|
53
|
+
const claude = options.harness ? asClaude(options.harness) : options.claude;
|
|
54
|
+
if (!claude) {
|
|
55
|
+
throw new Error("execute() needs options.harness (or the deprecated options.claude)");
|
|
56
|
+
}
|
|
51
57
|
// If the caller already aborted before we started, fail fast.
|
|
52
58
|
throwIfAborted(signal);
|
|
53
59
|
const dryRun = isDryRunInput(input);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared capabilities per adapter. No runtime imports, so the executor can use
|
|
3
|
+
* them without pulling in an agent SDK.
|
|
4
|
+
*/
|
|
5
|
+
import type { HarnessCapabilities } from "./types.js";
|
|
6
|
+
/** Claude Code enforces every sweny opinion natively, so `policyGate` never degrades or refuses it. */
|
|
7
|
+
export declare const CLAUDE_CODE_CAPABILITIES: HarnessCapabilities;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared capabilities per adapter. No runtime imports, so the executor can use
|
|
3
|
+
* them without pulling in an agent SDK.
|
|
4
|
+
*/
|
|
5
|
+
/** Claude Code enforces every sweny opinion natively, so `policyGate` never degrades or refuses it. */
|
|
6
|
+
export const CLAUDE_CODE_CAPABILITIES = {
|
|
7
|
+
structuredOutput: "native",
|
|
8
|
+
toolTrace: "full",
|
|
9
|
+
builtinDeny: "by-name",
|
|
10
|
+
mcp: { inject: true, exclusive: "native" },
|
|
11
|
+
sandbox: { fs: true, network: true },
|
|
12
|
+
readOnly: "native",
|
|
13
|
+
turnLimit: "native",
|
|
14
|
+
usage: { tokens: true, costUsd: true, live: false },
|
|
15
|
+
cancel: "signal",
|
|
16
|
+
resume: false,
|
|
17
|
+
};
|