@wrongstack/tools 0.306.3 → 0.307.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 (76) hide show
  1. package/dist/audit.js +50 -9
  2. package/dist/auto-proceed-loop-guard.js +8 -2
  3. package/dist/bash.js +57 -22
  4. package/dist/builtin.d.ts +6 -6
  5. package/dist/builtin.js +11315 -9317
  6. package/dist/clarify.d.ts +32 -0
  7. package/dist/codebase-index/ast-invariant-engine.d.ts +102 -0
  8. package/dist/codebase-index/ast-symbol-mutator.d.ts +28 -0
  9. package/dist/codebase-index/background-indexer.d.ts +9 -0
  10. package/dist/codebase-index/codebase-ast-replace-tool.d.ts +31 -0
  11. package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +40 -0
  12. package/dist/codebase-index/codebase-invariant-check-tool.d.ts +23 -0
  13. package/dist/codebase-index/codebase-repo-map-tool.d.ts +22 -0
  14. package/dist/codebase-index/codebase-skeleton-tool.d.ts +36 -0
  15. package/dist/codebase-index/codebase-targeted-test-tool.d.ts +30 -0
  16. package/dist/codebase-index/index.d.ts +11 -1
  17. package/dist/codebase-index/index.js +4141 -1479
  18. package/dist/codebase-index/project-server-client-state.d.ts +79 -0
  19. package/dist/codebase-index/project-server-client.d.ts +3 -71
  20. package/dist/codebase-index/project-server-protocol.d.ts +1 -0
  21. package/dist/codebase-index/project-server.js +751 -909
  22. package/dist/codebase-index/repo-map.d.ts +20 -0
  23. package/dist/codebase-index/skeleton-extractor.d.ts +64 -0
  24. package/dist/codebase-index/tree-sitter-parser.d.ts +11 -0
  25. package/dist/codebase-index/worker.js +723 -891
  26. package/dist/codebase-index/writer-mutations.d.ts +26 -0
  27. package/dist/codebase-index/writer-refs.d.ts +50 -0
  28. package/dist/codebase-index/writer-search.d.ts +30 -0
  29. package/dist/codebase-index/writer.d.ts +2 -320
  30. package/dist/diff.js +3 -2
  31. package/dist/document.js +37 -2
  32. package/dist/e2e.js +3 -2
  33. package/dist/edit.js +8558 -348
  34. package/dist/exec.js +76 -22
  35. package/dist/fetch.js +11 -9
  36. package/dist/format.js +50 -9
  37. package/dist/glob.js +8 -3
  38. package/dist/grep.js +22 -10
  39. package/dist/index.d.ts +3 -1
  40. package/dist/index.js +11411 -9440
  41. package/dist/install.js +50 -9
  42. package/dist/json.js +91 -17
  43. package/dist/kanban-board-actions.d.ts +4 -0
  44. package/dist/kanban-lifecycle-actions.d.ts +4 -0
  45. package/dist/kanban-serializer.d.ts +21 -0
  46. package/dist/kanban.js +985 -1034
  47. package/dist/languages/index.js +17 -10
  48. package/dist/lint.js +50 -9
  49. package/dist/logs.js +17 -6
  50. package/dist/next-steps.d.ts +8 -0
  51. package/dist/next-steps.js +18 -0
  52. package/dist/outdated.js +18 -11
  53. package/dist/pack.js +11308 -9317
  54. package/dist/patch.js +8301 -77
  55. package/dist/plan.js +1231 -1281
  56. package/dist/process-registry.js +14 -8
  57. package/dist/ps-slash.js +65 -30
  58. package/dist/read.js +754 -912
  59. package/dist/replace.js +8456 -195
  60. package/dist/scaffold.js +36 -1
  61. package/dist/search.js +21 -15
  62. package/dist/security-ast-scan-tool.d.ts +43 -0
  63. package/dist/session-kanban-graph.d.ts +9 -0
  64. package/dist/session-kanban-sync.d.ts +31 -0
  65. package/dist/session-kanban.d.ts +5 -141
  66. package/dist/session-kanban.js +367 -360
  67. package/dist/task.js +1157 -1207
  68. package/dist/test.js +50 -9
  69. package/dist/todo.js +2187 -2237
  70. package/dist/tool-diff.js +6 -1
  71. package/dist/tool-summary.js +4 -2
  72. package/dist/tool-tier.js +11315 -9317
  73. package/dist/tree.js +36 -1
  74. package/dist/typecheck.js +51 -10
  75. package/dist/write.js +8374 -152
  76. package/package.json +7 -7
package/dist/install.js CHANGED
@@ -429,13 +429,16 @@ function killWin32Tree(pid, opts = {}) {
429
429
  };
430
430
  child.on("error", settle);
431
431
  child.on("close", settle);
432
- timeout = setTimeout(() => {
433
- try {
434
- child.kill();
435
- } catch {
436
- }
437
- settle();
438
- }, Math.max(1, opts.timeoutMs ?? WIN32_TASKKILL_TIMEOUT_MS));
432
+ timeout = setTimeout(
433
+ () => {
434
+ try {
435
+ child.kill();
436
+ } catch {
437
+ }
438
+ settle();
439
+ },
440
+ Math.max(1, opts.timeoutMs ?? WIN32_TASKKILL_TIMEOUT_MS)
441
+ );
439
442
  timeout.unref?.();
440
443
  child.unref();
441
444
  return true;
@@ -609,7 +612,10 @@ var ProcessRegistryImpl = class {
609
612
  getBreakerCountdown() {
610
613
  if (this.autoKillArmedAt === null || this.autoKillResetMs <= 0) return null;
611
614
  const elapsed = Date.now() - this.autoKillArmedAt;
612
- return { remainingMs: Math.max(0, this.autoKillResetMs - elapsed), totalMs: this.autoKillResetMs };
615
+ return {
616
+ remainingMs: Math.max(0, this.autoKillResetMs - elapsed),
617
+ totalMs: this.autoKillResetMs
618
+ };
613
619
  }
614
620
  /**
615
621
  * Subscribe to countdown arm/cancel events. Returns an unsubscribe function.
@@ -1048,6 +1054,7 @@ function utf8Prefix(text, maxBytes) {
1048
1054
  }
1049
1055
 
1050
1056
  // src/_util.ts
1057
+ import * as fsp2 from "node:fs/promises";
1051
1058
  import * as path3 from "node:path";
1052
1059
  import * as Core from "@wrongstack/core/utils";
1053
1060
  async function detectPackageManager(cwd, stopAt) {
@@ -1114,6 +1121,40 @@ function ensureInsideRoot(absPath, ctx) {
1114
1121
  function safeResolve(input, ctx) {
1115
1122
  return ensureInsideRoot(resolvePath(input, ctx), ctx);
1116
1123
  }
1124
+ async function resolveRealInsideRoot(absPath, ctx) {
1125
+ if (ctx.allowOutsideProjectRoot) return absPath;
1126
+ const realRoots = await Promise.all(
1127
+ allowedRoots(ctx).map((r) => fsp2.realpath(r).catch(() => path3.resolve(r)))
1128
+ );
1129
+ let probe = absPath;
1130
+ const pendingTail = [];
1131
+ for (; ; ) {
1132
+ let real;
1133
+ try {
1134
+ real = await fsp2.realpath(probe);
1135
+ } catch (err) {
1136
+ if (err.code === "ENOENT") {
1137
+ const parent = path3.dirname(probe);
1138
+ if (parent === probe) return absPath;
1139
+ pendingTail.unshift(path3.basename(probe));
1140
+ probe = parent;
1141
+ continue;
1142
+ }
1143
+ throw err;
1144
+ }
1145
+ const candidate = pendingTail.length > 0 ? path3.join(real, ...pendingTail) : real;
1146
+ if (isInsideAny(candidate, realRoots)) {
1147
+ return candidate;
1148
+ }
1149
+ throw new Error(
1150
+ `Path "${absPath}" resolves through a symlink outside project root "${realRoots[0]}"`
1151
+ );
1152
+ }
1153
+ }
1154
+ async function safeResolveReal(input, ctx) {
1155
+ const abs = safeResolve(input, ctx);
1156
+ return await resolveRealInsideRoot(abs, ctx);
1157
+ }
1117
1158
  var COMMAND_OUTPUT_MAX_BYTES = 32768;
1118
1159
  var REPEAT_RUN_THRESHOLD = 3;
1119
1160
  function collapseCarriageReturns(text) {
@@ -3905,7 +3946,7 @@ var installTool = {
3905
3946
  return final;
3906
3947
  },
3907
3948
  async *executeStream(input, ctx, opts) {
3908
- const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;
3949
+ const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : ctx.cwd;
3909
3950
  if (!input.global) {
3910
3951
  const pkgList2 = input.packages ? Array.isArray(input.packages) ? input.packages : input.packages.split(",").map((p) => p.trim()) : [];
3911
3952
  const bridge = await tryLegacyPackageOperation(
package/dist/json.js CHANGED
@@ -174,8 +174,9 @@ async function resolveRealInsideRoot(absPath, ctx) {
174
174
  }
175
175
  throw err;
176
176
  }
177
- if (isInsideAny(real, realRoots)) {
178
- return pendingTail.length > 0 ? path.join(real, ...pendingTail) : real;
177
+ const candidate = pendingTail.length > 0 ? path.join(real, ...pendingTail) : real;
178
+ if (isInsideAny(candidate, realRoots)) {
179
+ return candidate;
179
180
  }
180
181
  throw new Error(
181
182
  `Path "${absPath}" resolves through a symlink outside project root "${realRoots[0]}"`
@@ -226,7 +227,10 @@ var jsonTool = {
226
227
  description: "Operation (default: parse). parse=read/pretty-print, query=JMESPath, validate=schema, transform=chained queries, merge=deep merge."
227
228
  },
228
229
  file: { type: "string", description: "Path to JSON/JSON5/YAML file (parse/query/validate)" },
229
- data: { type: "string", description: "JSON/JSON5/YAML string (parse/query/validate, alternative to file)" },
230
+ data: {
231
+ type: "string",
232
+ description: "JSON/JSON5/YAML string (parse/query/validate, alternative to file)"
233
+ },
230
234
  format: {
231
235
  type: "string",
232
236
  enum: ["json", "json5", "yaml"],
@@ -293,7 +297,13 @@ async function executeParse(input, ctx) {
293
297
  } else if (input.data) {
294
298
  raw = input.data;
295
299
  } else {
296
- return { data: null, formatted: "", type: "unknown", action: "parse", error: "Provide file or data" };
300
+ return {
301
+ data: null,
302
+ formatted: "",
303
+ type: "unknown",
304
+ action: "parse",
305
+ error: "Provide file or data"
306
+ };
297
307
  }
298
308
  try {
299
309
  parsed = JSON.parse(raw);
@@ -339,7 +349,13 @@ async function executeParse(input, ctx) {
339
349
  }
340
350
  async function executeQuery(input, ctx) {
341
351
  if (!input.query) {
342
- return { data: null, formatted: "", type: "unknown", action: "query", error: "query is required for action: query" };
352
+ return {
353
+ data: null,
354
+ formatted: "",
355
+ type: "unknown",
356
+ action: "query",
357
+ error: "query is required for action: query"
358
+ };
343
359
  }
344
360
  let parsed;
345
361
  if (input.file) {
@@ -359,10 +375,22 @@ async function executeQuery(input, ctx) {
359
375
  try {
360
376
  parsed = JSON.parse(input.data);
361
377
  } catch {
362
- return { data: null, formatted: "", type: "unknown", action: "query", error: "Could not parse data string" };
378
+ return {
379
+ data: null,
380
+ formatted: "",
381
+ type: "unknown",
382
+ action: "query",
383
+ error: "Could not parse data string"
384
+ };
363
385
  }
364
386
  } else {
365
- return { data: null, formatted: "", type: "unknown", action: "query", error: "Provide file or data" };
387
+ return {
388
+ data: null,
389
+ formatted: "",
390
+ type: "unknown",
391
+ action: "query",
392
+ error: "Provide file or data"
393
+ };
366
394
  }
367
395
  try {
368
396
  const result = jmespathSearch(parsed, input.query);
@@ -387,7 +415,13 @@ async function executeQuery(input, ctx) {
387
415
  }
388
416
  async function executeValidate(input, ctx) {
389
417
  if (!input.schema) {
390
- return { data: null, formatted: "", type: "unknown", action: "validate", error: "schema is required for action: validate" };
418
+ return {
419
+ data: null,
420
+ formatted: "",
421
+ type: "unknown",
422
+ action: "validate",
423
+ error: "schema is required for action: validate"
424
+ };
391
425
  }
392
426
  let parsed;
393
427
  if (input.file) {
@@ -407,10 +441,22 @@ async function executeValidate(input, ctx) {
407
441
  try {
408
442
  parsed = JSON.parse(input.data);
409
443
  } catch {
410
- return { data: null, formatted: "", type: "unknown", action: "validate", error: "Could not parse data string" };
444
+ return {
445
+ data: null,
446
+ formatted: "",
447
+ type: "unknown",
448
+ action: "validate",
449
+ error: "Could not parse data string"
450
+ };
411
451
  }
412
452
  } else {
413
- return { data: null, formatted: "", type: "unknown", action: "validate", error: "Provide file or data" };
453
+ return {
454
+ data: null,
455
+ formatted: "",
456
+ type: "unknown",
457
+ action: "validate",
458
+ error: "Provide file or data"
459
+ };
414
460
  }
415
461
  try {
416
462
  const { valid, errors } = validateJsonSchema(parsed, input.schema);
@@ -435,7 +481,13 @@ async function executeValidate(input, ctx) {
435
481
  }
436
482
  async function executeTransform(input, ctx) {
437
483
  if (!input.transforms || input.transforms.length === 0) {
438
- return { data: null, formatted: "", type: "unknown", action: "transform", error: "transforms array is required for action: transform" };
484
+ return {
485
+ data: null,
486
+ formatted: "",
487
+ type: "unknown",
488
+ action: "transform",
489
+ error: "transforms array is required for action: transform"
490
+ };
439
491
  }
440
492
  let parsed;
441
493
  if (input.file) {
@@ -455,10 +507,22 @@ async function executeTransform(input, ctx) {
455
507
  try {
456
508
  parsed = JSON.parse(input.data);
457
509
  } catch {
458
- return { data: null, formatted: "", type: "unknown", action: "transform", error: "Could not parse data string" };
510
+ return {
511
+ data: null,
512
+ formatted: "",
513
+ type: "unknown",
514
+ action: "transform",
515
+ error: "Could not parse data string"
516
+ };
459
517
  }
460
518
  } else {
461
- return { data: null, formatted: "", type: "unknown", action: "transform", error: "Provide file or data" };
519
+ return {
520
+ data: null,
521
+ formatted: "",
522
+ type: "unknown",
523
+ action: "transform",
524
+ error: "Provide file or data"
525
+ };
462
526
  }
463
527
  try {
464
528
  let current = parsed;
@@ -489,7 +553,13 @@ async function executeTransform(input, ctx) {
489
553
  }
490
554
  async function executeMerge(input) {
491
555
  if (input.base === void 0 || input.patch === void 0) {
492
- return { data: null, formatted: "", type: "unknown", action: "merge", error: "base and patch are required for action: merge" };
556
+ return {
557
+ data: null,
558
+ formatted: "",
559
+ type: "unknown",
560
+ action: "merge",
561
+ error: "base and patch are required for action: merge"
562
+ };
493
563
  }
494
564
  const conflictResolution = input.conflictResolution ?? "prefer-patch";
495
565
  try {
@@ -548,7 +618,9 @@ function jmespathSearch(data, query) {
548
618
  if (rest === void 0) return arr;
549
619
  return arr.map((item) => jmespathSearch(item, rest));
550
620
  }
551
- const filterMatch = query.match(/^\[\\?([a-zA-Z_][a-zA-Z0-9_]*)(==|!=|<|>|<=|>=)(`[^`]+`|'[^']*')\](?:\.(.+))?$/);
621
+ const filterMatch = query.match(
622
+ /^\[\\?([a-zA-Z_][a-zA-Z0-9_]*)(==|!=|<|>|<=|>=)(`[^`]+`|'[^']*')\](?:\.(.+))?$/
623
+ );
552
624
  if (filterMatch) {
553
625
  const field = filterMatch[1];
554
626
  const op = filterMatch[2];
@@ -590,10 +662,12 @@ function jmespathSearch(data, query) {
590
662
  if (typeof data === "object" && data !== null) return Object.keys(data).length;
591
663
  return 0;
592
664
  case "keys":
593
- if (typeof data === "object" && data !== null && !Array.isArray(data)) return Object.keys(data);
665
+ if (typeof data === "object" && data !== null && !Array.isArray(data))
666
+ return Object.keys(data);
594
667
  return [];
595
668
  case "values":
596
- if (typeof data === "object" && data !== null && !Array.isArray(data)) return Object.values(data);
669
+ if (typeof data === "object" && data !== null && !Array.isArray(data))
670
+ return Object.values(data);
597
671
  return [];
598
672
  case "type":
599
673
  if (data === null) return "null";
@@ -0,0 +1,4 @@
1
+ import type { Context } from '@wrongstack/core/agent';
2
+ import type { KanbanToolInput, KanbanToolOutput } from './kanban-tool-types.js';
3
+ export declare function handleKanbanBoardAction(projectRoot: string, input: KanbanToolInput, ctx: Context): Promise<KanbanToolOutput | undefined>;
4
+ //# sourceMappingURL=kanban-board-actions.d.ts.map
@@ -0,0 +1,4 @@
1
+ import type { Context } from '@wrongstack/core/agent';
2
+ import type { KanbanToolInput, KanbanToolOutput } from './kanban-tool-types.js';
3
+ export declare function handleKanbanLifecycleAction(projectRoot: string, input: KanbanToolInput, ctx: Context): Promise<KanbanToolOutput | undefined>;
4
+ //# sourceMappingURL=kanban-lifecycle-actions.d.ts.map
@@ -0,0 +1,21 @@
1
+ import type { KanbanToolOutput } from './kanban-tool-types.js';
2
+ /**
3
+ * How many serialized bytes a `board` may occupy in the transcript before a
4
+ * mutation result swaps it for a compact summary. Read actions whose purpose
5
+ * IS the board (`get_board`, exports) always keep the full payload.
6
+ */
7
+ export declare const KANBAN_BOARD_TRANSCRIPT_BYTE_CAP = 16384;
8
+ /** Actions whose whole point is returning the full board — never trimmed. */
9
+ export declare const KANBAN_FULL_BOARD_ACTIONS: Set<string>;
10
+ /**
11
+ * Transcript serializer for kanban results. Every mutation returns the full
12
+ * board so programmatic consumers (todo mirror, gates, tests) can chain off it,
13
+ * but replaying that board into the LLM transcript on EVERY add_note /
14
+ * transition_task turns a busy board into thousands of repeated tokens.
15
+ * When the serialized board exceeds the cap and the action is not a
16
+ * board-reading one, the transcript payload carries a compact summary
17
+ * ({column → task count}, totalTasks) plus the affected `task` and `message`.
18
+ * `execute()`'s return shape is unchanged — this only affects the transcript.
19
+ */
20
+ export declare function serializeKanbanOutput(output: KanbanToolOutput, input: unknown): string;
21
+ //# sourceMappingURL=kanban-serializer.d.ts.map