@wrongstack/tools 0.8.5 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/builtin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { spawn, execFileSync, spawnSync } from 'node:child_process';
2
2
  import { buildChildEnv, stripAnsi, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, compileGlob, loadPlan, emptyPlan, clearPlan, savePlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, formatPlan } from '@wrongstack/core';
3
3
  import * as path from 'node:path';
4
- import { dirname } from 'node:path';
4
+ import { resolve, sep, dirname } from 'node:path';
5
5
  import * as os from 'node:os';
6
6
  import * as fs11 from 'node:fs/promises';
7
7
  import { stat } from 'node:fs/promises';
@@ -66,8 +66,8 @@ async function* spawnStream(opts) {
66
66
  let spawnFailed = false;
67
67
  for (; ; ) {
68
68
  while (queue.length === 0) {
69
- await new Promise((resolve6) => {
70
- waiter = resolve6;
69
+ await new Promise((resolve7) => {
70
+ waiter = resolve7;
71
71
  });
72
72
  }
73
73
  const chunk = queue.shift();
@@ -742,10 +742,10 @@ var bashTool = {
742
742
  queue.push(c);
743
743
  }
744
744
  };
745
- const next = () => new Promise((resolve6) => {
745
+ const next = () => new Promise((resolve7) => {
746
746
  const c = queue.shift();
747
- if (c) resolve6(c);
748
- else resolveNext = resolve6;
747
+ if (c) resolve7(c);
748
+ else resolveNext = resolve7;
749
749
  });
750
750
  let lastFlush = Date.now();
751
751
  const flush = () => {
@@ -2970,7 +2970,7 @@ function findGitDir(cwd) {
2970
2970
  return null;
2971
2971
  }
2972
2972
  function runGit(args, cwd, signal) {
2973
- return new Promise((resolve6) => {
2973
+ return new Promise((resolve7) => {
2974
2974
  let stdout = "";
2975
2975
  let stderr = "";
2976
2976
  const child = spawn("git", args, { cwd, signal, env: buildChildEnv(), stdio: ["ignore", "pipe", "pipe"] });
@@ -2980,8 +2980,8 @@ function runGit(args, cwd, signal) {
2980
2980
  child.stderr?.on("data", (c) => {
2981
2981
  stderr += c.toString();
2982
2982
  });
2983
- child.on("close", (code) => resolve6({ stdout, stderr, exitCode: code ?? 0 }));
2984
- child.on("error", (e) => resolve6({ stdout: "", stderr: e.message, exitCode: 1 }));
2983
+ child.on("close", (code) => resolve7({ stdout, stderr, exitCode: code ?? 0 }));
2984
+ child.on("error", (e) => resolve7({ stdout: "", stderr: e.message, exitCode: 1 }));
2985
2985
  });
2986
2986
  }
2987
2987
  async function fileDiff(input, ctx, signal) {
@@ -3469,7 +3469,7 @@ var execTool = {
3469
3469
  }
3470
3470
  };
3471
3471
  function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
3472
- return new Promise((resolve6) => {
3472
+ return new Promise((resolve7) => {
3473
3473
  let stdout = "";
3474
3474
  let stderr = "";
3475
3475
  let killed = false;
@@ -3503,7 +3503,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
3503
3503
  const durationMs = Date.now() - startedAt;
3504
3504
  const exitCode = killed ? 124 : code ?? 1;
3505
3505
  registry.afterCall(durationMs, exitCode !== 0);
3506
- resolve6({
3506
+ resolve7({
3507
3507
  command: cmd,
3508
3508
  args,
3509
3509
  stdout: stdout.slice(0, MAX_OUTPUT2),
@@ -3517,7 +3517,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
3517
3517
  clearTimeout(timer);
3518
3518
  if (typeof pid === "number") registry.unregister(pid);
3519
3519
  registry.afterCall(Date.now() - startedAt, true);
3520
- resolve6({
3520
+ resolve7({
3521
3521
  command: cmd,
3522
3522
  args,
3523
3523
  stdout: stdout.slice(0, MAX_OUTPUT2),
@@ -4038,6 +4038,10 @@ var gitTool = {
4038
4038
  truncated: false
4039
4039
  };
4040
4040
  }
4041
+ if (input.command === "worktree") {
4042
+ const guard = validateWorktreeInput(input, ctx.projectRoot);
4043
+ if (guard) return guard;
4044
+ }
4041
4045
  const gitDir = findGitDir2(ctx.cwd, ctx.projectRoot);
4042
4046
  if (!gitDir) {
4043
4047
  return {
@@ -4052,13 +4056,34 @@ var gitTool = {
4052
4056
  return await runGit2(args, gitDir, opts.signal);
4053
4057
  }
4054
4058
  };
4059
+ function validateWorktreeInput(input, projectRoot) {
4060
+ const reject = (stderr) => ({
4061
+ command: "worktree",
4062
+ stdout: "",
4063
+ stderr,
4064
+ exitCode: 1,
4065
+ truncated: false
4066
+ });
4067
+ if (input.branch?.startsWith("-")) return reject(`unsafe branch name: ${input.branch}`);
4068
+ if (input.worktreePath?.startsWith("-")) {
4069
+ return reject(`unsafe worktree path: ${input.worktreePath}`);
4070
+ }
4071
+ if ((input.worktreeAction === "add" || input.worktreeAction === "remove") && input.worktreePath) {
4072
+ const root = resolve(projectRoot);
4073
+ const abs = resolve(root, input.worktreePath);
4074
+ if (abs !== root && !abs.startsWith(root + sep)) {
4075
+ return reject(`unsafe worktree path (escapes project root): ${input.worktreePath}`);
4076
+ }
4077
+ }
4078
+ return null;
4079
+ }
4055
4080
  function findGitDir2(cwd, projectRoot) {
4056
4081
  const root = projectRoot;
4057
4082
  let dir = cwd;
4058
4083
  for (let i = 0; i < 20; i++) {
4059
4084
  try {
4060
4085
  const stat11 = statSync(`${dir}/.git`);
4061
- if (stat11.isDirectory()) return dir;
4086
+ if (stat11.isDirectory() || stat11.isFile()) return dir;
4062
4087
  } catch {
4063
4088
  }
4064
4089
  if (dir === root) break;
@@ -4114,14 +4139,14 @@ function buildArgs(input) {
4114
4139
  switch (input.worktreeAction) {
4115
4140
  case "list":
4116
4141
  return ["worktree", "list"];
4117
- case "add":
4118
- return [
4119
- "worktree",
4120
- "add",
4121
- ...input.newBranch ? ["-b"] : [],
4122
- ...input.branch ? [input.branch] : [],
4123
- input.worktreePath ?? ""
4124
- ].filter(Boolean);
4142
+ case "add": {
4143
+ if (!input.worktreePath) return ["worktree", "list"];
4144
+ const add = ["worktree", "add"];
4145
+ if (input.newBranch && input.branch) add.push("-b", input.branch);
4146
+ add.push(input.worktreePath);
4147
+ if (!input.newBranch && input.branch) add.push(input.branch);
4148
+ return add;
4149
+ }
4125
4150
  case "remove":
4126
4151
  return [
4127
4152
  "worktree",
@@ -4139,7 +4164,7 @@ function buildArgs(input) {
4139
4164
  }
4140
4165
  }
4141
4166
  function runGit2(args, cwd, signal) {
4142
- return new Promise((resolve6) => {
4167
+ return new Promise((resolve7) => {
4143
4168
  let stdout = "";
4144
4169
  let stderr = "";
4145
4170
  const child = spawn("git", args, {
@@ -4159,7 +4184,7 @@ function runGit2(args, cwd, signal) {
4159
4184
  }
4160
4185
  });
4161
4186
  child.on("error", (err) => {
4162
- resolve6({
4187
+ resolve7({
4163
4188
  command: args[0],
4164
4189
  stdout,
4165
4190
  stderr: err.message,
@@ -4168,7 +4193,7 @@ function runGit2(args, cwd, signal) {
4168
4193
  });
4169
4194
  });
4170
4195
  child.on("close", (code) => {
4171
- resolve6({
4196
+ resolve7({
4172
4197
  command: args[0],
4173
4198
  stdout: stdout.slice(0, MAX_OUTPUT3),
4174
4199
  stderr: stderr.slice(0, MAX_OUTPUT3),
@@ -4354,13 +4379,13 @@ var grepTool = {
4354
4379
  }
4355
4380
  };
4356
4381
  async function detectRg(signal) {
4357
- return new Promise((resolve6) => {
4382
+ return new Promise((resolve7) => {
4358
4383
  try {
4359
4384
  const p = spawn("rg", ["--version"], { env: buildChildEnv(), stdio: "ignore", signal });
4360
- p.on("error", () => resolve6(false));
4361
- p.on("close", (code) => resolve6(code === 0));
4385
+ p.on("error", () => resolve7(false));
4386
+ p.on("close", (code) => resolve7(code === 0));
4362
4387
  } catch {
4363
- resolve6(false);
4388
+ resolve7(false);
4364
4389
  }
4365
4390
  });
4366
4391
  }
@@ -4967,7 +4992,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
4967
4992
  };
4968
4993
  }
4969
4994
  args.push("--timestamps", service);
4970
- return new Promise((resolve6) => {
4995
+ return new Promise((resolve7) => {
4971
4996
  let stdout = "";
4972
4997
  let stderr = "";
4973
4998
  const MAX = 2e5;
@@ -4983,7 +5008,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
4983
5008
  if (settled) return;
4984
5009
  settled = true;
4985
5010
  clearTimeout(timer);
4986
- resolve6(result);
5011
+ resolve7(result);
4987
5012
  };
4988
5013
  const child = spawn("docker", args, { cwd, signal, env: buildChildEnv(), stdio: ["ignore", "pipe", "pipe"] });
4989
5014
  const timer = setTimeout(() => {
@@ -5134,7 +5159,7 @@ async function detectManager2(cwd) {
5134
5159
  return "npm";
5135
5160
  }
5136
5161
  function runOutdated(manager, args, cwd, signal) {
5137
- return new Promise((resolve6) => {
5162
+ return new Promise((resolve7) => {
5138
5163
  let stdout = "";
5139
5164
  let stderr = "";
5140
5165
  const MAX = 1e5;
@@ -5147,10 +5172,10 @@ function runOutdated(manager, args, cwd, signal) {
5147
5172
  });
5148
5173
  child.on("close", (code) => {
5149
5174
  const result = parseOutdatedOutput(stdout, code ?? 0);
5150
- resolve6(result);
5175
+ resolve7(result);
5151
5176
  });
5152
5177
  child.on("error", (e) => {
5153
- resolve6({
5178
+ resolve7({
5154
5179
  exit_code: 1,
5155
5180
  packages: [],
5156
5181
  total: 0,
@@ -5280,7 +5305,7 @@ function stripPathComponents(p, strip) {
5280
5305
  return parts.slice(strip).join("/");
5281
5306
  }
5282
5307
  function runPatch(args, cwd, signal) {
5283
- return new Promise((resolve6) => {
5308
+ return new Promise((resolve7) => {
5284
5309
  let stdout = "";
5285
5310
  let stderr = "";
5286
5311
  const env = { ...buildChildEnv(), LANG: "C", LC_ALL: "C" };
@@ -5291,8 +5316,8 @@ function runPatch(args, cwd, signal) {
5291
5316
  child.stderr?.on("data", (c) => {
5292
5317
  stderr += c.toString();
5293
5318
  });
5294
- child.on("close", (code) => resolve6({ exitCode: code ?? 1, stdout, stderr }));
5295
- child.on("error", (e) => resolve6({ exitCode: 1, stdout: "", stderr: e.message }));
5319
+ child.on("close", (code) => resolve7({ exitCode: code ?? 1, stdout, stderr }));
5320
+ child.on("error", (e) => resolve7({ exitCode: 1, stdout: "", stderr: e.message }));
5296
5321
  });
5297
5322
  }
5298
5323
  function extractPatchedFiles(output) {
@@ -5635,13 +5660,13 @@ async function globFiles(pattern, base, extraGlob) {
5635
5660
  return await globNative(pattern, base, extraGlob);
5636
5661
  }
5637
5662
  function checkRg() {
5638
- return new Promise((resolve6) => {
5663
+ return new Promise((resolve7) => {
5639
5664
  try {
5640
5665
  const p = spawn("rg", ["--version"], { env: buildChildEnv(), stdio: "ignore" });
5641
- p.on("error", () => resolve6(false));
5642
- p.on("close", (code) => resolve6(code === 0));
5666
+ p.on("error", () => resolve7(false));
5667
+ p.on("close", (code) => resolve7(code === 0));
5643
5668
  } catch {
5644
- resolve6(false);
5669
+ resolve7(false);
5645
5670
  }
5646
5671
  });
5647
5672
  }
@@ -5653,10 +5678,10 @@ function spawnRgFind(pattern, base) {
5653
5678
  buf += chunk.toString();
5654
5679
  });
5655
5680
  return {
5656
- promise: new Promise((resolve6, reject) => {
5681
+ promise: new Promise((resolve7, reject) => {
5657
5682
  child.on("error", reject);
5658
5683
  child.on("close", () => {
5659
- resolve6(buf.split("\n").filter(Boolean));
5684
+ resolve7(buf.split("\n").filter(Boolean));
5660
5685
  });
5661
5686
  })
5662
5687
  };