@wrongstack/tools 0.282.1 → 0.283.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.d.ts CHANGED
@@ -5,7 +5,7 @@ export { batchToolUseTool } from './batch-tool-use.js';
5
5
  export { OPTIONAL_TOOLS, TIER1_TOOLS, TIER2_TOOLS, TIER3_TOOLS, builtinTools } from './builtin.js';
6
6
  export { CircuitBreaker, CircuitBreakerConfig, CircuitBreakerSnapshot } from './circuit-breaker.js';
7
7
  export { C as CircuitOpenError, e as CircuitSnapshot, f as CircuitState, h as IndexCircuitBreaker, i as IndexTimeoutError, k as cancelPendingReindexes, l as codebaseIndexStats, m as codebaseIndexTool, n as codebaseSearchTool, o as codebaseStatsTool, p as enqueueReindex, q as getIndexState, r as indexCircuitBreaker, s as isIndexReady, t as isIndexableFile, u as isIndexing, v as onIndexStateChange, w as resetIndexCircuitBreaker, x as runStartupIndex, y as searchCodebaseIndex, z as shutdownCodebaseIndexHost } from './background-indexer-BeDBxfSh.js';
8
- import { Tool, AssignKanbanTaskInput, KanbanTaskPriority, KanbanTaskStatus, KanbanAgentRunStatus, KanbanBoard, KanbanBoardSummary, KanbanTask, KanbanSearchResult, KanbanOrchestrationSnapshot, SerializedTaskGraph, SkillLoader } from '@wrongstack/core';
8
+ import { Tool, AssignKanbanTaskInput, KanbanTaskPriority, KanbanTaskStatus, KanbanAgentRunStatus, KanbanBoard, KanbanBoardSummary, KanbanTask, KanbanSearchResult, KanbanEvent, KanbanQueueHealth, KanbanOrchestrationSnapshot, SerializedTaskGraph, SkillLoader } from '@wrongstack/core';
9
9
  export { diffTool } from './diff.js';
10
10
  export { documentTool } from './document.js';
11
11
  export { editTool } from './edit.js';
@@ -184,7 +184,7 @@ interface DesignOutput {
184
184
  */
185
185
  declare const designTool: Tool<DesignInput, DesignOutput>;
186
186
 
187
- type KanbanAction = 'list_boards' | 'get_board' | 'create_board' | 'duplicate_board' | 'update_board' | 'delete_board' | 'generate_board' | 'export_markdown' | 'export_task_graph' | 'sync_task_graph' | 'search_tasks' | 'ready_tasks' | 'snapshot' | 'add_column' | 'update_column' | 'delete_column' | 'add_task' | 'split_task' | 'merge_tasks' | 'copy_task' | 'transfer_task' | 'get_task' | 'update_task' | 'move_task' | 'delete_task' | 'set_chain' | 'get_chain' | 'claim_task' | 'release_task' | 'assign_task' | 'mark_assignment' | 'add_dependency' | 'add_goal_metric' | 'update_goal_metric' | 'add_check' | 'update_check' | 'add_note' | 'add_link';
187
+ type KanbanAction = 'list_boards' | 'get_board' | 'create_board' | 'duplicate_board' | 'update_board' | 'delete_board' | 'generate_board' | 'export_markdown' | 'export_task_graph' | 'sync_task_graph' | 'search_tasks' | 'ready_tasks' | 'snapshot' | 'add_column' | 'update_column' | 'delete_column' | 'add_task' | 'split_task' | 'merge_tasks' | 'copy_task' | 'transfer_task' | 'get_task' | 'update_task' | 'move_task' | 'delete_task' | 'set_chain' | 'get_chain' | 'claim_task' | 'release_task' | 'assign_task' | 'mark_assignment' | 'heartbeat_assignment' | 'recover_stale' | 'events' | 'queue_health' | 'add_dependency' | 'add_goal_metric' | 'update_goal_metric' | 'add_check' | 'update_check' | 'add_note' | 'add_link';
188
188
  interface KanbanToolInput extends Omit<AssignKanbanTaskInput, 'status'> {
189
189
  action: KanbanAction;
190
190
  boardId?: string | undefined;
@@ -237,6 +237,15 @@ interface KanbanToolInput extends Omit<AssignKanbanTaskInput, 'status'> {
237
237
  includeCompletedTasks?: boolean | undefined;
238
238
  preserveAssignment?: boolean | undefined;
239
239
  preserveDependencies?: boolean | undefined;
240
+ leaseId?: string | undefined;
241
+ claimedAt?: string | undefined;
242
+ heartbeatAt?: string | undefined;
243
+ leaseExpiresAt?: string | undefined;
244
+ attempt?: number | undefined;
245
+ maxAttempts?: number | undefined;
246
+ costCeilingUsd?: number | undefined;
247
+ retryPolicy?: 'off' | 'incremental' | 'exponential' | undefined;
248
+ lastFailureKind?: string | undefined;
240
249
  subagentId?: string | undefined;
241
250
  runTaskId?: string | undefined;
242
251
  lastResult?: string | undefined;
@@ -245,6 +254,12 @@ interface KanbanToolInput extends Omit<AssignKanbanTaskInput, 'status'> {
245
254
  releaseStatus?: 'pending' | 'ready' | 'blocked' | undefined;
246
255
  releaseReason?: string | undefined;
247
256
  clearAssignee?: boolean | undefined;
257
+ recoveryMode?: 'auto' | 'release' | 'retry' | 'fail' | undefined;
258
+ recoveryNow?: string | undefined;
259
+ recoveryPolicyFailOnCostCeiling?: boolean | undefined;
260
+ recoveryPolicyReleaseOnFailureKinds?: string[] | undefined;
261
+ recoveryPolicyReleaseOnHeartbeatDue?: boolean | undefined;
262
+ recoveryPolicyRetryPolicyOverride?: 'off' | 'incremental' | 'exponential' | undefined;
248
263
  taskGraph?: unknown;
249
264
  graphId?: string | undefined;
250
265
  specId?: string | undefined;
@@ -262,6 +277,9 @@ interface KanbanToolOutput {
262
277
  boards?: KanbanBoardSummary[] | undefined;
263
278
  task?: KanbanTask | undefined;
264
279
  tasks?: KanbanSearchResult[] | undefined;
280
+ recoveredTasks?: KanbanTask[] | undefined;
281
+ events?: KanbanEvent[] | undefined;
282
+ queueHealth?: KanbanQueueHealth | undefined;
265
283
  children?: KanbanTask[] | undefined;
266
284
  chain?: KanbanTask[] | undefined;
267
285
  snapshot?: KanbanOrchestrationSnapshot | undefined;
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import * as path3 from 'node:path';
4
4
  import { resolve, sep, dirname, join } from 'node:path';
5
5
  import { spawn, execFileSync } from 'node:child_process';
6
6
  import * as Core from '@wrongstack/core';
7
- import { SKILL_LIMITS, buildChildEnv, getDesignKitLoader, isDesignStack, loadActiveKit, applyTokenOverrides, setActiveKit, recordKitChoice, recordOverrides, setDesignOverrides, materializeTokens, runDesignVerify, ToolValidationError, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, ToolError, FetchError, isPrivateIPv4, isPrivateIPv6, assessCommitSafety, compileGlob, expectDefined, recordPackageAction, detectPackageEcosystem, deepMerge, addLinkToTask, addNoteToTask, updateCheckOnTask, addCheckToTask, updateGoalMetricOnTask, addGoalMetricToTask, addDependency, updateTaskAssignment, assignTask, releaseTaskClaim, claimReadyTask, getTaskChain, setTaskChain, removeTask, moveTask, updateTask, getTask, transferTaskToBoard, copyTaskToBoard, mergeTasks, splitTask, addTask, removeColumn, updateColumn, addColumn, getKanbanOrchestrationSnapshot, listReadyTasks, searchKanban, deserializeTaskGraph, syncBoardFromTaskGraph, exportBoardToTaskGraph, serializeTaskGraph, exportBoardAsMarkdown, generateBoardFromDescription, createBoard, parseLinesIntoTasks, getBoard, removeBoard, duplicateBoard, updateBoard, listBoards, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, mutateTasks, formatTaskList, formatPlan, FsError, toErrorMessage as toErrorMessage$2, computeTaskItemProgress, loadPlan, savePlan, loadTasks, saveTasks, stripFrontmatter, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
7
+ import { SKILL_LIMITS, buildChildEnv, getDesignKitLoader, isDesignStack, loadActiveKit, applyTokenOverrides, setActiveKit, recordKitChoice, recordOverrides, setDesignOverrides, materializeTokens, runDesignVerify, ToolValidationError, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, ToolError, FetchError, isPrivateIPv4, isPrivateIPv6, assessCommitSafety, compileGlob, expectDefined, recordPackageAction, detectPackageEcosystem, deepMerge, addLinkToTask, addNoteToTask, updateCheckOnTask, addCheckToTask, updateGoalMetricOnTask, addGoalMetricToTask, addDependency, getKanbanQueueHealth, listKanbanEvents, recoverStaleTaskAssignments, heartbeatTaskAssignment, updateTaskAssignment, assignTask, releaseTaskClaim, claimReadyTask, getTaskChain, setTaskChain, removeTask, moveTask, updateTask, getTask, transferTaskToBoard, copyTaskToBoard, mergeTasks, splitTask, addTask, removeColumn, updateColumn, addColumn, getKanbanOrchestrationSnapshot, listReadyTasks, searchKanban, deserializeTaskGraph, syncBoardFromTaskGraph, exportBoardToTaskGraph, serializeTaskGraph, exportBoardAsMarkdown, generateBoardFromDescription, createBoard, parseLinesIntoTasks, getBoard, removeBoard, duplicateBoard, updateBoard, listBoards, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, mutateTasks, formatTaskList, formatPlan, FsError, toErrorMessage as toErrorMessage$2, computeTaskItemProgress, loadPlan, savePlan, loadTasks, saveTasks, stripFrontmatter, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
8
8
  import * as fs2 from 'node:fs/promises';
9
9
  import * as os2 from 'node:os';
10
10
  import { toErrorMessage as toErrorMessage$3 } from '@wrongstack/core/utils';
@@ -9454,6 +9454,10 @@ var kanbanTool = {
9454
9454
  "release_task",
9455
9455
  "assign_task",
9456
9456
  "mark_assignment",
9457
+ "heartbeat_assignment",
9458
+ "recover_stale",
9459
+ "events",
9460
+ "queue_health",
9457
9461
  "add_dependency",
9458
9462
  "add_goal_metric",
9459
9463
  "update_goal_metric",
@@ -9500,6 +9504,12 @@ var kanbanTool = {
9500
9504
  fallbackModels: { type: "array", items: { type: "string" } },
9501
9505
  tools: { type: "array", items: { type: "string" } },
9502
9506
  allowedCapabilities: { type: "array", items: { type: "string" } },
9507
+ leaseId: { type: "string" },
9508
+ claimedAt: { type: "string" },
9509
+ heartbeatAt: { type: "string" },
9510
+ leaseExpiresAt: { type: "string" },
9511
+ attempt: { type: "number" },
9512
+ maxAttempts: { type: "number" },
9503
9513
  subagentId: { type: "string" },
9504
9514
  runTaskId: { type: "string" },
9505
9515
  lastResult: { type: "string" },
@@ -9511,6 +9521,8 @@ var kanbanTool = {
9511
9521
  releaseStatus: { type: "string", enum: ["pending", "ready", "blocked"] },
9512
9522
  releaseReason: { type: "string" },
9513
9523
  clearAssignee: { type: "boolean" },
9524
+ recoveryMode: { type: "string", enum: ["release", "retry", "fail"] },
9525
+ recoveryNow: { type: "string" },
9514
9526
  taskGraph: { type: "object" },
9515
9527
  graphId: { type: "string" },
9516
9528
  specId: { type: "string" },
@@ -9926,10 +9938,80 @@ var kanbanTool = {
9926
9938
  ...input.runTaskId !== void 0 ? { runTaskId: input.runTaskId } : {},
9927
9939
  ...input.lastResult !== void 0 ? { lastResult: input.lastResult } : {},
9928
9940
  ...input.error !== void 0 ? { error: input.error } : {},
9929
- ...input.agentId !== void 0 ? { agentId: input.agentId } : {}
9941
+ ...input.agentId !== void 0 ? { agentId: input.agentId } : {},
9942
+ ...input.leaseId !== void 0 ? { leaseId: input.leaseId } : {},
9943
+ ...input.claimedAt !== void 0 ? { claimedAt: input.claimedAt } : {},
9944
+ ...input.heartbeatAt !== void 0 ? { heartbeatAt: input.heartbeatAt } : {},
9945
+ ...input.leaseExpiresAt !== void 0 ? { leaseExpiresAt: input.leaseExpiresAt } : {},
9946
+ ...input.attempt !== void 0 ? { attempt: input.attempt } : {},
9947
+ ...input.maxAttempts !== void 0 ? { maxAttempts: input.maxAttempts } : {}
9930
9948
  });
9931
9949
  return board ? okBoard(board, "Assignment updated.") : fail("Task not found.");
9932
9950
  }
9951
+ case "heartbeat_assignment": {
9952
+ if (!input.boardId || !input.taskId) {
9953
+ return fail("heartbeat_assignment requires boardId and taskId.");
9954
+ }
9955
+ const board = await heartbeatTaskAssignment(projectRoot, input.boardId, input.taskId, {
9956
+ ...input.heartbeatAt !== void 0 ? { heartbeatAt: input.heartbeatAt } : {},
9957
+ ...input.leaseExpiresAt !== void 0 ? { leaseExpiresAt: input.leaseExpiresAt } : {}
9958
+ });
9959
+ return board ? okBoard(board, "Assignment heartbeat updated.") : fail("Task assignment not found.");
9960
+ }
9961
+ case "recover_stale": {
9962
+ if (!input.boardId) return fail("recover_stale requires boardId.");
9963
+ const policyFields = [
9964
+ input.recoveryPolicyFailOnCostCeiling !== void 0,
9965
+ input.recoveryPolicyReleaseOnFailureKinds !== void 0,
9966
+ input.recoveryPolicyReleaseOnHeartbeatDue !== void 0,
9967
+ input.recoveryPolicyRetryPolicyOverride !== void 0
9968
+ ].some(Boolean);
9969
+ const result = await recoverStaleTaskAssignments(projectRoot, input.boardId, {
9970
+ ...input.recoveryMode !== void 0 ? { mode: input.recoveryMode } : {},
9971
+ ...input.recoveryNow !== void 0 ? { now: input.recoveryNow } : {},
9972
+ ...input.releaseReason !== void 0 ? { reason: input.releaseReason } : {},
9973
+ ...input.clearAssignee !== void 0 ? { clearAssignee: input.clearAssignee } : {},
9974
+ ...policyFields ? {
9975
+ policy: {
9976
+ ...input.recoveryPolicyFailOnCostCeiling !== void 0 ? { failWhenCostCeilingSet: input.recoveryPolicyFailOnCostCeiling } : {},
9977
+ ...input.recoveryPolicyReleaseOnFailureKinds !== void 0 ? {
9978
+ releaseOnFailureKinds: input.recoveryPolicyReleaseOnFailureKinds
9979
+ } : {},
9980
+ ...input.recoveryPolicyReleaseOnHeartbeatDue !== void 0 ? {
9981
+ releaseOnHeartbeatDue: input.recoveryPolicyReleaseOnHeartbeatDue
9982
+ } : {},
9983
+ ...input.recoveryPolicyRetryPolicyOverride !== void 0 ? {
9984
+ retryPolicyOverride: input.recoveryPolicyRetryPolicyOverride
9985
+ } : {}
9986
+ }
9987
+ } : {}
9988
+ });
9989
+ return result ? {
9990
+ ok: true,
9991
+ message: `Recovered ${result.tasks.length} stale assignment(s).`,
9992
+ board: result.board,
9993
+ recoveredTasks: result.tasks
9994
+ } : { ok: true, message: "No stale assignment matched.", recoveredTasks: [] };
9995
+ }
9996
+ case "events": {
9997
+ if (!input.boardId) return fail("events requires boardId.");
9998
+ const eventList = await listKanbanEvents(projectRoot, input.boardId);
9999
+ return {
10000
+ ok: true,
10001
+ message: `${eventList.length} event(s).`,
10002
+ events: eventList
10003
+ };
10004
+ }
10005
+ case "queue_health": {
10006
+ const health = await getKanbanQueueHealth(projectRoot, {
10007
+ ...input.boardId !== void 0 ? { boardId: input.boardId } : {}
10008
+ });
10009
+ return {
10010
+ ok: true,
10011
+ message: `Counts: ready=${health.counts.ready}, running=${health.counts.running}, stale=${health.staleAssignments.count}.`,
10012
+ queueHealth: health
10013
+ };
10014
+ }
9933
10015
  case "add_dependency": {
9934
10016
  if (!input.boardId || !input.taskId || !input.dependencyTaskId) {
9935
10017
  return fail("add_dependency requires boardId, taskId, and dependencyTaskId.");
@@ -10081,11 +10163,20 @@ function assignmentInput(input) {
10081
10163
  fallbackModels: input.fallbackModels,
10082
10164
  tools: input.tools,
10083
10165
  allowedCapabilities: input.allowedCapabilities,
10084
- assignee: input.assignee
10166
+ assignee: input.assignee,
10167
+ leaseId: input.leaseId,
10168
+ claimedAt: input.claimedAt,
10169
+ heartbeatAt: input.heartbeatAt,
10170
+ leaseExpiresAt: input.leaseExpiresAt,
10171
+ attempt: input.attempt,
10172
+ maxAttempts: input.maxAttempts,
10173
+ costCeilingUsd: input.costCeilingUsd,
10174
+ retryPolicy: input.retryPolicy,
10175
+ lastFailureKind: input.lastFailureKind
10085
10176
  };
10086
10177
  }
10087
10178
  function hasAssignmentInput(input) {
10088
- return input.agentId !== void 0 || input.name !== void 0 || input.role !== void 0 || input.provider !== void 0 || input.model !== void 0 || input.fallbackProfile !== void 0 || input.fallbackModels !== void 0 || input.tools !== void 0 || input.allowedCapabilities !== void 0 || input.assignee !== void 0 || input.assignmentStatus !== void 0;
10179
+ return input.agentId !== void 0 || input.name !== void 0 || input.role !== void 0 || input.provider !== void 0 || input.model !== void 0 || input.fallbackProfile !== void 0 || input.fallbackModels !== void 0 || input.tools !== void 0 || input.allowedCapabilities !== void 0 || input.assignee !== void 0 || input.leaseId !== void 0 || input.claimedAt !== void 0 || input.heartbeatAt !== void 0 || input.leaseExpiresAt !== void 0 || input.attempt !== void 0 || input.maxAttempts !== void 0 || input.costCeilingUsd !== void 0 || input.retryPolicy !== void 0 || input.lastFailureKind !== void 0 || input.assignmentStatus !== void 0;
10089
10180
  }
10090
10181
  function assignmentForTaskCreate(input) {
10091
10182
  return {
@@ -10098,7 +10189,16 @@ function assignmentForTaskCreate(input) {
10098
10189
  ...input.fallbackProfile !== void 0 ? { fallbackProfile: input.fallbackProfile } : {},
10099
10190
  ...input.fallbackModels !== void 0 ? { fallbackModels: input.fallbackModels } : {},
10100
10191
  ...input.tools !== void 0 ? { tools: input.tools } : {},
10101
- ...input.allowedCapabilities !== void 0 ? { allowedCapabilities: input.allowedCapabilities } : {}
10192
+ ...input.allowedCapabilities !== void 0 ? { allowedCapabilities: input.allowedCapabilities } : {},
10193
+ ...input.leaseId !== void 0 ? { leaseId: input.leaseId } : {},
10194
+ ...input.claimedAt !== void 0 ? { claimedAt: input.claimedAt } : {},
10195
+ ...input.heartbeatAt !== void 0 ? { heartbeatAt: input.heartbeatAt } : {},
10196
+ ...input.leaseExpiresAt !== void 0 ? { leaseExpiresAt: input.leaseExpiresAt } : {},
10197
+ ...input.attempt !== void 0 ? { attempt: input.attempt } : {},
10198
+ ...input.maxAttempts !== void 0 ? { maxAttempts: input.maxAttempts } : {},
10199
+ ...input.costCeilingUsd !== void 0 ? { costCeilingUsd: input.costCeilingUsd } : {},
10200
+ ...input.retryPolicy !== void 0 ? { retryPolicy: input.retryPolicy } : {},
10201
+ ...input.lastFailureKind !== void 0 ? { lastFailureKind: input.lastFailureKind } : {}
10102
10202
  };
10103
10203
  }
10104
10204
 
@@ -13490,6 +13590,12 @@ function relatedMemoryTool(memory) {
13490
13590
  }
13491
13591
 
13492
13592
  // src/mode.ts
13593
+ function modeFamily(mode) {
13594
+ if (mode.tags?.includes("lite")) return "lite";
13595
+ if (mode.tags?.includes("deep")) return "deep";
13596
+ if (mode.tags?.includes("balanced") || mode.id === "default") return "balanced";
13597
+ return "custom";
13598
+ }
13493
13599
  function createModeTool(modeStore) {
13494
13600
  return {
13495
13601
  name: "mode",
@@ -13529,10 +13635,16 @@ function createModeTool(modeStore) {
13529
13635
  }
13530
13636
  case "list": {
13531
13637
  const modes = await modeStore.listModes();
13532
- const lines = modes.map((m) => ` ${m.id.padEnd(20)} ${m.name} \u2014 ${m.description}`).join("\n");
13638
+ const lines = modes.map((m) => ` ${m.id.padEnd(20)} [${modeFamily(m)}] ${m.name} \u2014 ${m.description}`).join("\n");
13533
13639
  return {
13534
13640
  action: "list",
13535
- modes: modes.map((m) => ({ id: m.id, name: m.name, description: m.description })),
13641
+ modes: modes.map((m) => ({
13642
+ id: m.id,
13643
+ name: m.name,
13644
+ description: m.description,
13645
+ family: modeFamily(m),
13646
+ tags: m.tags ?? []
13647
+ })),
13536
13648
  success: true,
13537
13649
  message: lines
13538
13650
  };