@wrongstack/tools 0.293.0 → 0.295.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.
Files changed (248) hide show
  1. package/dist/_env.d.ts +1 -1
  2. package/dist/_env.d.ts.map +1 -1
  3. package/dist/_fetch-guard.d.ts.map +1 -1
  4. package/dist/_spawn-stream.d.ts +1 -1
  5. package/dist/_spawn-stream.d.ts.map +1 -1
  6. package/dist/_util.d.ts +1 -1
  7. package/dist/_util.d.ts.map +1 -1
  8. package/dist/audit.d.ts +1 -1
  9. package/dist/audit.d.ts.map +1 -1
  10. package/dist/audit.js +81 -16
  11. package/dist/audit.js.map +2 -2
  12. package/dist/bash.d.ts +1 -1
  13. package/dist/bash.d.ts.map +1 -1
  14. package/dist/bash.js +66 -52
  15. package/dist/bash.js.map +3 -3
  16. package/dist/batch-tool-use.d.ts +1 -1
  17. package/dist/batch-tool-use.d.ts.map +1 -1
  18. package/dist/batch-tool-use.js +1 -1
  19. package/dist/batch-tool-use.js.map +1 -1
  20. package/dist/browser/index.js +10 -1
  21. package/dist/browser/index.js.map +2 -2
  22. package/dist/browser/manager.d.ts +2 -0
  23. package/dist/browser/manager.d.ts.map +1 -1
  24. package/dist/browser/tools.d.ts +1 -1
  25. package/dist/browser/tools.d.ts.map +1 -1
  26. package/dist/builtin.d.ts +1 -1
  27. package/dist/builtin.d.ts.map +1 -1
  28. package/dist/builtin.js +1394 -553
  29. package/dist/builtin.js.map +4 -4
  30. package/dist/codebase-index/background-indexer.d.ts +2 -2
  31. package/dist/codebase-index/background-indexer.d.ts.map +1 -1
  32. package/dist/codebase-index/bm25.d.ts +3 -1
  33. package/dist/codebase-index/bm25.d.ts.map +1 -1
  34. package/dist/codebase-index/codebase-index-tool.d.ts +1 -1
  35. package/dist/codebase-index/codebase-index-tool.d.ts.map +1 -1
  36. package/dist/codebase-index/codebase-search-tool.d.ts +1 -1
  37. package/dist/codebase-index/codebase-search-tool.d.ts.map +1 -1
  38. package/dist/codebase-index/codebase-stats-tool.d.ts +1 -1
  39. package/dist/codebase-index/codebase-stats-tool.d.ts.map +1 -1
  40. package/dist/codebase-index/generic-parser.d.ts +34 -0
  41. package/dist/codebase-index/generic-parser.d.ts.map +1 -0
  42. package/dist/codebase-index/go-parser.d.ts +1 -1
  43. package/dist/codebase-index/go-parser.d.ts.map +1 -1
  44. package/dist/codebase-index/index.d.ts +4 -2
  45. package/dist/codebase-index/index.d.ts.map +1 -1
  46. package/dist/codebase-index/index.js +1036 -341
  47. package/dist/codebase-index/index.js.map +4 -4
  48. package/dist/codebase-index/indexer.d.ts +6 -1
  49. package/dist/codebase-index/indexer.d.ts.map +1 -1
  50. package/dist/codebase-index/json-parser.d.ts +1 -1
  51. package/dist/codebase-index/languages.d.ts +25 -0
  52. package/dist/codebase-index/languages.d.ts.map +1 -0
  53. package/dist/codebase-index/py-parser.d.ts +9 -1
  54. package/dist/codebase-index/py-parser.d.ts.map +1 -1
  55. package/dist/codebase-index/refs-extractor.d.ts.map +1 -1
  56. package/dist/codebase-index/rs-parser.d.ts +1 -1
  57. package/dist/codebase-index/rs-parser.d.ts.map +1 -1
  58. package/dist/codebase-index/schema.d.ts +9 -2
  59. package/dist/codebase-index/schema.d.ts.map +1 -1
  60. package/dist/codebase-index/spawn-gate.d.ts +15 -0
  61. package/dist/codebase-index/spawn-gate.d.ts.map +1 -0
  62. package/dist/codebase-index/ts-parser.d.ts +2 -2
  63. package/dist/codebase-index/ts-parser.d.ts.map +1 -1
  64. package/dist/codebase-index/worker.js +961 -317
  65. package/dist/codebase-index/worker.js.map +4 -4
  66. package/dist/codebase-index/writer.d.ts +83 -4
  67. package/dist/codebase-index/writer.d.ts.map +1 -1
  68. package/dist/codebase-index/yaml-parser.d.ts +1 -1
  69. package/dist/design.d.ts +5 -2
  70. package/dist/design.d.ts.map +1 -1
  71. package/dist/design.js +36 -3
  72. package/dist/design.js.map +2 -2
  73. package/dist/diff.d.ts +1 -1
  74. package/dist/diff.d.ts.map +1 -1
  75. package/dist/diff.js +2 -2
  76. package/dist/diff.js.map +1 -1
  77. package/dist/document.d.ts +1 -1
  78. package/dist/document.d.ts.map +1 -1
  79. package/dist/document.js +1 -1
  80. package/dist/document.js.map +1 -1
  81. package/dist/e2e.d.ts +1 -1
  82. package/dist/e2e.d.ts.map +1 -1
  83. package/dist/e2e.js +1 -1
  84. package/dist/e2e.js.map +1 -1
  85. package/dist/edit.d.ts +1 -1
  86. package/dist/edit.d.ts.map +1 -1
  87. package/dist/edit.js +3 -3
  88. package/dist/edit.js.map +2 -2
  89. package/dist/exec.d.ts +1 -1
  90. package/dist/exec.d.ts.map +1 -1
  91. package/dist/exec.js +60 -21
  92. package/dist/exec.js.map +3 -3
  93. package/dist/fetch.d.ts +1 -1
  94. package/dist/fetch.d.ts.map +1 -1
  95. package/dist/fetch.js +4 -5
  96. package/dist/fetch.js.map +2 -2
  97. package/dist/format.d.ts +1 -1
  98. package/dist/format.d.ts.map +1 -1
  99. package/dist/format.js +81 -16
  100. package/dist/format.js.map +2 -2
  101. package/dist/git.d.ts +1 -1
  102. package/dist/git.d.ts.map +1 -1
  103. package/dist/git.js +3 -2
  104. package/dist/git.js.map +2 -2
  105. package/dist/glob.d.ts +1 -1
  106. package/dist/glob.d.ts.map +1 -1
  107. package/dist/glob.js +2 -2
  108. package/dist/glob.js.map +1 -1
  109. package/dist/grep.d.ts +1 -1
  110. package/dist/grep.d.ts.map +1 -1
  111. package/dist/grep.js +4 -3
  112. package/dist/grep.js.map +2 -2
  113. package/dist/index.d.ts +4 -4
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +1657 -705
  116. package/dist/index.js.map +4 -4
  117. package/dist/install.d.ts +1 -1
  118. package/dist/install.d.ts.map +1 -1
  119. package/dist/install.js +85 -17
  120. package/dist/install.js.map +2 -2
  121. package/dist/json.d.ts +1 -1
  122. package/dist/json.d.ts.map +1 -1
  123. package/dist/json.js +2 -2
  124. package/dist/json.js.map +2 -2
  125. package/dist/kanban.d.ts +4 -3
  126. package/dist/kanban.d.ts.map +1 -1
  127. package/dist/kanban.js +94 -27
  128. package/dist/kanban.js.map +2 -2
  129. package/dist/languages/execute-tool.d.ts +1 -1
  130. package/dist/languages/execute-tool.d.ts.map +1 -1
  131. package/dist/languages/execute.d.ts +1 -1
  132. package/dist/languages/execute.d.ts.map +1 -1
  133. package/dist/languages/index.d.ts +1 -1
  134. package/dist/languages/index.d.ts.map +1 -1
  135. package/dist/languages/index.js +99 -17
  136. package/dist/languages/index.js.map +2 -2
  137. package/dist/languages/package-tool.d.ts +3 -4
  138. package/dist/languages/package-tool.d.ts.map +1 -1
  139. package/dist/languages/plan.d.ts.map +1 -1
  140. package/dist/languages/profiles/additional.d.ts.map +1 -1
  141. package/dist/languages/profiles/primary.d.ts.map +1 -1
  142. package/dist/languages/tool.d.ts +1 -1
  143. package/dist/languages/tool.d.ts.map +1 -1
  144. package/dist/lint.d.ts +1 -1
  145. package/dist/lint.d.ts.map +1 -1
  146. package/dist/lint.js +81 -16
  147. package/dist/lint.js.map +2 -2
  148. package/dist/logs.d.ts +1 -1
  149. package/dist/logs.d.ts.map +1 -1
  150. package/dist/logs.js +2 -2
  151. package/dist/logs.js.map +1 -1
  152. package/dist/memory.d.ts +1 -1
  153. package/dist/memory.d.ts.map +1 -1
  154. package/dist/memory.js +1 -1
  155. package/dist/memory.js.map +1 -1
  156. package/dist/mode.d.ts +1 -1
  157. package/dist/mode.d.ts.map +1 -1
  158. package/dist/mode.js.map +1 -1
  159. package/dist/outdated.d.ts +1 -1
  160. package/dist/outdated.d.ts.map +1 -1
  161. package/dist/outdated.js +101 -19
  162. package/dist/outdated.js.map +2 -2
  163. package/dist/pack.d.ts +1 -1
  164. package/dist/pack.js +1394 -553
  165. package/dist/pack.js.map +4 -4
  166. package/dist/patch.d.ts +1 -1
  167. package/dist/patch.d.ts.map +1 -1
  168. package/dist/patch.js +2 -2
  169. package/dist/patch.js.map +1 -1
  170. package/dist/plan.d.ts +1 -1
  171. package/dist/plan.d.ts.map +1 -1
  172. package/dist/plan.js +7 -7
  173. package/dist/plan.js.map +2 -2
  174. package/dist/process-guardian.d.ts +7 -0
  175. package/dist/process-guardian.d.ts.map +1 -1
  176. package/dist/process-registry-persistent.d.ts +5 -0
  177. package/dist/process-registry-persistent.d.ts.map +1 -1
  178. package/dist/process-registry.d.ts +9 -1
  179. package/dist/process-registry.d.ts.map +1 -1
  180. package/dist/process-registry.js +18 -3
  181. package/dist/process-registry.js.map +2 -2
  182. package/dist/ps-slash.js +54 -15
  183. package/dist/ps-slash.js.map +2 -2
  184. package/dist/read.d.ts +1 -1
  185. package/dist/read.d.ts.map +1 -1
  186. package/dist/read.js +3 -2
  187. package/dist/read.js.map +2 -2
  188. package/dist/replace.d.ts +1 -1
  189. package/dist/replace.d.ts.map +1 -1
  190. package/dist/replace.js +4 -4
  191. package/dist/replace.js.map +2 -2
  192. package/dist/scaffold.d.ts +1 -1
  193. package/dist/scaffold.d.ts.map +1 -1
  194. package/dist/scaffold.js +2 -2
  195. package/dist/scaffold.js.map +1 -1
  196. package/dist/search.d.ts +1 -1
  197. package/dist/search.d.ts.map +1 -1
  198. package/dist/search.js +4 -4
  199. package/dist/search.js.map +2 -2
  200. package/dist/session-kanban.d.ts +4 -1
  201. package/dist/session-kanban.d.ts.map +1 -1
  202. package/dist/session-kanban.js +23 -15
  203. package/dist/session-kanban.js.map +2 -2
  204. package/dist/set-working-dir.d.ts +1 -1
  205. package/dist/set-working-dir.d.ts.map +1 -1
  206. package/dist/skill.d.ts +1 -1
  207. package/dist/skill.d.ts.map +1 -1
  208. package/dist/skill.js +2 -5
  209. package/dist/skill.js.map +2 -2
  210. package/dist/spawn-background.d.ts.map +1 -1
  211. package/dist/task.d.ts +3 -2
  212. package/dist/task.d.ts.map +1 -1
  213. package/dist/task.js +6 -8
  214. package/dist/task.js.map +2 -2
  215. package/dist/test.d.ts +1 -1
  216. package/dist/test.d.ts.map +1 -1
  217. package/dist/test.js +81 -16
  218. package/dist/test.js.map +2 -2
  219. package/dist/todo.d.ts +2 -1
  220. package/dist/todo.d.ts.map +1 -1
  221. package/dist/todo.js +4 -4
  222. package/dist/todo.js.map +2 -2
  223. package/dist/tool-help.d.ts +1 -1
  224. package/dist/tool-help.d.ts.map +1 -1
  225. package/dist/tool-help.js.map +1 -1
  226. package/dist/tool-search.d.ts +1 -1
  227. package/dist/tool-search.d.ts.map +1 -1
  228. package/dist/tool-search.js.map +1 -1
  229. package/dist/tool-tier.d.ts +16 -0
  230. package/dist/tool-tier.d.ts.map +1 -0
  231. package/dist/tool-tier.js +22233 -0
  232. package/dist/tool-tier.js.map +7 -0
  233. package/dist/tool-use.d.ts +1 -1
  234. package/dist/tool-use.d.ts.map +1 -1
  235. package/dist/tool-use.js.map +1 -1
  236. package/dist/tree.d.ts +1 -1
  237. package/dist/tree.d.ts.map +1 -1
  238. package/dist/tree.js +2 -2
  239. package/dist/tree.js.map +1 -1
  240. package/dist/typecheck.d.ts +1 -1
  241. package/dist/typecheck.d.ts.map +1 -1
  242. package/dist/typecheck.js +81 -16
  243. package/dist/typecheck.js.map +2 -2
  244. package/dist/write.d.ts +1 -1
  245. package/dist/write.d.ts.map +1 -1
  246. package/dist/write.js +3 -2
  247. package/dist/write.js.map +2 -2
  248. package/package.json +7 -3
package/dist/json.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Tool } from '@wrongstack/core';
1
+ import type { Tool } from '@wrongstack/core/types';
2
2
  type JsonAction = 'parse' | 'query' | 'validate' | 'transform' | 'merge';
3
3
  interface JsonInput {
4
4
  /** Operation to perform. Defaults to 'parse'. */
@@ -1 +1 @@
1
- {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAOtD,KAAK,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;AAEzE,UAAU,SAAS;IACjB,iDAAiD;IACjD,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAGhC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAG/C,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAG/B,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAGlC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAG7C,6BAA6B;IAC7B,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,aAAa,GAAG,cAAc,GAAG,SAAS,CAAC;CACjE;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC;IAClE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,eAAO,MAAM,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CA2EhD,CAAC"}
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAOnD,KAAK,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;AAEzE,UAAU,SAAS;IACjB,iDAAiD;IACjD,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAGhC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAG/C,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAG/B,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAGlC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAG7C,6BAA6B;IAC7B,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,aAAa,GAAG,cAAc,GAAG,SAAS,CAAC;CACjE;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC;IAClE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,eAAO,MAAM,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CA2EhD,CAAC"}
package/dist/json.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // src/json.ts
2
2
  import * as fs from "node:fs/promises";
3
- import { deepMerge as deepMergeCore } from "@wrongstack/core";
3
+ import { deepMerge as deepMergeCore } from "@wrongstack/core/utils";
4
4
 
5
5
  // src/_util.ts
6
6
  import * as fsp from "node:fs/promises";
7
7
  import * as path from "node:path";
8
- import * as Core from "@wrongstack/core";
8
+ import * as Core from "@wrongstack/core/utils";
9
9
  function resolvePath(input, ctx) {
10
10
  return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);
11
11
  }
package/dist/json.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/json.ts", "../src/_util.ts"],
4
- "sourcesContent": ["import * as fs from 'node:fs/promises';\nimport { deepMerge as deepMergeCore } from '@wrongstack/core';\nimport type { Context, Tool } from '@wrongstack/core';\nimport { safeResolveReal } from './_util.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype JsonAction = 'parse' | 'query' | 'validate' | 'transform' | 'merge';\n\ninterface JsonInput {\n /** Operation to perform. Defaults to 'parse'. */\n action?: JsonAction | undefined;\n\n // --- parse / query / validate (single data source) ---\n /** Path to JSON/JSON5/YAML file (alternative to `data`). */\n file?: string | undefined;\n /** Inline JSON/JSON5/YAML string (alternative to `file`). */\n data?: string | undefined;\n /** Output format for parse/query/transform results. */\n format?: 'json' | 'json5' | 'yaml' | undefined;\n\n // --- parse: validate syntax only ---\n validate?: boolean | undefined;\n\n // --- query / transform ---\n /** JMESPath-like query expression. */\n query?: string | undefined;\n /** Ordered JMESPath transforms (transform action only). */\n transforms?: string[] | undefined;\n\n // --- validate against schema ---\n /** JSON Schema to validate against. */\n schema?: Record<string, unknown> | undefined;\n\n // --- merge ---\n /** Base object for merge. */\n base?: unknown | undefined;\n /** Patch object for merge. */\n patch?: unknown | undefined;\n /** Merge conflict resolution: 'prefer-patch' (default) or 'prefer-base'. */\n conflictResolution?: 'prefer-base' | 'prefer-patch' | undefined;\n}\n\ninterface JsonOutput {\n data: unknown;\n formatted: string;\n type: string;\n action: string;\n keys?: string[] | undefined;\n query_result?: unknown | undefined;\n result?: unknown | undefined;\n valid?: boolean | undefined;\n errors?: string[] | undefined;\n steps?: Array<{ transform: string; result: unknown }> | undefined;\n error?: string | undefined;\n}\n\nexport const jsonTool: Tool<JsonInput, JsonOutput> = {\n name: 'json',\n category: 'Data',\n description:\n 'Parse, pretty-print, query, validate, transform, and merge JSON/JSON5/YAML. Use `action` to select the operation: parse (default), query, validate, transform, or merge.',\n usageHint:\n 'VERY USEFUL FOR DATA INSPECTION:\\n\\n' +\n '- `action: \"parse\"` (default): read/pretty-print/convert JSON, JSON5, or YAML from `file` or `data`.\\n' +\n '- `action: \"query\"`: JMESPath-like query (`a.b[0].c`, `items[*].name`, filters, functions).\\n' +\n '- `action: \"validate\"`: validate data against a JSON Schema (`schema` param).\\n' +\n '- `action: \"transform\"`: chain multiple JMESPath transforms (`transforms` param).\\n' +\n '- `action: \"merge\"`: deep merge `base` and `patch` objects (`conflictResolution` param).\\n' +\n 'Prefer this over raw `read` + manual parsing when dealing with configuration or data files.',\n permission: 'auto',\n mutating: false,\n timeoutMs: 5_000,\n capabilities: ['fs.read'],\n icon: 'json',\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['parse', 'query', 'validate', 'transform', 'merge'],\n description: 'Operation (default: parse). parse=read/pretty-print, query=JMESPath, validate=schema, transform=chained queries, merge=deep merge.',\n },\n file: { type: 'string', description: 'Path to JSON/JSON5/YAML file (parse/query/validate)' },\n data: { type: 'string', description: 'JSON/JSON5/YAML string (parse/query/validate, alternative to file)' },\n format: {\n type: 'string',\n enum: ['json', 'json5', 'yaml'],\n description: 'Output format for parse/query/transform (default: json)',\n },\n query: {\n type: 'string',\n description: 'JMESPath-like query expression (query action)',\n },\n transforms: {\n type: 'array',\n items: { type: 'string' },\n description: 'Ordered JMESPath query strings (transform action)',\n },\n schema: {\n type: 'object',\n description: 'JSON Schema to validate against (validate action)',\n },\n base: { description: 'Base JSON object (merge action)' },\n patch: { description: 'Patch JSON object to merge in (merge action)' },\n conflictResolution: {\n type: 'string',\n enum: ['prefer-base', 'prefer-patch'],\n description: 'Merge conflict resolution (default: prefer-patch)',\n },\n validate: {\n type: 'boolean',\n description: 'Validate syntax only, no output (parse action, default: false)',\n },\n },\n },\n async execute(input, ctx) {\n const action = input.action ?? 'parse';\n\n switch (action) {\n case 'query':\n return executeQuery(input, ctx);\n case 'validate':\n return executeValidate(input, ctx);\n case 'transform':\n return executeTransform(input, ctx);\n case 'merge':\n return executeMerge(input);\n default:\n return executeParse(input, ctx);\n }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Action: parse (default \u2014 the original json tool behavior)\n// ---------------------------------------------------------------------------\n\nasync function executeParse(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n const format = input.format ?? 'json';\n\n let parsed: unknown;\n let raw: string;\n\n if (input.file) {\n try {\n raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'parse', error: 'Could not read file' };\n }\n } else if (input.data) {\n raw = input.data;\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'parse', error: 'Provide file or data' };\n }\n\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'parse',\n /* v8 ignore next -- JSON.parse only throws SyntaxError (an Error); the String(e) side is defensive. */\n error: `Parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n\n if (input.validate) {\n return {\n data: parsed,\n formatted: 'valid',\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n };\n }\n\n // Backward compat: if `query` is provided without an explicit action,\n // use the original simple path-based query (supports `a.b[0].c` notation).\n if (input.query) {\n const queryResult = simpleQuery(parsed, input.query);\n const formatted = formatOutput(queryResult, format);\n return {\n data: parsed,\n formatted,\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n query_result: queryResult,\n };\n }\n\n const formatted = formatOutput(parsed, format);\n\n return {\n data: parsed,\n formatted,\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Action: query (JMESPath-like \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeQuery(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.query) {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'query is required for action: query' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Provide file or data' };\n }\n\n try {\n const result = jmespathSearch(parsed, input.query);\n const format = input.format ?? 'json';\n return {\n data: parsed,\n formatted: formatOutput(result, format),\n type: result === null ? 'null' : Array.isArray(result) ? 'array' : typeof result,\n action: 'query',\n query_result: result,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'query',\n /* v8 ignore next -- defensive String(e) */\n error: `Query failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: validate (JSON Schema \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeValidate(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.schema) {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'schema is required for action: validate' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Provide file or data' };\n }\n\n try {\n const { valid, errors } = validateJsonSchema(parsed, input.schema as Record<string, unknown>);\n return {\n data: parsed,\n formatted: valid ? 'valid' : 'invalid',\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'validate',\n valid,\n errors,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'validate',\n /* v8 ignore next -- defensive String(e) */\n error: `Validation failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: transform (chained JMESPath \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeTransform(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.transforms || input.transforms.length === 0) {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'transforms array is required for action: transform' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Provide file or data' };\n }\n\n try {\n let current: unknown = parsed;\n const steps: Array<{ transform: string; result: unknown }> = [];\n\n for (const t of input.transforms) {\n current = jmespathSearch(current, t);\n steps.push({ transform: t, result: current });\n }\n\n const format = input.format ?? 'json';\n return {\n data: parsed,\n formatted: formatOutput(current, format),\n type: current === null ? 'null' : Array.isArray(current) ? 'array' : typeof current,\n action: 'transform',\n result: current,\n steps,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'transform',\n /* v8 ignore next -- defensive String(e) */\n error: `Transform failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: merge (deep merge \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeMerge(input: JsonInput): Promise<JsonOutput> {\n if (input.base === undefined || input.patch === undefined) {\n return { data: null, formatted: '', type: 'unknown', action: 'merge', error: 'base and patch are required for action: merge' };\n }\n\n const conflictResolution = input.conflictResolution ?? 'prefer-patch';\n\n try {\n const result = deepMergeCore(input.base, input.patch, { conflictResolution });\n const format = input.format ?? 'json';\n return {\n data: result,\n formatted: formatOutput(result, format),\n type: result === null ? 'null' : Array.isArray(result) ? 'array' : typeof result,\n action: 'merge',\n result,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'merge',\n /* v8 ignore next -- defensive String(e) */\n error: `Merge failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// JMESPath implementation (from json-path plugin)\n// ---------------------------------------------------------------------------\n\nfunction jmespathSearch(data: unknown, query: string): unknown {\n // Handle basic JMESPath expressions\n if (!query || query === '@') return data;\n\n // Root access\n if (query === '$') return data;\n\n // Dot notation: foo.bar\n const dotMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(?:\\.(.+))?$/);\n if (dotMatch) {\n const key = dotMatch[1]!;\n const rest = dotMatch[2];\n const val = (data as Record<string, unknown> | undefined)?.[key];\n if (rest === undefined) return val;\n return jmespathSearch(val, rest);\n }\n\n // Array access: [0]\n const arrMatch = query.match(/^\\[(\\d+)\\](?:\\.(.+))?$/);\n if (arrMatch) {\n const idx = Number.parseInt(arrMatch[1]!, 10);\n const rest = arrMatch[2];\n const arr = data as unknown[];\n const val = arr?.[idx];\n if (rest === undefined) return val;\n return jmespathSearch(val, rest);\n }\n\n // Wildcard: [*]\n if (query === '[*]') {\n if (Array.isArray(data)) {\n return data;\n }\n return data;\n }\n\n // Multi-select: foo.bar[*].baz\n const multiMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\\[\\*\\](?:\\.(.+))?$/);\n if (multiMatch) {\n const key = multiMatch[1]!;\n const rest = multiMatch[2];\n const arr = (data as Record<string, unknown[]> | undefined)?.[key];\n if (!Array.isArray(arr)) return [];\n if (rest === undefined) return arr;\n return arr.map((item) => jmespathSearch(item, rest));\n }\n\n // Filter: [?foo==`bar`]\n const filterMatch = query.match(/^\\[\\\\?([a-zA-Z_][a-zA-Z0-9_]*)(==|!=|<|>|<=|>=)(`[^`]+`|'[^']*')\\](?:\\.(.+))?$/);\n if (filterMatch) {\n const field = filterMatch[1]!;\n const op = filterMatch[2]!;\n const rawVal = filterMatch[3]!;\n const rest = filterMatch[4];\n const cmpVal = JSON.parse(rawVal.slice(1, -1));\n const arr = data as Record<string, unknown>[];\n if (!Array.isArray(arr)) return [];\n const filtered = arr.filter((item) => {\n const itemVal = (item as Record<string, unknown>)[field];\n switch (op) {\n case '==': return itemVal === cmpVal;\n case '!=': return itemVal !== cmpVal;\n case '>': return Number(itemVal) > Number(cmpVal);\n case '<': return Number(itemVal) < Number(cmpVal);\n case '>=': return Number(itemVal) >= Number(cmpVal);\n case '<=': return Number(itemVal) <= Number(cmpVal);\n /* v8 ignore next -- op is constrained to the six operators by the filter regex; default is unreachable. */\n default: return true;\n }\n });\n if (rest === undefined) return filtered;\n return filtered.map((item) => jmespathSearch(item, rest));\n }\n\n // Function calls: length(@)\n const fnMatch = query.match(/^(length|keys|values|type)\\(@\\)$/);\n if (fnMatch) {\n const fn = fnMatch[1]!;\n switch (fn) {\n case 'length':\n if (Array.isArray(data)) return data.length;\n if (typeof data === 'string') return data.length;\n if (typeof data === 'object' && data !== null) return Object.keys(data as object).length;\n return 0;\n case 'keys':\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) return Object.keys(data as object);\n return [];\n case 'values':\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) return Object.values(data as object);\n return [];\n case 'type':\n if (data === null) return 'null';\n if (Array.isArray(data)) return 'array';\n return typeof data;\n /* v8 ignore next 2 -- fn is constrained to the four names by the function regex; default is unreachable. */\n default:\n return null;\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema validator (from json-path plugin)\n// ---------------------------------------------------------------------------\n\nfunction validateJsonSchema(data: unknown, schema: Record<string, unknown>): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n function check(value: unknown, s: Record<string, unknown>, path: string): void {\n if (s['type']) {\n const expectedType = s['type'] as string;\n const actualType = Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value;\n if (expectedType === 'integer') {\n if (!Number.isInteger(value)) errors.push(`${path}: expected integer, got ${actualType}`);\n } else if (expectedType !== actualType) {\n errors.push(`${path}: expected ${expectedType}, got ${actualType}`);\n }\n }\n\n if (typeof value === 'string' && s['format'] === 'uri' && value) {\n try { new URL(value); } catch { errors.push(`${path}: not a valid URI`); }\n }\n\n if (typeof value === 'string' && s['pattern']) {\n const re = new RegExp(s['pattern'] as string);\n if (!re.test(value)) errors.push(`${path}: does not match pattern ${s['pattern']}`);\n }\n\n if (typeof value === 'string' && s['minLength'] !== undefined && value.length < (s['minLength'] as number)) {\n errors.push(`${path}: string too short (min ${s['minLength']})`);\n }\n\n if (typeof value === 'string' && s['maxLength'] !== undefined && value.length > (s['maxLength'] as number)) {\n errors.push(`${path}: string too long (max ${s['maxLength']})`);\n }\n\n if (typeof value === 'number' && s['minimum'] !== undefined && value < (s['minimum'] as number)) {\n errors.push(`${path}: below minimum ${s['minimum']}`);\n }\n\n if (typeof value === 'number' && s['maximum'] !== undefined && value > (s['maximum'] as number)) {\n errors.push(`${path}: above maximum ${s['maximum']}`);\n }\n\n if (Array.isArray(value) && s['items'] && Array.isArray(s['items'])) {\n for (let i = 0; i < value.length; i++) {\n check(value[i], s['items'] as never as Record<string, unknown>, `${path}[${i}]`);\n }\n }\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value) && s['properties']) {\n const props = s['properties'] as Record<string, Record<string, unknown>>;\n for (const [k, propSchema] of Object.entries(props)) {\n check((value as Record<string, unknown>)[k], propSchema, `${path}.${k}`);\n }\n }\n }\n\n check(data, schema, '$');\n return { valid: errors.length === 0, errors };\n}\n\n// ---------------------------------------------------------------------------\n// Simple path-based query (original json tool query, backward compat)\n// ---------------------------------------------------------------------------\n\nfunction simpleQuery(data: unknown, path: string): unknown {\n const parts = path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .filter(Boolean);\n let current: unknown = data;\n\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n\n const idx = Number(part);\n if (!Number.isNaN(idx) && Array.isArray(current)) {\n current = current[idx];\n } else if (typeof current === 'object' && current !== null) {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n\n return current;\n}\n\n// ---------------------------------------------------------------------------\n// Output formatting (original json tool helpers)\n// ---------------------------------------------------------------------------\n\nfunction formatOutput(data: unknown, format: string): string {\n if (format === 'json5') {\n return JSON.stringify(data, null, 2)\n .replace(/,\\s*}/g, '}')\n .replace(/,\\s*\\]/g, ']');\n }\n if (format === 'yaml') {\n return toYaml(data);\n }\n return JSON.stringify(data, null, 2);\n}\n\nfunction toYaml(data: unknown, indent = 0): string {\n if (data === null) return 'null\\n';\n /* v8 ignore next -- parsed JSON never contains `undefined`; defensive for recursive calls. */\n if (data === undefined) return '';\n if (typeof data === 'boolean') return String(data) + '\\n';\n if (typeof data === 'number') return String(data) + '\\n';\n if (typeof data === 'string') {\n if (data.includes('\\n') || data.includes(':') || data.includes('#')) {\n return `\"${data.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"\\n`;\n }\n return data + '\\n';\n }\n if (Array.isArray(data)) {\n if (data.length === 0) return '[]\\n';\n const prefix = ' '.repeat(indent);\n return data.map((item) => `${prefix}- ${toYaml(item, indent + 1).trimStart()}`).join('');\n }\n if (typeof data === 'object') {\n const prefix = ' '.repeat(indent);\n const entries = Object.entries(data as Record<string, unknown>);\n return entries.map(([k, v]) => `${prefix}${k}: ${toYaml(v, indent + 1)}`).join('');\n }\n /* v8 ignore next -- JSON.parse only yields null/bool/number/string/array/object; this fallback is defensive. */\n return String(data) + '\\n';\n}\n", "import { createHash } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as Core from '@wrongstack/core';\nimport type { Context } from '@wrongstack/core';\n\n/**\n * sha-256 hex of a UTF-8 string. Used by the file tools to record a content\n * hash alongside the mtime in `ctx.recordRead` \u2014 the hash is the authoritative\n * staleness arbiter for `edit` (mtime has a 2 s tolerance window on Windows).\n */\nexport function sha256hex(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n/** Detected package manager for a project directory. */\nexport type PackageManager = 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Detect the project's package manager by inspecting lockfiles in `cwd`.\n * Order: pnpm \u2192 yarn \u2192 npm (default). Missing or unreadable directories fall\n * back to `npm` rather than throwing, so a `safeResolve`-checked cwd that\n * happens to be empty never aborts the tool.\n */\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\n const { stat } = await import('node:fs/promises');\n try {\n await stat(`${cwd}/pnpm-lock.yaml`);\n return 'pnpm';\n } catch {\n /* not pnpm */\n }\n try {\n await stat(`${cwd}/yarn.lock`);\n return 'yarn';\n } catch {\n /* not yarn */\n }\n return 'npm';\n}\n\nexport function resolvePath(input: string, ctx: Context): string {\n return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);\n}\n\n/**\n * Roots every file tool may always reach, even in restricted mode: the\n * project root and the user-global `~/.wrongstack` directory (config, memory,\n * sessions, skills). `~/.wrongstack` honors the `WRONGSTACK_HOME` override.\n */\nfunction allowedRoots(ctx: Context): string[] {\n return [path.resolve(ctx.projectRoot), path.resolve(Core.wstackGlobalRoot())];\n}\n\n/** True if `target` is `root` itself or nested inside any of `roots`. */\nfunction isInsideAny(target: string, roots: string[]): boolean {\n return roots.some((root) => {\n const rel = path.relative(root, target);\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n });\n}\n\nexport function ensureInsideRoot(absPath: string, ctx: Context): string {\n const target = path.resolve(absPath);\n // Unrestricted filesystem access: skip the project-root containment check.\n if (ctx.allowOutsideProjectRoot) return target;\n if (isInsideAny(target, allowedRoots(ctx))) return target;\n throw new Error(`Path \"${absPath}\" is outside project root \"${path.resolve(ctx.projectRoot)}\"`);\n}\n\nexport function safeResolve(input: string, ctx: Context): string {\n return ensureInsideRoot(resolvePath(input, ctx), ctx);\n}\n\n/**\n * Defense against in-root\u2192out-of-root symlink escape (CWE-59). `safeResolve`\n * only does a syntactic `../` check, so a symlink that lives *inside* the\n * project root but points outside still passes it. This resolves the path\n * through `fs.realpath` and re-verifies containment against the realpath of\n * the project root (comparing like-for-like, since the root itself may be a\n * symlink \u2014 macOS `/var`\u2192`/private/var`, Windows 8.3 short names). For a path\n * that does not exist yet (e.g. a `write` to a new file) the nearest existing\n * ancestor directory is checked instead. Throws if the real target escapes.\n *\n * Mirrors the per-file guard already used in `replace.ts`/`grep.ts`; applied\n * to single-file `read`/`edit`/`write` it throws (rather than skips) because\n * the caller named exactly one file.\n */\nexport async function assertRealInsideRoot(absPath: string, ctx: Context): Promise<void> {\n // Unrestricted filesystem access: no symlink-escape check to perform.\n if (ctx.allowOutsideProjectRoot) return;\n // Compare like-for-like against the realpath of each always-allowed root\n // (project root + ~/.wrongstack), since a root may itself be a symlink.\n const realRoots = await Promise.all(\n allowedRoots(ctx).map((r) => fsp.realpath(r).catch(() => path.resolve(r))),\n );\n let probe = absPath;\n for (;;) {\n let real: string;\n try {\n real = await fsp.realpath(probe);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const parent = path.dirname(probe);\n if (parent === probe) return; // reached fs root without escaping\n probe = parent;\n continue;\n }\n throw err;\n }\n if (isInsideAny(real, realRoots)) return;\n throw new Error(\n `Path \"${absPath}\" resolves through a symlink outside project root \"${realRoots[0]}\"`,\n );\n }\n}\n\n/** `safeResolve` + symlink realpath containment check. Async. */\nexport async function safeResolveReal(input: string, ctx: Context): Promise<string> {\n const abs = safeResolve(input, ctx);\n await assertRealInsideRoot(abs, ctx);\n return abs;\n}\n\nexport function truncateMiddle(s: string, max: number): string {\n if (Buffer.byteLength(s, 'utf8') <= max) return s;\n const half = Math.floor(max / 2);\n return (\n s.slice(0, half) +\n `\\n\u2026[truncated ${Buffer.byteLength(s, 'utf8') - max} bytes from middle]\u2026\\n` +\n s.slice(-half)\n );\n}\n\nexport function isBinaryBuffer(buf: Buffer): boolean {\n const len = Math.min(buf.length, 8192);\n for (let i = 0; i < len; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n}\n\n// \u2500\u2500\u2500 Command-output normalization (token-saving) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Raw process output is full of tokens the model gains nothing from: ANSI\n// escapes, carriage-return progress spam, runs of identical warning lines, and\n// huge tails of build noise. These helpers strip that noise before the output\n// reaches the LLM. They are scoped to COMMAND tools (bash/git/exec and the\n// _spawn-stream consumers) \u2014 never applied to structured/code outputs.\n\n/** Unified byte cap for all command tool output fed to the model. */\nexport const COMMAND_OUTPUT_MAX_BYTES = 32_768;\n\n/** Runs of >= this many identical consecutive lines are collapsed. */\nconst REPEAT_RUN_THRESHOLD = 3;\n\n/**\n * Collapse carriage-return overwrites the way a terminal would: `\\r\\n` becomes\n * `\\n`, and a bare `\\r` (progress redraw) keeps only the text after the LAST\n * `\\r` on its physical line. Without this, a single progress bar that redraws\n * 200 times explodes into 200 lines.\n */\nexport function collapseCarriageReturns(text: string): string {\n const lf = text.replace(/\\r\\n/g, '\\n');\n if (!lf.includes('\\r')) return lf;\n return lf\n .split('\\n')\n .map((line) => (line.includes('\\r') ? line.slice(line.lastIndexOf('\\r') + 1) : line))\n .join('\\n');\n}\n\n/**\n * Collapse a run of `minRun`+ identical consecutive lines into the line once\n * plus a marker. Consecutive-only \u2014 it never reorders or dedups non-adjacent\n * lines, so diffs/source stay intact.\n */\nexport function collapseConsecutiveDuplicates(text: string, minRun = REPEAT_RUN_THRESHOLD): string {\n const lines = text.split('\\n');\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n let j = i + 1;\n while (j < lines.length && lines[j] === lines[i]) j++;\n const run = j - i;\n if (run >= minRun) {\n out.push(lines[i]!, `\u2026 \u27E8repeated ${run}\u00D7\u27E9`);\n } else {\n for (let k = i; k < j; k++) out.push(lines[k]!);\n }\n i = j;\n }\n return out.join('\\n');\n}\n\n/** Largest prefix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeHeadBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(0, mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(0, lo);\n}\n\n/** Largest suffix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeTailBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(s.length - mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(s.length - lo);\n}\n\n/**\n * Truncate to `maxBytes` keeping BOTH ends \u2014 the head (what ran / early context)\n * and the tail (errors and summaries usually land last), biased ~45/55 toward\n * the tail. The result never exceeds `maxBytes`.\n */\nexport function truncateHeadTail(s: string, maxBytes: number): string {\n const total = Buffer.byteLength(s, 'utf8');\n if (total <= maxBytes) return s;\n // Reserve a fixed allowance for the marker so the final string can't exceed\n // the cap even though the dropped-byte count's digit width varies.\n const MARKER_RESERVE = 64;\n const avail = Math.max(0, maxBytes - MARKER_RESERVE);\n const headBudget = Math.floor(avail * 0.45);\n const head = takeHeadBytes(s, headBudget);\n const tail = takeTailBytes(s, avail - Buffer.byteLength(head, 'utf8'));\n const kept = Buffer.byteLength(head, 'utf8') + Buffer.byteLength(tail, 'utf8');\n return `${head}\\n\u2026[truncated ${total - kept} bytes]\u2026\\n${tail}`;\n}\n\n/**\n * Full token-saving pipeline for command tool output: strip ANSI \u2192 collapse\n * carriage-return progress \u2192 trim trailing whitespace \u2192 collapse identical\n * consecutive lines \u2192 squeeze blank-line runs \u2192 head+tail truncate to the cap.\n */\nexport function normalizeCommandOutput(\n raw: string,\n opts: { maxBytes?: number | undefined } = {},\n): string {\n if (!raw) return raw;\n let text = Core.stripAnsi(raw);\n text = collapseCarriageReturns(text);\n text = text.replace(/[ \\t]+$/gm, ''); // trailing whitespace per line\n text = collapseConsecutiveDuplicates(text);\n text = text.replace(/\\n{3,}/g, '\\n\\n'); // >=2 blank lines \u2192 1\n return truncateHeadTail(text, opts.maxBytes ?? COMMAND_OUTPUT_MAX_BYTES);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as fs from 'node:fs/promises';\nimport { deepMerge as deepMergeCore } from '@wrongstack/core/utils';\nimport type { Context } from '@wrongstack/core/agent';\nimport type { Tool } from '@wrongstack/core/types';\nimport { safeResolveReal } from './_util.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype JsonAction = 'parse' | 'query' | 'validate' | 'transform' | 'merge';\n\ninterface JsonInput {\n /** Operation to perform. Defaults to 'parse'. */\n action?: JsonAction | undefined;\n\n // --- parse / query / validate (single data source) ---\n /** Path to JSON/JSON5/YAML file (alternative to `data`). */\n file?: string | undefined;\n /** Inline JSON/JSON5/YAML string (alternative to `file`). */\n data?: string | undefined;\n /** Output format for parse/query/transform results. */\n format?: 'json' | 'json5' | 'yaml' | undefined;\n\n // --- parse: validate syntax only ---\n validate?: boolean | undefined;\n\n // --- query / transform ---\n /** JMESPath-like query expression. */\n query?: string | undefined;\n /** Ordered JMESPath transforms (transform action only). */\n transforms?: string[] | undefined;\n\n // --- validate against schema ---\n /** JSON Schema to validate against. */\n schema?: Record<string, unknown> | undefined;\n\n // --- merge ---\n /** Base object for merge. */\n base?: unknown | undefined;\n /** Patch object for merge. */\n patch?: unknown | undefined;\n /** Merge conflict resolution: 'prefer-patch' (default) or 'prefer-base'. */\n conflictResolution?: 'prefer-base' | 'prefer-patch' | undefined;\n}\n\ninterface JsonOutput {\n data: unknown;\n formatted: string;\n type: string;\n action: string;\n keys?: string[] | undefined;\n query_result?: unknown | undefined;\n result?: unknown | undefined;\n valid?: boolean | undefined;\n errors?: string[] | undefined;\n steps?: Array<{ transform: string; result: unknown }> | undefined;\n error?: string | undefined;\n}\n\nexport const jsonTool: Tool<JsonInput, JsonOutput> = {\n name: 'json',\n category: 'Data',\n description:\n 'Parse, pretty-print, query, validate, transform, and merge JSON/JSON5/YAML. Use `action` to select the operation: parse (default), query, validate, transform, or merge.',\n usageHint:\n 'VERY USEFUL FOR DATA INSPECTION:\\n\\n' +\n '- `action: \"parse\"` (default): read/pretty-print/convert JSON, JSON5, or YAML from `file` or `data`.\\n' +\n '- `action: \"query\"`: JMESPath-like query (`a.b[0].c`, `items[*].name`, filters, functions).\\n' +\n '- `action: \"validate\"`: validate data against a JSON Schema (`schema` param).\\n' +\n '- `action: \"transform\"`: chain multiple JMESPath transforms (`transforms` param).\\n' +\n '- `action: \"merge\"`: deep merge `base` and `patch` objects (`conflictResolution` param).\\n' +\n 'Prefer this over raw `read` + manual parsing when dealing with configuration or data files.',\n permission: 'auto',\n mutating: false,\n timeoutMs: 5_000,\n capabilities: ['fs.read'],\n icon: 'json',\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['parse', 'query', 'validate', 'transform', 'merge'],\n description: 'Operation (default: parse). parse=read/pretty-print, query=JMESPath, validate=schema, transform=chained queries, merge=deep merge.',\n },\n file: { type: 'string', description: 'Path to JSON/JSON5/YAML file (parse/query/validate)' },\n data: { type: 'string', description: 'JSON/JSON5/YAML string (parse/query/validate, alternative to file)' },\n format: {\n type: 'string',\n enum: ['json', 'json5', 'yaml'],\n description: 'Output format for parse/query/transform (default: json)',\n },\n query: {\n type: 'string',\n description: 'JMESPath-like query expression (query action)',\n },\n transforms: {\n type: 'array',\n items: { type: 'string' },\n description: 'Ordered JMESPath query strings (transform action)',\n },\n schema: {\n type: 'object',\n description: 'JSON Schema to validate against (validate action)',\n },\n base: { description: 'Base JSON object (merge action)' },\n patch: { description: 'Patch JSON object to merge in (merge action)' },\n conflictResolution: {\n type: 'string',\n enum: ['prefer-base', 'prefer-patch'],\n description: 'Merge conflict resolution (default: prefer-patch)',\n },\n validate: {\n type: 'boolean',\n description: 'Validate syntax only, no output (parse action, default: false)',\n },\n },\n },\n async execute(input, ctx) {\n const action = input.action ?? 'parse';\n\n switch (action) {\n case 'query':\n return executeQuery(input, ctx);\n case 'validate':\n return executeValidate(input, ctx);\n case 'transform':\n return executeTransform(input, ctx);\n case 'merge':\n return executeMerge(input);\n default:\n return executeParse(input, ctx);\n }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Action: parse (default \u2014 the original json tool behavior)\n// ---------------------------------------------------------------------------\n\nasync function executeParse(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n const format = input.format ?? 'json';\n\n let parsed: unknown;\n let raw: string;\n\n if (input.file) {\n try {\n raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'parse', error: 'Could not read file' };\n }\n } else if (input.data) {\n raw = input.data;\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'parse', error: 'Provide file or data' };\n }\n\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'parse',\n /* v8 ignore next -- JSON.parse only throws SyntaxError (an Error); the String(e) side is defensive. */\n error: `Parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n\n if (input.validate) {\n return {\n data: parsed,\n formatted: 'valid',\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n };\n }\n\n // Backward compat: if `query` is provided without an explicit action,\n // use the original simple path-based query (supports `a.b[0].c` notation).\n if (input.query) {\n const queryResult = simpleQuery(parsed, input.query);\n const formatted = formatOutput(queryResult, format);\n return {\n data: parsed,\n formatted,\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n query_result: queryResult,\n };\n }\n\n const formatted = formatOutput(parsed, format);\n\n return {\n data: parsed,\n formatted,\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Action: query (JMESPath-like \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeQuery(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.query) {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'query is required for action: query' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Provide file or data' };\n }\n\n try {\n const result = jmespathSearch(parsed, input.query);\n const format = input.format ?? 'json';\n return {\n data: parsed,\n formatted: formatOutput(result, format),\n type: result === null ? 'null' : Array.isArray(result) ? 'array' : typeof result,\n action: 'query',\n query_result: result,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'query',\n /* v8 ignore next -- defensive String(e) */\n error: `Query failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: validate (JSON Schema \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeValidate(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.schema) {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'schema is required for action: validate' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Provide file or data' };\n }\n\n try {\n const { valid, errors } = validateJsonSchema(parsed, input.schema as Record<string, unknown>);\n return {\n data: parsed,\n formatted: valid ? 'valid' : 'invalid',\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'validate',\n valid,\n errors,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'validate',\n /* v8 ignore next -- defensive String(e) */\n error: `Validation failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: transform (chained JMESPath \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeTransform(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.transforms || input.transforms.length === 0) {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'transforms array is required for action: transform' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Provide file or data' };\n }\n\n try {\n let current: unknown = parsed;\n const steps: Array<{ transform: string; result: unknown }> = [];\n\n for (const t of input.transforms) {\n current = jmespathSearch(current, t);\n steps.push({ transform: t, result: current });\n }\n\n const format = input.format ?? 'json';\n return {\n data: parsed,\n formatted: formatOutput(current, format),\n type: current === null ? 'null' : Array.isArray(current) ? 'array' : typeof current,\n action: 'transform',\n result: current,\n steps,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'transform',\n /* v8 ignore next -- defensive String(e) */\n error: `Transform failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: merge (deep merge \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeMerge(input: JsonInput): Promise<JsonOutput> {\n if (input.base === undefined || input.patch === undefined) {\n return { data: null, formatted: '', type: 'unknown', action: 'merge', error: 'base and patch are required for action: merge' };\n }\n\n const conflictResolution = input.conflictResolution ?? 'prefer-patch';\n\n try {\n const result = deepMergeCore(input.base, input.patch, { conflictResolution });\n const format = input.format ?? 'json';\n return {\n data: result,\n formatted: formatOutput(result, format),\n type: result === null ? 'null' : Array.isArray(result) ? 'array' : typeof result,\n action: 'merge',\n result,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'merge',\n /* v8 ignore next -- defensive String(e) */\n error: `Merge failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// JMESPath implementation (from json-path plugin)\n// ---------------------------------------------------------------------------\n\nfunction jmespathSearch(data: unknown, query: string): unknown {\n // Handle basic JMESPath expressions\n if (!query || query === '@') return data;\n\n // Root access\n if (query === '$') return data;\n\n // Dot notation: foo.bar\n const dotMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(?:\\.(.+))?$/);\n if (dotMatch) {\n const key = dotMatch[1]!;\n const rest = dotMatch[2];\n const val = (data as Record<string, unknown> | undefined)?.[key];\n if (rest === undefined) return val;\n return jmespathSearch(val, rest);\n }\n\n // Array access: [0]\n const arrMatch = query.match(/^\\[(\\d+)\\](?:\\.(.+))?$/);\n if (arrMatch) {\n const idx = Number.parseInt(arrMatch[1]!, 10);\n const rest = arrMatch[2];\n const arr = data as unknown[];\n const val = arr?.[idx];\n if (rest === undefined) return val;\n return jmespathSearch(val, rest);\n }\n\n // Wildcard: [*]\n if (query === '[*]') {\n if (Array.isArray(data)) {\n return data;\n }\n return data;\n }\n\n // Multi-select: foo.bar[*].baz\n const multiMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\\[\\*\\](?:\\.(.+))?$/);\n if (multiMatch) {\n const key = multiMatch[1]!;\n const rest = multiMatch[2];\n const arr = (data as Record<string, unknown[]> | undefined)?.[key];\n if (!Array.isArray(arr)) return [];\n if (rest === undefined) return arr;\n return arr.map((item) => jmespathSearch(item, rest));\n }\n\n // Filter: [?foo==`bar`]\n const filterMatch = query.match(/^\\[\\\\?([a-zA-Z_][a-zA-Z0-9_]*)(==|!=|<|>|<=|>=)(`[^`]+`|'[^']*')\\](?:\\.(.+))?$/);\n if (filterMatch) {\n const field = filterMatch[1]!;\n const op = filterMatch[2]!;\n const rawVal = filterMatch[3]!;\n const rest = filterMatch[4];\n const cmpVal = JSON.parse(rawVal.slice(1, -1));\n const arr = data as Record<string, unknown>[];\n if (!Array.isArray(arr)) return [];\n const filtered = arr.filter((item) => {\n const itemVal = (item as Record<string, unknown>)[field];\n switch (op) {\n case '==': return itemVal === cmpVal;\n case '!=': return itemVal !== cmpVal;\n case '>': return Number(itemVal) > Number(cmpVal);\n case '<': return Number(itemVal) < Number(cmpVal);\n case '>=': return Number(itemVal) >= Number(cmpVal);\n case '<=': return Number(itemVal) <= Number(cmpVal);\n /* v8 ignore next -- op is constrained to the six operators by the filter regex; default is unreachable. */\n default: return true;\n }\n });\n if (rest === undefined) return filtered;\n return filtered.map((item) => jmespathSearch(item, rest));\n }\n\n // Function calls: length(@)\n const fnMatch = query.match(/^(length|keys|values|type)\\(@\\)$/);\n if (fnMatch) {\n const fn = fnMatch[1]!;\n switch (fn) {\n case 'length':\n if (Array.isArray(data)) return data.length;\n if (typeof data === 'string') return data.length;\n if (typeof data === 'object' && data !== null) return Object.keys(data as object).length;\n return 0;\n case 'keys':\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) return Object.keys(data as object);\n return [];\n case 'values':\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) return Object.values(data as object);\n return [];\n case 'type':\n if (data === null) return 'null';\n if (Array.isArray(data)) return 'array';\n return typeof data;\n /* v8 ignore next 2 -- fn is constrained to the four names by the function regex; default is unreachable. */\n default:\n return null;\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema validator (from json-path plugin)\n// ---------------------------------------------------------------------------\n\nfunction validateJsonSchema(data: unknown, schema: Record<string, unknown>): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n function check(value: unknown, s: Record<string, unknown>, path: string): void {\n if (s['type']) {\n const expectedType = s['type'] as string;\n const actualType = Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value;\n if (expectedType === 'integer') {\n if (!Number.isInteger(value)) errors.push(`${path}: expected integer, got ${actualType}`);\n } else if (expectedType !== actualType) {\n errors.push(`${path}: expected ${expectedType}, got ${actualType}`);\n }\n }\n\n if (typeof value === 'string' && s['format'] === 'uri' && value) {\n try { new URL(value); } catch { errors.push(`${path}: not a valid URI`); }\n }\n\n if (typeof value === 'string' && s['pattern']) {\n const re = new RegExp(s['pattern'] as string);\n if (!re.test(value)) errors.push(`${path}: does not match pattern ${s['pattern']}`);\n }\n\n if (typeof value === 'string' && s['minLength'] !== undefined && value.length < (s['minLength'] as number)) {\n errors.push(`${path}: string too short (min ${s['minLength']})`);\n }\n\n if (typeof value === 'string' && s['maxLength'] !== undefined && value.length > (s['maxLength'] as number)) {\n errors.push(`${path}: string too long (max ${s['maxLength']})`);\n }\n\n if (typeof value === 'number' && s['minimum'] !== undefined && value < (s['minimum'] as number)) {\n errors.push(`${path}: below minimum ${s['minimum']}`);\n }\n\n if (typeof value === 'number' && s['maximum'] !== undefined && value > (s['maximum'] as number)) {\n errors.push(`${path}: above maximum ${s['maximum']}`);\n }\n\n if (Array.isArray(value) && s['items'] && Array.isArray(s['items'])) {\n for (let i = 0; i < value.length; i++) {\n check(value[i], s['items'] as never as Record<string, unknown>, `${path}[${i}]`);\n }\n }\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value) && s['properties']) {\n const props = s['properties'] as Record<string, Record<string, unknown>>;\n for (const [k, propSchema] of Object.entries(props)) {\n check((value as Record<string, unknown>)[k], propSchema, `${path}.${k}`);\n }\n }\n }\n\n check(data, schema, '$');\n return { valid: errors.length === 0, errors };\n}\n\n// ---------------------------------------------------------------------------\n// Simple path-based query (original json tool query, backward compat)\n// ---------------------------------------------------------------------------\n\nfunction simpleQuery(data: unknown, path: string): unknown {\n const parts = path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .filter(Boolean);\n let current: unknown = data;\n\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n\n const idx = Number(part);\n if (!Number.isNaN(idx) && Array.isArray(current)) {\n current = current[idx];\n } else if (typeof current === 'object' && current !== null) {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n\n return current;\n}\n\n// ---------------------------------------------------------------------------\n// Output formatting (original json tool helpers)\n// ---------------------------------------------------------------------------\n\nfunction formatOutput(data: unknown, format: string): string {\n if (format === 'json5') {\n return JSON.stringify(data, null, 2)\n .replace(/,\\s*}/g, '}')\n .replace(/,\\s*\\]/g, ']');\n }\n if (format === 'yaml') {\n return toYaml(data);\n }\n return JSON.stringify(data, null, 2);\n}\n\nfunction toYaml(data: unknown, indent = 0): string {\n if (data === null) return 'null\\n';\n /* v8 ignore next -- parsed JSON never contains `undefined`; defensive for recursive calls. */\n if (data === undefined) return '';\n if (typeof data === 'boolean') return String(data) + '\\n';\n if (typeof data === 'number') return String(data) + '\\n';\n if (typeof data === 'string') {\n if (data.includes('\\n') || data.includes(':') || data.includes('#')) {\n return `\"${data.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"\\n`;\n }\n return data + '\\n';\n }\n if (Array.isArray(data)) {\n if (data.length === 0) return '[]\\n';\n const prefix = ' '.repeat(indent);\n return data.map((item) => `${prefix}- ${toYaml(item, indent + 1).trimStart()}`).join('');\n }\n if (typeof data === 'object') {\n const prefix = ' '.repeat(indent);\n const entries = Object.entries(data as Record<string, unknown>);\n return entries.map(([k, v]) => `${prefix}${k}: ${toYaml(v, indent + 1)}`).join('');\n }\n /* v8 ignore next -- JSON.parse only yields null/bool/number/string/array/object; this fallback is defensive. */\n return String(data) + '\\n';\n}\n", "import { createHash } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as Core from '@wrongstack/core/utils';\nimport type { Context } from '@wrongstack/core/agent';\n\n/**\n * sha-256 hex of a UTF-8 string. Used by the file tools to record a content\n * hash alongside the mtime in `ctx.recordRead` \u2014 the hash is the authoritative\n * staleness arbiter for `edit` (mtime has a 2 s tolerance window on Windows).\n */\nexport function sha256hex(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n/** Detected package manager for a project directory. */\nexport type PackageManager = 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Detect the project's package manager by inspecting lockfiles in `cwd`.\n * Order: pnpm \u2192 yarn \u2192 npm (default). Missing or unreadable directories fall\n * back to `npm` rather than throwing, so a `safeResolve`-checked cwd that\n * happens to be empty never aborts the tool.\n */\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\n const { stat } = await import('node:fs/promises');\n try {\n await stat(`${cwd}/pnpm-lock.yaml`);\n return 'pnpm';\n } catch {\n /* not pnpm */\n }\n try {\n await stat(`${cwd}/yarn.lock`);\n return 'yarn';\n } catch {\n /* not yarn */\n }\n return 'npm';\n}\n\nexport function resolvePath(input: string, ctx: Context): string {\n return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);\n}\n\n/**\n * Roots every file tool may always reach, even in restricted mode: the\n * project root and the user-global `~/.wrongstack` directory (config, memory,\n * sessions, skills). `~/.wrongstack` honors the `WRONGSTACK_HOME` override.\n */\nfunction allowedRoots(ctx: Context): string[] {\n return [path.resolve(ctx.projectRoot), path.resolve(Core.wstackGlobalRoot())];\n}\n\n/** True if `target` is `root` itself or nested inside any of `roots`. */\nfunction isInsideAny(target: string, roots: string[]): boolean {\n return roots.some((root) => {\n const rel = path.relative(root, target);\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n });\n}\n\nexport function ensureInsideRoot(absPath: string, ctx: Context): string {\n const target = path.resolve(absPath);\n // Unrestricted filesystem access: skip the project-root containment check.\n if (ctx.allowOutsideProjectRoot) return target;\n if (isInsideAny(target, allowedRoots(ctx))) return target;\n throw new Error(`Path \"${absPath}\" is outside project root \"${path.resolve(ctx.projectRoot)}\"`);\n}\n\nexport function safeResolve(input: string, ctx: Context): string {\n return ensureInsideRoot(resolvePath(input, ctx), ctx);\n}\n\n/**\n * Defense against in-root\u2192out-of-root symlink escape (CWE-59). `safeResolve`\n * only does a syntactic `../` check, so a symlink that lives *inside* the\n * project root but points outside still passes it. This resolves the path\n * through `fs.realpath` and re-verifies containment against the realpath of\n * the project root (comparing like-for-like, since the root itself may be a\n * symlink \u2014 macOS `/var`\u2192`/private/var`, Windows 8.3 short names). For a path\n * that does not exist yet (e.g. a `write` to a new file) the nearest existing\n * ancestor directory is checked instead. Throws if the real target escapes.\n *\n * Mirrors the per-file guard already used in `replace.ts`/`grep.ts`; applied\n * to single-file `read`/`edit`/`write` it throws (rather than skips) because\n * the caller named exactly one file.\n */\nexport async function assertRealInsideRoot(absPath: string, ctx: Context): Promise<void> {\n // Unrestricted filesystem access: no symlink-escape check to perform.\n if (ctx.allowOutsideProjectRoot) return;\n // Compare like-for-like against the realpath of each always-allowed root\n // (project root + ~/.wrongstack), since a root may itself be a symlink.\n const realRoots = await Promise.all(\n allowedRoots(ctx).map((r) => fsp.realpath(r).catch(() => path.resolve(r))),\n );\n let probe = absPath;\n for (;;) {\n let real: string;\n try {\n real = await fsp.realpath(probe);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const parent = path.dirname(probe);\n if (parent === probe) return; // reached fs root without escaping\n probe = parent;\n continue;\n }\n throw err;\n }\n if (isInsideAny(real, realRoots)) return;\n throw new Error(\n `Path \"${absPath}\" resolves through a symlink outside project root \"${realRoots[0]}\"`,\n );\n }\n}\n\n/** `safeResolve` + symlink realpath containment check. Async. */\nexport async function safeResolveReal(input: string, ctx: Context): Promise<string> {\n const abs = safeResolve(input, ctx);\n await assertRealInsideRoot(abs, ctx);\n return abs;\n}\n\nexport function truncateMiddle(s: string, max: number): string {\n if (Buffer.byteLength(s, 'utf8') <= max) return s;\n const half = Math.floor(max / 2);\n return (\n s.slice(0, half) +\n `\\n\u2026[truncated ${Buffer.byteLength(s, 'utf8') - max} bytes from middle]\u2026\\n` +\n s.slice(-half)\n );\n}\n\nexport function isBinaryBuffer(buf: Buffer): boolean {\n const len = Math.min(buf.length, 8192);\n for (let i = 0; i < len; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n}\n\n// \u2500\u2500\u2500 Command-output normalization (token-saving) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Raw process output is full of tokens the model gains nothing from: ANSI\n// escapes, carriage-return progress spam, runs of identical warning lines, and\n// huge tails of build noise. These helpers strip that noise before the output\n// reaches the LLM. They are scoped to COMMAND tools (bash/git/exec and the\n// _spawn-stream consumers) \u2014 never applied to structured/code outputs.\n\n/** Unified byte cap for all command tool output fed to the model. */\nexport const COMMAND_OUTPUT_MAX_BYTES = 32_768;\n\n/** Runs of >= this many identical consecutive lines are collapsed. */\nconst REPEAT_RUN_THRESHOLD = 3;\n\n/**\n * Collapse carriage-return overwrites the way a terminal would: `\\r\\n` becomes\n * `\\n`, and a bare `\\r` (progress redraw) keeps only the text after the LAST\n * `\\r` on its physical line. Without this, a single progress bar that redraws\n * 200 times explodes into 200 lines.\n */\nexport function collapseCarriageReturns(text: string): string {\n const lf = text.replace(/\\r\\n/g, '\\n');\n if (!lf.includes('\\r')) return lf;\n return lf\n .split('\\n')\n .map((line) => (line.includes('\\r') ? line.slice(line.lastIndexOf('\\r') + 1) : line))\n .join('\\n');\n}\n\n/**\n * Collapse a run of `minRun`+ identical consecutive lines into the line once\n * plus a marker. Consecutive-only \u2014 it never reorders or dedups non-adjacent\n * lines, so diffs/source stay intact.\n */\nexport function collapseConsecutiveDuplicates(text: string, minRun = REPEAT_RUN_THRESHOLD): string {\n const lines = text.split('\\n');\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n let j = i + 1;\n while (j < lines.length && lines[j] === lines[i]) j++;\n const run = j - i;\n if (run >= minRun) {\n out.push(lines[i]!, `\u2026 \u27E8repeated ${run}\u00D7\u27E9`);\n } else {\n for (let k = i; k < j; k++) out.push(lines[k]!);\n }\n i = j;\n }\n return out.join('\\n');\n}\n\n/** Largest prefix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeHeadBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(0, mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(0, lo);\n}\n\n/** Largest suffix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeTailBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(s.length - mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(s.length - lo);\n}\n\n/**\n * Truncate to `maxBytes` keeping BOTH ends \u2014 the head (what ran / early context)\n * and the tail (errors and summaries usually land last), biased ~45/55 toward\n * the tail. The result never exceeds `maxBytes`.\n */\nexport function truncateHeadTail(s: string, maxBytes: number): string {\n const total = Buffer.byteLength(s, 'utf8');\n if (total <= maxBytes) return s;\n // Reserve a fixed allowance for the marker so the final string can't exceed\n // the cap even though the dropped-byte count's digit width varies.\n const MARKER_RESERVE = 64;\n const avail = Math.max(0, maxBytes - MARKER_RESERVE);\n const headBudget = Math.floor(avail * 0.45);\n const head = takeHeadBytes(s, headBudget);\n const tail = takeTailBytes(s, avail - Buffer.byteLength(head, 'utf8'));\n const kept = Buffer.byteLength(head, 'utf8') + Buffer.byteLength(tail, 'utf8');\n return `${head}\\n\u2026[truncated ${total - kept} bytes]\u2026\\n${tail}`;\n}\n\n/**\n * Full token-saving pipeline for command tool output: strip ANSI \u2192 collapse\n * carriage-return progress \u2192 trim trailing whitespace \u2192 collapse identical\n * consecutive lines \u2192 squeeze blank-line runs \u2192 head+tail truncate to the cap.\n */\nexport function normalizeCommandOutput(\n raw: string,\n opts: { maxBytes?: number | undefined } = {},\n): string {\n if (!raw) return raw;\n let text = Core.stripAnsi(raw);\n text = collapseCarriageReturns(text);\n text = text.replace(/[ \\t]+$/gm, ''); // trailing whitespace per line\n text = collapseConsecutiveDuplicates(text);\n text = text.replace(/\\n{3,}/g, '\\n\\n'); // >=2 blank lines \u2192 1\n return truncateHeadTail(text, opts.maxBytes ?? COMMAND_OUTPUT_MAX_BYTES);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["formatted", "path"]
7
7
  }
package/dist/kanban.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { SerializedTaskGraph, Tool } from '@wrongstack/core';
2
- import type { AssignKanbanTaskInput, KanbanAgentRunStatus, KanbanBoard, KanbanBoardSummary, KanbanEvent, KanbanLifecycleStage, KanbanOrchestrationSnapshot, KanbanQueueHealth, KanbanSearchResult, KanbanTask, KanbanTaskPriority, KanbanTaskStatus, KanbanTaskType } from '@wrongstack/kanban';
3
- type KanbanAction = 'list_boards' | 'get_board' | 'create_board' | 'duplicate_board' | 'update_board' | 'delete_board' | 'generate_board' | 'export_markdown' | 'export_task_graph' | 'sync_task_graph' | 'create_from_graph' | 'import_session_tasks' | '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' | 'transition_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';
1
+ import type { SerializedTaskGraph, Tool } from '@wrongstack/core/types';
2
+ import type { AssignKanbanTaskInput, KanbanAgentRunStatus, KanbanBoard, KanbanBoardSummary, KanbanEvent, KanbanLifecycleStage, KanbanOrchestrationSnapshot, KanbanQueueHealth, KanbanSearchResult, KanbanTask, KanbanTaskPriority, KanbanTaskStatus, KanbanTaskType, KanbanVerificationReport } from '@wrongstack/kanban';
3
+ type KanbanAction = 'list_boards' | 'get_board' | 'create_board' | 'duplicate_board' | 'update_board' | 'delete_board' | 'generate_board' | 'export_markdown' | 'export_task_graph' | 'sync_task_graph' | 'create_from_graph' | 'import_session_tasks' | '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' | 'transition_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' | 'verify_completion' | 'split_atomic';
4
4
  interface KanbanToolInput extends Omit<AssignKanbanTaskInput, 'status'> {
5
5
  action: KanbanAction;
6
6
  boardId?: string | undefined;
@@ -112,6 +112,7 @@ interface KanbanToolInput extends Omit<AssignKanbanTaskInput, 'status'> {
112
112
  }
113
113
  interface KanbanToolOutput {
114
114
  ok: boolean;
115
+ verdict?: KanbanVerificationReport['verdict'] | undefined;
115
116
  message: string;
116
117
  board?: KanbanBoard | undefined;
117
118
  boards?: KanbanBoardSummary[] | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"kanban.d.ts","sourceRoot":"","sources":["../src/kanban.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAyB,mBAAmB,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,KAAK,EACV,qBAAqB,EAErB,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,2BAA2B,EAC3B,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACf,MAAM,oBAAoB,CAAC;AAmD5B,KAAK,YAAY,GACb,aAAa,GACb,WAAW,GACX,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,GACnB,sBAAsB,GACtB,cAAc,GACd,aAAa,GACb,UAAU,GACV,YAAY,GACZ,eAAe,GACf,eAAe,GACf,UAAU,GACV,YAAY,GACZ,aAAa,GACb,WAAW,GACX,eAAe,GACf,UAAU,GACV,aAAa,GACb,iBAAiB,GACjB,WAAW,GACX,aAAa,GACb,WAAW,GACX,WAAW,GACX,YAAY,GACZ,cAAc,GACd,aAAa,GACb,iBAAiB,GACjB,sBAAsB,GACtB,eAAe,GACf,QAAQ,GACR,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,oBAAoB,GACpB,WAAW,GACX,cAAc,GACd,UAAU,GACV,UAAU,CAAC;AAEf,UAAU,eAAgB,SAAQ,IAAI,CAAC,qBAAqB,EAAE,QAAQ,CAAC;IACrE,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,QAAQ,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACnC,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,sBAAsB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7C,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAC5C,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,YAAY,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACnE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IACtE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC;IAC/F,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,qBAAqB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5C,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,CAAC,EAAE,KAAK,GAAG,aAAa,GAAG,aAAa,GAAG,SAAS,CAAC;IAChE,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,gBAAgB,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACpD,cAAc,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAClD,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC;IACrG,aAAa,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5D,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACjE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,+BAA+B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtD,mCAAmC,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3D,mCAAmC,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1D,iCAAiC,CAAC,EAAE,KAAK,GAAG,aAAa,GAAG,aAAa,GAAG,SAAS,CAAC;IACtF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,qBAAqB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5C,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACjC,0DAA0D;IAC1D,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,UAAU,gBAAgB;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAAC;IAC1C,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAAC;IACzC,cAAc,CAAC,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACpC,KAAK,CAAC,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;IACnD,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,eAAO,MAAM,UAAU,EAAE,IAAI,CAAC,eAAe,EAAE,gBAAgB,CA+7B9D,CAAC"}
1
+ {"version":3,"file":"kanban.d.ts","sourceRoot":"","sources":["../src/kanban.ts"],"names":[],"mappings":"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"}
package/dist/kanban.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // src/kanban.ts
2
2
  import { randomUUID } from "node:crypto";
3
- import { deserializeTaskGraph as deserializeTaskGraph2, loadTasks as loadTasks2, serializeTaskGraph } from "@wrongstack/core";
3
+ import { deserializeTaskGraph as deserializeTaskGraph2, serializeTaskGraph } from "@wrongstack/core/tasking";
4
+ import { loadTasks as loadTasks2 } from "@wrongstack/core/storage";
4
5
  import {
5
6
  addCheckToTask,
6
7
  addColumn,
@@ -47,18 +48,19 @@ import {
47
48
  updateColumn,
48
49
  updateGoalMetricOnTask,
49
50
  updateTask,
50
- updateTaskAssignment
51
+ updateTaskAssignment,
52
+ verifyTaskCompletion
51
53
  } from "@wrongstack/kanban";
52
54
 
53
55
  // src/session-kanban.ts
56
+ import { GlobalMailbox } from "@wrongstack/core/coordination";
54
57
  import {
55
- deserializeTaskGraph,
56
- GlobalMailbox,
57
58
  loadPlan,
58
59
  loadTasks,
59
60
  mutatePlan,
60
61
  mutateTasks
61
- } from "@wrongstack/core";
62
+ } from "@wrongstack/core/storage";
63
+ import { deserializeTaskGraph } from "@wrongstack/core/tasking";
62
64
  import { resolveWstackPaths } from "@wrongstack/core/utils";
63
65
  import {
64
66
  createBoard,
@@ -111,8 +113,8 @@ function taskFileToSerializedGraph(tasks, sessionId) {
111
113
  var kanbanTool = {
112
114
  name: "kanban",
113
115
  category: "Project",
114
- description: "Manage and audit project-scoped multi-kanban boards stored under .wrongstack/kanbans. Managed cards enforce fully specified details and adjacent Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions with persistent comments and evidence. Successful board access records live agent/session presence.",
115
- usageHint: "Use this for durable project kanban state. Reassess with get_board whenever evidence changes; agents may add, update, split, merge, reprioritize, or remove tasks so the board remains a live plan. Presence includes active/last-seen session and agent metadata. For managed boards, fully fill card details, use transition_task after every material step, attach truthful evidence, and never use update_task/move_task to bypass lifecycle guards. Worker completion enters Review; only passed acceptance criteria plus review evidence allow Done.",
116
+ description: "Manage and audit project-scoped multi-kanban boards stored under .wrongstack/kanbans. Managed cards enforce fully specified details and adjacent Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions with persistent comments and evidence. Successful board access records live agent/session presence. Use verify_completion to validate a task against its success criteria and persist the verification report. Use split_atomic to split a task into child tasks with parent.atomic=true in a single atomic board mutation, enforcing subtree verification before the parent can complete.",
117
+ usageHint: "Use this for durable project kanban state. Reassess with get_board whenever evidence changes; agents may add, update, split, merge, reprioritize, or remove tasks so the board remains a live plan. Presence includes active/last-seen session and agent metadata. For managed boards, fully fill card details, use transition_task after every material step, attach truthful evidence, and never use update_task/move_task to bypass lifecycle guards. Worker completion enters Review; only passed acceptance criteria plus review evidence allow Done. Use verify_completion to generate a verification report (persisted automatically) and split_atomic to atomically create child subtasks with the atomic flag pre-set.",
116
118
  permission: "confirm",
117
119
  mutating: true,
118
120
  capabilities: ["fs.write"],
@@ -168,7 +170,9 @@ var kanbanTool = {
168
170
  "add_check",
169
171
  "update_check",
170
172
  "add_note",
171
- "add_link"
173
+ "add_link",
174
+ "verify_completion",
175
+ "split_atomic"
172
176
  ]
173
177
  },
174
178
  boardId: { type: "string" },
@@ -223,6 +227,7 @@ var kanbanTool = {
223
227
  runTaskId: { type: "string" },
224
228
  lastResult: { type: "string" },
225
229
  error: { type: "string" },
230
+ expectedLeaseId: { type: "string" },
226
231
  assignmentStatus: {
227
232
  type: "string",
228
233
  enum: ["assigned", "queued", "running", "completed", "failed", "cancelled"]
@@ -257,6 +262,7 @@ var kanbanTool = {
257
262
  lastFailureKind: { type: "string" },
258
263
  dependsOn: { type: "array", items: { type: "string" } },
259
264
  estimatedHours: { type: "number" },
265
+ actualHours: { type: "number" },
260
266
  taskGraph: { type: "object" },
261
267
  graphId: { type: "string" },
262
268
  specId: { type: "string" },
@@ -565,24 +571,7 @@ var kanbanTool = {
565
571
  if (!input.boardId || !input.taskId || !input.childTitles?.length) {
566
572
  return fail("split_task requires boardId, taskId, and childTitles.");
567
573
  }
568
- const result2 = await splitTask(projectRoot, input.boardId, input.taskId, {
569
- titles: input.childTitles,
570
- ...input.targetColumnId !== void 0 ? { columnId: input.targetColumnId } : {},
571
- ...input.inheritAssignment !== void 0 ? { inheritAssignment: input.inheritAssignment } : {},
572
- ...input.inheritLabels !== void 0 ? { inheritLabels: input.inheritLabels } : {},
573
- ...input.inheritSuccessCriteria !== void 0 ? { inheritSuccessCriteria: input.inheritSuccessCriteria } : {},
574
- ...input.inheritGoalMetrics !== void 0 ? { inheritGoalMetrics: input.inheritGoalMetrics } : {},
575
- ...input.inheritDependencies !== void 0 ? { inheritDependencies: input.inheritDependencies } : {},
576
- ...input.chainChildren !== void 0 ? { chainChildren: input.chainChildren } : {},
577
- ...input.rewireDependents !== void 0 ? { rewireDependents: input.rewireDependents } : {}
578
- });
579
- return result2 ? {
580
- ok: true,
581
- message: `${result2.children.length} child task(s) created.`,
582
- board: result2.board,
583
- task: result2.parent,
584
- children: result2.children
585
- } : fail("Task not found.");
574
+ return handleSplitTask(projectRoot, input, {});
586
575
  }
587
576
  case "merge_tasks": {
588
577
  if (!input.boardId || !input.taskIds?.length || !input.title) {
@@ -947,6 +936,39 @@ var kanbanTool = {
947
936
  });
948
937
  return board ? okBoard(board, "Link added.") : fail("Task not found.");
949
938
  }
939
+ case "verify_completion": {
940
+ if (!input.boardId || !input.taskId) {
941
+ return fail("verify_completion requires boardId and taskId.");
942
+ }
943
+ const verResult = await verifyTaskCompletion(projectRoot, input.boardId, input.taskId);
944
+ const persistedBoard = await updateTask(projectRoot, input.boardId, input.taskId, {
945
+ verificationReport: verResult.report,
946
+ successCriteria: verResult.task.successCriteria
947
+ });
948
+ if (!persistedBoard) {
949
+ return {
950
+ ok: false,
951
+ verdict: verResult.report.verdict,
952
+ message: `Verification succeeded but persist failed: ${verResult.report.markdownSummary}. Board may be stale \u2014 re-run verify_completion.`,
953
+ board: verResult.board
954
+ };
955
+ }
956
+ const freshTask = persistedBoard.tasks?.find((t) => t.id === input.taskId);
957
+ const deterministicVerdicts = ["passed", "failed", "needs_human", "incomplete"];
958
+ return {
959
+ ok: deterministicVerdicts.includes(verResult.report.verdict),
960
+ verdict: verResult.report.verdict,
961
+ message: verResult.report.markdownSummary,
962
+ board: persistedBoard,
963
+ task: freshTask ?? verResult.task
964
+ };
965
+ }
966
+ case "split_atomic": {
967
+ if (!input.boardId || !input.taskId || !input.childTitles?.length) {
968
+ return fail("split_atomic requires boardId, taskId, and childTitles (at least one).");
969
+ }
970
+ return handleSplitTask(projectRoot, input, { atomic: true });
971
+ }
950
972
  default:
951
973
  return fail(`Unknown kanban action: ${input.action}`);
952
974
  }
@@ -966,6 +988,50 @@ function okBoard(board, message = "Board loaded.") {
966
988
  function okTask(board, task, message) {
967
989
  return { ok: true, message, board, task };
968
990
  }
991
+ async function handleSplitTask(projectRoot, input, extraSplitOptions) {
992
+ const boardId = input.boardId;
993
+ const taskId = input.taskId;
994
+ const childTitles = input.childTitles;
995
+ if (!boardId || !taskId || !childTitles?.length) {
996
+ return fail("split requires boardId, taskId, and at least one childTitles.");
997
+ }
998
+ const {
999
+ targetColumnId,
1000
+ inheritAssignment,
1001
+ inheritLabels,
1002
+ inheritSuccessCriteria,
1003
+ inheritGoalMetrics,
1004
+ inheritDependencies,
1005
+ chainChildren,
1006
+ rewireDependents
1007
+ } = input;
1008
+ const result = await splitTask(projectRoot, boardId, taskId, {
1009
+ titles: childTitles,
1010
+ ...extraSplitOptions,
1011
+ ...targetColumnId !== void 0 ? { columnId: targetColumnId } : {},
1012
+ ...inheritAssignment !== void 0 ? { inheritAssignment } : {},
1013
+ ...inheritLabels !== void 0 ? { inheritLabels } : {},
1014
+ ...inheritSuccessCriteria !== void 0 ? { inheritSuccessCriteria } : {},
1015
+ ...inheritGoalMetrics !== void 0 ? { inheritGoalMetrics } : {},
1016
+ ...inheritDependencies !== void 0 ? { inheritDependencies } : {},
1017
+ ...chainChildren !== void 0 ? { chainChildren } : {},
1018
+ ...rewireDependents !== void 0 ? { rewireDependents } : {}
1019
+ });
1020
+ if (!result) return fail("Task not found.");
1021
+ const freshParent = result.board.tasks?.find((t) => t.id === taskId);
1022
+ if (!freshParent) {
1023
+ return fail(
1024
+ `Split succeeded but parent ${taskId} not found in returned board. Children: [${result.children.map((c) => c.id).join(", ")}].`
1025
+ );
1026
+ }
1027
+ return {
1028
+ ok: true,
1029
+ message: `${result.children.length} child task(s) created.`,
1030
+ board: result.board,
1031
+ task: freshParent,
1032
+ children: result.children
1033
+ };
1034
+ }
969
1035
  async function requireBoard(projectRoot, boardId) {
970
1036
  return boardId ? getBoard2(projectRoot, boardId) : null;
971
1037
  }
@@ -1067,7 +1133,8 @@ function taskPatch(input) {
1067
1133
  labels: input.labels,
1068
1134
  assignedAgent: input.agentId,
1069
1135
  ...mergedDependsOn(input) ? { dependsOn: mergedDependsOn(input) } : {},
1070
- ...input.estimatedHours !== void 0 ? { estimatedHours: input.estimatedHours } : {}
1136
+ ...input.estimatedHours !== void 0 ? { estimatedHours: input.estimatedHours } : {},
1137
+ ...input.actualHours !== void 0 ? { actualHours: input.actualHours } : {}
1071
1138
  };
1072
1139
  }
1073
1140
  function assignmentInput(input) {