@netnodeag/kraftwerk 0.80.0 → 0.82.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 +57 -2
- package/dist/cli/boards.d.ts +2 -0
- package/dist/cli/boards.js +486 -0
- package/dist/cli/init.js +4 -2
- package/dist/cli/kraftwerk.js +6 -0
- package/dist/cli/temp.d.ts +2 -0
- package/dist/cli/temp.js +62 -0
- package/dist/client/routes.d.ts +16 -0
- package/dist/client/routes.js +16 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.js +24 -1
- package/dist/core/attention.d.ts +2 -2
- package/dist/core/attention.js +22 -2
- package/dist/core/board-wake.d.ts +21 -0
- package/dist/core/board-wake.js +221 -0
- package/dist/core/boards.d.ts +256 -0
- package/dist/core/boards.js +936 -0
- package/dist/core/chat/acp.d.ts +1 -1
- package/dist/core/chat/acp.js +3 -1
- package/dist/core/chat/backend.d.ts +13 -0
- package/dist/core/chat/backend.js +9 -1
- package/dist/core/chat/context.js +26 -9
- package/dist/core/chat/pi.d.ts +1 -1
- package/dist/core/chat/pi.js +3 -1
- package/dist/core/chat/seats.js +6 -2
- package/dist/core/chat/sessions.d.ts +2 -0
- package/dist/core/chat/sessions.js +4 -0
- package/dist/core/chat/state.js +1 -1
- package/dist/core/chat/types.d.ts +11 -1
- package/dist/core/files.d.ts +1 -1
- package/dist/core/files.js +20 -1
- package/dist/core/git.js +3 -1
- package/dist/core/notifications.d.ts +1 -1
- package/dist/core/projects.js +1 -1
- package/dist/core/refs.d.ts +1 -1
- package/dist/core/refs.js +25 -1
- package/dist/core/search.d.ts +12 -0
- package/dist/core/search.js +19 -0
- package/dist/core/settings.d.ts +2 -0
- package/dist/core/settings.js +13 -1
- package/dist/core/temp.d.ts +73 -0
- package/dist/core/temp.js +154 -0
- package/dist/core/trash.d.ts +1 -1
- package/dist/harness.d.ts +2 -0
- package/dist/harnesses/acp.js +1 -1
- package/dist/harnesses/claude.js +1 -0
- package/dist/harnesses/codex.js +1 -0
- package/dist/harnesses/pi.js +1 -0
- package/dist/run.d.ts +7 -0
- package/dist/run.js +13 -1
- package/dist/server/api/boards.d.ts +105 -0
- package/dist/server/api/boards.js +160 -0
- package/dist/server/api/chats.d.ts +2 -0
- package/dist/server/api/chats.js +9 -3
- package/dist/server/api/files.d.ts +9 -1
- package/dist/server/api/files.js +13 -0
- package/dist/server/api/index.d.ts +113 -2
- package/dist/server/api/index.js +2 -0
- package/dist/server/api/workspace.d.ts +5 -0
- package/dist/server/api/workspace.js +2 -0
- package/dist/server/push.js +1 -1
- package/dist/server/server.js +3 -0
- package/dist/yaml.js +1 -0
- package/package.json +1 -1
- package/schema/kraftwerk.schema.json +39 -0
- package/web/dist/assets/{dist-DlZPeneT.js → dist-BBFUIftm.js} +1 -1
- package/web/dist/assets/{dist-u_oAKIhZ.js → dist-Bie1ebP9.js} +1 -1
- package/web/dist/assets/{dist-NX4_yvho.js → dist-BuwdjX6z.js} +1 -1
- package/web/dist/assets/{dist-1PajaYPg.js → dist-C0ve4Tka.js} +1 -1
- package/web/dist/assets/{dist-DgKgeYFJ.js → dist-C16bXf8c.js} +1 -1
- package/web/dist/assets/{dist-DKduisGW.js → dist-CDUZdAAS.js} +1 -1
- package/web/dist/assets/{dist-B4dqwo7_.js → dist-CH73jsgO.js} +1 -1
- package/web/dist/assets/{dist-D-f0nszo.js → dist-C_rJjRj7.js} +1 -1
- package/web/dist/assets/dist-DYICNp09.js +1 -0
- package/web/dist/assets/{dist-K_3Y5Nbl.js → dist-DtUB2Uu2.js} +1 -1
- package/web/dist/assets/{dist-CK2u1OXb.js → dist-DvkrCSGL.js} +1 -1
- package/web/dist/assets/{editor-CE9TlKkJ.js → editor-3z92i0tV.js} +3 -3
- package/web/dist/assets/{editor-CZMrhTTL.css → editor-C0_Snnzk.css} +1 -1
- package/web/dist/assets/index-DRhNELK_.js +232 -0
- package/web/dist/assets/index-unGEux3Y.css +2 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/dist-Bp1iMuQ7.js +0 -1
- package/web/dist/assets/index-Dvt-vE1h.css +0 -2
- package/web/dist/assets/index-IAuwD22j.js +0 -231
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { type ResolvedWorkspace } from "../config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Boards and tasks: the work of a project (or of the whole workspace) as
|
|
4
|
+
* columns of cards, stored as plain folders so humans, agents and git all
|
|
5
|
+
* read the same thing. A board holds columns and tasks; a task is a folder
|
|
6
|
+
* with the markdown that describes it, an append-only log of what happened
|
|
7
|
+
* to it, and whatever files it needs.
|
|
8
|
+
*
|
|
9
|
+
* projects/<p>/boards/<board>/board.md # title, columns, default agent + the board's rules (body)
|
|
10
|
+
* projects/<p>/boards/<board>/tasks/<n>-<slug>/task.md # title, status (a column), order, assignee, due, tags, refs + the task (body)
|
|
11
|
+
* projects/<p>/boards/<board>/tasks/<n>-<slug>/log.md # newest first: moves, hand-overs, comments, files (journal format)
|
|
12
|
+
* projects/<p>/boards/<board>/tasks/<n>-<slug>/… # the task's files
|
|
13
|
+
* kraftwerk-data/boards/<board>/… # workspace boards, same shape (`boards.root`)
|
|
14
|
+
*
|
|
15
|
+
* The folder is the registry: a folder with a board.md is a board, a
|
|
16
|
+
* folder under tasks/ with a task.md is a task. The column is a field of
|
|
17
|
+
* task.md, not a folder per column, so a move is a one-line diff and the
|
|
18
|
+
* task's path (links, files) never changes. Task folders are numbered per
|
|
19
|
+
* board (`50-write-a-press-release`): the number is the short handle in
|
|
20
|
+
* the CLI, the whole name is the reference token (task:50-write-a-press-release).
|
|
21
|
+
*
|
|
22
|
+
* Agents are woken by events, not by polling: whoever writes a task (an API
|
|
23
|
+
* route, the CLI in another process) appends a line to <output>/boards/events.jsonl
|
|
24
|
+
* when a task with an agent as assignee sits in a work column, and the server
|
|
25
|
+
* on this machine consumes the file (board-wake.ts). The output folder is
|
|
26
|
+
* local, so a clone of the workspace never sees another machine's events.
|
|
27
|
+
*/
|
|
28
|
+
export declare const BOARD_FILE = "board.md";
|
|
29
|
+
export declare const TASK_FILE = "task.md";
|
|
30
|
+
export declare const TASK_LOG = "log.md";
|
|
31
|
+
/** The folder (and the default board's slug) a project's tasks go to when no board is named. */
|
|
32
|
+
export declare const DEFAULT_BOARD = "tasks";
|
|
33
|
+
export interface Column {
|
|
34
|
+
slug: string;
|
|
35
|
+
label: string;
|
|
36
|
+
/** Work-in-progress limit; the UI marks the column when it is exceeded, nothing is refused. */
|
|
37
|
+
limit?: number;
|
|
38
|
+
/** Tasks here are finished. */
|
|
39
|
+
done?: boolean;
|
|
40
|
+
/** Tasks here wait for a human: they count as attention. */
|
|
41
|
+
review?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare const DEFAULT_COLUMNS: Column[];
|
|
44
|
+
/** Where a board lives: in a project, or at the workspace level. */
|
|
45
|
+
export interface BoardRef {
|
|
46
|
+
project?: string;
|
|
47
|
+
board: string;
|
|
48
|
+
}
|
|
49
|
+
export interface BoardDef extends BoardRef {
|
|
50
|
+
title: string;
|
|
51
|
+
columns: Column[];
|
|
52
|
+
/** Tasks entering todo without an assignee get this agent (and wake it). */
|
|
53
|
+
agent?: string;
|
|
54
|
+
/** A task in a work column with no log entry for this long shows as stale. Default: 1d. */
|
|
55
|
+
staleAfter?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface BoardSummary extends BoardDef {
|
|
58
|
+
/** Absolute folder path. */
|
|
59
|
+
path: string;
|
|
60
|
+
updatedAt?: string;
|
|
61
|
+
/** Set when board.md exists but is unusable; the rest shows defaults. */
|
|
62
|
+
configError?: string;
|
|
63
|
+
/** Tasks per column slug (tasks in no known column under ""). */
|
|
64
|
+
counts: Record<string, number>;
|
|
65
|
+
tasks: number;
|
|
66
|
+
/** Tasks in a review column. */
|
|
67
|
+
review: number;
|
|
68
|
+
}
|
|
69
|
+
export interface BoardDetail extends BoardSummary {
|
|
70
|
+
/** The body of board.md: what the board is for, the rules agents follow. */
|
|
71
|
+
notes: string;
|
|
72
|
+
items: TaskSummary[];
|
|
73
|
+
}
|
|
74
|
+
export interface TaskDef {
|
|
75
|
+
/** The folder name: <number>-<slug>. */
|
|
76
|
+
slug: string;
|
|
77
|
+
number: number;
|
|
78
|
+
title: string;
|
|
79
|
+
/** A column slug of the board. */
|
|
80
|
+
status: string;
|
|
81
|
+
/** Position inside the column; sparse, renumbered on save. */
|
|
82
|
+
order: number;
|
|
83
|
+
/** An agent slug; absent = unassigned. */
|
|
84
|
+
assignee?: string;
|
|
85
|
+
due?: string;
|
|
86
|
+
created: string;
|
|
87
|
+
tags: string[];
|
|
88
|
+
/** kind:slug tokens this task refers to. */
|
|
89
|
+
refs: string[];
|
|
90
|
+
/** Unknown frontmatter keys, kept as written. */
|
|
91
|
+
extra?: Record<string, unknown>;
|
|
92
|
+
}
|
|
93
|
+
export interface TaskSummary extends TaskDef {
|
|
94
|
+
/** The task's reference: <project>/<board>/<slug> or <board>/<slug>. */
|
|
95
|
+
ref: string;
|
|
96
|
+
path: string;
|
|
97
|
+
updatedAt?: string;
|
|
98
|
+
configError?: string;
|
|
99
|
+
/** Files in the folder (task.md, log.md and dot files not counted). */
|
|
100
|
+
files: number;
|
|
101
|
+
/** The newest log line, without its stamp. */
|
|
102
|
+
lastLog?: string;
|
|
103
|
+
/** In a work column with an assignee and nothing logged for staleAfter. */
|
|
104
|
+
stale?: boolean;
|
|
105
|
+
}
|
|
106
|
+
export interface TaskDetail extends TaskSummary {
|
|
107
|
+
/** The body of task.md. */
|
|
108
|
+
notes: string;
|
|
109
|
+
/** log.md as written. */
|
|
110
|
+
log: string;
|
|
111
|
+
/** The task's files, relative to its folder. */
|
|
112
|
+
fileList: string[];
|
|
113
|
+
board: string;
|
|
114
|
+
project?: string;
|
|
115
|
+
}
|
|
116
|
+
export interface BoardsView {
|
|
117
|
+
enabled: boolean;
|
|
118
|
+
/** The workspace boards root. */
|
|
119
|
+
root?: string;
|
|
120
|
+
boards: BoardSummary[];
|
|
121
|
+
error?: string;
|
|
122
|
+
}
|
|
123
|
+
/** Every field optional: omitted = untouched. */
|
|
124
|
+
export interface SaveBoardInput {
|
|
125
|
+
title?: string;
|
|
126
|
+
columns?: unknown;
|
|
127
|
+
agent?: string | null;
|
|
128
|
+
staleAfter?: string | null;
|
|
129
|
+
notes?: string;
|
|
130
|
+
}
|
|
131
|
+
export interface TaskInput {
|
|
132
|
+
title?: string;
|
|
133
|
+
status?: string;
|
|
134
|
+
order?: number;
|
|
135
|
+
assignee?: string | null;
|
|
136
|
+
due?: string | null;
|
|
137
|
+
tags?: unknown;
|
|
138
|
+
refs?: unknown;
|
|
139
|
+
notes?: string;
|
|
140
|
+
}
|
|
141
|
+
/** Who writes (an actor string: human:user, lisa/claude, …) and an optional message for the log. */
|
|
142
|
+
export interface WriteOpts {
|
|
143
|
+
actor?: string;
|
|
144
|
+
message?: string;
|
|
145
|
+
}
|
|
146
|
+
export declare function openBoards(): Promise<{
|
|
147
|
+
project?: ResolvedWorkspace;
|
|
148
|
+
root?: string;
|
|
149
|
+
off?: boolean;
|
|
150
|
+
error?: string;
|
|
151
|
+
}>;
|
|
152
|
+
/** Make sure the workspace boards root exists; runs when the feature is switched on. */
|
|
153
|
+
export declare function ensureBoardsRoot(): Promise<void>;
|
|
154
|
+
export declare function safeBoardSlug(slug: string): string;
|
|
155
|
+
/** The folder name of a task: <number>-<slug>. */
|
|
156
|
+
export declare function safeTaskSlug(slug: string): string;
|
|
157
|
+
/** The folder a board lives in: inside its project (projects must be on) or under the workspace root. */
|
|
158
|
+
export declare function boardDir(ref: BoardRef): Promise<string>;
|
|
159
|
+
/** "<project>/<board>" or "<board>". */
|
|
160
|
+
export declare const boardKey: (ref: BoardRef) => string;
|
|
161
|
+
/** "<project>/<board>/<task>" or "<board>/<task>". */
|
|
162
|
+
export declare const taskRef: (ref: BoardRef, task: string) => string;
|
|
163
|
+
/** Parse "<project>/<board>/<task>" or "<board>/<task>" (and the two-or-one-part board forms when `task` is false). */
|
|
164
|
+
export declare function parseTaskRef(text: string): {
|
|
165
|
+
board: BoardRef;
|
|
166
|
+
task: string;
|
|
167
|
+
};
|
|
168
|
+
export declare function parseBoardRef(text: string): BoardRef;
|
|
169
|
+
/** "1d", "12h", "90m" -> milliseconds. */
|
|
170
|
+
export declare function parseDuration(text: string): number;
|
|
171
|
+
/** The column `tasks pick` takes from: "todo" when the board has it, else the second column (the first is the inbox), else the only one. */
|
|
172
|
+
export declare const pickColumn: (columns: Column[]) => Column | undefined;
|
|
173
|
+
/** A column's role: work columns — from the pick column on, review and done excepted — are where an assigned agent is expected to act. */
|
|
174
|
+
export declare const isWorkColumn: (c: Column | undefined, columns: Column[]) => boolean;
|
|
175
|
+
export declare const reviewColumn: (columns: Column[]) => Column | undefined;
|
|
176
|
+
/** The boards of a project (its boards/ folder), or the workspace boards when no project is given. */
|
|
177
|
+
export declare function listBoards(project?: string): Promise<BoardsView>;
|
|
178
|
+
/** Every board of the workspace: the workspace ones first, then each project's. */
|
|
179
|
+
export declare function listAllBoards(): Promise<BoardSummary[]>;
|
|
180
|
+
export declare function getBoard(ref: BoardRef): Promise<BoardDetail | null>;
|
|
181
|
+
/** Tasks of a board, optionally narrowed by column, assignee (or "" for unassigned) and tag. */
|
|
182
|
+
export declare function listTasks(ref: BoardRef, filter?: {
|
|
183
|
+
status?: string;
|
|
184
|
+
assignee?: string;
|
|
185
|
+
tag?: string;
|
|
186
|
+
}): Promise<TaskSummary[]>;
|
|
187
|
+
export declare function getTask(ref: BoardRef, idOrNumber: string): Promise<TaskDetail | null>;
|
|
188
|
+
/** Find a task by its reference anywhere: "<project>/<board>/<task>" or "<board>/<task>". */
|
|
189
|
+
export declare function findTask(reference: string): Promise<TaskDetail | null>;
|
|
190
|
+
export declare function createBoard(input: {
|
|
191
|
+
project?: string;
|
|
192
|
+
title: string;
|
|
193
|
+
slug?: string;
|
|
194
|
+
columns?: unknown;
|
|
195
|
+
agent?: string;
|
|
196
|
+
notes?: string;
|
|
197
|
+
}): Promise<BoardDetail>;
|
|
198
|
+
export declare function saveBoard(ref: BoardRef, input: SaveBoardInput): Promise<BoardDetail>;
|
|
199
|
+
/** Move the board folder, tasks and all, to the trash. */
|
|
200
|
+
export declare function deleteBoard(ref: BoardRef): Promise<void>;
|
|
201
|
+
/** The project's default board (`tasks`), created on first use. */
|
|
202
|
+
export declare function ensureDefaultBoard(project?: string): Promise<BoardRef>;
|
|
203
|
+
/** Append a free entry to a task's log: what was done, a comment, a question. */
|
|
204
|
+
export declare function appendTaskLog(ref: BoardRef, idOrNumber: string, entry: string, actor?: string): Promise<TaskDetail>;
|
|
205
|
+
/** What the server acts on: a task with an agent in a work column, after a change of that pair. */
|
|
206
|
+
export interface TaskEvent {
|
|
207
|
+
at: string;
|
|
208
|
+
ref: string;
|
|
209
|
+
project?: string;
|
|
210
|
+
board: string;
|
|
211
|
+
task: string;
|
|
212
|
+
title: string;
|
|
213
|
+
agent: string;
|
|
214
|
+
status: string;
|
|
215
|
+
/** Why the agent is woken, for the message it gets. */
|
|
216
|
+
reason: "assigned" | "moved" | "created";
|
|
217
|
+
actor: string;
|
|
218
|
+
message?: string;
|
|
219
|
+
}
|
|
220
|
+
export declare const EVENTS_FILE = "boards/events.jsonl";
|
|
221
|
+
export declare function createTask(ref: BoardRef, input: TaskInput & {
|
|
222
|
+
actor?: string;
|
|
223
|
+
message?: string;
|
|
224
|
+
}): Promise<TaskDetail>;
|
|
225
|
+
/** Merge fields (and the notes when given) into task.md; a status or assignee change is logged and may wake the assignee. */
|
|
226
|
+
export declare function saveTask(ref: BoardRef, idOrNumber: string, input: TaskInput, opts?: WriteOpts): Promise<TaskDetail>;
|
|
227
|
+
/** Put a task into a column (and, with `order`, at a position: the orders of the column are renumbered around it). */
|
|
228
|
+
export declare function moveTask(ref: BoardRef, idOrNumber: string, status: string, opts?: WriteOpts & {
|
|
229
|
+
order?: number;
|
|
230
|
+
before?: string;
|
|
231
|
+
}): Promise<TaskDetail>;
|
|
232
|
+
/** Give the task to an agent, or back to the humans (`to` = null: unassigned and into the review column). */
|
|
233
|
+
export declare function assignTask(ref: BoardRef, idOrNumber: string, to: string | null, opts?: WriteOpts): Promise<TaskDetail>;
|
|
234
|
+
/**
|
|
235
|
+
* An agent takes the next task: the first unassigned (or its own) task in
|
|
236
|
+
* the pick column, in the column's order (due date as tie-break), becomes
|
|
237
|
+
* its and moves to the first work column after it. Exclusive: under the
|
|
238
|
+
* task's lock the file is read again, so two agents never take the same one.
|
|
239
|
+
*/
|
|
240
|
+
export declare function pickTask(ref: BoardRef, agent: string, opts?: {
|
|
241
|
+
column?: string;
|
|
242
|
+
actor?: string;
|
|
243
|
+
}): Promise<TaskDetail | null>;
|
|
244
|
+
/** Move the task folder, files and log included, to the trash. */
|
|
245
|
+
export declare function deleteTask(ref: BoardRef, idOrNumber: string): Promise<void>;
|
|
246
|
+
/** Called by the files API after a file was added to or removed from a task folder. */
|
|
247
|
+
export declare function noteTaskFile(reference: string, what: "added" | "removed", file: string, actor?: string): Promise<void>;
|
|
248
|
+
/**
|
|
249
|
+
* The "## Board: …" blocks of a project chat (or of an agent for the
|
|
250
|
+
* boards it has tasks on): the board's rules, its columns with counts, the
|
|
251
|
+
* open tasks, and the CLI. `agent` narrows the task list to that agent's
|
|
252
|
+
* and the unassigned ones in the pick column.
|
|
253
|
+
*/
|
|
254
|
+
export declare function boardsContext(project: string | undefined, actor: string, agent?: string): Promise<string>;
|
|
255
|
+
/** The block a session gets when it was opened for one task: the task, its files and its whole log. */
|
|
256
|
+
export declare function taskContext(reference: string): Promise<string>;
|