@wrongstack/tools 0.308.6 → 0.309.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/builtin.js CHANGED
@@ -25425,13 +25425,7 @@ function broadcastTodoUpdate(context, todos) {
25425
25425
  to: `@session:${sessionId}`,
25426
25426
  type: "status",
25427
25427
  subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
25428
- body: JSON.stringify({
25429
- kind: "kanban.todos.updated",
25430
- sessionId,
25431
- revision: context.state.revision,
25432
- todoCount: todos.length,
25433
- statusCounts
25434
- }),
25428
+ body: `Shared Kanban board synced this session's todo list: ${todos.length} item${todos.length === 1 ? "" : "s"} \u2014 ${statusCounts.completed} completed, ${statusCounts.inProgress} in progress, ${statusCounts.pending} pending.`,
25435
25429
  priority: "normal",
25436
25430
  senderSessionId: sessionId
25437
25431
  }).catch(() => {
@@ -26246,6 +26240,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
26246
26240
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
26247
26241
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26248
26242
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26243
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26249
26244
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26250
26245
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26251
26246
  });
@@ -26265,6 +26260,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
26265
26260
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
26266
26261
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26267
26262
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26263
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26268
26264
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26269
26265
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26270
26266
  }
@@ -26427,6 +26423,7 @@ function taskInput(input) {
26427
26423
  status: input.metricStatus ?? "pending",
26428
26424
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26429
26425
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26426
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26430
26427
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26431
26428
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26432
26429
  }
@@ -27116,7 +27113,7 @@ function serializeKanbanOutput(output, input) {
27116
27113
 
27117
27114
  // src/kanban-tool-schema.ts
27118
27115
  var KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
27119
- var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.';
27116
+ var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection "at_most" with add_goal_metric / update_goal_metric so verification compares current <= target instead.';
27120
27117
  var KANBAN_INPUT_SCHEMA = {
27121
27118
  type: "object",
27122
27119
  properties: {
@@ -27325,6 +27322,7 @@ var KANBAN_INPUT_SCHEMA = {
27325
27322
  metricName: { type: "string" },
27326
27323
  metricTarget: { oneOf: [{ type: "string" }, { type: "number" }] },
27327
27324
  metricCurrent: { oneOf: [{ type: "string" }, { type: "number" }] },
27325
+ metricDirection: { type: "string", enum: ["at_least", "at_most"] },
27328
27326
  metricUnit: { type: "string" },
27329
27327
  metricStatus: { type: "string", enum: ["pending", "met", "missed", "waived"] },
27330
27328
  metricNotes: { type: "string" },
package/dist/index.js CHANGED
@@ -25594,13 +25594,7 @@ function broadcastTodoUpdate(context, todos) {
25594
25594
  to: `@session:${sessionId}`,
25595
25595
  type: "status",
25596
25596
  subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
25597
- body: JSON.stringify({
25598
- kind: "kanban.todos.updated",
25599
- sessionId,
25600
- revision: context.state.revision,
25601
- todoCount: todos.length,
25602
- statusCounts
25603
- }),
25597
+ body: `Shared Kanban board synced this session's todo list: ${todos.length} item${todos.length === 1 ? "" : "s"} \u2014 ${statusCounts.completed} completed, ${statusCounts.inProgress} in progress, ${statusCounts.pending} pending.`,
25604
25598
  priority: "normal",
25605
25599
  senderSessionId: sessionId
25606
25600
  }).catch(() => {
@@ -26849,6 +26843,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
26849
26843
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
26850
26844
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26851
26845
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26846
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26852
26847
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26853
26848
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26854
26849
  });
@@ -26868,6 +26863,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
26868
26863
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
26869
26864
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26870
26865
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26866
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26871
26867
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26872
26868
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26873
26869
  }
@@ -27030,6 +27026,7 @@ function taskInput(input) {
27030
27026
  status: input.metricStatus ?? "pending",
27031
27027
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
27032
27028
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
27029
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
27033
27030
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
27034
27031
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
27035
27032
  }
@@ -27719,7 +27716,7 @@ function serializeKanbanOutput(output, input) {
27719
27716
 
27720
27717
  // src/kanban-tool-schema.ts
27721
27718
  var KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
27722
- var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.';
27719
+ var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection "at_most" with add_goal_metric / update_goal_metric so verification compares current <= target instead.';
27723
27720
  var KANBAN_INPUT_SCHEMA = {
27724
27721
  type: "object",
27725
27722
  properties: {
@@ -27928,6 +27925,7 @@ var KANBAN_INPUT_SCHEMA = {
27928
27925
  metricName: { type: "string" },
27929
27926
  metricTarget: { oneOf: [{ type: "string" }, { type: "number" }] },
27930
27927
  metricCurrent: { oneOf: [{ type: "string" }, { type: "number" }] },
27928
+ metricDirection: { type: "string", enum: ["at_least", "at_most"] },
27931
27929
  metricUnit: { type: "string" },
27932
27930
  metricStatus: { type: "string", enum: ["pending", "met", "missed", "waived"] },
27933
27931
  metricNotes: { type: "string" },
@@ -33,6 +33,7 @@ export declare function taskInput(input: KanbanToolInput): {
33
33
  status: "met" | "missed" | "pending" | "waived";
34
34
  target?: string | number;
35
35
  current?: string | number;
36
+ direction?: "at_least" | "at_most";
36
37
  unit?: string;
37
38
  notes?: string;
38
39
  }[];
@@ -1,5 +1,5 @@
1
1
  import type { JSONSchema } from '@wrongstack/core/types';
2
2
  export declare const KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
3
- export declare const KANBAN_TOOL_USAGE_HINT = "Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus \"passed\" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType (\"command\", \"test\", \"file_exists\", \"file_matches\", \"git_diff\", \"metric\") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or \"manual\") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.";
3
+ export declare const KANBAN_TOOL_USAGE_HINT = "Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus \"passed\" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType (\"command\", \"test\", \"file_exists\", \"file_matches\", \"git_diff\", \"metric\") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or \"manual\") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection \"at_most\" with add_goal_metric / update_goal_metric so verification compares current <= target instead.";
4
4
  export declare const KANBAN_INPUT_SCHEMA: JSONSchema;
5
5
  //# sourceMappingURL=kanban-tool-schema.d.ts.map
@@ -41,6 +41,8 @@ export interface KanbanToolInput extends Omit<AssignKanbanTaskInput, 'status'> {
41
41
  metricName?: string | undefined;
42
42
  metricTarget?: string | number | undefined;
43
43
  metricCurrent?: string | number | undefined;
44
+ /** Comparison direction for the goal metric: `at_least` (default) or `at_most`. */
45
+ metricDirection?: 'at_least' | 'at_most' | undefined;
44
46
  metricUnit?: string | undefined;
45
47
  metricStatus?: 'pending' | 'met' | 'missed' | 'waived' | undefined;
46
48
  metricNotes?: string | undefined;
package/dist/kanban.js CHANGED
@@ -721,6 +721,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
721
721
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
722
722
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
723
723
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
724
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
724
725
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
725
726
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
726
727
  });
@@ -740,6 +741,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
740
741
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
741
742
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
742
743
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
744
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
743
745
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
744
746
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
745
747
  }
@@ -902,6 +904,7 @@ function taskInput(input) {
902
904
  status: input.metricStatus ?? "pending",
903
905
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
904
906
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
907
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
905
908
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
906
909
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
907
910
  }
@@ -1591,7 +1594,7 @@ function serializeKanbanOutput(output, input) {
1591
1594
 
1592
1595
  // src/kanban-tool-schema.ts
1593
1596
  var KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
1594
- var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.';
1597
+ var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection "at_most" with add_goal_metric / update_goal_metric so verification compares current <= target instead.';
1595
1598
  var KANBAN_INPUT_SCHEMA = {
1596
1599
  type: "object",
1597
1600
  properties: {
@@ -1800,6 +1803,7 @@ var KANBAN_INPUT_SCHEMA = {
1800
1803
  metricName: { type: "string" },
1801
1804
  metricTarget: { oneOf: [{ type: "string" }, { type: "number" }] },
1802
1805
  metricCurrent: { oneOf: [{ type: "string" }, { type: "number" }] },
1806
+ metricDirection: { type: "string", enum: ["at_least", "at_most"] },
1803
1807
  metricUnit: { type: "string" },
1804
1808
  metricStatus: { type: "string", enum: ["pending", "met", "missed", "waived"] },
1805
1809
  metricNotes: { type: "string" },
package/dist/pack.js CHANGED
@@ -25425,13 +25425,7 @@ function broadcastTodoUpdate(context, todos) {
25425
25425
  to: `@session:${sessionId}`,
25426
25426
  type: "status",
25427
25427
  subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
25428
- body: JSON.stringify({
25429
- kind: "kanban.todos.updated",
25430
- sessionId,
25431
- revision: context.state.revision,
25432
- todoCount: todos.length,
25433
- statusCounts
25434
- }),
25428
+ body: `Shared Kanban board synced this session's todo list: ${todos.length} item${todos.length === 1 ? "" : "s"} \u2014 ${statusCounts.completed} completed, ${statusCounts.inProgress} in progress, ${statusCounts.pending} pending.`,
25435
25429
  priority: "normal",
25436
25430
  senderSessionId: sessionId
25437
25431
  }).catch(() => {
@@ -26246,6 +26240,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
26246
26240
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
26247
26241
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26248
26242
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26243
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26249
26244
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26250
26245
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26251
26246
  });
@@ -26265,6 +26260,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
26265
26260
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
26266
26261
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26267
26262
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26263
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26268
26264
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26269
26265
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26270
26266
  }
@@ -26427,6 +26423,7 @@ function taskInput(input) {
26427
26423
  status: input.metricStatus ?? "pending",
26428
26424
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26429
26425
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26426
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26430
26427
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26431
26428
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26432
26429
  }
@@ -27116,7 +27113,7 @@ function serializeKanbanOutput(output, input) {
27116
27113
 
27117
27114
  // src/kanban-tool-schema.ts
27118
27115
  var KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
27119
- var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.';
27116
+ var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection "at_most" with add_goal_metric / update_goal_metric so verification compares current <= target instead.';
27120
27117
  var KANBAN_INPUT_SCHEMA = {
27121
27118
  type: "object",
27122
27119
  properties: {
@@ -27325,6 +27322,7 @@ var KANBAN_INPUT_SCHEMA = {
27325
27322
  metricName: { type: "string" },
27326
27323
  metricTarget: { oneOf: [{ type: "string" }, { type: "number" }] },
27327
27324
  metricCurrent: { oneOf: [{ type: "string" }, { type: "number" }] },
27325
+ metricDirection: { type: "string", enum: ["at_least", "at_most"] },
27328
27326
  metricUnit: { type: "string" },
27329
27327
  metricStatus: { type: "string", enum: ["pending", "met", "missed", "waived"] },
27330
27328
  metricNotes: { type: "string" },
package/dist/plan.js CHANGED
@@ -226,13 +226,7 @@ function broadcastTodoUpdate(context, todos) {
226
226
  to: `@session:${sessionId}`,
227
227
  type: "status",
228
228
  subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
229
- body: JSON.stringify({
230
- kind: "kanban.todos.updated",
231
- sessionId,
232
- revision: context.state.revision,
233
- todoCount: todos.length,
234
- statusCounts
235
- }),
229
+ body: `Shared Kanban board synced this session's todo list: ${todos.length} item${todos.length === 1 ? "" : "s"} \u2014 ${statusCounts.completed} completed, ${statusCounts.inProgress} in progress, ${statusCounts.pending} pending.`,
236
230
  priority: "normal",
237
231
  senderSessionId: sessionId
238
232
  }).catch(() => {
@@ -1193,6 +1187,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
1193
1187
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
1194
1188
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1195
1189
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1190
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1196
1191
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1197
1192
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1198
1193
  });
@@ -1212,6 +1207,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
1212
1207
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
1213
1208
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1214
1209
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1210
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1215
1211
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1216
1212
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1217
1213
  }
@@ -1374,6 +1370,7 @@ function taskInput(input) {
1374
1370
  status: input.metricStatus ?? "pending",
1375
1371
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1376
1372
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1373
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1377
1374
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1378
1375
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1379
1376
  }
@@ -2063,7 +2060,7 @@ function serializeKanbanOutput(output, input) {
2063
2060
 
2064
2061
  // src/kanban-tool-schema.ts
2065
2062
  var KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
2066
- var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.';
2063
+ var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection "at_most" with add_goal_metric / update_goal_metric so verification compares current <= target instead.';
2067
2064
  var KANBAN_INPUT_SCHEMA = {
2068
2065
  type: "object",
2069
2066
  properties: {
@@ -2272,6 +2269,7 @@ var KANBAN_INPUT_SCHEMA = {
2272
2269
  metricName: { type: "string" },
2273
2270
  metricTarget: { oneOf: [{ type: "string" }, { type: "number" }] },
2274
2271
  metricCurrent: { oneOf: [{ type: "string" }, { type: "number" }] },
2272
+ metricDirection: { type: "string", enum: ["at_least", "at_most"] },
2275
2273
  metricUnit: { type: "string" },
2276
2274
  metricStatus: { type: "string", enum: ["pending", "met", "missed", "waived"] },
2277
2275
  metricNotes: { type: "string" },
@@ -213,13 +213,7 @@ function broadcastTodoUpdate(context, todos) {
213
213
  to: `@session:${sessionId}`,
214
214
  type: "status",
215
215
  subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
216
- body: JSON.stringify({
217
- kind: "kanban.todos.updated",
218
- sessionId,
219
- revision: context.state.revision,
220
- todoCount: todos.length,
221
- statusCounts
222
- }),
216
+ body: `Shared Kanban board synced this session's todo list: ${todos.length} item${todos.length === 1 ? "" : "s"} \u2014 ${statusCounts.completed} completed, ${statusCounts.inProgress} in progress, ${statusCounts.pending} pending.`,
223
217
  priority: "normal",
224
218
  senderSessionId: sessionId
225
219
  }).catch(() => {
package/dist/task.js CHANGED
@@ -186,13 +186,7 @@ function broadcastTodoUpdate(context, todos) {
186
186
  to: `@session:${sessionId}`,
187
187
  type: "status",
188
188
  subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
189
- body: JSON.stringify({
190
- kind: "kanban.todos.updated",
191
- sessionId,
192
- revision: context.state.revision,
193
- todoCount: todos.length,
194
- statusCounts
195
- }),
189
+ body: `Shared Kanban board synced this session's todo list: ${todos.length} item${todos.length === 1 ? "" : "s"} \u2014 ${statusCounts.completed} completed, ${statusCounts.inProgress} in progress, ${statusCounts.pending} pending.`,
196
190
  priority: "normal",
197
191
  senderSessionId: sessionId
198
192
  }).catch(() => {
@@ -1153,6 +1147,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
1153
1147
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
1154
1148
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1155
1149
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1150
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1156
1151
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1157
1152
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1158
1153
  });
@@ -1172,6 +1167,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
1172
1167
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
1173
1168
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1174
1169
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1170
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1175
1171
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1176
1172
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1177
1173
  }
@@ -1334,6 +1330,7 @@ function taskInput(input) {
1334
1330
  status: input.metricStatus ?? "pending",
1335
1331
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1336
1332
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1333
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1337
1334
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1338
1335
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1339
1336
  }
@@ -2023,7 +2020,7 @@ function serializeKanbanOutput(output, input) {
2023
2020
 
2024
2021
  // src/kanban-tool-schema.ts
2025
2022
  var KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
2026
- var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.';
2023
+ var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection "at_most" with add_goal_metric / update_goal_metric so verification compares current <= target instead.';
2027
2024
  var KANBAN_INPUT_SCHEMA = {
2028
2025
  type: "object",
2029
2026
  properties: {
@@ -2232,6 +2229,7 @@ var KANBAN_INPUT_SCHEMA = {
2232
2229
  metricName: { type: "string" },
2233
2230
  metricTarget: { oneOf: [{ type: "string" }, { type: "number" }] },
2234
2231
  metricCurrent: { oneOf: [{ type: "string" }, { type: "number" }] },
2232
+ metricDirection: { type: "string", enum: ["at_least", "at_most"] },
2235
2233
  metricUnit: { type: "string" },
2236
2234
  metricStatus: { type: "string", enum: ["pending", "met", "missed", "waived"] },
2237
2235
  metricNotes: { type: "string" },
package/dist/todo.js CHANGED
@@ -335,13 +335,7 @@ function broadcastTodoUpdate(context, todos) {
335
335
  to: `@session:${sessionId}`,
336
336
  type: "status",
337
337
  subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
338
- body: JSON.stringify({
339
- kind: "kanban.todos.updated",
340
- sessionId,
341
- revision: context.state.revision,
342
- todoCount: todos.length,
343
- statusCounts
344
- }),
338
+ body: `Shared Kanban board synced this session's todo list: ${todos.length} item${todos.length === 1 ? "" : "s"} \u2014 ${statusCounts.completed} completed, ${statusCounts.inProgress} in progress, ${statusCounts.pending} pending.`,
345
339
  priority: "normal",
346
340
  senderSessionId: sessionId
347
341
  }).catch(() => {
@@ -1140,6 +1134,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
1140
1134
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
1141
1135
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1142
1136
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1137
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1143
1138
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1144
1139
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1145
1140
  });
@@ -1159,6 +1154,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
1159
1154
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
1160
1155
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1161
1156
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1157
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1162
1158
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1163
1159
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1164
1160
  }
@@ -1321,6 +1317,7 @@ function taskInput(input) {
1321
1317
  status: input.metricStatus ?? "pending",
1322
1318
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
1323
1319
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
1320
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
1324
1321
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
1325
1322
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
1326
1323
  }
@@ -2010,7 +2007,7 @@ function serializeKanbanOutput(output, input) {
2010
2007
 
2011
2008
  // src/kanban-tool-schema.ts
2012
2009
  var KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
2013
- var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.';
2010
+ var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection "at_most" with add_goal_metric / update_goal_metric so verification compares current <= target instead.';
2014
2011
  var KANBAN_INPUT_SCHEMA = {
2015
2012
  type: "object",
2016
2013
  properties: {
@@ -2219,6 +2216,7 @@ var KANBAN_INPUT_SCHEMA = {
2219
2216
  metricName: { type: "string" },
2220
2217
  metricTarget: { oneOf: [{ type: "string" }, { type: "number" }] },
2221
2218
  metricCurrent: { oneOf: [{ type: "string" }, { type: "number" }] },
2219
+ metricDirection: { type: "string", enum: ["at_least", "at_most"] },
2222
2220
  metricUnit: { type: "string" },
2223
2221
  metricStatus: { type: "string", enum: ["pending", "met", "missed", "waived"] },
2224
2222
  metricNotes: { type: "string" },
package/dist/tool-tier.js CHANGED
@@ -25425,13 +25425,7 @@ function broadcastTodoUpdate(context, todos) {
25425
25425
  to: `@session:${sessionId}`,
25426
25426
  type: "status",
25427
25427
  subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? "" : "s"})`,
25428
- body: JSON.stringify({
25429
- kind: "kanban.todos.updated",
25430
- sessionId,
25431
- revision: context.state.revision,
25432
- todoCount: todos.length,
25433
- statusCounts
25434
- }),
25428
+ body: `Shared Kanban board synced this session's todo list: ${todos.length} item${todos.length === 1 ? "" : "s"} \u2014 ${statusCounts.completed} completed, ${statusCounts.inProgress} in progress, ${statusCounts.pending} pending.`,
25435
25429
  priority: "normal",
25436
25430
  senderSessionId: sessionId
25437
25431
  }).catch(() => {
@@ -26246,6 +26240,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
26246
26240
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
26247
26241
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26248
26242
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26243
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26249
26244
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26250
26245
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26251
26246
  });
@@ -26265,6 +26260,7 @@ async function handleKanbanDetailAction(projectRoot, input) {
26265
26260
  ...input.metricStatus !== void 0 ? { status: input.metricStatus } : {},
26266
26261
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26267
26262
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26263
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26268
26264
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26269
26265
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26270
26266
  }
@@ -26427,6 +26423,7 @@ function taskInput(input) {
26427
26423
  status: input.metricStatus ?? "pending",
26428
26424
  ...input.metricTarget !== void 0 ? { target: input.metricTarget } : {},
26429
26425
  ...input.metricCurrent !== void 0 ? { current: input.metricCurrent } : {},
26426
+ ...input.metricDirection !== void 0 ? { direction: input.metricDirection } : {},
26430
26427
  ...input.metricUnit !== void 0 ? { unit: input.metricUnit } : {},
26431
26428
  ...input.metricNotes !== void 0 ? { notes: input.metricNotes } : {}
26432
26429
  }
@@ -27116,7 +27113,7 @@ function serializeKanbanOutput(output, input) {
27116
27113
 
27117
27114
  // src/kanban-tool-schema.ts
27118
27115
  var KANBAN_TOOL_DESCRIPTION = "Durable project task boards: create and move cards, record checks, notes, links and assignments. The board is a record of the work, not a permit for it \u2014 nothing here gates other tools. Managed boards additionally enforce ordered Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions; release_managed_lifecycle turns that off.";
27119
- var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything.';
27116
+ var KANBAN_TOOL_USAGE_HINT = 'Track substantial or multi-step work so it survives the session; a trivial edit or a question needs no card. Work stays on ONE board: call list_boards first and add_task to the board this project already uses. create_board is for a genuinely separate line of work, not for each new piece of it \u2014 a second board splits the same effort in two, and a board holding a single card is the usual sign. Common flow: list_boards or search_tasks to orient, add_task to record work, start_task when you begin, update_check with checkStatus "passed" to tick acceptance criteria (read their ids from get_task), then transition_task. On a managed board a refused transition names the field it wants \u2014 supply it and retry. When the acceptance criterion is something a machine can run, say so: set checkType ("command", "test", "file_exists", "file_matches", "git_diff", "metric") and put the command, pattern or path in checkNotes, then verify_completion executes it and the result is real evidence. Leave checkType off (or "manual") only for criteria that genuinely need a human eye \u2014 a manual check records your assertion, it does not test anything. Goal metrics pass when current >= target by default; when lower is better (error rate, cost ceiling, latency, open-bug count), pass metricDirection "at_most" with add_goal_metric / update_goal_metric so verification compares current <= target instead.';
27120
27117
  var KANBAN_INPUT_SCHEMA = {
27121
27118
  type: "object",
27122
27119
  properties: {
@@ -27325,6 +27322,7 @@ var KANBAN_INPUT_SCHEMA = {
27325
27322
  metricName: { type: "string" },
27326
27323
  metricTarget: { oneOf: [{ type: "string" }, { type: "number" }] },
27327
27324
  metricCurrent: { oneOf: [{ type: "string" }, { type: "number" }] },
27325
+ metricDirection: { type: "string", enum: ["at_least", "at_most"] },
27328
27326
  metricUnit: { type: "string" },
27329
27327
  metricStatus: { type: "string", enum: ["pending", "met", "missed", "waived"] },
27330
27328
  metricNotes: { type: "string" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/tools",
3
- "version": "0.308.6",
3
+ "version": "0.309.0",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack built-in tools: read/write/edit, bash/exec, grep/glob, git, fetch, test, lint, and more.",
6
6
  "repository": {
@@ -253,9 +253,9 @@
253
253
  "turndown": "^7.2.4",
254
254
  "undici": "^8.10.0",
255
255
  "web-tree-sitter": "0.26.12",
256
- "@wrongstack/kanban": "0.308.6",
257
- "@wrongstack/core": "0.308.6",
258
- "@wrongstack/persistence": "0.308.6"
256
+ "@wrongstack/core": "0.309.0",
257
+ "@wrongstack/persistence": "0.309.0",
258
+ "@wrongstack/kanban": "0.309.0"
259
259
  },
260
260
  "devDependencies": {
261
261
  "@types/node": "^26.2.0",