@wrongstack/webui 0.264.0 → 0.265.1
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/assets/index-CC3KdGXG.js +118 -0
- package/dist/assets/index-CFHDQU3T.css +2 -0
- package/dist/assets/{vendor-CEQg2uSG.css → vendor-B2D6LvU3.css} +1 -1
- package/dist/assets/vendor-BX-wfDR9.js +1326 -0
- package/dist/index.html +4 -4
- package/dist/index.js +8949 -4311
- package/dist/index.js.map +1 -1
- package/dist/server/entry.js +1612 -339
- package/dist/server/entry.js.map +1 -1
- package/dist/server/handlers.d.ts +45 -0
- package/dist/server/handlers.js +179 -0
- package/dist/server/handlers.js.map +1 -0
- package/dist/server/index.d.ts +147 -6
- package/dist/server/index.js +1945 -405
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +391 -2
- package/package.json +7 -5
- package/dist/assets/index-BBPaC1tO.js +0 -170
- package/dist/assets/index-DJmqJ5Wo.css +0 -2
- package/dist/assets/vendor-pWpGJmMc.js +0 -1303
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
import { TodoItem } from '@wrongstack/core';
|
|
3
|
+
|
|
4
|
+
interface WorklistContext {
|
|
5
|
+
context: {
|
|
6
|
+
todos: TodoItem[];
|
|
7
|
+
meta: Record<string, unknown>;
|
|
8
|
+
session: {
|
|
9
|
+
id: string;
|
|
10
|
+
} | null;
|
|
11
|
+
state?: unknown;
|
|
12
|
+
};
|
|
13
|
+
send: (ws: WebSocket, msg: object) => void;
|
|
14
|
+
broadcast: (msg: object) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Optional mutator for in-memory todo state. Servers that manage live
|
|
17
|
+
* agent state (e.g. the CLI embedded server) provide this so handlers
|
|
18
|
+
* can update the agent's todo list directly. Standalone server may omit.
|
|
19
|
+
*/
|
|
20
|
+
replaceTodos?: (todos: TodoItem[]) => void;
|
|
21
|
+
}
|
|
22
|
+
declare function handleTodosGet(ctx: WorklistContext, ws: WebSocket): void;
|
|
23
|
+
declare function handleTodosClear(ctx: WorklistContext, ws: WebSocket): void;
|
|
24
|
+
declare function handleTodosRemove(ctx: WorklistContext, ws: WebSocket, payload: {
|
|
25
|
+
id?: string;
|
|
26
|
+
index?: number;
|
|
27
|
+
} | undefined): void;
|
|
28
|
+
declare function handleTodoUpdate(ctx: WorklistContext, ws: WebSocket, payload: {
|
|
29
|
+
id: string;
|
|
30
|
+
status?: TodoItem['status'];
|
|
31
|
+
activeForm?: string;
|
|
32
|
+
}): void;
|
|
33
|
+
declare function handleTasksGet(ctx: WorklistContext, ws: WebSocket): Promise<void>;
|
|
34
|
+
declare function handleTaskUpdate(ctx: WorklistContext, ws: WebSocket, payload: {
|
|
35
|
+
id: string;
|
|
36
|
+
status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';
|
|
37
|
+
}): Promise<void>;
|
|
38
|
+
declare function handlePlanGet(ctx: WorklistContext, ws: WebSocket): Promise<void>;
|
|
39
|
+
declare function handlePlanTemplateUse(ctx: WorklistContext, ws: WebSocket, template: string): Promise<void>;
|
|
40
|
+
declare function handlePlanItemUpdate(ctx: WorklistContext, ws: WebSocket, payload: {
|
|
41
|
+
target: string;
|
|
42
|
+
status: 'open' | 'in_progress' | 'done';
|
|
43
|
+
}): Promise<void>;
|
|
44
|
+
|
|
45
|
+
export { type WorklistContext, handlePlanGet, handlePlanItemUpdate, handlePlanTemplateUse, handleTaskUpdate, handleTasksGet, handleTodoUpdate, handleTodosClear, handleTodosGet, handleTodosRemove };
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// src/server/handlers/worklist-handlers.ts
|
|
2
|
+
function sendResult(ws, ctx, ok, message) {
|
|
3
|
+
ctx.send(ws, { type: ok ? "ok" : "error", message });
|
|
4
|
+
}
|
|
5
|
+
function handleTodosGet(ctx, ws) {
|
|
6
|
+
ctx.send(ws, { type: "todos.updated", payload: { todos: ctx.context.todos } });
|
|
7
|
+
}
|
|
8
|
+
function handleTodosClear(ctx, ws) {
|
|
9
|
+
ctx.replaceTodos?.([]);
|
|
10
|
+
ctx.broadcast({ type: "todos.cleared" });
|
|
11
|
+
sendResult(ws, ctx, true, "Todo board cleared.");
|
|
12
|
+
}
|
|
13
|
+
function handleTodosRemove(ctx, ws, payload) {
|
|
14
|
+
if (!payload || payload.id === void 0 && payload.index === void 0) {
|
|
15
|
+
sendResult(ws, ctx, false, "todos.remove requires id or index.");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const next = payload.id !== void 0 ? ctx.context.todos.filter((t) => t.id !== payload.id) : ctx.context.todos.filter((_, i) => i !== payload.index);
|
|
19
|
+
ctx.replaceTodos?.(next);
|
|
20
|
+
ctx.broadcast({ type: "todos.updated", payload: { todos: next } });
|
|
21
|
+
sendResult(ws, ctx, true, "Todo item removed.");
|
|
22
|
+
}
|
|
23
|
+
function handleTodoUpdate(ctx, ws, payload) {
|
|
24
|
+
const todo = ctx.context.todos.find((t) => t.id === payload.id);
|
|
25
|
+
if (!todo) {
|
|
26
|
+
sendResult(ws, ctx, false, `No todo with id "${payload.id}".`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const next = ctx.context.todos.map(
|
|
30
|
+
(t) => t.id === payload.id ? { ...t, ...payload.status !== void 0 && { status: payload.status }, ...payload.activeForm !== void 0 && { activeForm: payload.activeForm } } : t
|
|
31
|
+
);
|
|
32
|
+
ctx.replaceTodos?.(next);
|
|
33
|
+
ctx.broadcast({ type: "todos.updated", payload: { todos: next } });
|
|
34
|
+
sendResult(ws, ctx, true, `Todo "${todo.content}" updated.`);
|
|
35
|
+
}
|
|
36
|
+
async function handleTasksGet(ctx, ws) {
|
|
37
|
+
const taskPath = ctx.context.meta["task.path"];
|
|
38
|
+
if (typeof taskPath === "string" && taskPath) {
|
|
39
|
+
try {
|
|
40
|
+
const { loadTasks } = await import("@wrongstack/core");
|
|
41
|
+
const file = await loadTasks(taskPath);
|
|
42
|
+
ctx.send(ws, { type: "tasks.updated", payload: { tasks: file?.tasks ?? [] } });
|
|
43
|
+
} catch {
|
|
44
|
+
ctx.send(ws, { type: "tasks.updated", payload: { tasks: [] } });
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
ctx.send(ws, {
|
|
48
|
+
type: "tasks.updated",
|
|
49
|
+
payload: { tasks: [], error: "Task storage not configured." }
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function handleTaskUpdate(ctx, ws, payload) {
|
|
54
|
+
const taskPath = ctx.context.meta["task.path"];
|
|
55
|
+
if (typeof taskPath !== "string" || !taskPath) {
|
|
56
|
+
sendResult(ws, ctx, false, "Task storage is not configured for this session.");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const { loadTasks, saveTasks } = await import("@wrongstack/core");
|
|
61
|
+
const file = await loadTasks(taskPath);
|
|
62
|
+
if (!file) {
|
|
63
|
+
sendResult(ws, ctx, false, "No task file found.");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const idx = file.tasks.findIndex((t) => t.id === payload.id);
|
|
67
|
+
if (idx === -1) {
|
|
68
|
+
sendResult(ws, ctx, false, `Task "${payload.id}" not found.`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
file.tasks[idx] = { ...file.tasks[idx], status: payload.status };
|
|
72
|
+
await saveTasks(taskPath, file);
|
|
73
|
+
ctx.broadcast({ type: "tasks.updated", payload: { tasks: file.tasks } });
|
|
74
|
+
sendResult(ws, ctx, true, `Task "${payload.id}" marked ${payload.status}.`);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
sendResult(ws, ctx, false, String(err));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function handlePlanGet(ctx, ws) {
|
|
80
|
+
const planPath = ctx.context.meta["plan.path"];
|
|
81
|
+
const sessionId = ctx.context.session?.id ?? "";
|
|
82
|
+
if (typeof planPath === "string" && planPath) {
|
|
83
|
+
try {
|
|
84
|
+
const { loadPlan } = await import("@wrongstack/core");
|
|
85
|
+
const plan = await loadPlan(planPath);
|
|
86
|
+
ctx.send(ws, {
|
|
87
|
+
type: "plan.updated",
|
|
88
|
+
payload: {
|
|
89
|
+
plan: plan ?? {
|
|
90
|
+
version: 1,
|
|
91
|
+
sessionId,
|
|
92
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
93
|
+
items: []
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
} catch {
|
|
98
|
+
ctx.send(ws, {
|
|
99
|
+
type: "plan.updated",
|
|
100
|
+
payload: {
|
|
101
|
+
plan: {
|
|
102
|
+
version: 1,
|
|
103
|
+
sessionId,
|
|
104
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
105
|
+
items: []
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
ctx.send(ws, {
|
|
112
|
+
type: "plan.updated",
|
|
113
|
+
payload: { plan: null, error: "Plan storage is not configured for this session." }
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function handlePlanTemplateUse(ctx, ws, template) {
|
|
118
|
+
const planPath = ctx.context.meta["plan.path"];
|
|
119
|
+
const sessionId = ctx.context.session?.id ?? "";
|
|
120
|
+
if (typeof planPath !== "string" || !planPath) {
|
|
121
|
+
sendResult(ws, ctx, false, "Plan storage is not configured for this session.");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const { getPlanTemplate, loadPlan, savePlan, emptyPlan, addPlanItem } = await import("@wrongstack/core");
|
|
126
|
+
const tpl = getPlanTemplate(template);
|
|
127
|
+
if (!tpl) {
|
|
128
|
+
sendResult(ws, ctx, false, `Unknown template "${template}".`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
let plan = await loadPlan(planPath) ?? emptyPlan(sessionId);
|
|
132
|
+
for (const item of tpl.items) {
|
|
133
|
+
({ plan } = addPlanItem(plan, item.title, item.details));
|
|
134
|
+
}
|
|
135
|
+
await savePlan(planPath, plan);
|
|
136
|
+
sendResult(ws, ctx, true, `Applied template "${tpl.name}" \u2014 ${tpl.items.length} items added.`);
|
|
137
|
+
ctx.broadcast({ type: "plan.updated", payload: { plan } });
|
|
138
|
+
} catch (err) {
|
|
139
|
+
sendResult(ws, ctx, false, String(err));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function handlePlanItemUpdate(ctx, ws, payload) {
|
|
143
|
+
const planPath = ctx.context.meta["plan.path"];
|
|
144
|
+
const sessionId = ctx.context.session?.id ?? "";
|
|
145
|
+
if (typeof planPath !== "string" || !planPath) {
|
|
146
|
+
sendResult(ws, ctx, false, "Plan storage is not configured for this session.");
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
const { loadPlan, savePlan, mutatePlan, setPlanItemStatus } = await import("@wrongstack/core");
|
|
151
|
+
let changed = false;
|
|
152
|
+
const plan = await mutatePlan(planPath, sessionId, async (p) => {
|
|
153
|
+
const before = p.updatedAt;
|
|
154
|
+
const updated = setPlanItemStatus(p, payload.target, payload.status);
|
|
155
|
+
changed = updated.updatedAt !== before;
|
|
156
|
+
return updated;
|
|
157
|
+
});
|
|
158
|
+
if (!changed) {
|
|
159
|
+
sendResult(ws, ctx, false, `No plan item matched "${payload.target}".`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
sendResult(ws, ctx, true, `Plan item status updated to "${payload.status}".`);
|
|
163
|
+
ctx.broadcast({ type: "plan.updated", payload: { plan } });
|
|
164
|
+
} catch (err) {
|
|
165
|
+
sendResult(ws, ctx, false, String(err));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export {
|
|
169
|
+
handlePlanGet,
|
|
170
|
+
handlePlanItemUpdate,
|
|
171
|
+
handlePlanTemplateUse,
|
|
172
|
+
handleTaskUpdate,
|
|
173
|
+
handleTasksGet,
|
|
174
|
+
handleTodoUpdate,
|
|
175
|
+
handleTodosClear,
|
|
176
|
+
handleTodosGet,
|
|
177
|
+
handleTodosRemove
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/server/handlers/worklist-handlers.ts"],"sourcesContent":["// ── Shared Worklist Handlers ─────────────────────────────────────────────────\n// Extracted from standalone server (packages/webui/src/server/index.ts) and CLI\n// embedded server (packages/cli/src/webui-server/). Both servers use these\n// handlers for todos, tasks, and plan operations. Keep them in sync.\n//\n// Message types handled here:\n// todos.get | todos.clear | todos.remove | todo.update\n// tasks.get | task.update\n// plan.get | plan.template_use | plan.item.update\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { WebSocket } from 'ws';\nimport type { TodoItem } from '@wrongstack/core';\n\n// ── Shared result helper ───────────────────────────────────────────────────────\n\nfunction sendResult(\n ws: WebSocket,\n ctx: WorklistContext,\n ok: boolean,\n message: string,\n): void {\n ctx.send(ws, { type: ok ? 'ok' : 'error', message });\n}\n\n// ── Context interface ─────────────────────────────────────────────────────────\n// Both servers satisfy this with their own local state.\n\nexport interface WorklistContext {\n context: {\n todos: TodoItem[];\n meta: Record<string, unknown>;\n session: { id: string } | null;\n state?: unknown;\n };\n send: (ws: WebSocket, msg: object) => void;\n broadcast: (msg: object) => void;\n /**\n * Optional mutator for in-memory todo state. Servers that manage live\n * agent state (e.g. the CLI embedded server) provide this so handlers\n * can update the agent's todo list directly. Standalone server may omit.\n */\n replaceTodos?: (todos: TodoItem[]) => void;\n}\n\n// ── Todos ─────────────────────────────────────────────────────────────────────\n\nexport function handleTodosGet(ctx: WorklistContext, ws: WebSocket): void {\n ctx.send(ws, { type: 'todos.updated', payload: { todos: ctx.context.todos } });\n}\n\nexport function handleTodosClear(ctx: WorklistContext, ws: WebSocket): void {\n ctx.replaceTodos?.([]);\n ctx.broadcast({ type: 'todos.cleared' });\n sendResult(ws, ctx, true, 'Todo board cleared.');\n}\n\nexport function handleTodosRemove(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id?: string; index?: number } | undefined,\n): void {\n if (!payload || (payload.id === undefined && payload.index === undefined)) {\n sendResult(ws, ctx, false, 'todos.remove requires id or index.');\n return;\n }\n const next =\n payload.id !== undefined\n ? ctx.context.todos.filter((t) => t.id !== payload.id)\n : ctx.context.todos.filter((_, i) => i !== (payload.index as number));\n ctx.replaceTodos?.(next);\n ctx.broadcast({ type: 'todos.updated', payload: { todos: next } });\n sendResult(ws, ctx, true, 'Todo item removed.');\n}\n\nexport function handleTodoUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id: string; status?: TodoItem['status']; activeForm?: string },\n): void {\n const todo = ctx.context.todos.find((t) => t.id === payload.id);\n if (!todo) {\n sendResult(ws, ctx, false, `No todo with id \"${payload.id}\".`);\n return;\n }\n const next = ctx.context.todos.map((t) =>\n t.id === payload.id\n ? { ...t, ...(payload.status !== undefined && { status: payload.status }), ...(payload.activeForm !== undefined && { activeForm: payload.activeForm }) }\n : t,\n );\n ctx.replaceTodos?.(next);\n ctx.broadcast({ type: 'todos.updated', payload: { todos: next } });\n sendResult(ws, ctx, true, `Todo \"${todo.content}\" updated.`);\n}\n\n// ── Tasks ─────────────────────────────────────────────────────────────────────\n\nexport async function handleTasksGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const taskPath = ctx.context.meta['task.path'];\n if (typeof taskPath === 'string' && taskPath) {\n try {\n const { loadTasks } = await import('@wrongstack/core');\n const file = await loadTasks(taskPath);\n ctx.send(ws, { type: 'tasks.updated', payload: { tasks: file?.tasks ?? [] } });\n } catch {\n ctx.send(ws, { type: 'tasks.updated', payload: { tasks: [] } });\n }\n } else {\n ctx.send(ws, {\n type: 'tasks.updated',\n payload: { tasks: [], error: 'Task storage not configured.' },\n });\n }\n}\n\nexport async function handleTaskUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n): Promise<void> {\n const taskPath = ctx.context.meta['task.path'];\n if (typeof taskPath !== 'string' || !taskPath) {\n sendResult(ws, ctx, false, 'Task storage is not configured for this session.');\n return;\n }\n try {\n const { loadTasks, saveTasks } = await import('@wrongstack/core');\n const file = await loadTasks(taskPath);\n if (!file) {\n sendResult(ws, ctx, false, 'No task file found.');\n return;\n }\n const idx = file.tasks.findIndex((t) => t.id === payload.id);\n if (idx === -1) {\n sendResult(ws, ctx, false, `Task \"${payload.id}\" not found.`);\n return;\n }\n file.tasks[idx] = { ...file.tasks[idx], status: payload.status };\n await saveTasks(taskPath, file);\n ctx.broadcast({ type: 'tasks.updated', payload: { tasks: file.tasks } });\n sendResult(ws, ctx, true, `Task \"${payload.id}\" marked ${payload.status}.`);\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n\n// ── Plan ───────────────────────────────────────────────────────────────────────\n\nexport async function handlePlanGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath === 'string' && planPath) {\n try {\n const { loadPlan } = await import('@wrongstack/core');\n const plan = await loadPlan(planPath);\n ctx.send(ws, {\n type: 'plan.updated',\n payload: {\n plan: plan ?? {\n version: 1,\n sessionId,\n updatedAt: new Date().toISOString(),\n items: [],\n },\n },\n });\n } catch {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: {\n plan: {\n version: 1,\n sessionId,\n updatedAt: new Date().toISOString(),\n items: [],\n },\n },\n });\n }\n } else {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: { plan: null, error: 'Plan storage is not configured for this session.' },\n });\n }\n}\n\nexport async function handlePlanTemplateUse(ctx: WorklistContext, ws: WebSocket, template: string): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath !== 'string' || !planPath) {\n sendResult(ws, ctx, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n const { getPlanTemplate, loadPlan, savePlan, emptyPlan, addPlanItem } = await import('@wrongstack/core');\n const tpl = getPlanTemplate(template);\n if (!tpl) {\n sendResult(ws, ctx, false, `Unknown template \"${template}\".`);\n return;\n }\n let plan = (await loadPlan(planPath)) ?? emptyPlan(sessionId);\n for (const item of tpl.items) {\n ({ plan } = addPlanItem(plan, item.title, item.details));\n }\n await savePlan(planPath, plan);\n sendResult(ws, ctx, true, `Applied template \"${tpl.name}\" — ${tpl.items.length} items added.`);\n ctx.broadcast({ type: 'plan.updated', payload: { plan } });\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n\nexport async function handlePlanItemUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { target: string; status: 'open' | 'in_progress' | 'done' },\n): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath !== 'string' || !planPath) {\n sendResult(ws, ctx, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n const { loadPlan, savePlan, mutatePlan, setPlanItemStatus } = await import('@wrongstack/core');\n let changed = false;\n const plan = await mutatePlan(planPath, sessionId, async (p) => {\n const before = p.updatedAt;\n const updated = setPlanItemStatus(p, payload.target, payload.status);\n changed = updated.updatedAt !== before;\n return updated;\n });\n if (!changed) {\n sendResult(ws, ctx, false, `No plan item matched \"${payload.target}\".`);\n return;\n }\n sendResult(ws, ctx, true, `Plan item status updated to \"${payload.status}\".`);\n ctx.broadcast({ type: 'plan.updated', payload: { plan } });\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WebSocket } from 'ws';
|
|
2
|
-
import { Agent, EventBus, SessionStore, ToolRegistry, ModelsRegistry, ConfigStore, SecretVault, JournalEntry, Logger, MemoryStore, ProviderConfig, ProviderApiKey, Context } from '@wrongstack/core';
|
|
2
|
+
import { Agent, EventBus, SessionStore, ToolRegistry, ModelsRegistry, ConfigStore, SecretVault, JournalEntry, Logger, MemoryStore, Config, MCPRegistryHandle, ProviderConfig, ProviderApiKey, Context, SkillLoader } from '@wrongstack/core';
|
|
3
3
|
import * as http from 'node:http';
|
|
4
|
+
import { SkillInstaller } from '@wrongstack/core/skills';
|
|
4
5
|
|
|
5
6
|
interface WSServerMessage {
|
|
6
7
|
type: string;
|
|
@@ -68,6 +69,25 @@ interface ConnectedClient {
|
|
|
68
69
|
ws: WebSocket;
|
|
69
70
|
sessionId: string | null;
|
|
70
71
|
connectedAt: number;
|
|
72
|
+
/** Unique per-connection id — used to key per-connection state (e.g. the
|
|
73
|
+
* rate-limit bucket) so distinct browser tabs that share the same
|
|
74
|
+
* `sessionId` do not collide, and so the entry is reliably removable on
|
|
75
|
+
* close (`String(ws)` is `"[object Object]"` for every socket). */
|
|
76
|
+
connId: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Metrics for the file watcher that watches status.json files. */
|
|
80
|
+
interface FileWatcherMetrics {
|
|
81
|
+
fileChangesDetected: number;
|
|
82
|
+
filesProcessed: number;
|
|
83
|
+
broadcastsSent: number;
|
|
84
|
+
debounceResets: number;
|
|
85
|
+
totalDebounceDelayMs: number;
|
|
86
|
+
activeProjects: number;
|
|
87
|
+
/** Average debounce delay in ms across all broadcasts. */
|
|
88
|
+
averageDebounceDelayMs: number;
|
|
89
|
+
/** Whether the file watcher is currently active. */
|
|
90
|
+
watcherActive: boolean;
|
|
71
91
|
}
|
|
72
92
|
|
|
73
93
|
interface CreateHttpServerOptions {
|
|
@@ -102,6 +122,17 @@ interface CreateHttpServerOptions {
|
|
|
102
122
|
* URL-token-only flow (e.g. in tests that don't want cookie state).
|
|
103
123
|
*/
|
|
104
124
|
enableWsCookie?: boolean | undefined;
|
|
125
|
+
/**
|
|
126
|
+
* Optional file watcher metrics object. When provided, the
|
|
127
|
+
* /debug/watcher-metrics endpoint will be enabled to expose these metrics.
|
|
128
|
+
*/
|
|
129
|
+
watcherMetrics?: FileWatcherMetrics | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Push-on-write hook. `POST /api/fleet/ping` (loopback only) invokes this to
|
|
132
|
+
* trigger an immediate fleet re-broadcast, so a TUI/REPL's registry write
|
|
133
|
+
* reaches the map without waiting on the file-watch/poll. Best-effort.
|
|
134
|
+
*/
|
|
135
|
+
onFleetPing?: (() => void) | undefined;
|
|
105
136
|
}
|
|
106
137
|
/**
|
|
107
138
|
* Inject the live WS port into the served HTML so the frontend connects to
|
|
@@ -291,13 +322,13 @@ declare function handleShellOpen(req: ShellOpenRequest, logger: Logger): Promise
|
|
|
291
322
|
* Send a JSON message to a single WebSocket client.
|
|
292
323
|
* No-op when the socket is not in OPEN state (disconnected / closing).
|
|
293
324
|
*/
|
|
294
|
-
declare function send(ws: WebSocket, msg:
|
|
325
|
+
declare function send(ws: WebSocket, msg: object): void;
|
|
295
326
|
/**
|
|
296
327
|
* Broadcast a JSON message to every connected client.
|
|
297
328
|
* Swallows per-socket send errors — a client that disconnected between the
|
|
298
329
|
* readyState check and `ws.send()` is cleaned up by its own `close` handler.
|
|
299
330
|
*/
|
|
300
|
-
declare function broadcast(clients: Map<WebSocket, ConnectedClient>, msg:
|
|
331
|
+
declare function broadcast(clients: Map<WebSocket, ConnectedClient>, msg: object): void;
|
|
301
332
|
/**
|
|
302
333
|
* Send a success/failure result message (used by key.* and provider.* handlers).
|
|
303
334
|
* The frontend expects `key.operation_result` with `{ success, message }`.
|
|
@@ -355,6 +386,23 @@ declare function handleFilesWrite(ws: WebSocket, msg: unknown, projectRoot: stri
|
|
|
355
386
|
*/
|
|
356
387
|
declare function handleFilesList(ws: WebSocket, msg: unknown, projectRoot: string): Promise<void>;
|
|
357
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Shared `git.info` WebSocket handler for both the standalone WebUI server and
|
|
391
|
+
* the CLI's `--webui` embedded server. Extracted from the duplicated switch
|
|
392
|
+
* cases in `index.ts` and `cli/src/webui-server.ts`, which had drifted (the
|
|
393
|
+
* standalone copy transposed ahead/behind and never matched deletions). One
|
|
394
|
+
* implementation here keeps both surfaces in lockstep.
|
|
395
|
+
*
|
|
396
|
+
* case 'git.info': return handleGitInfo(ws, projectRoot);
|
|
397
|
+
*/
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Read git branch, change stats, and upstream sync status from `projectRoot`
|
|
401
|
+
* and broadcast a `git.info` message. Never throws — a non-repo / missing-git
|
|
402
|
+
* directory yields an empty-but-valid payload.
|
|
403
|
+
*/
|
|
404
|
+
declare function handleGitInfo(ws: WebSocket, projectRoot: string): Promise<void>;
|
|
405
|
+
|
|
358
406
|
/**
|
|
359
407
|
* Shared memory-operation WebSocket handlers for both the standalone WebUI
|
|
360
408
|
* server and the CLI's `--webui` embedded server. Extracted from the
|
|
@@ -382,6 +430,32 @@ declare function handleMemoryRemember(ws: WebSocket, msg: unknown, memoryStore:
|
|
|
382
430
|
*/
|
|
383
431
|
declare function handleMemoryForget(ws: WebSocket, msg: unknown, memoryStore: MemoryStore): Promise<void>;
|
|
384
432
|
|
|
433
|
+
/**
|
|
434
|
+
* MCP management handlers for the WebUI server.
|
|
435
|
+
* Handles MCP-related WS messages from the browser client.
|
|
436
|
+
*/
|
|
437
|
+
|
|
438
|
+
/** Handle mcp.list — return all configured MCP servers */
|
|
439
|
+
declare function handleMcpList(ws: WebSocket, _msg: WSClientMessage, config: Config, _globalConfigPath: string, mcpRegistry?: MCPRegistryHandle): Promise<void>;
|
|
440
|
+
/** Handle mcp.add — add a new MCP server configuration */
|
|
441
|
+
declare function handleMcpAdd(ws: WebSocket, msg: WSClientMessage, config: Config, globalConfigPath: string, mcpRegistry?: MCPRegistryHandle): Promise<void>;
|
|
442
|
+
/** Handle mcp.remove — remove an MCP server configuration */
|
|
443
|
+
declare function handleMcpRemove(ws: WebSocket, msg: WSClientMessage, _config: Config, globalConfigPath: string, mcpRegistry?: MCPRegistryHandle): Promise<void>;
|
|
444
|
+
/** Handle mcp.update — update an existing MCP server configuration */
|
|
445
|
+
declare function handleMcpUpdate(ws: WebSocket, msg: WSClientMessage, _config: Config, globalConfigPath: string): Promise<void>;
|
|
446
|
+
/** Handle mcp.wake — wake a sleeping MCP server (restart it) */
|
|
447
|
+
declare function handleMcpWake(ws: WebSocket, msg: WSClientMessage, _config: Config, _globalConfigPath: string, mcpRegistry?: MCPRegistryHandle): Promise<void>;
|
|
448
|
+
/** Handle mcp.sleep — put an MCP server to sleep (stop it) */
|
|
449
|
+
declare function handleMcpSleep(ws: WebSocket, msg: WSClientMessage, _config: Config, _globalConfigPath: string, mcpRegistry?: MCPRegistryHandle): Promise<void>;
|
|
450
|
+
/** Handle mcp.discover — perform one-time tool discovery on an MCP server */
|
|
451
|
+
declare function handleMcpDiscover(ws: WebSocket, msg: WSClientMessage, _config: Config, _globalConfigPath: string, _mcpRegistry?: MCPRegistryHandle): Promise<void>;
|
|
452
|
+
/** Handle mcp.enable — enable an MCP server */
|
|
453
|
+
declare function handleMcpEnable(ws: WebSocket, msg: WSClientMessage, _config: Config, _globalConfigPath: string): Promise<void>;
|
|
454
|
+
/** Handle mcp.disable — disable an MCP server */
|
|
455
|
+
declare function handleMcpDisable(ws: WebSocket, msg: WSClientMessage, _config: Config, _globalConfigPath: string): Promise<void>;
|
|
456
|
+
/** Handle mcp.restart — restart an MCP server */
|
|
457
|
+
declare function handleMcpRestart(ws: WebSocket, msg: WSClientMessage, _config: Config, _globalConfigPath: string): Promise<void>;
|
|
458
|
+
|
|
385
459
|
/**
|
|
386
460
|
* Custom context modes — user-defined presets that are loaded from disk,
|
|
387
461
|
* merged with the built-in modes, and managed via WebSocket CRUD handlers.
|
|
@@ -510,8 +584,10 @@ interface KeyOpResult {
|
|
|
510
584
|
declare function normalizeKeys(cfg: ProviderConfig): ProviderApiKey[];
|
|
511
585
|
/**
|
|
512
586
|
* Write a normalized key list back onto a provider config: drop all key fields
|
|
513
|
-
* when empty, otherwise sync `apiKeys
|
|
514
|
-
* key
|
|
587
|
+
* when empty, otherwise sync `apiKeys` and re-point `activeKey` if it no longer
|
|
588
|
+
* names a present key. Does NOT mirror the plaintext key to the legacy `apiKey`
|
|
589
|
+
* field — that would leak the secret on accidental serialization. Consumers
|
|
590
|
+
* that need the real key should read from `apiKeys[]` directly.
|
|
515
591
|
*/
|
|
516
592
|
declare function writeKeysBack(cfg: ProviderConfig, keys: ProviderApiKey[]): void;
|
|
517
593
|
/** Mask a secret for display: `••••` for short keys, `abcd…wxyz` otherwise. */
|
|
@@ -607,10 +683,75 @@ declare class AutoPhaseWebSocketHandler {
|
|
|
607
683
|
private send;
|
|
608
684
|
}
|
|
609
685
|
|
|
686
|
+
/**
|
|
687
|
+
* Shared skills WebSocket handlers for both the standalone WebUI server
|
|
688
|
+
* (`packages/webui/src/server/index.ts`) and the CLI's `--webui` embedded
|
|
689
|
+
* server (`packages/cli/src/webui-server.ts`).
|
|
690
|
+
*
|
|
691
|
+
* These were previously inlined in BOTH servers, and the CLI copy had
|
|
692
|
+
* drifted — it only wired `skills.list`, so `skills.content` /
|
|
693
|
+
* `skills.export` / `skills.update` (and install/uninstall/create/edit)
|
|
694
|
+
* fell through to the "Unhandled message type" warning even though the
|
|
695
|
+
* SkillsPanel sends them. Extracting the full set here gives both servers
|
|
696
|
+
* one source of truth. Each function handles the full request→response
|
|
697
|
+
* cycle for one message type; callers drop them into their switch:
|
|
698
|
+
*
|
|
699
|
+
* case 'skills.content': return handleSkillsContent(ws, skillsCtx, msg);
|
|
700
|
+
*
|
|
701
|
+
* The logic is a verbatim lift of the standalone's inline cases — only the
|
|
702
|
+
* dependency references changed (`skillLoader`/`skillInstaller`/
|
|
703
|
+
* `projectRoot` → `ctx.*`, local `send`/`errMessage` → imported helpers).
|
|
704
|
+
*/
|
|
705
|
+
|
|
706
|
+
interface SkillsContext {
|
|
707
|
+
/** Backs skills.list/content/edit/export. Absent ⇒ feature disabled. */
|
|
708
|
+
skillLoader: SkillLoader | undefined;
|
|
709
|
+
/** Backs skills.install/uninstall/update. Absent ⇒ those ops disabled. */
|
|
710
|
+
skillInstaller: SkillInstaller | undefined;
|
|
711
|
+
/** Project root — used by skills.create to write `.wrongstack/skills/…`. */
|
|
712
|
+
projectRoot: string;
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Read a single skill's body + its directory's related files + which other
|
|
716
|
+
* skills reference it by name. Powers the skill detail/preview view.
|
|
717
|
+
*/
|
|
718
|
+
declare function handleSkillsContent(ws: WebSocket, ctx: SkillsContext, msg: unknown): Promise<void>;
|
|
719
|
+
/**
|
|
720
|
+
* Install a skill from a git ref (`owner/repo` or URL). Optional `global`
|
|
721
|
+
* installs into the user-wide skills dir instead of the project's.
|
|
722
|
+
*/
|
|
723
|
+
declare function handleSkillsInstall(ws: WebSocket, ctx: SkillsContext, msg: unknown): Promise<void>;
|
|
724
|
+
/**
|
|
725
|
+
* Uninstall a skill by name. Optional `global` restricts/Targets the
|
|
726
|
+
* user-wide install.
|
|
727
|
+
*/
|
|
728
|
+
declare function handleSkillsUninstall(ws: WebSocket, ctx: SkillsContext, msg: unknown): Promise<void>;
|
|
729
|
+
/**
|
|
730
|
+
* Update one skill (`name`) or all installed skills (when `name` is
|
|
731
|
+
* omitted). Reports per-skill updated/unchanged/error tallies.
|
|
732
|
+
*/
|
|
733
|
+
declare function handleSkillsUpdate(ws: WebSocket, ctx: SkillsContext, msg: unknown): Promise<void>;
|
|
734
|
+
/**
|
|
735
|
+
* Scaffold a new project- or global-scoped skill from a name + description.
|
|
736
|
+
* Writes a templated `SKILL.md` under `.wrongstack/skills/<name>/` (project)
|
|
737
|
+
* or the user-wide skills dir (global).
|
|
738
|
+
*/
|
|
739
|
+
declare function handleSkillsCreate(ws: WebSocket, ctx: SkillsContext, msg: unknown): Promise<void>;
|
|
740
|
+
/**
|
|
741
|
+
* Overwrite a skill's body. Refuses bundled skills (read-only) and unknown
|
|
742
|
+
* names.
|
|
743
|
+
*/
|
|
744
|
+
declare function handleSkillsEdit(ws: WebSocket, ctx: SkillsContext, msg: unknown): Promise<void>;
|
|
745
|
+
/**
|
|
746
|
+
* Export every readable skill as a base64-encoded zip (one folder per skill,
|
|
747
|
+
* each with its `SKILL.md`). Powers the panel's "Export all" button.
|
|
748
|
+
*/
|
|
749
|
+
declare function handleSkillsExport(ws: WebSocket, ctx: SkillsContext): Promise<void>;
|
|
750
|
+
|
|
610
751
|
declare function startWebUI(opts?: WebUIOptions & {
|
|
611
752
|
wsPort?: number | undefined;
|
|
612
753
|
wsHost?: string | undefined;
|
|
613
754
|
open?: boolean | undefined;
|
|
614
755
|
}): Promise<void>;
|
|
615
756
|
|
|
616
|
-
export { AutoPhaseWebSocketHandler, type BackendServices, type ConnectedClient, type ContextBreakdown, type CreateHttpServerOptions, type CustomContextMode, type CustomModeStore, type EternalBroadcast, type EternalSubscribe, type EternalSubscription, type KeyOpResult, type MessageTokenEntry, type ProvidersRecord, type ShellOpenRequest, type ShellOpenResult, type ShellOpenTarget, type ToolTokenEntry, type VerifyClientInput, type WSClientMessage, type WSServerMessage, type WebUIInstanceRecord, type WebUIOptions, addProvider, broadcast, browserOpenCommand, buildCspHeader, createCustomModeStore, createEternalSubscription, createHttpServer, createProviderConfigIO, defaultBaseDir, deleteKey, errMessage, estimateTokens, extractToken, findFreePort, formatInstances, generateAuthToken, handleFilesList, handleFilesRead, handleFilesTree, handleFilesWrite, handleMemoryForget, handleMemoryList, handleMemoryRemember, handleShellOpen, hostHeaderOk, injectWsPort, isLoopbackBind, isLoopbackHostname, isPortFree, listInstances, loadSavedProviders, maskedKey, messagePreview, messageTokens, normalizeKeys, openBrowser, registerInstance, registryPath, removeProvider, saveProviders, send, sendResult, setActiveKey, startWebUI, stringifyContent, tokenMatches, unregisterInstance, upsertKey, verifyClient, writeKeysBack };
|
|
757
|
+
export { AutoPhaseWebSocketHandler, type BackendServices, type ConnectedClient, type ContextBreakdown, type CreateHttpServerOptions, type CustomContextMode, type CustomModeStore, type EternalBroadcast, type EternalSubscribe, type EternalSubscription, type KeyOpResult, type MessageTokenEntry, type ProvidersRecord, type ShellOpenRequest, type ShellOpenResult, type ShellOpenTarget, type SkillsContext, type ToolTokenEntry, type VerifyClientInput, type WSClientMessage, type WSServerMessage, type WebUIInstanceRecord, type WebUIOptions, addProvider, broadcast, browserOpenCommand, buildCspHeader, createCustomModeStore, createEternalSubscription, createHttpServer, createProviderConfigIO, defaultBaseDir, deleteKey, errMessage, estimateTokens, extractToken, findFreePort, formatInstances, generateAuthToken, handleFilesList, handleFilesRead, handleFilesTree, handleFilesWrite, handleGitInfo, handleMcpAdd, handleMcpDisable, handleMcpDiscover, handleMcpEnable, handleMcpList, handleMcpRemove, handleMcpRestart, handleMcpSleep, handleMcpUpdate, handleMcpWake, handleMemoryForget, handleMemoryList, handleMemoryRemember, handleShellOpen, handleSkillsContent, handleSkillsCreate, handleSkillsEdit, handleSkillsExport, handleSkillsInstall, handleSkillsUninstall, handleSkillsUpdate, hostHeaderOk, injectWsPort, isLoopbackBind, isLoopbackHostname, isPortFree, listInstances, loadSavedProviders, maskedKey, messagePreview, messageTokens, normalizeKeys, openBrowser, registerInstance, registryPath, removeProvider, saveProviders, send, sendResult, setActiveKey, startWebUI, stringifyContent, tokenMatches, unregisterInstance, upsertKey, verifyClient, writeKeysBack };
|