@netnodeag/kraftwerk 0.72.0 → 0.74.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 +6 -0
- package/dist/cli/daemon-control.d.ts +15 -0
- package/dist/cli/daemon-control.js +228 -0
- package/dist/cli/daemon-login.d.ts +2 -0
- package/dist/cli/daemon-login.js +9 -2
- package/dist/cli/daemon.js +48 -2
- package/dist/cli/doctor.js +3 -1
- package/dist/cli/ui.js +33 -11
- package/dist/client/routes.d.ts +1 -0
- package/dist/client/routes.js +1 -0
- package/dist/core/chat/sessions.d.ts +13 -0
- package/dist/core/chat/sessions.js +22 -0
- package/dist/core/daemon.d.ts +16 -0
- package/dist/core/daemon.js +18 -1
- package/dist/core/skills.js +4 -2
- package/dist/server/api/chats.d.ts +4 -1
- package/dist/server/api/chats.js +29 -3
- package/dist/server/api/index.d.ts +4 -1
- package/dist/server/live.d.ts +4 -2
- package/dist/server/live.js +3 -2
- package/dist/server/server.js +2 -1
- package/package.json +1 -1
- package/web/dist/assets/{dist-LUiVqSl6.js → dist-BJQuUDA0.js} +1 -1
- package/web/dist/assets/{dist-Bu0rxkzF.js → dist-CESw77ha.js} +1 -1
- package/web/dist/assets/dist-CMMQorId.js +1 -0
- package/web/dist/assets/{dist-CYnXUgv0.js → dist-CRrnyH8Z.js} +1 -1
- package/web/dist/assets/{dist-BLd_aA1g.js → dist-CaGkA8bH.js} +1 -1
- package/web/dist/assets/{dist-C8xoYPYE.js → dist-Cnm1S16W.js} +1 -1
- package/web/dist/assets/{dist-CVuec2Mm.js → dist-D746Qhyu.js} +1 -1
- package/web/dist/assets/{dist-H3OFzCSU.js → dist-Df4EJMUZ.js} +1 -1
- package/web/dist/assets/{dist-GJo81x50.js → dist-INPpBMuI.js} +1 -1
- package/web/dist/assets/{dist-WCCGMh5F.js → dist-XZFWBcL9.js} +1 -1
- package/web/dist/assets/{dist-DFZgINkL.js → dist-r61B6qLC.js} +1 -1
- package/web/dist/assets/{editor-6D-WNjZY.js → editor-ByOSpxTX.js} +3 -3
- package/web/dist/assets/{index-D8-2MY0Q.js → index-CJTkdJMe.js} +3 -3
- package/web/dist/index.html +1 -1
- package/web/dist/assets/dist-D-uSPljm.js +0 -1
|
@@ -33,6 +33,7 @@ export declare const chatRoutes: (import("./router.js").Route<"agents.sessions",
|
|
|
33
33
|
slug: z.ZodOptional<z.ZodString>;
|
|
34
34
|
}, z.core.$strip>>;
|
|
35
35
|
resume: z.ZodOptional<z.ZodString>;
|
|
36
|
+
project: z.ZodOptional<z.ZodString>;
|
|
36
37
|
}, z.core.$strip>> | import("./router.js").Route<"chats.delete", import("./router.js").Reply<{
|
|
37
38
|
error?: string;
|
|
38
39
|
}>, "/api/chats/:id", undefined> | import("./router.js").Route<"chats.elicitation", import("./router.js").Reply<{
|
|
@@ -80,7 +81,9 @@ export declare const chatRoutes: (import("./router.js").Route<"agents.sessions",
|
|
|
80
81
|
error?: string;
|
|
81
82
|
}>, "/api/chats/:id", z.ZodObject<{
|
|
82
83
|
title: z.ZodString;
|
|
83
|
-
}, z.core.$strip>> | import("./router.js").Route<"chats.resetSession", import("../../core/chat/types.js").ChatMeta, "/api/chats/:id/reset-session", undefined> | import("./router.js").Route<"chats.
|
|
84
|
+
}, z.core.$strip>> | import("./router.js").Route<"chats.resetSession", import("../../core/chat/types.js").ChatMeta, "/api/chats/:id/reset-session", undefined> | import("./router.js").Route<"chats.setProject", import("../../core/chat/types.js").ChatMeta, "/api/chats/:id/project", z.ZodObject<{
|
|
85
|
+
project: z.ZodNullable<z.ZodString>;
|
|
86
|
+
}, z.core.$strip>> | import("./router.js").Route<"chats.setVibeable", import("../../core/chat/types.js").ChatMeta, "/api/chats/:id/vibeable", z.ZodObject<{
|
|
84
87
|
slug: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
85
88
|
}, z.core.$strip>> | import("./router.js").Route<"chats.steer", import("./router.js").Reply<{
|
|
86
89
|
error: string;
|
package/dist/server/api/chats.js
CHANGED
|
@@ -2,7 +2,7 @@ import { promises as fs } from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import { getAgent } from "../../core/agents.js";
|
|
5
|
-
import { answerElicitation, cancelChat, createChat, deleteChat, forkChat, getChat, listAgentSessionsFor, listChats, postMessage, renameChat, resetSession, resolvePermission, setChatConfig, setChatVibeable, steerChat, stopChatTask, subscribeChat, } from "../../core/chat/sessions.js";
|
|
5
|
+
import { answerElicitation, cancelChat, createChat, deleteChat, forkChat, getChat, listAgentSessionsFor, listChats, postMessage, renameChat, resetSession, resolvePermission, setChatConfig, setChatProject, setChatVibeable, steerChat, stopChatTask, subscribeChat, } from "../../core/chat/sessions.js";
|
|
6
6
|
import { attachmentPath, saveAttachment } from "../../core/chat/store.js";
|
|
7
7
|
import { getProject } from "../../core/projects.js";
|
|
8
8
|
import { MIME } from "./mime.js";
|
|
@@ -25,6 +25,8 @@ const NewChat = z.object({
|
|
|
25
25
|
agent: z.string().optional(),
|
|
26
26
|
scope: z.object({ kind: z.string(), runId: z.string().optional(), bundle: z.string().optional(), slug: z.string().optional() }).optional(),
|
|
27
27
|
resume: z.string().optional(),
|
|
28
|
+
/** An agent's chat started in a project: listed with the project (meta.project). */
|
|
29
|
+
project: z.string().optional(),
|
|
28
30
|
});
|
|
29
31
|
/** An action on a running chat: `{ok}` when it went through, 409 with the reason when the chat refused. */
|
|
30
32
|
const act = (name, path, summary, body, run) => route({ name, method: "POST", path, summary, errors: 400, body }, async (c) => {
|
|
@@ -64,17 +66,29 @@ async function scopeOf(body) {
|
|
|
64
66
|
return { agent, scope: { kind: "knowledge", ...(s.bundle ? { bundle: s.bundle } : {}) } };
|
|
65
67
|
return { agent, scope: { kind: "general" } };
|
|
66
68
|
}
|
|
69
|
+
/** The slug of an existing project, else a 404 (or the error reading it). */
|
|
70
|
+
async function projectSlug(slug) {
|
|
71
|
+
const found = await getProject(slug).catch((err) => {
|
|
72
|
+
throw new ApiError(projectErrors(err.message), err.message);
|
|
73
|
+
});
|
|
74
|
+
if (!found)
|
|
75
|
+
fail(404, "project not found");
|
|
76
|
+
return found.slug;
|
|
77
|
+
}
|
|
67
78
|
/** Chats: ACP sessions with a coding agent, their event stream, and what a person does in them. */
|
|
68
79
|
export const chatRoutes = [
|
|
69
80
|
route({ name: "chats.list", method: "GET", path: "/api/chats", summary: "every chat with its live state" }, async () => ({ chats: await listChats() })),
|
|
70
|
-
route({ name: "chats.create", method: "POST", path: "/api/chats", summary: "start a chat {agent, scope, resume?}", body: NewChat }, async (c) => {
|
|
81
|
+
route({ name: "chats.create", method: "POST", path: "/api/chats", summary: "start a chat {agent, scope, resume?, project?}", body: NewChat }, async (c) => {
|
|
71
82
|
// `resume` continues one of the agent's own sessions (see agents.sessions).
|
|
72
83
|
const body = await c.body();
|
|
73
84
|
const { agent, scope } = await scopeOf(body);
|
|
74
85
|
if (!AGENTS.includes(agent))
|
|
75
86
|
fail(400, "agent must be claude, codex, or pi");
|
|
87
|
+
if (body.project && scope.kind !== "agent")
|
|
88
|
+
fail(400, "only an agent's chat takes a project");
|
|
89
|
+
const project = body.project ? await projectSlug(body.project) : undefined;
|
|
76
90
|
try {
|
|
77
|
-
return await createChat({ agent: agent, scope, ...(body.resume ? { resume: body.resume } : {}) });
|
|
91
|
+
return await createChat({ agent: agent, scope, ...(project ? { project } : {}), ...(body.resume ? { resume: body.resume } : {}) });
|
|
78
92
|
}
|
|
79
93
|
catch (err) {
|
|
80
94
|
throw new ApiError(400, err.message);
|
|
@@ -96,6 +110,18 @@ export const chatRoutes = [
|
|
|
96
110
|
const result = await validChat(renameChat(c.params.id, title), "invalid chat id or body");
|
|
97
111
|
return reply(result.error ? (result.error === "not found" ? 404 : 400) : 200, result);
|
|
98
112
|
}),
|
|
113
|
+
route({
|
|
114
|
+
name: "chats.setProject",
|
|
115
|
+
method: "POST",
|
|
116
|
+
path: "/api/chats/:id/project",
|
|
117
|
+
summary: "file an agent's chat under a project {project}, or under none {project: null}",
|
|
118
|
+
errors: 400,
|
|
119
|
+
body: z.object({ project: z.string().nullable() }),
|
|
120
|
+
}, async (c) => {
|
|
121
|
+
const { project } = await c.body();
|
|
122
|
+
const slug = project ? await projectSlug(project) : null;
|
|
123
|
+
return metaOf(await validChat(setChatProject(c.params.id, slug)));
|
|
124
|
+
}),
|
|
99
125
|
// Replays from ?after=N, then streams new events as they happen.
|
|
100
126
|
route({ name: "chats.events", method: "GET", path: "/api/chats/:id/events", summary: "SSE: the chat's events from ?after=N", raw: true }, async ({ req, res, params, query }) => {
|
|
101
127
|
const afterSeq = Number(query.get("after") ?? "0") || 0;
|
|
@@ -218,6 +218,7 @@ export declare const routes: (Route<"agents.addJournal", {
|
|
|
218
218
|
slug: z.ZodOptional<z.ZodString>;
|
|
219
219
|
}, z.core.$strip>>;
|
|
220
220
|
resume: z.ZodOptional<z.ZodString>;
|
|
221
|
+
project: z.ZodOptional<z.ZodString>;
|
|
221
222
|
}, z.core.$strip>> | Route<"chats.delete", import("./router.js").Reply<{
|
|
222
223
|
error?: string;
|
|
223
224
|
}>, "/api/chats/:id", undefined> | Route<"chats.elicitation", import("./router.js").Reply<{
|
|
@@ -265,7 +266,9 @@ export declare const routes: (Route<"agents.addJournal", {
|
|
|
265
266
|
error?: string;
|
|
266
267
|
}>, "/api/chats/:id", z.ZodObject<{
|
|
267
268
|
title: z.ZodString;
|
|
268
|
-
}, z.core.$strip>> | Route<"chats.resetSession", import("../../core/chat/types.js").ChatMeta, "/api/chats/:id/reset-session", undefined> | Route<"chats.
|
|
269
|
+
}, z.core.$strip>> | Route<"chats.resetSession", import("../../core/chat/types.js").ChatMeta, "/api/chats/:id/reset-session", undefined> | Route<"chats.setProject", import("../../core/chat/types.js").ChatMeta, "/api/chats/:id/project", z.ZodObject<{
|
|
270
|
+
project: z.ZodNullable<z.ZodString>;
|
|
271
|
+
}, z.core.$strip>> | Route<"chats.setVibeable", import("../../core/chat/types.js").ChatMeta, "/api/chats/:id/vibeable", z.ZodObject<{
|
|
269
272
|
slug: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
270
273
|
}, z.core.$strip>> | Route<"chats.steer", import("./router.js").Reply<{
|
|
271
274
|
error: string;
|
package/dist/server/live.d.ts
CHANGED
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
* - and on the watch's interval, for changes nobody announces (an agent
|
|
10
10
|
* writing files, a run progressing on disk).
|
|
11
11
|
*
|
|
12
|
-
* Evaluation runs in the watch's workspace
|
|
13
|
-
*
|
|
12
|
+
* Evaluation runs in the watch's workspace — bound when the watch is made,
|
|
13
|
+
* so a re-evaluation whatever triggers it (a timer, a change elsewhere)
|
|
14
|
+
* never runs without one. This module knows nothing about routes: the
|
|
15
|
+
* socket hands it an `evaluate` closure.
|
|
14
16
|
*/
|
|
15
17
|
interface Watcher {
|
|
16
18
|
interval: number;
|
package/dist/server/live.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { onChanged } from "../core/changes.js";
|
|
2
|
-
import { perWorkspace } from "../core/workspace.js";
|
|
2
|
+
import { currentWorkspace, perWorkspace } from "../core/workspace.js";
|
|
3
3
|
const MIN_INTERVAL = 1000;
|
|
4
4
|
const TOUCH_DEBOUNCE_MS = 60;
|
|
5
5
|
const state = perWorkspace(() => ({ watches: new Map(), touchTimer: undefined }));
|
|
@@ -52,7 +52,8 @@ export function watch(key, evaluate, interval, push) {
|
|
|
52
52
|
const { watches } = state();
|
|
53
53
|
let w = watches.get(key);
|
|
54
54
|
if (!w) {
|
|
55
|
-
|
|
55
|
+
const ws = currentWorkspace();
|
|
56
|
+
w = { evaluate: () => ws.run(evaluate), watchers: new Set() };
|
|
56
57
|
watches.set(key, w);
|
|
57
58
|
}
|
|
58
59
|
const watcher = { interval, push };
|
package/dist/server/server.js
CHANGED
|
@@ -136,6 +136,7 @@ function installExitHandlers() {
|
|
|
136
136
|
// Something still running for a workspace that was closed (a late callback) finds its state gone and throws
|
|
137
137
|
// "workspace closed". That must not take the other workspaces down with it; anything else still crashes, as by default.
|
|
138
138
|
const closedOnly = (err) => err instanceof Error && err.message === "workspace closed";
|
|
139
|
+
// Logged with the time, so `kraftwerk daemon logs` says when; the supervisor starts the server again.
|
|
139
140
|
process.on("unhandledRejection", (err) => {
|
|
140
141
|
if (closedOnly(err))
|
|
141
142
|
return;
|
|
@@ -144,7 +145,7 @@ function installExitHandlers() {
|
|
|
144
145
|
process.on("uncaughtException", (err) => {
|
|
145
146
|
if (closedOnly(err))
|
|
146
147
|
return;
|
|
147
|
-
console.error(err);
|
|
148
|
+
console.error(`✖ ${new Date().toISOString()} crashed:`, err);
|
|
148
149
|
process.exit(1);
|
|
149
150
|
});
|
|
150
151
|
// Chat agent subprocesses must die with the server — signals bypass "exit" handlers, so hook the signals themselves.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netnodeag/kraftwerk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.74.0",
|
|
4
4
|
"description": "Open-source agentic workspace for teams — where people and AI agents get work done together: agents (Claude Code, Codex, Pi), skills, shared knowledge, repeatable workflows, and deterministic verification",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|