@netnodeag/kraftwerk 0.3.0 → 0.4.0

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 (57) hide show
  1. package/README.md +7 -5
  2. package/dist/cli/ui.js +36 -32
  3. package/dist/inspector/context.d.ts +5 -0
  4. package/dist/inspector/context.js +19 -0
  5. package/dist/inspector/runner.d.ts +13 -0
  6. package/dist/inspector/runner.js +66 -0
  7. package/dist/inspector/runs.d.ts +57 -0
  8. package/dist/inspector/runs.js +240 -0
  9. package/dist/inspector/server.d.ts +8 -0
  10. package/dist/inspector/server.js +186 -0
  11. package/dist/inspector/workflows.d.ts +45 -0
  12. package/dist/inspector/workflows.js +186 -0
  13. package/inspector/dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  14. package/inspector/dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  15. package/inspector/dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  16. package/inspector/dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  17. package/inspector/dist/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
  18. package/inspector/dist/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
  19. package/inspector/dist/assets/ibm-plex-mono-latin-700-normal-7sUh57Bg.woff2 +0 -0
  20. package/inspector/dist/assets/ibm-plex-mono-latin-700-normal-CNHXzs6v.woff +0 -0
  21. package/inspector/dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  22. package/inspector/dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  23. package/inspector/dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  24. package/inspector/dist/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  25. package/inspector/dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  26. package/inspector/dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  27. package/inspector/dist/assets/ibm-plex-sans-latin-700-normal-Bth3BMcD.woff +0 -0
  28. package/inspector/dist/assets/ibm-plex-sans-latin-700-normal-Bxkt5Cjx.woff2 +0 -0
  29. package/inspector/dist/assets/index-BCSWkslF.css +1 -0
  30. package/inspector/dist/assets/index-D6WuziFQ.js +9 -0
  31. package/inspector/dist/index.html +24 -0
  32. package/package.json +4 -10
  33. package/inspector/README.md +0 -67
  34. package/inspector/app/api/runs/[id]/file/route.ts +0 -56
  35. package/inspector/app/api/runs/[id]/route.ts +0 -15
  36. package/inspector/app/api/runs/[id]/stop/route.ts +0 -15
  37. package/inspector/app/api/runs/route.ts +0 -9
  38. package/inspector/app/api/workflows/[slug]/route.ts +0 -11
  39. package/inspector/app/api/workflows/[slug]/run/route.ts +0 -37
  40. package/inspector/app/api/workflows/route.ts +0 -8
  41. package/inspector/app/globals.css +0 -460
  42. package/inspector/app/layout.tsx +0 -54
  43. package/inspector/app/page.tsx +0 -16
  44. package/inspector/app/runs/[id]/page.tsx +0 -6
  45. package/inspector/app/runs/[id]/run-detail.tsx +0 -343
  46. package/inspector/app/shared.tsx +0 -81
  47. package/inspector/app/theme-toggle.tsx +0 -19
  48. package/inspector/app/workflows/[slug]/page.tsx +0 -6
  49. package/inspector/app/workflows/[slug]/workflow-view.tsx +0 -271
  50. package/inspector/app/workflows/page.tsx +0 -43
  51. package/inspector/lib/runner.ts +0 -78
  52. package/inspector/lib/runs.ts +0 -313
  53. package/inspector/lib/workflows.ts +0 -240
  54. package/inspector/next.config.ts +0 -5
  55. package/inspector/package-lock.json +0 -982
  56. package/inspector/package.json +0 -24
  57. package/inspector/tsconfig.json +0 -21
@@ -0,0 +1,24 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>kraftwerk inspector</title>
7
+ <meta name="description" content="Inspect kraftwerk workflow runs: live executions, phase traces, artifacts" />
8
+ <script>
9
+ (function () {
10
+ try {
11
+ var t = localStorage.getItem("kw-theme");
12
+ if (t) document.documentElement.dataset.theme = t;
13
+ else if (matchMedia("(prefers-color-scheme: light)").matches)
14
+ document.documentElement.dataset.theme = "light";
15
+ } catch (e) {}
16
+ })();
17
+ </script>
18
+ <script type="module" crossorigin src="/assets/index-D6WuziFQ.js"></script>
19
+ <link rel="stylesheet" crossorigin href="/assets/index-BCSWkslF.css">
20
+ </head>
21
+ <body>
22
+ <div id="root"></div>
23
+ </body>
24
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netnodeag/kraftwerk",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Deterministic workflow-as-code framework: agents (persona + model + tools + harness) run in bounded phases on headless CLI harnesses (claude -p, codex exec, pi); code owns the control flow, envelopes + gates judge the results",
5
5
  "keywords": [
6
6
  "agents",
@@ -33,14 +33,7 @@
33
33
  "dist",
34
34
  "runner",
35
35
  "schema",
36
- "inspector/app",
37
- "inspector/lib",
38
- "inspector/next.config.ts",
39
- "inspector/next-env.d.ts",
40
- "inspector/tsconfig.json",
41
- "inspector/package.json",
42
- "inspector/package-lock.json",
43
- "inspector/README.md"
36
+ "inspector/dist"
44
37
  ],
45
38
  "exports": {
46
39
  ".": {
@@ -52,7 +45,8 @@
52
45
  "typecheck": "tsc --noEmit",
53
46
  "validate": "tsx src/validate.ts",
54
47
  "build": "rm -rf dist && tsc -p tsconfig.build.json",
55
- "prepublishOnly": "npm run build"
48
+ "build:inspector": "npm --prefix inspector install --no-fund --no-audit && npm --prefix inspector run build",
49
+ "prepublishOnly": "npm run build && npm run build:inspector"
56
50
  },
57
51
  "license": "MIT",
58
52
  "devDependencies": {
@@ -1,67 +0,0 @@
1
- # kraftwerk inspector
2
-
3
- Web UI to look into the `output/` folder of a kraftwerk consumer project:
4
- all runs at a glance, live phase timelines while a run executes, and every
5
- file per run with inline preview (HTML reports render in place, text tails
6
- live, images display).
7
-
8
- ## Run
9
-
10
- ```bash
11
- kraftwerk ui # from any consumer project — installs deps on first launch,
12
- # points at the project's output dir; --port, --output
13
- ```
14
-
15
- Or directly from a checkout:
16
-
17
- ```bash
18
- cd inspector
19
- npm install
20
- npm run dev # http://localhost:4499
21
- ```
22
-
23
- By default it inspects `../../agent-playground/output` (the playground next
24
- to this repo). Point it anywhere else with:
25
-
26
- ```bash
27
- KRAFTWERK_OUTPUT=/path/to/your-project/output npm run dev
28
- ```
29
-
30
- ## What it shows
31
-
32
- - **Run index** — every `run-*` folder: workflow, request, status lamp
33
- (ok / running / failed / aborted), phase progress, duration, cost.
34
- Running runs tick live.
35
- - **Run detail** — the phase timeline parsed from `trace.jsonl`: agent +
36
- model chips, attempts, duration, token and cost figures, gate results
37
- (including failure messages), envelope summaries, and for the running
38
- phase the last tool activity. Steps that have not started yet appear as
39
- pending — the `run_start` trace event declares them.
40
- - **Files** — all files of the run dir with size; click to view. `.html`
41
- renders in a sandboxed iframe (reports look like reports), images render
42
- inline, everything else is text with live tail while the run is active.
43
- - **Workflows** — browses `src/workflows/` (or `workflows/`) of the same
44
- project: every workflow as a card, and per workflow a visualization of
45
- how it is built — agent cards (model, tools, persona) with identity
46
- colors, the step pipeline in order with each step's resolved prompt or
47
- script (file references are inlined), the gates per step, the workflow
48
- folder contents, and links to recent runs of that workflow. Broken
49
- YAML still shows up, flagged with its parse error.
50
-
51
- - **Trigger runs** — every workflow page has a "trigger run" panel: enter a
52
- request and launch. Default is the **Docker sandbox** (one
53
- `kraftwerk-runner` container per run, workflow mounted read-only, run dir
54
- bind-mounted back into `output/` so the live timeline works unchanged;
55
- build the image once with `kraftwerk runner build`). Optional: forward
56
- the SSH agent, or run locally instead. Sandboxed runs show a "sandbox"
57
- chip and a stop button while running (`docker stop` under the hood).
58
- Env vars for sandboxed runs go into `<project>/runner.env`.
59
-
60
- Realtime is plain polling (1.5 s while something runs, 6 s otherwise) —
61
- no daemon, no socket, works on a plain filesystem.
62
-
63
- ## Requirements
64
-
65
- Traces written by kraftwerk ≥ the `run_start` event carry workflow
66
- name, request, and the declared step list; older traces still render, only
67
- without those labels.
@@ -1,56 +0,0 @@
1
- import { promises as fs } from "node:fs";
2
- import { NextResponse } from "next/server";
3
- import { readRunFile } from "@/lib/runs";
4
-
5
- export const dynamic = "force-dynamic";
6
-
7
- const TYPES: Record<string, string> = {
8
- ".html": "text/html; charset=utf-8",
9
- ".svg": "image/svg+xml",
10
- ".png": "image/png",
11
- ".jpg": "image/jpeg",
12
- ".jpeg": "image/jpeg",
13
- ".gif": "image/gif",
14
- ".webp": "image/webp",
15
- ".pdf": "application/pdf",
16
- ".json": "application/json; charset=utf-8",
17
- };
18
-
19
- /** Text preview payloads are capped; the tail matters most for logs. */
20
- const MAX_TEXT = 400_000;
21
-
22
- export async function GET(req: Request, ctx: { params: Promise<{ id: string }> }) {
23
- const { id } = await ctx.params;
24
- const url = new URL(req.url);
25
- const name = url.searchParams.get("name") ?? "";
26
- const raw = url.searchParams.get("raw") === "1";
27
-
28
- let file;
29
- try {
30
- file = await readRunFile(id, name);
31
- } catch {
32
- return NextResponse.json({ error: "invalid request" }, { status: 400 });
33
- }
34
- if (!file) return NextResponse.json({ error: "not found" }, { status: 404 });
35
-
36
- const ext = name.slice(name.lastIndexOf(".")).toLowerCase();
37
-
38
- if (raw) {
39
- const buf = await fs.readFile(file.absPath);
40
- return new NextResponse(new Uint8Array(buf), {
41
- headers: {
42
- "content-type": TYPES[ext] ?? "text/plain; charset=utf-8",
43
- "cache-control": "no-store",
44
- },
45
- });
46
- }
47
-
48
- const buf = await fs.readFile(file.absPath);
49
- let text = buf.toString("utf8");
50
- let truncated = false;
51
- if (text.length > MAX_TEXT) {
52
- text = text.slice(-MAX_TEXT);
53
- truncated = true;
54
- }
55
- return NextResponse.json({ name, size: file.size, truncated, content: text });
56
- }
@@ -1,15 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { getRun } from "@/lib/runs";
3
-
4
- export const dynamic = "force-dynamic";
5
-
6
- export async function GET(_req: Request, ctx: { params: Promise<{ id: string }> }) {
7
- const { id } = await ctx.params;
8
- try {
9
- const run = await getRun(id);
10
- if (!run) return NextResponse.json({ error: "not found" }, { status: 404 });
11
- return NextResponse.json(run);
12
- } catch {
13
- return NextResponse.json({ error: "invalid run id" }, { status: 400 });
14
- }
15
- }
@@ -1,15 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { stopRun } from "@/lib/runner";
3
-
4
- export const dynamic = "force-dynamic";
5
-
6
- export async function POST(_req: Request, ctx: { params: Promise<{ id: string }> }) {
7
- const { id } = await ctx.params;
8
- const stopped = stopRun(id);
9
- return stopped
10
- ? NextResponse.json({ stopped: true })
11
- : NextResponse.json(
12
- { error: "no running sandbox container for this run (local runs cannot be stopped here)" },
13
- { status: 404 }
14
- );
15
- }
@@ -1,9 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { listRuns, OUTPUT_DIR } from "@/lib/runs";
3
-
4
- export const dynamic = "force-dynamic";
5
-
6
- export async function GET() {
7
- const runs = await listRuns();
8
- return NextResponse.json({ outputDir: OUTPUT_DIR, runs });
9
- }
@@ -1,11 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { getWorkflow } from "@/lib/workflows";
3
-
4
- export const dynamic = "force-dynamic";
5
-
6
- export async function GET(_req: Request, ctx: { params: Promise<{ slug: string }> }) {
7
- const { slug } = await ctx.params;
8
- const wf = await getWorkflow(slug);
9
- if (!wf) return NextResponse.json({ error: "not found" }, { status: 404 });
10
- return NextResponse.json(wf);
11
- }
@@ -1,37 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { getWorkflow } from "@/lib/workflows";
3
- import { triggerRun, dockerStatus } from "@/lib/runner";
4
-
5
- export const dynamic = "force-dynamic";
6
-
7
- export async function GET() {
8
- return NextResponse.json(dockerStatus());
9
- }
10
-
11
- export async function POST(req: Request, ctx: { params: Promise<{ slug: string }> }) {
12
- const { slug } = await ctx.params;
13
- const wf = await getWorkflow(decodeURIComponent(slug));
14
- if (!wf || wf.error || !wf.name) {
15
- return NextResponse.json({ error: "workflow not found or broken" }, { status: 404 });
16
- }
17
- let body: { request?: string; sandbox?: boolean; ssh?: boolean };
18
- try {
19
- body = await req.json();
20
- } catch {
21
- return NextResponse.json({ error: "invalid JSON body" }, { status: 400 });
22
- }
23
- const request = (body.request ?? "").trim();
24
- if (!request) return NextResponse.json({ error: "request text is required" }, { status: 400 });
25
-
26
- try {
27
- const { runId } = triggerRun({
28
- workflowName: wf.name,
29
- request,
30
- sandbox: body.sandbox ?? true,
31
- ssh: !!body.ssh,
32
- });
33
- return NextResponse.json({ runId });
34
- } catch (err) {
35
- return NextResponse.json({ error: (err as Error).message }, { status: 503 });
36
- }
37
- }
@@ -1,8 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { listWorkflows } from "@/lib/workflows";
3
-
4
- export const dynamic = "force-dynamic";
5
-
6
- export async function GET() {
7
- return NextResponse.json(await listWorkflows());
8
- }