next-issue 2.4.0 → 2.4.2

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/exec.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { spawn } from "node:child_process";
1
+ import { spawn } from 'node:child_process';
2
2
  let observer;
3
3
  let defaultTimeoutMs = 10 * 60_000;
4
4
  const STDERR_TAIL = 200_000;
@@ -20,16 +20,16 @@ export function stopChildren(signal) {
20
20
  catch { }
21
21
  }
22
22
  groups.clear();
23
- process.off("SIGTERM", onTerminate);
23
+ process.off('SIGTERM', onTerminate);
24
24
  process.kill(process.pid, signal);
25
25
  }
26
- const onTerminate = () => stopChildren("SIGTERM");
26
+ const onTerminate = () => stopChildren('SIGTERM');
27
27
  function watch(pid) {
28
28
  if (pid === undefined) {
29
29
  return;
30
30
  }
31
31
  if (groups.size === 0) {
32
- process.on("SIGTERM", onTerminate);
32
+ process.on('SIGTERM', onTerminate);
33
33
  }
34
34
  groups.add(pid);
35
35
  }
@@ -39,13 +39,13 @@ function unwatch(pid) {
39
39
  }
40
40
  groups.delete(pid);
41
41
  if (groups.size === 0) {
42
- process.off("SIGTERM", onTerminate);
42
+ process.off('SIGTERM', onTerminate);
43
43
  }
44
44
  }
45
45
  export function track(child) {
46
46
  watch(child.pid);
47
- child.on("close", () => unwatch(child.pid));
48
- child.on("error", () => unwatch(child.pid));
47
+ child.on('close', () => unwatch(child.pid));
48
+ child.on('error', () => unwatch(child.pid));
49
49
  }
50
50
  export function setCommandObserver(next) {
51
51
  observer = next;
@@ -61,19 +61,19 @@ export function run(command, args, options = {}) {
61
61
  cwd: options.cwd,
62
62
  detached: true,
63
63
  stdio: [
64
- options.input === undefined ? "ignore" : "pipe",
65
- options.show === true ? 2 : "pipe",
66
- "pipe",
64
+ options.input === undefined ? 'ignore' : 'pipe',
65
+ options.show === true ? 2 : 'pipe',
66
+ 'pipe',
67
67
  ],
68
68
  });
69
69
  const pid = child.pid;
70
70
  watch(pid);
71
- let stdout = "";
72
- let stderr = "";
71
+ let stdout = '';
72
+ let stderr = '';
73
73
  let timedOut = false;
74
- child.stdout?.setEncoding("utf8");
75
- child.stderr?.setEncoding("utf8");
76
- child.stdout?.on("data", (chunk) => {
74
+ child.stdout?.setEncoding('utf8');
75
+ child.stderr?.setEncoding('utf8');
76
+ child.stdout?.on('data', (chunk) => {
77
77
  options.onStdout?.(chunk);
78
78
  stdout += chunk;
79
79
  if (options.tailChars !== undefined && stdout.length > options.tailChars) {
@@ -81,7 +81,7 @@ export function run(command, args, options = {}) {
81
81
  }
82
82
  });
83
83
  const stderrLimit = options.tailChars ?? STDERR_TAIL;
84
- child.stderr?.on("data", (chunk) => {
84
+ child.stderr?.on('data', (chunk) => {
85
85
  stderr += chunk;
86
86
  if (stderr.length > stderrLimit) {
87
87
  stderr = stderr.slice(-stderrLimit);
@@ -90,14 +90,14 @@ export function run(command, args, options = {}) {
90
90
  const timer = setTimeout(() => {
91
91
  timedOut = true;
92
92
  if (pid === undefined) {
93
- child.kill("SIGKILL");
93
+ child.kill('SIGKILL');
94
94
  return;
95
95
  }
96
96
  try {
97
- process.kill(-pid, "SIGKILL");
97
+ process.kill(-pid, 'SIGKILL');
98
98
  }
99
99
  catch {
100
- child.kill("SIGKILL");
100
+ child.kill('SIGKILL');
101
101
  }
102
102
  }, limit);
103
103
  let done = false;
@@ -115,18 +115,18 @@ export function run(command, args, options = {}) {
115
115
  cwd: options.cwd,
116
116
  code: result.code,
117
117
  ms: Date.now() - started,
118
- stderr: result.code === 0 ? "" : stderr.trim(),
118
+ stderr: result.code === 0 ? '' : stderr.trim(),
119
119
  timedOut,
120
120
  });
121
121
  resolve(result);
122
122
  };
123
- child.on("error", (error) => {
123
+ child.on('error', (error) => {
124
124
  clearTimeout(timer);
125
125
  unwatch(pid);
126
126
  done = true;
127
127
  reject(error);
128
128
  });
129
- child.on("exit", (code) => {
129
+ child.on('exit', (code) => {
130
130
  if (!timedOut) {
131
131
  return;
132
132
  }
@@ -134,9 +134,9 @@ export function run(command, args, options = {}) {
134
134
  child.stderr?.destroy();
135
135
  settle(code);
136
136
  });
137
- child.on("close", settle);
137
+ child.on('close', settle);
138
138
  if (options.input !== undefined) {
139
- child.stdin?.on("error", () => undefined);
139
+ child.stdin?.on('error', () => undefined);
140
140
  child.stdin?.end(options.input);
141
141
  }
142
142
  });
@@ -144,10 +144,10 @@ export function run(command, args, options = {}) {
144
144
  export async function must(command, args, options = {}) {
145
145
  const result = await run(command, args, options);
146
146
  if (result.timedOut) {
147
- throw new Error(`${command} ${args.join(" ")} did not finish in time.`);
147
+ throw new Error(`${command} ${args.join(' ')} did not finish in time.`);
148
148
  }
149
149
  if (result.code !== 0) {
150
- throw new Error(`${command} ${args.join(" ")} failed with code ${result.code}: ${result.stderr.trim()}`);
150
+ throw new Error(`${command} ${args.join(' ')} failed with code ${result.code}: ${result.stderr.trim()}`);
151
151
  }
152
152
  return result.stdout.trim();
153
153
  }
package/dist/git.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { appendFile, readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { must, run } from "./exec.mjs";
1
+ import { appendFile, readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { must, run } from './exec.mjs';
4
4
  const REMOTE_PATTERNS = [
5
5
  /^git@[^:]+:(?<owner>[^/]+)\/(?<name>[^/]+?)(?:\.git)?$/,
6
6
  /^ssh:\/\/[^/]+\/(?<owner>[^/]+)\/(?<name>[^/]+?)(?:\.git)?$/,
@@ -16,74 +16,74 @@ export function parseRemote(url) {
16
16
  throw new Error(`Cannot parse the git remote URL: ${url}`);
17
17
  }
18
18
  export async function repoRoot(cwd) {
19
- return must("git", ["rev-parse", "--show-toplevel"], { cwd });
19
+ return must('git', ['rev-parse', '--show-toplevel'], { cwd });
20
20
  }
21
21
  export async function detectRepo(cwd, remote) {
22
22
  const root = await repoRoot(cwd);
23
- const url = await must("git", ["remote", "get-url", remote], { cwd });
23
+ const url = await must('git', ['remote', 'get-url', remote], { cwd });
24
24
  const { owner, name } = parseRemote(url);
25
25
  return { owner, name, root };
26
26
  }
27
- export const WORKTREE_DIR = ".worktrees";
27
+ export const WORKTREE_DIR = '.worktrees';
28
28
  export function worktreePath(repo, issue) {
29
29
  return join(repo.root, WORKTREE_DIR, String(issue));
30
30
  }
31
31
  export async function addWorktree(repo, issue, branch, base, remote) {
32
32
  const upstream = `${remote}/${branch}`;
33
- await must("git", ["fetch", remote], { cwd: repo.root });
33
+ await must('git', ['fetch', remote], { cwd: repo.root });
34
34
  const baseUpdated = await updateBase(repo, base, remote);
35
- await must("git", ["worktree", "prune"], { cwd: repo.root });
36
- const pushed = await hasBranch(repo, upstream, "--remotes");
35
+ await must('git', ['worktree', 'prune'], { cwd: repo.root });
36
+ const pushed = await hasBranch(repo, upstream, '--remotes');
37
37
  const existing = await findWorktree(repo, branch);
38
38
  const path = existing ?? worktreePath(repo, issue);
39
39
  if (existing === undefined) {
40
40
  const args = (await hasBranch(repo, branch))
41
- ? ["worktree", "add", path, branch]
42
- : ["worktree", "add", "-b", branch, path, pushed ? upstream : `${remote}/${base}`];
43
- await must("git", args, { cwd: repo.root });
41
+ ? ['worktree', 'add', path, branch]
42
+ : ['worktree', 'add', '-b', branch, path, pushed ? upstream : `${remote}/${base}`];
43
+ await must('git', args, { cwd: repo.root });
44
44
  }
45
45
  if (pushed) {
46
- await run("git", ["merge", "--ff-only", upstream], { cwd: path });
46
+ await run('git', ['merge', '--ff-only', upstream], { cwd: path });
47
47
  }
48
48
  return { path, baseUpdated };
49
49
  }
50
50
  async function hasBranch(repo, name, ...flags) {
51
- const list = await must("git", ["branch", "--list", ...flags, name], { cwd: repo.root });
51
+ const list = await must('git', ['branch', '--list', ...flags, name], { cwd: repo.root });
52
52
  return list.length > 0;
53
53
  }
54
54
  export async function updateBase(repo, base, remote) {
55
- const head = await run("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], { cwd: repo.root });
55
+ const head = await run('git', ['symbolic-ref', '--quiet', '--short', 'HEAD'], { cwd: repo.root });
56
56
  const args = head.code === 0 && head.stdout.trim() === base
57
- ? ["merge", "--ff-only", `${remote}/${base}`]
58
- : ["fetch", ".", `${remote}/${base}:${base}`];
59
- const result = await run("git", args, { cwd: repo.root });
57
+ ? ['merge', '--ff-only', `${remote}/${base}`]
58
+ : ['fetch', '.', `${remote}/${base}:${base}`];
59
+ const result = await run('git', args, { cwd: repo.root });
60
60
  return result.code === 0;
61
61
  }
62
62
  export async function findWorktree(repo, branch) {
63
- const list = await must("git", ["worktree", "list", "--porcelain"], { cwd: repo.root });
63
+ const list = await must('git', ['worktree', 'list', '--porcelain'], { cwd: repo.root });
64
64
  const entry = list
65
- .split("\n\n")
66
- .map((block) => block.split("\n"))
65
+ .split('\n\n')
66
+ .map((block) => block.split('\n'))
67
67
  .find((lines) => lines.includes(`branch refs/heads/${branch}`));
68
- return entry?.find((line) => line.startsWith("worktree "))?.slice("worktree ".length);
68
+ return entry?.find((line) => line.startsWith('worktree '))?.slice('worktree '.length);
69
69
  }
70
70
  export async function removeWorktree(repo, path) {
71
- const result = await run("git", ["worktree", "remove", path], { cwd: repo.root });
71
+ const result = await run('git', ['worktree', 'remove', path], { cwd: repo.root });
72
72
  return result.code === 0;
73
73
  }
74
74
  export async function ensureIgnored(root, entry) {
75
- const path = join(root, ".gitignore");
76
- let current = "";
75
+ const path = join(root, '.gitignore');
76
+ let current = '';
77
77
  try {
78
- current = await readFile(path, "utf8");
78
+ current = await readFile(path, 'utf8');
79
79
  }
80
80
  catch {
81
- current = "";
81
+ current = '';
82
82
  }
83
- if (current.split("\n").some((line) => line.trim() === entry)) {
83
+ if (current.split('\n').some((line) => line.trim() === entry)) {
84
84
  return false;
85
85
  }
86
- const gap = current.length === 0 || current.endsWith("\n") ? "" : "\n";
86
+ const gap = current.length === 0 || current.endsWith('\n') ? '' : '\n';
87
87
  await appendFile(path, `${gap}${entry}\n`);
88
88
  return true;
89
89
  }
@@ -91,39 +91,39 @@ export function branchName(issue) {
91
91
  return String(issue);
92
92
  }
93
93
  export async function isDirty(cwd) {
94
- const status = await must("git", ["status", "--porcelain"], { cwd });
94
+ const status = await must('git', ['status', '--porcelain'], { cwd });
95
95
  return status.length > 0;
96
96
  }
97
97
  export async function diff(cwd, base, remote) {
98
- return must("git", ["diff", `${remote}/${base}...HEAD`], { cwd });
98
+ return must('git', ['diff', `${remote}/${base}...HEAD`], { cwd });
99
99
  }
100
100
  export async function commitAll(cwd, message) {
101
101
  if (!(await isDirty(cwd))) {
102
102
  return false;
103
103
  }
104
- await must("git", ["add", "-A"], { cwd });
105
- await must("git", ["commit", "-m", message], { cwd });
104
+ await must('git', ['add', '-A'], { cwd });
105
+ await must('git', ['commit', '-m', message], { cwd });
106
106
  return true;
107
107
  }
108
108
  export async function discardChanges(cwd, target) {
109
109
  if (!(await isDirty(cwd)) && (await revision(cwd)) === target) {
110
110
  return false;
111
111
  }
112
- await must("git", ["reset", "--hard", target], { cwd });
113
- await must("git", ["clean", "-fd"], { cwd });
112
+ await must('git', ['reset', '--hard', target], { cwd });
113
+ await must('git', ['clean', '-fd'], { cwd });
114
114
  return true;
115
115
  }
116
116
  export async function push(cwd, remote, branch, force = false) {
117
- await must("git", ["push", "-u", ...(force ? ["--force"] : []), remote, branch], { cwd });
117
+ await must('git', ['push', '-u', ...(force ? ['--force'] : []), remote, branch], { cwd });
118
118
  }
119
119
  export async function resetToBase(cwd, base, remote) {
120
- await must("git", ["fetch", remote, base], { cwd });
121
- await must("git", ["reset", "--hard", `${remote}/${base}`], { cwd });
120
+ await must('git', ['fetch', remote, base], { cwd });
121
+ await must('git', ['reset', '--hard', `${remote}/${base}`], { cwd });
122
122
  }
123
123
  export async function revision(cwd) {
124
- return must("git", ["rev-parse", "HEAD"], { cwd });
124
+ return must('git', ['rev-parse', 'HEAD'], { cwd });
125
125
  }
126
126
  export async function deleteBranch(repo, branch) {
127
- const result = await run("git", ["branch", "-D", branch], { cwd: repo.root });
127
+ const result = await run('git', ['branch', '-D', branch], { cwd: repo.root });
128
128
  return result.code === 0;
129
129
  }