@sweny-ai/core 0.1.208 → 0.1.209
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/cli/record.d.ts +6 -0
- package/dist/cli/record.js +7 -0
- package/dist/cli/try-fixture.json +59 -19
- package/dist/cli/try.d.ts +12 -0
- package/dist/cli/try.js +39 -2
- package/package.json +1 -1
package/dist/cli/record.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ import { type TryFixture } from "./try.js";
|
|
|
18
18
|
export declare const RECORD_COLUMNS = 80;
|
|
19
19
|
/** Lines longer than this wrap in the window, like a terminal would. */
|
|
20
20
|
export declare const RECORD_WRAP = 96;
|
|
21
|
+
/**
|
|
22
|
+
* Items of each list the recorded answer shows (the rest is counted in the heading). The README's
|
|
23
|
+
* first screen has a 900px budget; the real answer is longer than that, so the recording shows a
|
|
24
|
+
* summary of it. `sweny try` in a terminal shows all of it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const RECORD_ANSWER_ITEMS = 2;
|
|
21
27
|
/** Width of one terminal column in the window, in px. Every segment is placed at column * CELL_W. */
|
|
22
28
|
export declare const CELL_W = 7.85;
|
|
23
29
|
/** Left edge of column 0. */
|
package/dist/cli/record.js
CHANGED
|
@@ -22,6 +22,12 @@ import { loadTryFixture, runTry, SUMMARY_PREVIEW_LEAD } from "./try.js";
|
|
|
22
22
|
export const RECORD_COLUMNS = 80;
|
|
23
23
|
/** Lines longer than this wrap in the window, like a terminal would. */
|
|
24
24
|
export const RECORD_WRAP = 96;
|
|
25
|
+
/**
|
|
26
|
+
* Items of each list the recorded answer shows (the rest is counted in the heading). The README's
|
|
27
|
+
* first screen has a 900px budget; the real answer is longer than that, so the recording shows a
|
|
28
|
+
* summary of it. `sweny try` in a terminal shows all of it.
|
|
29
|
+
*/
|
|
30
|
+
export const RECORD_ANSWER_ITEMS = 2;
|
|
25
31
|
const FONT_SIZE = 13;
|
|
26
32
|
/** Width of one terminal column in the window, in px. Every segment is placed at column * CELL_W. */
|
|
27
33
|
export const CELL_W = 7.85;
|
|
@@ -317,6 +323,7 @@ export async function recordTrySvg(fixture = loadTryFixture()) {
|
|
|
317
323
|
rich: true,
|
|
318
324
|
unicode: true,
|
|
319
325
|
columns: RECORD_COLUMNS,
|
|
326
|
+
compactAnswer: RECORD_ANSWER_ITEMS,
|
|
320
327
|
fixture,
|
|
321
328
|
write: (s) => {
|
|
322
329
|
out += s;
|
|
@@ -1,33 +1,73 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
|
-
"illustrative":
|
|
4
|
-
"
|
|
3
|
+
"illustrative": false,
|
|
4
|
+
"captured_at": "2026-11-10T20:09:47.380Z",
|
|
5
|
+
"notice": "A replay of a real run of explain-repo on swenyai/sweny, started 2026-11-10T20:09:47Z (2026-11-10). Durations, tool-call counts, token usage and cost are as recorded; the answer is redacted. Made by `sweny try --capture`; do not edit by hand.",
|
|
5
6
|
"workflow": "explain-repo",
|
|
6
|
-
"sample_repo": "
|
|
7
|
-
"harness": {
|
|
8
|
-
|
|
7
|
+
"sample_repo": "swenyai/sweny",
|
|
8
|
+
"harness": {
|
|
9
|
+
"id": "claude-code",
|
|
10
|
+
"version": "0.3.322"
|
|
11
|
+
},
|
|
12
|
+
"policy": {
|
|
13
|
+
"envScope": true,
|
|
14
|
+
"sandbox": "strict",
|
|
15
|
+
"sandboxStarted": true
|
|
16
|
+
},
|
|
9
17
|
"nodes": {
|
|
10
18
|
"survey": {
|
|
11
|
-
"duration_ms":
|
|
12
|
-
"tool_calls": {
|
|
13
|
-
|
|
19
|
+
"duration_ms": 15711,
|
|
20
|
+
"tool_calls": {
|
|
21
|
+
"Bash": 2
|
|
22
|
+
},
|
|
23
|
+
"usage": {
|
|
24
|
+
"inputTokens": 6,
|
|
25
|
+
"outputTokens": 2006,
|
|
26
|
+
"costUsd": 0.1197956,
|
|
27
|
+
"numTurns": 3
|
|
28
|
+
}
|
|
14
29
|
},
|
|
15
30
|
"explain": {
|
|
16
|
-
"duration_ms":
|
|
17
|
-
"tool_calls": {
|
|
18
|
-
|
|
31
|
+
"duration_ms": 7211,
|
|
32
|
+
"tool_calls": {
|
|
33
|
+
"StructuredOutput": 1
|
|
34
|
+
},
|
|
35
|
+
"usage": {
|
|
36
|
+
"inputTokens": 2,
|
|
37
|
+
"outputTokens": 877,
|
|
38
|
+
"costUsd": 0.0871939,
|
|
39
|
+
"numTurns": 2
|
|
40
|
+
},
|
|
19
41
|
"output": {
|
|
20
|
-
"purpose": "
|
|
21
|
-
"how_to_run": [
|
|
42
|
+
"purpose": "SWEny runs DAGs of coding-agent steps (Claude Code, Codex, pi, ACP agents) defined in YAML workflows, locally or in CI. It scopes each step's env and tools, validates output schemas, and records a receipt per run. For teams automating coding-agent work.",
|
|
43
|
+
"how_to_run": [
|
|
44
|
+
"Use Node >=22, then run: npm install (installs all workspaces)",
|
|
45
|
+
"npm run build",
|
|
46
|
+
"npm run typecheck",
|
|
47
|
+
"npm test (Vitest)",
|
|
48
|
+
"npm run lint",
|
|
49
|
+
"Run the CLI: node packages/core/dist/cli/main.js workflow run <file.yml> (the `sweny` bin)",
|
|
50
|
+
"Docs site: npm run dev:web",
|
|
51
|
+
"In CI: use the GitHub Action swenyai/sweny@v5 (action.yml)"
|
|
52
|
+
],
|
|
22
53
|
"key_files": [
|
|
23
|
-
"
|
|
24
|
-
"src/
|
|
25
|
-
"src/
|
|
26
|
-
"
|
|
54
|
+
"README.md, ARCHITECTURE.md, CONTRIBUTING.md, CLAUDE.md: start here for the concepts and the contributor rules",
|
|
55
|
+
"packages/core/src/executor.ts: runs the DAG",
|
|
56
|
+
"packages/core/src/cli/: CLI entry point (main.js is built from here)",
|
|
57
|
+
"packages/core/src/schema.ts, types.ts, loader.ts: workflow definition and validation",
|
|
58
|
+
"packages/core/src/node-policy.ts, agent-env.ts, safe-outputs.ts, untrusted.ts: security scoping and output checks",
|
|
59
|
+
"packages/core/src/journal.ts: run receipts",
|
|
60
|
+
"packages/core/src/workflows/, .sweny/workflows/, examples/: built-in and sample workflows",
|
|
61
|
+
"packages/mcp/src/index.ts: MCP server",
|
|
62
|
+
"packages/studio: visual workflow editor",
|
|
63
|
+
"action.yml and .github/workflows/ci.yml, release.yml: Action and CI/release"
|
|
27
64
|
],
|
|
28
65
|
"risks": [
|
|
29
|
-
"
|
|
30
|
-
"
|
|
66
|
+
"Only Claude Code is fully supported. Codex, pi and ACP agents are experimental.",
|
|
67
|
+
"Every push to main triggers release.yml, which publishes to npm, so merges ship straight away. There are no changesets.",
|
|
68
|
+
"The build, test and run commands above come from a survey of the root scripts, not from running them. Check them against package.json.",
|
|
69
|
+
"The repo has many moving parts: 5 packages, 2 Astro sites, the plugin and the Action. Run builds from the repo root so workspaces resolve.",
|
|
70
|
+
"Security-sensitive code (env scoping, input fencing, output checks) needs careful review. Read SECURITY.md first."
|
|
31
71
|
]
|
|
32
72
|
}
|
|
33
73
|
}
|
package/dist/cli/try.d.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import type { Command } from "commander";
|
|
17
17
|
import type { AgentHarness } from "../harness/types.js";
|
|
18
18
|
import type { Workflow } from "../types.js";
|
|
19
|
+
import { type FinalOutput } from "./final-output.js";
|
|
19
20
|
import { type Paint } from "./style.js";
|
|
20
21
|
export interface TryFixtureNode {
|
|
21
22
|
/** Recorded wall-clock time of the node. */
|
|
@@ -109,6 +110,12 @@ export interface TryOptions {
|
|
|
109
110
|
rich?: boolean;
|
|
110
111
|
/** Terminal width. Default: stdout's. */
|
|
111
112
|
columns?: number;
|
|
113
|
+
/**
|
|
114
|
+
* Show at most this many items of each list in the answer, with the count in its heading
|
|
115
|
+
* ("How to run it (2 of 8):"). The recording uses it to stay README-sized; a real terminal run
|
|
116
|
+
* leaves it unset and shows the whole answer.
|
|
117
|
+
*/
|
|
118
|
+
compactAnswer?: number;
|
|
112
119
|
fixture?: TryFixture;
|
|
113
120
|
}
|
|
114
121
|
/** A default replay takes about this long in total, however long the real run took. */
|
|
@@ -117,6 +124,11 @@ export declare const REPLAY_TARGET_MS = 8000;
|
|
|
117
124
|
export declare const REPLAY_NODE_MIN_MS = 250;
|
|
118
125
|
/** Per-node replay time: the recorded durations scaled to {@link REPLAY_TARGET_MS} in total (never slowed down). */
|
|
119
126
|
export declare function scaledPace(fixture: TryFixture, targetMs?: number): (nodeId: string) => number;
|
|
127
|
+
/**
|
|
128
|
+
* The answer with each list cut to its first `maxItems` items; the heading then says
|
|
129
|
+
* "<title> (<maxItems> of <total>):". Scalars, short lists and errors pass through. Pure.
|
|
130
|
+
*/
|
|
131
|
+
export declare function compactAnswer(out: FinalOutput, maxItems: number): FinalOutput;
|
|
120
132
|
/** The line that opens the job summary preview (record.ts cuts the preview from here). */
|
|
121
133
|
export declare const SUMMARY_PREVIEW_LEAD = "In CI, the job summary gets this heading, this DAG and the receipt below:";
|
|
122
134
|
/** Replay the recording. Returns the process exit code. */
|
package/dist/cli/try.js
CHANGED
|
@@ -211,6 +211,41 @@ export function scaledPace(fixture, targetMs = REPLAY_TARGET_MS) {
|
|
|
211
211
|
const scale = total > targetMs ? targetMs / total : 1;
|
|
212
212
|
return (id) => Math.max(REPLAY_NODE_MIN_MS, Math.round((fixture.nodes[id]?.duration_ms ?? 0) * scale));
|
|
213
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* The answer with each list cut to its first `maxItems` items; the heading then says
|
|
216
|
+
* "<title> (<maxItems> of <total>):". Scalars, short lists and errors pass through. Pure.
|
|
217
|
+
*/
|
|
218
|
+
export function compactAnswer(out, maxItems) {
|
|
219
|
+
if (out.kind !== "result" || !Number.isInteger(maxItems) || maxItems < 1)
|
|
220
|
+
return out;
|
|
221
|
+
const src = out.lines;
|
|
222
|
+
const lines = [];
|
|
223
|
+
let i = 0;
|
|
224
|
+
while (i < src.length) {
|
|
225
|
+
const head = src[i];
|
|
226
|
+
// A list is a heading with no value ("Key files:") followed by "- " items and their indented continuations.
|
|
227
|
+
if (!/^[^\s-].*:$/.test(head) || !src[i + 1]?.startsWith("- ")) {
|
|
228
|
+
lines.push(head);
|
|
229
|
+
i++;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const items = [];
|
|
233
|
+
let j = i + 1;
|
|
234
|
+
while (j < src.length && (src[j].startsWith("- ") || src[j].startsWith(" "))) {
|
|
235
|
+
if (src[j].startsWith("- "))
|
|
236
|
+
items.push([src[j]]);
|
|
237
|
+
else
|
|
238
|
+
items[items.length - 1].push(src[j]);
|
|
239
|
+
j++;
|
|
240
|
+
}
|
|
241
|
+
if (items.length <= maxItems)
|
|
242
|
+
lines.push(head, ...items.flat());
|
|
243
|
+
else
|
|
244
|
+
lines.push(`${head.slice(0, -1)} (${maxItems} of ${items.length}):`, ...items.slice(0, maxItems).flat());
|
|
245
|
+
i = j;
|
|
246
|
+
}
|
|
247
|
+
return { ...out, lines };
|
|
248
|
+
}
|
|
214
249
|
const silentLogger = { info() { }, warn() { }, error() { }, debug() { } };
|
|
215
250
|
/** The line that opens the job summary preview (record.ts cuts the preview from here). */
|
|
216
251
|
export const SUMMARY_PREVIEW_LEAD = "In CI, the job summary gets this heading, this DAG and the receipt below:";
|
|
@@ -291,8 +326,10 @@ export async function runTry(opts = {}) {
|
|
|
291
326
|
const totalMs = Object.values(durationsMs).reduce((a, b) => a + b, 0);
|
|
292
327
|
const receipt = summarizeRun(results, totalMs, false, trace);
|
|
293
328
|
const answer = resolveFinalOutput(workflow, results);
|
|
294
|
-
if (answer)
|
|
295
|
-
|
|
329
|
+
if (answer) {
|
|
330
|
+
const shown = opts.compactAnswer ? compactAnswer(answer, opts.compactAnswer) : answer;
|
|
331
|
+
write(`${formatFinalOutput(shown)}\n\n`);
|
|
332
|
+
}
|
|
296
333
|
// Compact preview of CI's job summary: heading and DAG here, receipt below.
|
|
297
334
|
const comment = formatRunComment(workflow, results, receipt, { trace, durationsMs });
|
|
298
335
|
write(` ${paint.muted(SUMMARY_PREVIEW_LEAD)}\n\n`);
|