@wrongstack/webui-server 0.302.2 → 0.303.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/dist/index.js +343 -187
- package/dist/server/agent-roster-handlers.d.ts +7 -6
- package/dist/server/codemap-cache.d.ts +13 -1
- package/dist/server/entry.js +325 -185
- package/dist/server/handlers/worklist-handlers.d.ts +23 -4
- package/dist/server/handlers.js +126 -23
- package/dist/server/kanban-route-protocol.d.ts +1 -1
- package/dist/server/kanban-routes.d.ts +2 -2
- package/dist/server/server-runtime.d.ts +14 -2
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -1464,7 +1464,13 @@ function indexDbVersion(projectRoot, indexDir) {
|
|
|
1464
1464
|
try {
|
|
1465
1465
|
const dir = resolveIndexDir(projectRoot, indexDir);
|
|
1466
1466
|
const st = fs.statSync(path.join(dir, DB_FILE));
|
|
1467
|
-
|
|
1467
|
+
let wal = "";
|
|
1468
|
+
try {
|
|
1469
|
+
const walSt = fs.statSync(path.join(dir, `${DB_FILE}-wal`));
|
|
1470
|
+
wal = `:${walSt.mtimeMs}:${walSt.size}`;
|
|
1471
|
+
} catch {
|
|
1472
|
+
}
|
|
1473
|
+
return `${st.mtimeMs}:${st.size}${wal}`;
|
|
1468
1474
|
} catch {
|
|
1469
1475
|
return "missing";
|
|
1470
1476
|
}
|
|
@@ -7689,12 +7695,34 @@ function handleTodosGet(ctx, ws) {
|
|
|
7689
7695
|
payload: sessionPayload(ctx, { todos: [...ctx.context.todos] })
|
|
7690
7696
|
});
|
|
7691
7697
|
}
|
|
7692
|
-
function
|
|
7693
|
-
ctx.
|
|
7694
|
-
|
|
7695
|
-
|
|
7698
|
+
async function commitTodos(ctx, todos) {
|
|
7699
|
+
if (ctx.mutateTodos) {
|
|
7700
|
+
const result = await ctx.mutateTodos(todos);
|
|
7701
|
+
return { todos: result.todos, warnings: result.warnings ?? [] };
|
|
7702
|
+
}
|
|
7703
|
+
ctx.replaceTodos?.(todos);
|
|
7704
|
+
return { todos: [...todos], warnings: [] };
|
|
7696
7705
|
}
|
|
7697
|
-
function
|
|
7706
|
+
function managedProjectionMessage() {
|
|
7707
|
+
return "Kanban-bound todos are task projections. Change or remove the task from Kanban.";
|
|
7708
|
+
}
|
|
7709
|
+
async function handleTodosClear(ctx, ws) {
|
|
7710
|
+
if (ctx.context.todos.some((todo) => todo.kanbanBoardId && todo.kanbanTaskId)) {
|
|
7711
|
+
sendResult3(ctx, ws, false, managedProjectionMessage());
|
|
7712
|
+
return;
|
|
7713
|
+
}
|
|
7714
|
+
try {
|
|
7715
|
+
const result = await commitTodos(ctx, []);
|
|
7716
|
+
sendResult3(ctx, ws, true, "Todos cleared");
|
|
7717
|
+
ctx.broadcast({
|
|
7718
|
+
type: "todos.updated",
|
|
7719
|
+
payload: sessionPayload(ctx, { todos: result.todos })
|
|
7720
|
+
});
|
|
7721
|
+
} catch (error2) {
|
|
7722
|
+
sendResult3(ctx, ws, false, error2 instanceof Error ? error2.message : String(error2));
|
|
7723
|
+
}
|
|
7724
|
+
}
|
|
7725
|
+
async function handleTodosRemove(ctx, ws, payload) {
|
|
7698
7726
|
if (!payload) {
|
|
7699
7727
|
sendResult3(ctx, ws, false, "Missing id or index");
|
|
7700
7728
|
return;
|
|
@@ -7711,12 +7739,27 @@ function handleTodosRemove(ctx, ws, payload) {
|
|
|
7711
7739
|
sendResult3(ctx, ws, false, "Todo not found");
|
|
7712
7740
|
return;
|
|
7713
7741
|
}
|
|
7742
|
+
if (removed.kanbanBoardId && removed.kanbanTaskId) {
|
|
7743
|
+
sendResult3(ctx, ws, false, managedProjectionMessage());
|
|
7744
|
+
return;
|
|
7745
|
+
}
|
|
7714
7746
|
const next = [...todos.slice(0, targetIndex), ...todos.slice(targetIndex + 1)];
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7747
|
+
try {
|
|
7748
|
+
const result = await commitTodos(ctx, next);
|
|
7749
|
+
sendResult3(ctx, ws, true, `Removed: ${removed.content}`);
|
|
7750
|
+
ctx.broadcast({
|
|
7751
|
+
type: "todos.updated",
|
|
7752
|
+
payload: sessionPayload(ctx, { todos: result.todos })
|
|
7753
|
+
});
|
|
7754
|
+
} catch (error2) {
|
|
7755
|
+
sendResult3(ctx, ws, false, error2 instanceof Error ? error2.message : String(error2));
|
|
7756
|
+
}
|
|
7718
7757
|
}
|
|
7719
|
-
function handleTodoUpdate(ctx, ws, payload) {
|
|
7758
|
+
async function handleTodoUpdate(ctx, ws, payload) {
|
|
7759
|
+
if (!payload || typeof payload.id !== "string" || payload.status !== void 0 && payload.status !== "pending" && payload.status !== "in_progress" && payload.status !== "completed" || payload.activeForm !== void 0 && typeof payload.activeForm !== "string") {
|
|
7760
|
+
sendResult3(ctx, ws, false, "Invalid todo update payload");
|
|
7761
|
+
return;
|
|
7762
|
+
}
|
|
7720
7763
|
const index = ctx.context.todos.findIndex((todo) => todo.id === payload.id);
|
|
7721
7764
|
const existing = ctx.context.todos[index];
|
|
7722
7765
|
if (index === -1 || !existing) {
|
|
@@ -7729,9 +7772,25 @@ function handleTodoUpdate(ctx, ws, payload) {
|
|
|
7729
7772
|
status: payload.status ?? existing.status,
|
|
7730
7773
|
activeForm: payload.activeForm !== void 0 ? payload.activeForm : existing.activeForm
|
|
7731
7774
|
};
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7775
|
+
try {
|
|
7776
|
+
const result = await commitTodos(ctx, next);
|
|
7777
|
+
const projected = result.todos.find((todo) => todo.id === existing.id);
|
|
7778
|
+
const requestedStatus = payload.status ?? existing.status;
|
|
7779
|
+
const projectionRejected = Boolean(existing.kanbanBoardId && existing.kanbanTaskId) && projected?.status !== requestedStatus;
|
|
7780
|
+
const warning = result.warnings[0];
|
|
7781
|
+
sendResult3(
|
|
7782
|
+
ctx,
|
|
7783
|
+
ws,
|
|
7784
|
+
!projectionRejected,
|
|
7785
|
+
projectionRejected ? warning ?? `Kanban kept "${existing.content}" at ${projected?.status ?? "its current state"}.` : warning ? `Todo "${existing.content}" updated. ${warning}` : `Todo "${existing.content}" updated`
|
|
7786
|
+
);
|
|
7787
|
+
ctx.broadcast({
|
|
7788
|
+
type: "todos.updated",
|
|
7789
|
+
payload: sessionPayload(ctx, { todos: result.todos })
|
|
7790
|
+
});
|
|
7791
|
+
} catch (error2) {
|
|
7792
|
+
sendResult3(ctx, ws, false, error2 instanceof Error ? error2.message : String(error2));
|
|
7793
|
+
}
|
|
7735
7794
|
}
|
|
7736
7795
|
async function handleTasksGet(ctx, ws) {
|
|
7737
7796
|
const taskPath = taskPathOf(ctx);
|
|
@@ -7759,14 +7818,32 @@ async function handleTaskUpdate(ctx, ws, payload) {
|
|
|
7759
7818
|
return;
|
|
7760
7819
|
}
|
|
7761
7820
|
try {
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7821
|
+
let file;
|
|
7822
|
+
if (ctx.mutateTaskStatus) {
|
|
7823
|
+
const result = await ctx.mutateTaskStatus(payload.id, payload.status);
|
|
7824
|
+
if (!result.ok) {
|
|
7825
|
+
sendResult3(ctx, ws, false, result.message);
|
|
7826
|
+
return;
|
|
7827
|
+
}
|
|
7828
|
+
file = await loadTasks(taskPath);
|
|
7829
|
+
if (!file) throw new Error("Task mutation succeeded but its persisted snapshot is missing.");
|
|
7830
|
+
sendResult3(ctx, ws, true, result.message);
|
|
7831
|
+
} else {
|
|
7832
|
+
let matched = false;
|
|
7833
|
+
file = await mutateTasks(taskPath, currentSessionId(ctx), async (tasks) => {
|
|
7834
|
+
const task = tasks.tasks.find((candidate) => candidate.id === payload.id);
|
|
7835
|
+
if (!task) return tasks;
|
|
7836
|
+
matched = true;
|
|
7837
|
+
task.status = payload.status;
|
|
7838
|
+
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7839
|
+
return tasks;
|
|
7840
|
+
});
|
|
7841
|
+
if (!matched) {
|
|
7842
|
+
sendResult3(ctx, ws, false, `Task "${payload.id}" not found.`);
|
|
7843
|
+
return;
|
|
7844
|
+
}
|
|
7845
|
+
sendResult3(ctx, ws, true, `Task status updated to "${payload.status}".`);
|
|
7846
|
+
}
|
|
7770
7847
|
ctx.broadcast({
|
|
7771
7848
|
type: "tasks.updated",
|
|
7772
7849
|
payload: sessionPayload(ctx, { tasks: file.tasks })
|
|
@@ -7813,6 +7890,18 @@ async function handlePlanTemplateUse(ctx, ws, template) {
|
|
|
7813
7890
|
return;
|
|
7814
7891
|
}
|
|
7815
7892
|
try {
|
|
7893
|
+
if (ctx.mutatePlan) {
|
|
7894
|
+
const result = await ctx.mutatePlan({ action: "template_use", template });
|
|
7895
|
+
if (!result.ok) {
|
|
7896
|
+
sendResult3(ctx, ws, false, result.message);
|
|
7897
|
+
return;
|
|
7898
|
+
}
|
|
7899
|
+
const plan2 = await loadPlan(planPath);
|
|
7900
|
+
if (!plan2) throw new Error("Plan mutation succeeded but its persisted snapshot is missing.");
|
|
7901
|
+
sendResult3(ctx, ws, true, result.message);
|
|
7902
|
+
ctx.broadcast({ type: "plan.updated", payload: sessionPayload(ctx, { plan: plan2 }) });
|
|
7903
|
+
return;
|
|
7904
|
+
}
|
|
7816
7905
|
const templateDefinition = getPlanTemplate(template);
|
|
7817
7906
|
if (!templateDefinition) {
|
|
7818
7907
|
sendResult3(ctx, ws, false, `Unknown template "${template}".`);
|
|
@@ -7841,6 +7930,22 @@ async function handlePlanItemUpdate(ctx, ws, payload) {
|
|
|
7841
7930
|
return;
|
|
7842
7931
|
}
|
|
7843
7932
|
try {
|
|
7933
|
+
if (ctx.mutatePlan) {
|
|
7934
|
+
const result = await ctx.mutatePlan({
|
|
7935
|
+
action: "status",
|
|
7936
|
+
target: payload.target,
|
|
7937
|
+
status: payload.status
|
|
7938
|
+
});
|
|
7939
|
+
if (!result.ok) {
|
|
7940
|
+
sendResult3(ctx, ws, false, result.message);
|
|
7941
|
+
return;
|
|
7942
|
+
}
|
|
7943
|
+
const plan2 = await loadPlan(planPath);
|
|
7944
|
+
if (!plan2) throw new Error("Plan mutation succeeded but its persisted snapshot is missing.");
|
|
7945
|
+
sendResult3(ctx, ws, true, result.message);
|
|
7946
|
+
ctx.broadcast({ type: "plan.updated", payload: sessionPayload(ctx, { plan: plan2 }) });
|
|
7947
|
+
return;
|
|
7948
|
+
}
|
|
7844
7949
|
let changed = false;
|
|
7845
7950
|
const plan = await mutatePlan(planPath, currentSessionId(ctx), async (currentPlan) => {
|
|
7846
7951
|
const before = currentPlan.updatedAt;
|
|
@@ -7864,13 +7969,17 @@ async function handleWorklistMessage(ctx, ws, message) {
|
|
|
7864
7969
|
handleTodosGet(ctx, ws);
|
|
7865
7970
|
return;
|
|
7866
7971
|
case "todos.clear":
|
|
7867
|
-
handleTodosClear(ctx, ws);
|
|
7972
|
+
await handleTodosClear(ctx, ws);
|
|
7868
7973
|
return;
|
|
7869
7974
|
case "todos.remove":
|
|
7870
|
-
handleTodosRemove(
|
|
7975
|
+
await handleTodosRemove(
|
|
7976
|
+
ctx,
|
|
7977
|
+
ws,
|
|
7978
|
+
message.payload
|
|
7979
|
+
);
|
|
7871
7980
|
return;
|
|
7872
7981
|
case "todo.update":
|
|
7873
|
-
handleTodoUpdate(
|
|
7982
|
+
await handleTodoUpdate(
|
|
7874
7983
|
ctx,
|
|
7875
7984
|
ws,
|
|
7876
7985
|
message.payload
|
|
@@ -10928,9 +11037,9 @@ import {
|
|
|
10928
11037
|
claimReadyTask,
|
|
10929
11038
|
copyTaskToBoard,
|
|
10930
11039
|
createBoard,
|
|
11040
|
+
createBoardFromText,
|
|
10931
11041
|
duplicateBoard,
|
|
10932
11042
|
exportBoardToTaskGraph,
|
|
10933
|
-
createBoardFromText,
|
|
10934
11043
|
getBoard,
|
|
10935
11044
|
getKanbanOrchestrationSnapshot,
|
|
10936
11045
|
getKanbanQueueHealth,
|
|
@@ -11118,8 +11227,35 @@ async function handleTaskVerification(ws, type, payload, ctx) {
|
|
|
11118
11227
|
}
|
|
11119
11228
|
}
|
|
11120
11229
|
|
|
11230
|
+
// src/server/kanban-route-pagination.ts
|
|
11231
|
+
function paginateKanbanBoards(boards, input) {
|
|
11232
|
+
const pageSize = Math.min(100, Math.max(1, Math.floor(input.pageSize)));
|
|
11233
|
+
const activeSessionIds = new Set(input.activeSessionIds ?? []);
|
|
11234
|
+
const isActive = (board) => board.presence?.some((entry) => entry.active) === true || board.tags?.some((tag) => tag.startsWith("session:") && activeSessionIds.has(tag.slice(8))) === true;
|
|
11235
|
+
const sorted = [...boards].sort((left, right) => {
|
|
11236
|
+
const activityOrder = Number(isActive(right)) - Number(isActive(left));
|
|
11237
|
+
return activityOrder || right.updatedAt.localeCompare(left.updatedAt);
|
|
11238
|
+
});
|
|
11239
|
+
const activeTotal = sorted.filter(isActive).length;
|
|
11240
|
+
const total = sorted.length;
|
|
11241
|
+
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
11242
|
+
const requestedPage = Number.isFinite(input.page) ? Math.floor(input.page) : 1;
|
|
11243
|
+
const page = Math.min(totalPages, Math.max(1, requestedPage));
|
|
11244
|
+
const start = (page - 1) * pageSize;
|
|
11245
|
+
return {
|
|
11246
|
+
items: sorted.slice(start, start + pageSize),
|
|
11247
|
+
total,
|
|
11248
|
+
page,
|
|
11249
|
+
pageSize,
|
|
11250
|
+
totalPages,
|
|
11251
|
+
activeTotal,
|
|
11252
|
+
orphanedTotal: total - activeTotal
|
|
11253
|
+
};
|
|
11254
|
+
}
|
|
11255
|
+
|
|
11121
11256
|
// src/server/kanban-task-routes.ts
|
|
11122
11257
|
import {
|
|
11258
|
+
getKanbanWorkbench,
|
|
11123
11259
|
getTask,
|
|
11124
11260
|
listTaskActivity,
|
|
11125
11261
|
recordTaskActivity,
|
|
@@ -11127,6 +11263,16 @@ import {
|
|
|
11127
11263
|
} from "@wrongstack/kanban";
|
|
11128
11264
|
async function handleKanbanTaskRoute(ws, type, payload, ctx) {
|
|
11129
11265
|
switch (type) {
|
|
11266
|
+
case "kanban.workbench":
|
|
11267
|
+
ok(
|
|
11268
|
+
ws,
|
|
11269
|
+
type,
|
|
11270
|
+
await getKanbanWorkbench(ctx.projectRoot, {
|
|
11271
|
+
...typeof payload?.limitPerLane === "number" ? { limitPerLane: payload.limitPerLane } : {},
|
|
11272
|
+
...typeof payload?.alertLimit === "number" ? { alertLimit: payload.alertLimit } : {}
|
|
11273
|
+
})
|
|
11274
|
+
);
|
|
11275
|
+
return true;
|
|
11130
11276
|
case "kanban.task.remove":
|
|
11131
11277
|
await handleTaskRemove(ws, type, payload, ctx);
|
|
11132
11278
|
return true;
|
|
@@ -11219,40 +11365,11 @@ async function handleTaskActivityAdd(ws, type, payload, ctx) {
|
|
|
11219
11365
|
outcome,
|
|
11220
11366
|
...typeof payload?.details === "string" && payload.details.trim() ? { details: payload.details.trim() } : {}
|
|
11221
11367
|
},
|
|
11222
|
-
activityContext(
|
|
11223
|
-
ctx,
|
|
11224
|
-
payload?.actor ?? ctx.context?.agentId ?? "webui"
|
|
11225
|
-
)
|
|
11368
|
+
activityContext(ctx, payload?.actor ?? ctx.context?.agentId ?? "webui")
|
|
11226
11369
|
);
|
|
11227
11370
|
board ? ok(ws, type, board) : fail(ws, type, "Board or task not found");
|
|
11228
11371
|
}
|
|
11229
11372
|
|
|
11230
|
-
// src/server/kanban-route-pagination.ts
|
|
11231
|
-
function paginateKanbanBoards(boards, input) {
|
|
11232
|
-
const pageSize = Math.min(100, Math.max(1, Math.floor(input.pageSize)));
|
|
11233
|
-
const activeSessionIds = new Set(input.activeSessionIds ?? []);
|
|
11234
|
-
const isActive = (board) => board.presence?.some((entry) => entry.active) === true || board.tags?.some((tag) => tag.startsWith("session:") && activeSessionIds.has(tag.slice(8))) === true;
|
|
11235
|
-
const sorted = [...boards].sort((left, right) => {
|
|
11236
|
-
const activityOrder = Number(isActive(right)) - Number(isActive(left));
|
|
11237
|
-
return activityOrder || right.updatedAt.localeCompare(left.updatedAt);
|
|
11238
|
-
});
|
|
11239
|
-
const activeTotal = sorted.filter(isActive).length;
|
|
11240
|
-
const total = sorted.length;
|
|
11241
|
-
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
11242
|
-
const requestedPage = Number.isFinite(input.page) ? Math.floor(input.page) : 1;
|
|
11243
|
-
const page = Math.min(totalPages, Math.max(1, requestedPage));
|
|
11244
|
-
const start = (page - 1) * pageSize;
|
|
11245
|
-
return {
|
|
11246
|
-
items: sorted.slice(start, start + pageSize),
|
|
11247
|
-
total,
|
|
11248
|
-
page,
|
|
11249
|
-
pageSize,
|
|
11250
|
-
totalPages,
|
|
11251
|
-
activeTotal,
|
|
11252
|
-
orphanedTotal: total - activeTotal
|
|
11253
|
-
};
|
|
11254
|
-
}
|
|
11255
|
-
|
|
11256
11373
|
// src/server/kanban-route-protocol.ts
|
|
11257
11374
|
var KANBAN_CLIENT_MESSAGE_TYPES = [
|
|
11258
11375
|
"kanban.capabilities",
|
|
@@ -11297,7 +11414,8 @@ var KANBAN_CLIENT_MESSAGE_TYPES = [
|
|
|
11297
11414
|
"kanban.task.verify",
|
|
11298
11415
|
"kanban.taskgraph.export",
|
|
11299
11416
|
"kanban.taskgraph.sync",
|
|
11300
|
-
"kanban.update"
|
|
11417
|
+
"kanban.update",
|
|
11418
|
+
"kanban.workbench"
|
|
11301
11419
|
];
|
|
11302
11420
|
|
|
11303
11421
|
// src/server/kanban-routes.ts
|
|
@@ -12078,7 +12196,9 @@ function subscribeKanbanDaemonEvents(projectRoot, broadcastMessage) {
|
|
|
12078
12196
|
projectRoot,
|
|
12079
12197
|
async (event) => {
|
|
12080
12198
|
const family = event.event?.split(".")[0];
|
|
12081
|
-
if (family !== "board" && family !== "task" && family !== "column")
|
|
12199
|
+
if (family !== "board" && family !== "task" && family !== "column" && family !== "contract") {
|
|
12200
|
+
return;
|
|
12201
|
+
}
|
|
12082
12202
|
const evData = event.data;
|
|
12083
12203
|
const boardId = evData?.boardId;
|
|
12084
12204
|
if (!boardId) return;
|
|
@@ -13395,14 +13515,17 @@ async function handleSageForFile(ws, msg, memoryStore) {
|
|
|
13395
13515
|
send(ws, { type: "memory.sage.forFile", payload: { error: "filePath is required" } });
|
|
13396
13516
|
return;
|
|
13397
13517
|
}
|
|
13518
|
+
const includeSuperseded = typeof payload["showSuperseded"] === "boolean" ? payload["showSuperseded"] : typeof payload["includeSuperseded"] === "boolean" ? payload["includeSuperseded"] : void 0;
|
|
13519
|
+
const includeDeleted = payload["showDeleted"] === true || payload["includeDeleted"] === true;
|
|
13398
13520
|
try {
|
|
13399
13521
|
const response = await Sage.findMemoriesForFile(filePath, {
|
|
13400
13522
|
...typeof payload["lineStart"] === "number" ? { lineStart: payload["lineStart"] } : {},
|
|
13401
13523
|
...typeof payload["lineEnd"] === "number" ? { lineEnd: payload["lineEnd"] } : {},
|
|
13402
13524
|
...typeof payload["limit"] === "number" ? { limit: payload["limit"] } : {},
|
|
13403
|
-
...
|
|
13525
|
+
...includeSuperseded !== void 0 ? { includeSuperseded } : {},
|
|
13526
|
+
...includeDeleted ? { includeDeleted: true } : {}
|
|
13404
13527
|
});
|
|
13405
|
-
send(ws, { type: "memory.sage.forFile", payload: response });
|
|
13528
|
+
send(ws, { type: "memory.sage.forFile", payload: { response } });
|
|
13406
13529
|
} catch (err) {
|
|
13407
13530
|
send(ws, { type: "memory.sage.forFile", payload: { error: errMessage(err) } });
|
|
13408
13531
|
}
|
|
@@ -15104,7 +15227,8 @@ function createKanbanSupervisor(deps2) {
|
|
|
15104
15227
|
mode: config.recoveryMode ?? "auto",
|
|
15105
15228
|
reason: "Kanban supervisor found an expired worker lease."
|
|
15106
15229
|
}) : null;
|
|
15107
|
-
if (recovered)
|
|
15230
|
+
if (recovered)
|
|
15231
|
+
health = await getKanbanQueueHealth2(resolveProjectRoot(deps2), { boardId: board.id });
|
|
15108
15232
|
const anomalyCount = countAnomalies(health);
|
|
15109
15233
|
const snapshot = {
|
|
15110
15234
|
boardId: board.id,
|
|
@@ -15199,7 +15323,9 @@ function createKanbanSupervisor(deps2) {
|
|
|
15199
15323
|
} else {
|
|
15200
15324
|
const summaries = await listBoards4(resolveProjectRoot(deps2));
|
|
15201
15325
|
pruneAbsentBoards(new Set(summaries.map((summary) => summary.id)));
|
|
15202
|
-
boards = (await Promise.all(
|
|
15326
|
+
boards = (await Promise.all(
|
|
15327
|
+
summaries.map((summary) => getBoard3(resolveProjectRoot(deps2), summary.id))
|
|
15328
|
+
)).filter((board) => Boolean(board));
|
|
15203
15329
|
}
|
|
15204
15330
|
const results = [];
|
|
15205
15331
|
for (const board of boards) results.push(await auditBoard(board));
|
|
@@ -19071,89 +19197,56 @@ function createEmbeddedProjectRoutes(ctx) {
|
|
|
19071
19197
|
|
|
19072
19198
|
// src/server/embedded-message-router.ts
|
|
19073
19199
|
import { makeProviderFromConfig as makeProviderFromConfig2 } from "@wrongstack/providers";
|
|
19200
|
+
import { planTool, taskTool, todoTool } from "@wrongstack/tools";
|
|
19074
19201
|
|
|
19075
19202
|
// src/server/agent-roster-handlers.ts
|
|
19076
19203
|
import {
|
|
19077
19204
|
applyProjectAgentConfig,
|
|
19078
|
-
buildConsolidationInstruction,
|
|
19079
19205
|
captureLearnedFromAgentOutputDetailed,
|
|
19080
19206
|
clearProjectAgentConsolidated,
|
|
19207
|
+
clearProjectSkillAugmentation,
|
|
19081
19208
|
createProjectAgent,
|
|
19082
19209
|
detectLearnedConflicts,
|
|
19210
|
+
evaluateAutoOptimize,
|
|
19083
19211
|
FLEET_ROSTER,
|
|
19084
19212
|
getProjectAgentLearnStats,
|
|
19085
19213
|
isConsolidated,
|
|
19086
19214
|
listProjectAgentLearnedEntries,
|
|
19087
19215
|
listProjectAgentRoles,
|
|
19216
|
+
listProjectSkillAugmentations,
|
|
19088
19217
|
loadConsolidationMetadata,
|
|
19089
19218
|
loadProjectAgentConfig,
|
|
19090
19219
|
loadProjectAgentConsolidated,
|
|
19091
19220
|
loadProjectAgentIdentity,
|
|
19092
19221
|
loadProjectAgentLearned,
|
|
19093
19222
|
loadProjectAgentProfile,
|
|
19223
|
+
loadProjectSkillAugmentation,
|
|
19224
|
+
loadSkillAffinity,
|
|
19225
|
+
optimizeProjectAgentLearning,
|
|
19226
|
+
readRawLearnedEntries,
|
|
19094
19227
|
resetProjectAgentIdentity,
|
|
19228
|
+
resolveAutoOptimizePolicy,
|
|
19229
|
+
resolveRoleSkillCandidates,
|
|
19095
19230
|
saveProjectAgentConsolidated,
|
|
19231
|
+
saveProjectSkillAugmentation,
|
|
19232
|
+
setSkillPinned,
|
|
19096
19233
|
slugifyProjectAgentRole,
|
|
19097
19234
|
updateProjectAgentConfig,
|
|
19098
19235
|
updateProjectAgentIdentity,
|
|
19099
19236
|
updateProjectAgentLearned,
|
|
19100
19237
|
updateProjectAgentLearningPolicy
|
|
19101
19238
|
} from "@wrongstack/core/coordination";
|
|
19102
|
-
import { isTextBlock } from "@wrongstack/core/types";
|
|
19103
|
-
var CONSOLIDATION_MAX_TOKENS = 8e3;
|
|
19104
|
-
var CONSOLIDATION_TIMEOUT_MS = 12e4;
|
|
19105
19239
|
var AgentRosterWSHandler = class {
|
|
19106
19240
|
getProjectRoot;
|
|
19107
19241
|
getLlm;
|
|
19108
19242
|
broadcast;
|
|
19243
|
+
getAutoOptimizeSettings;
|
|
19109
19244
|
constructor(opts) {
|
|
19110
19245
|
this.getProjectRoot = typeof opts.projectRoot === "function" ? opts.projectRoot : () => opts.projectRoot;
|
|
19111
19246
|
this.getLlm = opts.getLlm ?? (() => void 0);
|
|
19112
19247
|
this.broadcast = opts.broadcast ?? (() => {
|
|
19113
19248
|
});
|
|
19114
|
-
|
|
19115
|
-
/**
|
|
19116
|
-
* Run the consolidation LLM synthesis headlessly and return the cleaned
|
|
19117
|
-
* document text. Returns undefined when no LLM is available so the caller
|
|
19118
|
-
* can fall back to the instruction-only path.
|
|
19119
|
-
*/
|
|
19120
|
-
async synthesizeConsolidation(instruction) {
|
|
19121
|
-
const llm = this.getLlm();
|
|
19122
|
-
if (!llm) return void 0;
|
|
19123
|
-
const req = {
|
|
19124
|
-
model: llm.model,
|
|
19125
|
-
system: [
|
|
19126
|
-
{
|
|
19127
|
-
type: "text",
|
|
19128
|
-
text: "You are a precise technical editor. You consolidate an AI agent role's captured learning entries into a single, durable, role-scoped instruction document. Output ONLY the consolidated markdown document \u2014 no preamble, no code fences, no commentary about the consolidation process."
|
|
19129
|
-
}
|
|
19130
|
-
],
|
|
19131
|
-
messages: [{ role: "user", content: instruction }],
|
|
19132
|
-
maxTokens: CONSOLIDATION_MAX_TOKENS
|
|
19133
|
-
};
|
|
19134
|
-
const timer = new AbortController();
|
|
19135
|
-
let timedOut = false;
|
|
19136
|
-
const to = setTimeout(() => {
|
|
19137
|
-
timedOut = true;
|
|
19138
|
-
timer.abort(new Error("consolidation timeout"));
|
|
19139
|
-
}, CONSOLIDATION_TIMEOUT_MS);
|
|
19140
|
-
to.unref();
|
|
19141
|
-
try {
|
|
19142
|
-
const res = await llm.provider.complete(req, { signal: timer.signal });
|
|
19143
|
-
const text2 = res.content.filter(isTextBlock).map((block) => block.text).join("\n").trim();
|
|
19144
|
-
const wholeDocFence = /^```(?:markdown|md)?[^\n]*\n([\s\S]*?)\n?```\s*$/i;
|
|
19145
|
-
const wrapped = wholeDocFence.exec(text2);
|
|
19146
|
-
const inner = wrapped?.[1];
|
|
19147
|
-
const unfenced = inner !== void 0 ? inner.trim() : text2;
|
|
19148
|
-
return { content: unfenced, model: llm.model };
|
|
19149
|
-
} catch (err) {
|
|
19150
|
-
if (timedOut) {
|
|
19151
|
-
throw new Error(`consolidation timed out after ${CONSOLIDATION_TIMEOUT_MS}ms`);
|
|
19152
|
-
}
|
|
19153
|
-
throw err;
|
|
19154
|
-
} finally {
|
|
19155
|
-
clearTimeout(to);
|
|
19156
|
-
}
|
|
19249
|
+
this.getAutoOptimizeSettings = opts.getAutoOptimizeSettings;
|
|
19157
19250
|
}
|
|
19158
19251
|
/** Handle an incoming client message. Returns a response payload. */
|
|
19159
19252
|
async handleMessage(_ws, type, payload) {
|
|
@@ -19358,70 +19451,47 @@ ${String(p.content ?? "")}`;
|
|
|
19358
19451
|
const conflicts = detectLearnedConflicts(projectRoot);
|
|
19359
19452
|
return { type, payload: { conflicts } };
|
|
19360
19453
|
}
|
|
19361
|
-
// ──
|
|
19362
|
-
//
|
|
19363
|
-
//
|
|
19364
|
-
//
|
|
19365
|
-
|
|
19366
|
-
|
|
19367
|
-
case "agent-roster.consolidate": {
|
|
19454
|
+
// ── Optimize: distil captures into skill addenda + a consolidated doc,
|
|
19455
|
+
// then archive and reset the raw buffer. Shared implementation with the
|
|
19456
|
+
// CLI (`optimizeProjectAgentLearning`) so both surfaces persist the same
|
|
19457
|
+
// artifacts instead of the CLI producing markdown nobody saved.
|
|
19458
|
+
case "agent-roster.consolidate":
|
|
19459
|
+
case "agent-roster.optimize": {
|
|
19368
19460
|
if (!role) return { type, payload: { error: "role required" } };
|
|
19369
|
-
const
|
|
19370
|
-
|
|
19461
|
+
const hasExistingConsolidation = isConsolidated(role, projectRoot);
|
|
19462
|
+
const pending = readRawLearnedEntries(role, projectRoot);
|
|
19463
|
+
if (pending.length === 0) {
|
|
19371
19464
|
return {
|
|
19372
19465
|
type: "agent-roster.consolidate",
|
|
19373
19466
|
payload: {
|
|
19374
19467
|
role,
|
|
19375
19468
|
consolidated: false,
|
|
19376
19469
|
rawEntryCount: 0,
|
|
19470
|
+
skills: [],
|
|
19377
19471
|
hasExistingConsolidation,
|
|
19378
19472
|
currentStats: getProjectAgentLearnStats(role, projectRoot)
|
|
19379
19473
|
}
|
|
19380
19474
|
};
|
|
19381
19475
|
}
|
|
19382
|
-
|
|
19383
|
-
|
|
19384
|
-
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
|
|
19394
|
-
|
|
19395
|
-
|
|
19396
|
-
|
|
19397
|
-
}
|
|
19398
|
-
if (synth && synth.content.length > 0) {
|
|
19399
|
-
let stats;
|
|
19400
|
-
let metadata;
|
|
19401
|
-
try {
|
|
19402
|
-
saveProjectAgentConsolidated(role, synth.content, projectRoot, {
|
|
19403
|
-
trigger: "manual",
|
|
19404
|
-
model: synth.model
|
|
19405
|
-
});
|
|
19406
|
-
stats = getProjectAgentLearnStats(role, projectRoot);
|
|
19407
|
-
metadata = loadConsolidationMetadata(role, projectRoot);
|
|
19408
|
-
} catch (err) {
|
|
19409
|
-
return {
|
|
19410
|
-
type: "agent-roster.consolidate",
|
|
19411
|
-
payload: {
|
|
19412
|
-
role,
|
|
19413
|
-
consolidated: false,
|
|
19414
|
-
rawEntryCount: rawEntries.length,
|
|
19415
|
-
hasExistingConsolidation,
|
|
19416
|
-
currentStats: getProjectAgentLearnStats(role, projectRoot),
|
|
19417
|
-
error: err instanceof Error ? err.message : "failed to persist consolidation"
|
|
19418
|
-
}
|
|
19419
|
-
};
|
|
19420
|
-
}
|
|
19476
|
+
const llm = this.getLlm();
|
|
19477
|
+
const result = await optimizeProjectAgentLearning(role, projectRoot, {
|
|
19478
|
+
...llm ? { llm } : {},
|
|
19479
|
+
trigger: "manual"
|
|
19480
|
+
});
|
|
19481
|
+
const currentStats = getProjectAgentLearnStats(role, projectRoot);
|
|
19482
|
+
const metadata = loadConsolidationMetadata(role, projectRoot);
|
|
19483
|
+
const basePayload = {
|
|
19484
|
+
role,
|
|
19485
|
+
rawEntryCount: result.rawEntryCount,
|
|
19486
|
+
skills: result.skills,
|
|
19487
|
+
hasExistingConsolidation,
|
|
19488
|
+
currentStats
|
|
19489
|
+
};
|
|
19490
|
+
if (result.status === "optimized") {
|
|
19421
19491
|
try {
|
|
19422
19492
|
this.broadcast({
|
|
19423
19493
|
type: "agent-roster.updated",
|
|
19424
|
-
payload: { role, reason: "consolidated", currentStats
|
|
19494
|
+
payload: { role, reason: "consolidated", currentStats, metadata }
|
|
19425
19495
|
});
|
|
19426
19496
|
} catch (e) {
|
|
19427
19497
|
console.warn(
|
|
@@ -19437,44 +19507,101 @@ ${String(p.content ?? "")}`;
|
|
|
19437
19507
|
return {
|
|
19438
19508
|
type: "agent-roster.consolidate",
|
|
19439
19509
|
payload: {
|
|
19440
|
-
|
|
19510
|
+
...basePayload,
|
|
19441
19511
|
consolidated: true,
|
|
19442
|
-
|
|
19443
|
-
|
|
19444
|
-
|
|
19445
|
-
currentStats: stats,
|
|
19512
|
+
content: result.content,
|
|
19513
|
+
model: result.model,
|
|
19514
|
+
pruned: result.pruned,
|
|
19446
19515
|
metadata
|
|
19447
19516
|
}
|
|
19448
19517
|
};
|
|
19449
19518
|
}
|
|
19450
|
-
if (synth) {
|
|
19451
|
-
return {
|
|
19452
|
-
type: "agent-roster.consolidate",
|
|
19453
|
-
payload: {
|
|
19454
|
-
role,
|
|
19455
|
-
consolidated: false,
|
|
19456
|
-
emptySynthesis: true,
|
|
19457
|
-
model: synth.model,
|
|
19458
|
-
rawEntryCount: rawEntries.length,
|
|
19459
|
-
hasExistingConsolidation,
|
|
19460
|
-
currentStats: getProjectAgentLearnStats(role, projectRoot)
|
|
19461
|
-
}
|
|
19462
|
-
};
|
|
19463
|
-
}
|
|
19464
19519
|
return {
|
|
19465
19520
|
type: "agent-roster.consolidate",
|
|
19466
19521
|
payload: {
|
|
19467
|
-
|
|
19522
|
+
...basePayload,
|
|
19468
19523
|
consolidated: false,
|
|
19469
|
-
|
|
19470
|
-
|
|
19471
|
-
|
|
19472
|
-
|
|
19473
|
-
|
|
19474
|
-
|
|
19524
|
+
...result.status === "empty-synthesis" ? { emptySynthesis: true, model: result.model } : {},
|
|
19525
|
+
...result.status === "failed" ? { error: result.error } : {},
|
|
19526
|
+
...result.status === "no-llm" ? {
|
|
19527
|
+
instruction: result.instruction,
|
|
19528
|
+
leaderInstruction: `Optimize what the "${role}" agent has learned. Read its raw learned entries, synthesize them into a single narrowly-scoped document preserving every fact, and save the result. The instruction text contains the full details and raw entries.`
|
|
19529
|
+
} : {}
|
|
19475
19530
|
}
|
|
19476
19531
|
};
|
|
19477
19532
|
}
|
|
19533
|
+
// ── Automatic-optimization status ─────────────────────────────────
|
|
19534
|
+
// Read-only: says whether the background scheduler considers each role
|
|
19535
|
+
// eligible right now, and why not when it does not. Surfacing the reason
|
|
19536
|
+
// is what keeps "nothing happened" from looking like a broken feature.
|
|
19537
|
+
case "agent-roster.auto-optimize-status": {
|
|
19538
|
+
const policy = resolveAutoOptimizePolicy(
|
|
19539
|
+
this.getAutoOptimizeSettings?.() ?? void 0
|
|
19540
|
+
);
|
|
19541
|
+
const roles = role ? [role] : listProjectAgentRoles(projectRoot);
|
|
19542
|
+
return {
|
|
19543
|
+
type,
|
|
19544
|
+
payload: {
|
|
19545
|
+
policy,
|
|
19546
|
+
roles: roles.map((current2) => {
|
|
19547
|
+
try {
|
|
19548
|
+
const decision = evaluateAutoOptimize(current2, projectRoot, policy);
|
|
19549
|
+
return { role: current2, ...decision };
|
|
19550
|
+
} catch {
|
|
19551
|
+
return { role: current2, eligible: false, reason: "disabled" };
|
|
19552
|
+
}
|
|
19553
|
+
})
|
|
19554
|
+
}
|
|
19555
|
+
};
|
|
19556
|
+
}
|
|
19557
|
+
// ── Skill layer: what this project has developed for each role skill ──
|
|
19558
|
+
case "agent-roster.skills": {
|
|
19559
|
+
if (!role) return { type, payload: { error: "role required" } };
|
|
19560
|
+
const candidates = resolveRoleSkillCandidates(role, projectRoot);
|
|
19561
|
+
const developed = listProjectSkillAugmentations(role, projectRoot);
|
|
19562
|
+
const affinity = loadSkillAffinity(role, projectRoot);
|
|
19563
|
+
return {
|
|
19564
|
+
type,
|
|
19565
|
+
payload: {
|
|
19566
|
+
role,
|
|
19567
|
+
skills: candidates.map((skill) => ({
|
|
19568
|
+
skill,
|
|
19569
|
+
developed: developed.includes(skill),
|
|
19570
|
+
affinity: affinity.entries[skill] ?? null
|
|
19571
|
+
}))
|
|
19572
|
+
}
|
|
19573
|
+
};
|
|
19574
|
+
}
|
|
19575
|
+
case "agent-roster.read-skill": {
|
|
19576
|
+
const skill = typeof p.skill === "string" ? p.skill : "";
|
|
19577
|
+
if (!role || !skill) return { type, payload: { error: "role and skill required" } };
|
|
19578
|
+
return {
|
|
19579
|
+
type,
|
|
19580
|
+
payload: { role, skill, content: loadProjectSkillAugmentation(role, skill, projectRoot) }
|
|
19581
|
+
};
|
|
19582
|
+
}
|
|
19583
|
+
case "agent-roster.save-skill": {
|
|
19584
|
+
const skill = typeof p.skill === "string" ? p.skill : "";
|
|
19585
|
+
if (!role || !skill || typeof p.content !== "string") {
|
|
19586
|
+
return { type, payload: { error: "role, skill and content required" } };
|
|
19587
|
+
}
|
|
19588
|
+
const savedPath = saveProjectSkillAugmentation(role, skill, p.content, projectRoot);
|
|
19589
|
+
return { type, payload: { role, skill, path: savedPath, success: true } };
|
|
19590
|
+
}
|
|
19591
|
+
case "agent-roster.clear-skill": {
|
|
19592
|
+
const skill = typeof p.skill === "string" ? p.skill : "";
|
|
19593
|
+
if (!role) return { type, payload: { error: "role required" } };
|
|
19594
|
+
clearProjectSkillAugmentation(role, skill || void 0, projectRoot);
|
|
19595
|
+
return { type, payload: { role, skill: skill || null, success: true } };
|
|
19596
|
+
}
|
|
19597
|
+
case "agent-roster.pin-skill": {
|
|
19598
|
+
const skill = typeof p.skill === "string" ? p.skill : "";
|
|
19599
|
+
if (!role || !skill || typeof p.pinned !== "boolean") {
|
|
19600
|
+
return { type, payload: { error: "role, skill and boolean pinned required" } };
|
|
19601
|
+
}
|
|
19602
|
+
const affinity = setSkillPinned(role, skill, p.pinned, projectRoot);
|
|
19603
|
+
return { type, payload: { role, skill, pinned: p.pinned, affinity, success: true } };
|
|
19604
|
+
}
|
|
19478
19605
|
// ── Save consolidated document ────────────────────────────────────
|
|
19479
19606
|
case "agent-roster.save-consolidated": {
|
|
19480
19607
|
if (!role || typeof p.content !== "string") {
|
|
@@ -20447,7 +20574,20 @@ function createEmbeddedMessageRouter(deps2) {
|
|
|
20447
20574
|
},
|
|
20448
20575
|
send: send2,
|
|
20449
20576
|
broadcast: deps2.providerCtx.broadcast,
|
|
20450
|
-
replaceTodos: (todos) => opts.agent.ctx.state.replaceTodos(todos)
|
|
20577
|
+
replaceTodos: (todos) => opts.agent.ctx.state.replaceTodos(todos),
|
|
20578
|
+
mutateTodos: async (todos) => {
|
|
20579
|
+
const result = await todoTool.execute({ todos }, opts.agent.ctx, {
|
|
20580
|
+
signal: AbortSignal.timeout(3e4)
|
|
20581
|
+
});
|
|
20582
|
+
return {
|
|
20583
|
+
todos: [...opts.agent.ctx.todos],
|
|
20584
|
+
...result.kanban_warnings ? { warnings: result.kanban_warnings } : {}
|
|
20585
|
+
};
|
|
20586
|
+
},
|
|
20587
|
+
mutateTaskStatus: async (id, status) => taskTool.execute({ action: "status", id, status }, opts.agent.ctx, {
|
|
20588
|
+
signal: AbortSignal.timeout(3e4)
|
|
20589
|
+
}),
|
|
20590
|
+
mutatePlan: async (operation) => planTool.execute(operation, opts.agent.ctx, { signal: AbortSignal.timeout(3e4) })
|
|
20451
20591
|
})
|
|
20452
20592
|
});
|
|
20453
20593
|
const processRoutes = {
|
|
@@ -20531,6 +20671,7 @@ function createEmbeddedMessageRouter(deps2) {
|
|
|
20531
20671
|
agentRoster: {
|
|
20532
20672
|
rosterHandler: new AgentRosterWSHandler({
|
|
20533
20673
|
projectRoot,
|
|
20674
|
+
getAutoOptimizeSettings: () => deps2.agentConfigCtx.getConfig?.()?.fleet?.learning?.autoOptimize,
|
|
20534
20675
|
getLlm: () => {
|
|
20535
20676
|
const ctx = opts.agent.ctx;
|
|
20536
20677
|
return ctx.provider && ctx.model ? { provider: ctx.provider, model: ctx.model } : void 0;
|
|
@@ -24526,6 +24667,7 @@ async function setupWebUiGovernance(input, dependencies = DEFAULT_DEPENDENCIES)
|
|
|
24526
24667
|
|
|
24527
24668
|
// src/server/message-dispatcher.ts
|
|
24528
24669
|
import path28 from "node:path";
|
|
24670
|
+
import { planTool as planTool2, taskTool as taskTool2, todoTool as todoTool2 } from "@wrongstack/tools";
|
|
24529
24671
|
function createMessageDispatcher(opts) {
|
|
24530
24672
|
const { state, deps: deps2, routes, promptsCtx, codebaseIndexing, runLock, pendingConfirms } = opts;
|
|
24531
24673
|
function makeWorklistContext() {
|
|
@@ -24537,7 +24679,20 @@ function createMessageDispatcher(opts) {
|
|
|
24537
24679
|
},
|
|
24538
24680
|
send: (w, m) => send(w, m),
|
|
24539
24681
|
broadcast: (m) => broadcast(state.getClients(), m),
|
|
24540
|
-
replaceTodos: (todos) => deps2.context.state.replaceTodos(todos)
|
|
24682
|
+
replaceTodos: (todos) => deps2.context.state.replaceTodos(todos),
|
|
24683
|
+
mutateTodos: async (todos) => {
|
|
24684
|
+
const result = await todoTool2.execute({ todos }, deps2.context, {
|
|
24685
|
+
signal: AbortSignal.timeout(3e4)
|
|
24686
|
+
});
|
|
24687
|
+
return {
|
|
24688
|
+
todos: [...deps2.context.todos],
|
|
24689
|
+
...result.kanban_warnings ? { warnings: result.kanban_warnings } : {}
|
|
24690
|
+
};
|
|
24691
|
+
},
|
|
24692
|
+
mutateTaskStatus: async (id, status) => taskTool2.execute({ action: "status", id, status }, deps2.context, {
|
|
24693
|
+
signal: AbortSignal.timeout(3e4)
|
|
24694
|
+
}),
|
|
24695
|
+
mutatePlan: async (operation) => planTool2.execute(operation, deps2.context, { signal: AbortSignal.timeout(3e4) })
|
|
24541
24696
|
};
|
|
24542
24697
|
}
|
|
24543
24698
|
function makeSkillsContext() {
|
|
@@ -24749,6 +24904,7 @@ function createMessageDispatcher(opts) {
|
|
|
24749
24904
|
agentRoster: {
|
|
24750
24905
|
rosterHandler: new AgentRosterWSHandler({
|
|
24751
24906
|
projectRoot: state.getProjectRoot,
|
|
24907
|
+
getAutoOptimizeSettings: () => state.getConfig().fleet?.learning?.autoOptimize,
|
|
24752
24908
|
getLlm: () => {
|
|
24753
24909
|
const ctx = deps2.agent.ctx;
|
|
24754
24910
|
return ctx.provider && ctx.model ? { provider: ctx.provider, model: ctx.model } : void 0;
|
|
@@ -25959,11 +26115,11 @@ function buildRoutes(state, deps2, cb) {
|
|
|
25959
26115
|
}
|
|
25960
26116
|
|
|
25961
26117
|
// src/server/server-runtime.ts
|
|
25962
|
-
import * as path33 from "node:path";
|
|
25963
26118
|
import { createRequire as createRequire4 } from "node:module";
|
|
26119
|
+
import * as path33 from "node:path";
|
|
25964
26120
|
import { fileURLToPath } from "node:url";
|
|
25965
|
-
import { WebSocketServer } from "ws";
|
|
25966
26121
|
import { toErrorMessage as toErrorMessage13 } from "@wrongstack/core/utils";
|
|
26122
|
+
import { WebSocketServer } from "ws";
|
|
25967
26123
|
async function resolvePorts(opts) {
|
|
25968
26124
|
const surface = opts.surface ?? "webui";
|
|
25969
26125
|
const surfaceDefaults = surface === "simpleui" ? { http: 3466 } : { http: 3456 };
|