@netnodeag/kraftwerk 0.58.1 → 0.60.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.
package/README.md CHANGED
@@ -171,8 +171,8 @@ kraftwerk tunnel setup kw.example.com # Cloudflare Tunnel to the inspector: lo
171
171
  kraftwerk tunnel # run that tunnel alone (the UI runs elsewhere)
172
172
  ```
173
173
 
174
- Nothing is deleted at once. Removing an agent, a project, a knowledge bundle,
175
- a vibeable, a channel, a repository, a chat or a run, in the inspector or the
174
+ Nothing is deleted at once. Removing an agent, a project, a workflow, a knowledge
175
+ bundle, a vibeable, a channel, a repository, a chat or a run, in the inspector or the
176
176
  CLI, moves its folder to `kraftwerk-data/trash/`. The trash mirrors the
177
177
  workspace (`trash/agents/<slug>`, `trash/knowledge/<bundle>`,
178
178
  `trash/projects/<slug>`, `trash/chats/<id>`, …) and ignores itself in git.
@@ -14,7 +14,7 @@ import { appendJournal, readJournal } from "./journal.js";
14
14
  import { emptyTrash, listTrash, purgeFromTrash, restoreFromTrash, trashRoot } from "./trash.js";
15
15
  import { decide } from "./decisions.js";
16
16
  import { canSelfUpdate, startUpdate, updateStatus } from "./update.js";
17
- import { listWorkflows, getWorkflow } from "./workflows.js";
17
+ import { listWorkflows, getWorkflow, deleteWorkflow } from "./workflows.js";
18
18
  import { dockerStatus, triggerRun, stopRun } from "./runner.js";
19
19
  import { clearNotifications, listNotifications, markNotificationsRead } from "./notifications.js";
20
20
  import { startDiagnosis } from "./diagnose.js";
@@ -862,6 +862,15 @@ async function handleApi(req, res, url) {
862
862
  const wf = await getWorkflow(decodeURIComponent(seg[2]));
863
863
  return wf ? json(res, wf) : json(res, { error: "not found" }, 404);
864
864
  }
865
+ // DELETE /api/workflows/:slug — move it to the trash
866
+ if (seg.length === 3 && seg[1] === "workflows" && method === "DELETE") {
867
+ const outcome = await deleteWorkflow(decodeURIComponent(seg[2]));
868
+ if (outcome === "missing")
869
+ return json(res, { error: "not found" }, 404);
870
+ if (outcome === "running")
871
+ return json(res, { error: "a run of this workflow is still running — stop it first" }, 409);
872
+ return json(res, { ok: true });
873
+ }
865
874
  // GET/POST /api/workflows/:slug/run
866
875
  if (seg.length === 4 && seg[1] === "workflows" && seg[3] === "run") {
867
876
  if (method === "GET")
@@ -2,13 +2,13 @@
2
2
  * The trash: what the inspector or the CLI deletes is moved here first and
3
3
  * only gone for good once it is deleted from the trash. The trash mirrors
4
4
  * the workspace — trash/agents/<slug>, trash/knowledge/<bundle>,
5
- * trash/projects/<slug>, trash/chats/<id>, … — and every trashed folder
5
+ * trash/projects/<slug>, trash/workflows/<slug>, trash/chats/<id>, … — and every trashed folder
6
6
  * carries a small TRASH_FILE saying what it was and where it came from, so
7
7
  * it can be put back. The trash is local: it is kept out of the workspace git.
8
8
  */
9
9
  export declare const TRASH_DIR = "kraftwerk-data/trash";
10
10
  /** What can be in the trash; also the folder under trash/ it lands in. */
11
- export type TrashKind = "agents" | "agent-skills" | "projects" | "knowledge" | "vibeables" | "channels" | "repos" | "chats" | "runs" | "files";
11
+ export type TrashKind = "agents" | "agent-skills" | "projects" | "workflows" | "knowledge" | "vibeables" | "channels" | "repos" | "chats" | "runs" | "files";
12
12
  export interface TrashEntry {
13
13
  /** Path inside the trash, forward slashes — the entry's handle. */
14
14
  id: string;
@@ -6,7 +6,7 @@ import { getProjectRoot } from "./context.js";
6
6
  * The trash: what the inspector or the CLI deletes is moved here first and
7
7
  * only gone for good once it is deleted from the trash. The trash mirrors
8
8
  * the workspace — trash/agents/<slug>, trash/knowledge/<bundle>,
9
- * trash/projects/<slug>, trash/chats/<id>, … — and every trashed folder
9
+ * trash/projects/<slug>, trash/workflows/<slug>, trash/chats/<id>, … — and every trashed folder
10
10
  * carries a small TRASH_FILE saying what it was and where it came from, so
11
11
  * it can be put back. The trash is local: it is kept out of the workspace git.
12
12
  */
@@ -42,6 +42,11 @@ export interface WorkflowDetail {
42
42
  usesRequest: boolean;
43
43
  error?: string;
44
44
  }
45
+ /**
46
+ * Move a workflow to the trash: its folder, or its lone yml. Refused while
47
+ * one of its runs is still going; its finished runs stay where they are.
48
+ */
49
+ export declare function deleteWorkflow(slug: string): Promise<"deleted" | "running" | "missing">;
45
50
  export declare function listWorkflows(): Promise<{
46
51
  root?: string;
47
52
  workflows: WorkflowSummary[];
@@ -4,6 +4,8 @@ import { parse as parseYaml } from "yaml";
4
4
  import { resolveProject } from "../config.js";
5
5
  import { referencesRequest } from "../yaml.js";
6
6
  import { getProjectRoot } from "./context.js";
7
+ import { listRuns } from "./runs.js";
8
+ import { moveToTrash } from "./trash.js";
7
9
  /**
8
10
  * Workflow discovery + parsing for the inspector. Uses the same root
9
11
  * resolution as the CLI (kraftwerk.yml `workflows:` key, else src/workflows/
@@ -77,6 +79,21 @@ async function locate() {
77
79
  }
78
80
  return found.sort((a, b) => a.slug.localeCompare(b.slug));
79
81
  }
82
+ /**
83
+ * Move a workflow to the trash: its folder, or its lone yml. Refused while
84
+ * one of its runs is still going; its finished runs stay where they are.
85
+ */
86
+ export async function deleteWorkflow(slug) {
87
+ const l = (await locate()).find((x) => x.slug === slug);
88
+ if (!l)
89
+ return "missing";
90
+ const name = (await parseRaw(l).catch(() => null))?.name;
91
+ const runs = await listRuns();
92
+ if (runs.some((r) => r.status === "running" && (r.workflow === slug || (name && r.workflow === name))))
93
+ return "running";
94
+ await moveToTrash("workflows", slug, l.baseDir ?? l.yamlPath);
95
+ return "deleted";
96
+ }
80
97
  async function parseRaw(l) {
81
98
  const text = await fs.readFile(l.yamlPath, "utf8");
82
99
  return parseYaml(text);
@@ -0,0 +1 @@
1
+ import{a as e}from"./editor-dsYnSWbf.js";export{e as markdown};