@wrongstack/webui 0.282.0 → 0.282.2

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.
Files changed (47) hide show
  1. package/dist/assets/{AnalyticsDashboard-BrQc2ss-.js → AnalyticsDashboard-CPLSpHzV.js} +1 -1
  2. package/dist/assets/{AutoPhaseView-8NTdnZ0a.js → AutoPhaseView-HIzNPExo.js} +1 -1
  3. package/dist/assets/{CodeEditor-C-pJLtUR.js → CodeEditor-dOQDoCfn.js} +1 -1
  4. package/dist/assets/{DebugDashboard-BHpiEOcf.js → DebugDashboard-CQCI-B4W.js} +1 -1
  5. package/dist/assets/{DesignGalleryView-M6Hp7s9b.js → DesignGalleryView-BxTlrmrr.js} +1 -1
  6. package/dist/assets/{KanbanView-nMv98m0N.js → KanbanView-2uDRr6Qd.js} +1 -1
  7. package/dist/assets/{MailboxDetailView-g3IQx4DB.js → MailboxDetailView-B0DCs5lu.js} +1 -1
  8. package/dist/assets/OfficeMapPanel-lGSaptet.js +4 -0
  9. package/dist/assets/{ProcessMonitor-CbfQYneY.js → ProcessMonitor-eTb8_-ZW.js} +1 -1
  10. package/dist/assets/{QueuePanel-eGK1SSKx.js → QueuePanel-TbbkNAx_.js} +1 -1
  11. package/dist/assets/{RefreshDebugView-BXq2P3wo.js → RefreshDebugView-CX6x-xHs.js} +1 -1
  12. package/dist/assets/SddBoardView-BXQsH6fr.js +2 -0
  13. package/dist/assets/{SddFlowGraph-CtMpzU4S.js → SddFlowGraph-DTWV-DPB.js} +1 -1
  14. package/dist/assets/SddWizard-1ZhDgcgM.js +1 -0
  15. package/dist/assets/{SessionsDashboard-Dqsrp5CK.js → SessionsDashboard-CfNbqjeh.js} +1 -1
  16. package/dist/assets/SkillDetailView-UzixISza.js +2 -0
  17. package/dist/assets/{SpecsView-BnUsqkrG.js → SpecsView-BO8yG6ID.js} +1 -1
  18. package/dist/assets/{TerminalPanel-BCpddej2.js → TerminalPanel-Bjbu9ktV.js} +1 -1
  19. package/dist/assets/{chat-store-CIMOL6-x.js → chat-store-7ekEnPAf.js} +1 -1
  20. package/dist/assets/{i18n-CNo6A2vu.js → i18n-BCQuDmQo.js} +2 -2
  21. package/dist/assets/index-Cb-hw9qG.js +147 -0
  22. package/dist/assets/index-ZtF5f7wy.css +1 -0
  23. package/dist/assets/{session-store-DN1UYDL9.js → session-store-KCJiKVqL.js} +1 -1
  24. package/dist/assets/settings-wb322bGN.js +1 -0
  25. package/dist/assets/{ui-store-BdOsq6T-.js → ui-store-CcznRsiV.js} +1 -1
  26. package/dist/assets/utils-C3qJEm2b.js +1 -0
  27. package/dist/assets/{vendor-Ch4m_qLI.js → vendor-Cm3Womkr.js} +25 -25
  28. package/dist/assets/{ws-client-BAV7SLzK.js → ws-client-9j1mjm9I.js} +1 -1
  29. package/dist/assets/{xyflow-D5_yey7w.js → xyflow-Dy5Edi88.js} +3 -3
  30. package/dist/index.html +10 -10
  31. package/dist/index.js +4168 -3743
  32. package/dist/index.js.map +1 -1
  33. package/dist/providers.json +2 -2
  34. package/dist/server/entry.js +342 -16
  35. package/dist/server/entry.js.map +1 -1
  36. package/dist/server/index.js +342 -16
  37. package/dist/server/index.js.map +1 -1
  38. package/dist/types.d.ts +28 -0
  39. package/package.json +6 -6
  40. package/dist/assets/OfficeMapPanel-D3VE7UCd.js +0 -4
  41. package/dist/assets/SddBoardView-DvuH4f4e.js +0 -2
  42. package/dist/assets/SddWizard-G55Yw9Bb.js +0 -1
  43. package/dist/assets/SkillDetailView-CX9zeWBG.js +0 -2
  44. package/dist/assets/index-BhO3caLf.js +0 -146
  45. package/dist/assets/index-D7_FeyCA.css +0 -1
  46. package/dist/assets/settings-CGhOOFpI.js +0 -1
  47. package/dist/assets/utils-DBns3uMk.js +0 -1
@@ -12,7 +12,7 @@
12
12
  {
13
13
  "id": "anthropic",
14
14
  "name": "Anthropic",
15
- "description": "Claude Opus, Sonnet, and Haiku",
15
+ "description": "Claude model access",
16
16
  "icon": "🧠",
17
17
  "color": "from-amber-500/20 to-amber-500/5 border-amber-500/30 hover:border-amber-500/50",
18
18
  "keyPlaceholder": "sk-ant-...",
@@ -104,4 +104,4 @@
104
104
  "url": "https://opencode.ai/go?ref=6VZAER87H4"
105
105
  }
106
106
  }
107
- ]
107
+ ]
@@ -4864,7 +4864,7 @@ ${trigger}
4864
4864
  ` : "",
4865
4865
  "## Skills in scope",
4866
4866
  "- `bug-hunter` \u2014 for systematic bug detection patterns",
4867
- "- `output-standards` \u2014 for standardized `<next_steps>` formatting"
4867
+ "- `output-standards` \u2014 for standardized `<nextsteps>` formatting"
4868
4868
  ].join("\n");
4869
4869
  await atomicWrite5(path11.join(targetDir, "SKILL.md"), skillContent);
4870
4870
  send(ws, {
@@ -6069,7 +6069,14 @@ function setupEvents(deps2) {
6069
6069
  await fs10.mkdir(dir, { recursive: true });
6070
6070
  await fs10.writeFile(statusFile, JSON.stringify(e, null, 2), "utf-8");
6071
6071
  } catch (err) {
6072
- console.error("[setup-events] Failed to write status.json:", err);
6072
+ console.error(
6073
+ JSON.stringify({
6074
+ level: "error",
6075
+ event: "setup_events.status_write_failed",
6076
+ message: err instanceof Error ? err.message : String(err),
6077
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
6078
+ })
6079
+ );
6073
6080
  }
6074
6081
  }
6075
6082
  });
@@ -6159,7 +6166,14 @@ function setupEvents(deps2) {
6159
6166
  console.log(`[setup-events] Watching ${projectsDir} for status.json changes (hash-filtered, debounced)`);
6160
6167
  }
6161
6168
  } catch (err) {
6162
- console.error("[setup-events] Failed to start status file watcher:", err);
6169
+ console.error(
6170
+ JSON.stringify({
6171
+ level: "error",
6172
+ event: "setup_events.status_watcher_start_failed",
6173
+ message: err instanceof Error ? err.message : String(err),
6174
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
6175
+ })
6176
+ );
6163
6177
  }
6164
6178
  };
6165
6179
  events.on("client.status", (e) => {
@@ -6619,6 +6633,39 @@ import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
6619
6633
  import { expectDefined as expectDefined2 } from "@wrongstack/core";
6620
6634
  import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
6621
6635
  import { makeProviderFromConfig } from "@wrongstack/providers";
6636
+ var UNCONFIGURED_CAPABILITIES = {
6637
+ tools: false,
6638
+ parallelTools: false,
6639
+ vision: false,
6640
+ streaming: false,
6641
+ promptCache: false,
6642
+ systemPrompt: false,
6643
+ jsonMode: false,
6644
+ reasoning: false,
6645
+ maxContext: 0,
6646
+ cacheControl: "none",
6647
+ topK: false,
6648
+ frequencyPenalty: false,
6649
+ presencePenalty: false,
6650
+ seed: false,
6651
+ structuredOutput: false,
6652
+ logprobs: false,
6653
+ audio: false,
6654
+ multipleCompletions: false
6655
+ };
6656
+ function makeUnconfiguredProvider() {
6657
+ const message = "No provider configured. Complete setup before starting an agent run.";
6658
+ return {
6659
+ id: "unconfigured",
6660
+ capabilities: UNCONFIGURED_CAPABILITIES,
6661
+ async *stream() {
6662
+ throw new Error(message);
6663
+ },
6664
+ async complete() {
6665
+ throw new Error(message);
6666
+ }
6667
+ };
6668
+ }
6622
6669
  function logCreateFailure(event, err) {
6623
6670
  console.error(
6624
6671
  JSON.stringify({
@@ -6665,11 +6712,7 @@ function resolveSetupProvider(opts) {
6665
6712
  }
6666
6713
  }
6667
6714
  console.log("[WebUI] No providers configured \u2014 showing setup screen");
6668
- const provider = makeProviderFromConfig("anthropic", {
6669
- type: "anthropic",
6670
- family: "anthropic",
6671
- apiKey: "stub-key-replaced-on-setup"
6672
- });
6715
+ const provider = makeUnconfiguredProvider();
6673
6716
  return { provider, needsSetup: true };
6674
6717
  }
6675
6718
 
@@ -9069,22 +9112,36 @@ async function handleWorklistMessage(ctx, ws, msg) {
9069
9112
  // src/server/kanban-routes.ts
9070
9113
  import {
9071
9114
  addColumn,
9115
+ addGoalMetricToTask,
9072
9116
  addTask,
9073
9117
  assignTask,
9118
+ claimReadyTask,
9074
9119
  copyTaskToBoard,
9075
9120
  createBoard,
9121
+ deserializeTaskGraph,
9076
9122
  duplicateBoard,
9123
+ exportBoardToTaskGraph,
9077
9124
  generateBoardFromDescription,
9078
9125
  getBoard,
9126
+ getKanbanOrchestrationSnapshot,
9079
9127
  getTask,
9128
+ getTaskChain,
9129
+ listReadyTasks,
9080
9130
  listBoards,
9131
+ mergeTasks,
9081
9132
  moveTask,
9082
9133
  parseLinesIntoTasks,
9083
9134
  removeBoard,
9084
9135
  removeColumn,
9085
9136
  removeTask,
9137
+ releaseTaskClaim,
9138
+ serializeTaskGraph,
9139
+ setTaskChain,
9140
+ splitTask,
9141
+ syncBoardFromTaskGraph,
9086
9142
  transferTaskToBoard,
9087
9143
  updateBoard,
9144
+ updateGoalMetricOnTask,
9088
9145
  updateTask
9089
9146
  } from "@wrongstack/core";
9090
9147
  function ok(ws, type, data) {
@@ -9166,7 +9223,11 @@ async function handleKanbanRoute(ws, msg, ctx) {
9166
9223
  fail(ws, type, "boardId required");
9167
9224
  return true;
9168
9225
  }
9169
- ok(ws, type, { removed: await removeBoard(ctx.projectRoot, boardId) });
9226
+ const board = await getBoard(ctx.projectRoot, boardId);
9227
+ ok(ws, type, {
9228
+ removed: board ? await removeBoard(ctx.projectRoot, board.id) : false,
9229
+ boardId: board?.id ?? boardId
9230
+ });
9170
9231
  return true;
9171
9232
  }
9172
9233
  case "kanban.generate": {
@@ -9192,6 +9253,86 @@ async function handleKanbanRoute(ws, msg, ctx) {
9192
9253
  ok(ws, type, await getBoard(ctx.projectRoot, board.id) ?? board);
9193
9254
  return true;
9194
9255
  }
9256
+ case "kanban.task.ready": {
9257
+ ok(
9258
+ ws,
9259
+ type,
9260
+ await listReadyTasks(ctx.projectRoot, {
9261
+ ...payload?.boardId ? { boardId: payload.boardId } : {},
9262
+ ...payload?.query ? { query: payload.query } : {},
9263
+ ...payload?.assignedAgent ? { assignedAgent: payload.assignedAgent } : {},
9264
+ ...payload?.priority ? { priority: payload.priority } : {},
9265
+ ...payload?.label ? { label: payload.label } : {},
9266
+ ...payload?.chainId ? { chainId: payload.chainId } : {},
9267
+ ...typeof payload?.limit === "number" ? { limit: payload.limit } : {}
9268
+ })
9269
+ );
9270
+ return true;
9271
+ }
9272
+ case "kanban.snapshot": {
9273
+ ok(
9274
+ ws,
9275
+ type,
9276
+ await getKanbanOrchestrationSnapshot(ctx.projectRoot, {
9277
+ ...payload?.boardId ? { boardId: payload.boardId } : {},
9278
+ ...payload?.query ? { query: payload.query } : {},
9279
+ ...payload?.assignedAgent ? { assignedAgent: payload.assignedAgent } : {},
9280
+ ...payload?.priority ? { priority: payload.priority } : {},
9281
+ ...payload?.status ? { status: payload.status } : {},
9282
+ ...payload?.label ? { label: payload.label } : {},
9283
+ ...payload?.chainId ? { chainId: payload.chainId } : {}
9284
+ })
9285
+ );
9286
+ return true;
9287
+ }
9288
+ case "kanban.taskgraph.export": {
9289
+ const boardId = payload?.boardId;
9290
+ if (!boardId) {
9291
+ fail(ws, type, "boardId required");
9292
+ return true;
9293
+ }
9294
+ const exported = await exportBoardToTaskGraph(ctx.projectRoot, boardId, {
9295
+ ...payload?.graphId ? { graphId: payload.graphId } : {},
9296
+ ...payload?.specId ? { specId: payload.specId } : {},
9297
+ ...payload?.title ? { title: payload.title } : {},
9298
+ ...typeof payload?.preserveOriginTaskIds === "boolean" ? { preserveOriginTaskIds: payload.preserveOriginTaskIds } : {},
9299
+ ...typeof payload?.includeArchived === "boolean" ? { includeArchived: payload.includeArchived } : {}
9300
+ });
9301
+ exported ? ok(ws, type, { board: exported.board, taskGraph: serializeTaskGraph(exported.graph) }) : fail(ws, type, `Board not found: ${boardId}`);
9302
+ return true;
9303
+ }
9304
+ case "kanban.taskgraph.sync": {
9305
+ const boardId = payload?.boardId;
9306
+ const taskGraph = payload?.taskGraph;
9307
+ if (!boardId || !taskGraph) {
9308
+ fail(ws, type, "boardId and taskGraph required");
9309
+ return true;
9310
+ }
9311
+ const result = await syncBoardFromTaskGraph(
9312
+ ctx.projectRoot,
9313
+ boardId,
9314
+ deserializeTaskGraph(taskGraph),
9315
+ {
9316
+ ...payload?.title ? { title: payload.title } : {},
9317
+ ...payload?.description ? { description: payload.description } : {},
9318
+ ...payload?.tags ? { tags: payload.tags } : {},
9319
+ ...payload?.generatedBy ? { generatedBy: payload.generatedBy } : {},
9320
+ ...payload?.sourceSystem ? { sourceSystem: payload.sourceSystem } : {},
9321
+ ...payload?.phaseId ? { phaseId: payload.phaseId } : {},
9322
+ ...typeof payload?.includeCompletedTasks === "boolean" ? { includeCompletedTasks: payload.includeCompletedTasks } : {},
9323
+ ...typeof payload?.archiveMissingTasks === "boolean" ? { archiveMissingTasks: payload.archiveMissingTasks } : {},
9324
+ ...typeof payload?.preserveManualDependencies === "boolean" ? { preserveManualDependencies: payload.preserveManualDependencies } : {}
9325
+ }
9326
+ );
9327
+ result ? ok(ws, type, {
9328
+ board: result.board,
9329
+ taskIdMap: Object.fromEntries(result.taskIdMap),
9330
+ createdTaskIds: result.createdTaskIds,
9331
+ updatedTaskIds: result.updatedTaskIds,
9332
+ archivedTaskIds: result.archivedTaskIds
9333
+ }) : fail(ws, type, `Board not found: ${boardId}`);
9334
+ return true;
9335
+ }
9195
9336
  case "kanban.task.add": {
9196
9337
  const boardId = payload?.boardId;
9197
9338
  const title = payload?.title;
@@ -9210,6 +9351,51 @@ async function handleKanbanRoute(ws, msg, ctx) {
9210
9351
  result ? ok(ws, type, result.task) : fail(ws, type, `Board not found: ${boardId}`);
9211
9352
  return true;
9212
9353
  }
9354
+ case "kanban.task.split": {
9355
+ const boardId = payload?.boardId;
9356
+ const taskId = payload?.taskId;
9357
+ const childTitles = payload?.childTitles;
9358
+ if (!boardId || !taskId || !childTitles?.length) {
9359
+ fail(ws, type, "boardId, taskId, and childTitles required");
9360
+ return true;
9361
+ }
9362
+ const result = await splitTask(ctx.projectRoot, boardId, taskId, {
9363
+ titles: childTitles,
9364
+ ...payload?.targetColumnId ? { columnId: payload.targetColumnId } : {},
9365
+ ...typeof payload?.inheritAssignment === "boolean" ? { inheritAssignment: payload.inheritAssignment } : {},
9366
+ ...typeof payload?.inheritLabels === "boolean" ? { inheritLabels: payload.inheritLabels } : {},
9367
+ ...typeof payload?.inheritSuccessCriteria === "boolean" ? { inheritSuccessCriteria: payload.inheritSuccessCriteria } : {},
9368
+ ...typeof payload?.inheritGoalMetrics === "boolean" ? { inheritGoalMetrics: payload.inheritGoalMetrics } : {},
9369
+ ...typeof payload?.inheritDependencies === "boolean" ? { inheritDependencies: payload.inheritDependencies } : {},
9370
+ ...typeof payload?.chainChildren === "boolean" ? { chainChildren: payload.chainChildren } : {},
9371
+ ...typeof payload?.rewireDependents === "boolean" ? { rewireDependents: payload.rewireDependents } : {}
9372
+ });
9373
+ result ? ok(ws, type, { board: result.board, parent: result.parent, children: result.children }) : fail(ws, type, "Board or task not found");
9374
+ return true;
9375
+ }
9376
+ case "kanban.task.merge": {
9377
+ const boardId = payload?.boardId;
9378
+ const taskIds = payload?.taskIds;
9379
+ const title = payload?.title;
9380
+ if (!boardId || !taskIds?.length || !title) {
9381
+ fail(ws, type, "boardId, taskIds, and title required");
9382
+ return true;
9383
+ }
9384
+ const result = await mergeTasks(ctx.projectRoot, boardId, {
9385
+ taskIds,
9386
+ title,
9387
+ ...payload?.description ? { description: payload.description } : {},
9388
+ ...payload?.targetColumnId ? { targetColumnId: payload.targetColumnId } : {},
9389
+ ...typeof payload?.preserveAssignment === "boolean" ? { preserveAssignment: payload.preserveAssignment } : {},
9390
+ ...typeof payload?.closeSourceTasks === "boolean" ? { closeSourceTasks: payload.closeSourceTasks } : {}
9391
+ });
9392
+ result ? ok(ws, type, {
9393
+ board: result.board,
9394
+ task: result.task,
9395
+ sourceTasks: result.sourceTasks
9396
+ }) : fail(ws, type, "Board or task not found");
9397
+ return true;
9398
+ }
9213
9399
  case "kanban.task.update": {
9214
9400
  const boardId = payload?.boardId;
9215
9401
  const taskId = payload?.taskId;
@@ -9268,6 +9454,104 @@ async function handleKanbanRoute(ws, msg, ctx) {
9268
9454
  result ? ok(ws, type, result.targetBoard) : fail(ws, type, "Board or task not found");
9269
9455
  return true;
9270
9456
  }
9457
+ case "kanban.task.chain": {
9458
+ const boardId = payload?.boardId;
9459
+ const taskIds = payload?.taskIds;
9460
+ if (!boardId || !taskIds?.length) {
9461
+ fail(ws, type, "boardId and taskIds required");
9462
+ return true;
9463
+ }
9464
+ const result = await setTaskChain(ctx.projectRoot, boardId, {
9465
+ taskIds,
9466
+ ...payload?.chainId ? { chainId: payload.chainId } : {},
9467
+ ...typeof payload?.enforceDependencies === "boolean" ? { enforceDependencies: payload.enforceDependencies } : {}
9468
+ });
9469
+ result ? ok(ws, type, { board: result.board, chainId: result.chainId, tasks: result.tasks }) : fail(ws, type, "Board or task not found");
9470
+ return true;
9471
+ }
9472
+ case "kanban.task.chain.get": {
9473
+ const boardId = payload?.boardId;
9474
+ const taskOrChainId = payload?.taskId ?? payload?.chainId;
9475
+ if (!boardId || !taskOrChainId) {
9476
+ fail(ws, type, "boardId and taskId or chainId required");
9477
+ return true;
9478
+ }
9479
+ const result = await getTaskChain(ctx.projectRoot, boardId, taskOrChainId);
9480
+ result ? ok(ws, type, { board: result.board, chainId: result.chainId, tasks: result.tasks }) : fail(ws, type, "Chain not found");
9481
+ return true;
9482
+ }
9483
+ case "kanban.task.claim": {
9484
+ const result = await claimReadyTask(ctx.projectRoot, {
9485
+ ...payload?.boardId ? { boardId: payload.boardId } : {},
9486
+ ...payload?.taskId ? { taskId: payload.taskId } : {},
9487
+ ...payload?.agentId ? { agentId: payload.agentId } : {},
9488
+ ...payload?.name ? { name: payload.name } : {},
9489
+ ...payload?.role ? { role: payload.role } : {},
9490
+ ...payload?.provider ? { provider: payload.provider } : {},
9491
+ ...payload?.model ? { model: payload.model } : {},
9492
+ ...payload?.fallbackProfile ? { fallbackProfile: payload.fallbackProfile } : {},
9493
+ ...payload?.fallbackModels ? { fallbackModels: payload.fallbackModels } : {},
9494
+ ...payload?.tools ? { tools: payload.tools } : {},
9495
+ ...payload?.allowedCapabilities ? { allowedCapabilities: payload.allowedCapabilities } : {},
9496
+ ...payload?.assignee ? { assignee: payload.assignee } : {},
9497
+ status: payload?.assignmentStatus ?? "queued"
9498
+ });
9499
+ result ? ok(ws, type, { board: result.board, task: result.task }) : fail(ws, type, "No ready kanban task matched the claim");
9500
+ return true;
9501
+ }
9502
+ case "kanban.task.release": {
9503
+ const boardId = payload?.boardId;
9504
+ const taskId = payload?.taskId;
9505
+ if (!boardId || !taskId) {
9506
+ fail(ws, type, "boardId and taskId required");
9507
+ return true;
9508
+ }
9509
+ const board = await releaseTaskClaim(ctx.projectRoot, boardId, taskId, {
9510
+ ...payload?.status ? { status: payload.status } : {},
9511
+ ...payload?.reason ? { reason: payload.reason } : {},
9512
+ ...typeof payload?.clearAssignee === "boolean" ? { clearAssignee: payload.clearAssignee } : {}
9513
+ });
9514
+ board ? ok(ws, type, board) : fail(ws, type, "Board or task not found");
9515
+ return true;
9516
+ }
9517
+ case "kanban.task.metric.add": {
9518
+ const boardId = payload?.boardId;
9519
+ const taskId = payload?.taskId;
9520
+ const name2 = payload?.name;
9521
+ if (!boardId || !taskId || !name2) {
9522
+ fail(ws, type, "boardId, taskId, and name required");
9523
+ return true;
9524
+ }
9525
+ const board = await addGoalMetricToTask(ctx.projectRoot, boardId, taskId, {
9526
+ name: name2,
9527
+ ...payload?.status ? { status: payload.status } : {},
9528
+ ...payload?.target !== void 0 ? { target: payload.target } : {},
9529
+ ...payload?.current !== void 0 ? { current: payload.current } : {},
9530
+ ...payload?.unit ? { unit: payload.unit } : {},
9531
+ ...payload?.notes ? { notes: payload.notes } : {}
9532
+ });
9533
+ board ? ok(ws, type, board) : fail(ws, type, "Board or task not found");
9534
+ return true;
9535
+ }
9536
+ case "kanban.task.metric.update": {
9537
+ const boardId = payload?.boardId;
9538
+ const taskId = payload?.taskId;
9539
+ const metricId = payload?.metricId;
9540
+ if (!boardId || !taskId || !metricId) {
9541
+ fail(ws, type, "boardId, taskId, and metricId required");
9542
+ return true;
9543
+ }
9544
+ const board = await updateGoalMetricOnTask(ctx.projectRoot, boardId, taskId, metricId, {
9545
+ ...payload?.name ? { name: payload.name } : {},
9546
+ ...payload?.status ? { status: payload.status } : {},
9547
+ ...payload?.target !== void 0 ? { target: payload.target } : {},
9548
+ ...payload?.current !== void 0 ? { current: payload.current } : {},
9549
+ ...payload?.unit ? { unit: payload.unit } : {},
9550
+ ...payload?.notes ? { notes: payload.notes } : {}
9551
+ });
9552
+ board ? ok(ws, type, board) : fail(ws, type, "Metric not found");
9553
+ return true;
9554
+ }
9271
9555
  case "kanban.task.assign": {
9272
9556
  const boardId = payload?.boardId;
9273
9557
  const taskId = payload?.taskId;
@@ -9303,8 +9587,13 @@ async function handleKanbanRoute(ws, msg, ctx) {
9303
9587
  fail(ws, type, "boardId and taskId required");
9304
9588
  return true;
9305
9589
  }
9590
+ const task = await getTask(ctx.projectRoot, boardId, taskId);
9591
+ if (!task) {
9592
+ fail(ws, type, "Board or task not found");
9593
+ return true;
9594
+ }
9306
9595
  const board = await removeTask(ctx.projectRoot, boardId, taskId);
9307
- board ? ok(ws, type, { removed: true }) : fail(ws, type, "Board or task not found");
9596
+ board ? ok(ws, type, { removed: true, boardId: board.id, taskId: task.id, board }) : fail(ws, type, "Board or task not found");
9308
9597
  return true;
9309
9598
  }
9310
9599
  case "kanban.task.get": {
@@ -9339,7 +9628,7 @@ async function handleKanbanRoute(ws, msg, ctx) {
9339
9628
  const board = await removeColumn(ctx.projectRoot, boardId, columnId, {
9340
9629
  moveTasksToColumnId: payload?.moveTasksToColumnId
9341
9630
  });
9342
- board ? ok(ws, type, { removed: true }) : fail(ws, type, `Column not found: ${columnId}`);
9631
+ board ? ok(ws, type, { removed: true, boardId: board.id, columnId, board }) : fail(ws, type, `Column not found: ${columnId}`);
9343
9632
  return true;
9344
9633
  }
9345
9634
  default:
@@ -9939,18 +10228,55 @@ function createMessageDispatcher(opts) {
9939
10228
  send(ws, { type: "pong", payload: {} });
9940
10229
  break;
9941
10230
  case "tools.list": {
9942
- const list = deps2.toolRegistry.list().map((t) => {
9943
- const schema = t.inputSchema ?? {};
10231
+ const entries = [...deps2.toolRegistry.listWithOwner(), ...deps2.toolRegistry.listDisabled()];
10232
+ const list = entries.map(({ tool, owner }) => {
10233
+ const schema = tool.inputSchema ?? {};
9944
10234
  const params = schema.properties ? Object.keys(schema.properties) : [];
9945
10235
  return {
9946
- name: t.name,
9947
- description: t.description ?? "",
9948
- params
10236
+ name: tool.name,
10237
+ owner,
10238
+ description: tool.description ?? "",
10239
+ params,
10240
+ disabled: deps2.toolRegistry.isDisabled(tool.name),
10241
+ mutating: tool.mutating,
10242
+ permission: tool.permission
9949
10243
  };
9950
10244
  });
9951
10245
  send(ws, { type: "tools.list", payload: { tools: list } });
9952
10246
  break;
9953
10247
  }
10248
+ case "tool.disable": {
10249
+ const name2 = (msg.payload ?? {}).name;
10250
+ if (!name2) {
10251
+ send(ws, { type: "error", payload: { message: "tool.disable requires a name" } });
10252
+ break;
10253
+ }
10254
+ const ok2 = deps2.toolRegistry.disable(name2);
10255
+ const currentCfg = deps2.configStore.get().tools ?? {};
10256
+ const currentDisabled = currentCfg.disabledTools ?? [];
10257
+ if (ok2 && !currentDisabled.includes(name2)) {
10258
+ deps2.configStore.update({ tools: { ...currentCfg, disabledTools: [...currentDisabled, name2] } });
10259
+ }
10260
+ send(ws, { type: "tool.disabled", payload: { name: name2, ok: ok2 } });
10261
+ break;
10262
+ }
10263
+ case "tool.enable": {
10264
+ const name2 = (msg.payload ?? {}).name;
10265
+ if (!name2) {
10266
+ send(ws, { type: "error", payload: { message: "tool.enable requires a name" } });
10267
+ break;
10268
+ }
10269
+ const ok2 = deps2.toolRegistry.enable(name2);
10270
+ if (ok2) {
10271
+ const currentCfg = deps2.configStore.get().tools ?? {};
10272
+ const currentDisabled = currentCfg.disabledTools ?? [];
10273
+ deps2.configStore.update({
10274
+ tools: { ...currentCfg, disabledTools: currentDisabled.filter((n) => n !== name2) }
10275
+ });
10276
+ }
10277
+ send(ws, { type: "tool.enabled", payload: { name: name2, ok: ok2 } });
10278
+ break;
10279
+ }
9954
10280
  // ── Memory operations — delegated to shared handlers (memory-handlers.ts) ──
9955
10281
  case "memory.list":
9956
10282
  return handleMemoryList(ws, deps2.memoryStore);