git-stack-cli 2.0.1-beta → 2.1.1-beta

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/js/index.js CHANGED
@@ -28099,6 +28099,7 @@ var require_last = __commonJS((exports, module) => {
28099
28099
 
28100
28100
  // src/index.tsx
28101
28101
  var React55 = __toESM(require_react(), 1);
28102
+ import fs14 from "node:fs/promises";
28102
28103
 
28103
28104
  // node_modules/.pnpm/ink-cjs@4.4.1_@types+react@18.2.33_react-devtools-core@4.19.1_react@18.2.0/node_modules/ink-cjs/build/render.js
28104
28105
  import { Stream } from "node:stream";
@@ -37796,7 +37797,7 @@ function Url(props) {
37796
37797
  import fs7 from "node:fs";
37797
37798
  import path4 from "node:path";
37798
37799
  function is_command_available(command) {
37799
- const PATH = "/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/.bun/bin:/Users/noah/Library/Caches/fnm_multishells/10609_1737115106756/bin:/usr/local/sbin:/usr/local/bin:/usr/local/bin:/usr/local/sbin:/Users/noah/.dotfiles/bin:/usr/local/sbin:/usr/local/bin:/Users/noah/.rvm/gems/ruby-2.6.3/bin:/Users/noah/.rvm/gems/ruby-2.6.3@global/bin:/Users/noah/.rvm/rubies/ruby-2.6.3/bin:/Users/noah/Library/pnpm:/Users/noah/.bun/bin:/Users/noah/Library/Caches/fnm_multishells/7244_1737114463742/bin:/usr/local/sbin:/usr/local/bin:/usr/local/bin:/usr/local/sbin:/Users/noah/.dotfiles/bin:/usr/local/sbin:/usr/local/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Library/Apple/usr/bin:/Applications/Postgres.app/Contents/Versions/latest/bin:/Users/noah/.cargo/bin:/Applications/iTerm.app/Contents/Resources/utilities:/Users/noah/google-cloud-sdk/bin:/Users/noah/.yarn/bin:/Users/noah/.fastlane/bin:/usr/local/opt/fzf/bin:/Users/noah/google-cloud-sdk/bin:/Users/noah/.yarn/bin:/Users/noah/.fastlane/bin:/Users/noah/.rvm/bin:/Users/noah/google-cloud-sdk/bin:/Users/noah/.yarn/bin:/Users/noah/.fastlane/bin:/Users/noah/google-cloud-sdk/bin:/Users/noah/.yarn/bin:/Users/noah/.fastlane/bin";
37800
+ const PATH = "/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/.rvm/gems/ruby-2.6.3/bin:/Users/noah/.rvm/gems/ruby-2.6.3@global/bin:/Users/noah/.rvm/rubies/ruby-2.6.3/bin:/Users/noah/Library/pnpm:/Users/noah/.bun/bin:/Users/noah/Library/Caches/fnm_multishells/45565_1737429645385/bin:/usr/local/sbin:/usr/local/bin:/usr/local/bin:/usr/local/sbin:/Users/noah/.dotfiles/bin:/usr/local/sbin:/usr/local/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Library/Apple/usr/bin:/Applications/Postgres.app/Contents/Versions/latest/bin:/Users/noah/.cargo/bin:/Applications/iTerm.app/Contents/Resources/utilities:/Users/noah/google-cloud-sdk/bin:/Users/noah/.yarn/bin:/Users/noah/.fastlane/bin:/usr/local/opt/fzf/bin:/Users/noah/google-cloud-sdk/bin:/Users/noah/.yarn/bin:/Users/noah/.fastlane/bin:/Users/noah/.rvm/bin";
37800
37801
  invariant(PATH, "PATH env must exist");
37801
37802
  const path_list = PATH.split(path4.delimiter);
37802
37803
  for (const dir of path_list) {
@@ -38015,9 +38016,21 @@ var RE3 = {
38015
38016
 
38016
38017
  // src/core/github.tsx
38017
38018
  var React24 = __toESM(require_react(), 1);
38019
+ import crypto from "node:crypto";
38020
+ import fs9 from "node:fs/promises";
38021
+ import path6 from "node:path";
38022
+
38023
+ // src/core/get_tmp_dir.ts
38018
38024
  import fs8 from "node:fs/promises";
38019
38025
  import os2 from "node:os";
38020
38026
  import path5 from "node:path";
38027
+ async function get_tmp_dir() {
38028
+ const dir = path5.join(os2.tmpdir(), "git-stack-cli");
38029
+ await fs8.mkdir(dir, { recursive: true });
38030
+ return dir;
38031
+ }
38032
+
38033
+ // src/core/github.tsx
38021
38034
  async function pr_list() {
38022
38035
  const state = Store.getState();
38023
38036
  const actions = state.actions;
@@ -38054,7 +38067,7 @@ async function pr_status(branch) {
38054
38067
  const cache4 = state.pr[branch];
38055
38068
  if (cache4) {
38056
38069
  if (actions.isDebug()) {
38057
- actions.output(/* @__PURE__ */ React24.createElement(Text, null, /* @__PURE__ */ React24.createElement(Text, {
38070
+ actions.debug(/* @__PURE__ */ React24.createElement(Text, null, /* @__PURE__ */ React24.createElement(Text, {
38058
38071
  dimColor: true
38059
38072
  }, "Github pr_status cache"), /* @__PURE__ */ React24.createElement(Text, null, " "), /* @__PURE__ */ React24.createElement(Text, {
38060
38073
  bold: true,
@@ -38066,7 +38079,7 @@ async function pr_status(branch) {
38066
38079
  return cache4;
38067
38080
  }
38068
38081
  if (actions.isDebug()) {
38069
- actions.output(/* @__PURE__ */ React24.createElement(Text, null, /* @__PURE__ */ React24.createElement(Text, {
38082
+ actions.debug(/* @__PURE__ */ React24.createElement(Text, null, /* @__PURE__ */ React24.createElement(Text, {
38070
38083
  dimColor: true
38071
38084
  }, "Github pr_status cache"), /* @__PURE__ */ React24.createElement(Text, null, " "), /* @__PURE__ */ React24.createElement(Text, {
38072
38085
  bold: true,
@@ -38146,15 +38159,21 @@ async function pr_draft(args) {
38146
38159
  }
38147
38160
  var JSON_FIELDS = "--json id,number,state,baseRefName,headRefName,commits,title,body,url,isDraft";
38148
38161
  async function gh_json(command) {
38149
- const tmp_pr_json = path5.join(os2.tmpdir(), "git-stack-gh.json");
38162
+ let hash = crypto.createHash("md5").update(command).digest("hex");
38163
+ let tmp_filename = safe_filename(`gh_json-${hash}`);
38164
+ const tmp_pr_json = path6.join(await get_tmp_dir(), `${tmp_filename}.json`);
38150
38165
  const options = { ignoreExitCode: true };
38151
38166
  const cli_result = await cli(`gh ${command} > ${tmp_pr_json}`, options);
38152
38167
  if (cli_result.code !== 0) {
38153
38168
  return new Error(cli_result.output);
38154
38169
  }
38155
- const json_str = await fs8.readFile(tmp_pr_json, "utf-8");
38156
- const json = JSON.parse(json_str);
38157
- return json;
38170
+ const json_str = String(await fs9.readFile(tmp_pr_json));
38171
+ try {
38172
+ const json = JSON.parse(json_str);
38173
+ return json;
38174
+ } catch (error) {
38175
+ return new Error(`gh_json JSON.parse: ${error}`);
38176
+ }
38158
38177
  }
38159
38178
  function handle_error(output) {
38160
38179
  const state = Store.getState();
@@ -38166,14 +38185,15 @@ function handle_error(output) {
38166
38185
  }
38167
38186
  async function write_body_file(args) {
38168
38187
  invariant(args.body, "args.body must exist");
38169
- const temp_dir = os2.tmpdir();
38170
- let temp_filename = `git-stack-body-${args.base}`;
38171
- temp_filename = temp_filename.replace(RE4.non_alphanumeric_dash, "-");
38172
- const temp_path = path5.join(temp_dir, temp_filename);
38188
+ let tmp_filename = safe_filename(`git-stack-body-${args.base}`);
38189
+ const temp_path = path6.join(await get_tmp_dir(), tmp_filename);
38173
38190
  await safe_rm(temp_path);
38174
- await fs8.writeFile(temp_path, args.body);
38191
+ await fs9.writeFile(temp_path, args.body);
38175
38192
  return temp_path;
38176
38193
  }
38194
+ function safe_filename(value) {
38195
+ return value.replace(RE4.non_alphanumeric_dash, "-");
38196
+ }
38177
38197
  var RE4 = {
38178
38198
  non_alphanumeric_dash: /[^a-zA-Z0-9_-]+/g
38179
38199
  };
@@ -38226,13 +38246,25 @@ async function range(commit_group_map) {
38226
38246
  const group_value_list = Array.from(group_map.values());
38227
38247
  const group_list = [];
38228
38248
  let unassigned_group;
38249
+ const pr_status_promise_list = {};
38250
+ for (const group of group_value_list) {
38251
+ if (group.id !== UNASSIGNED) {
38252
+ pr_status_promise_list[group.id] = pr_status(group.id);
38253
+ }
38254
+ }
38255
+ await Promise.all(Array.from(Object.values(pr_status_promise_list)));
38256
+ for (const [group_id, pr_status_promise] of Object.entries(pr_status_promise_list)) {
38257
+ const pr_status2 = await pr_status_promise;
38258
+ if (pr_status2) {
38259
+ pr_lookup[group_id] = pr_status2;
38260
+ }
38261
+ }
38229
38262
  for (let i2 = 0;i2 < group_value_list.length; i2++) {
38230
38263
  const group = group_value_list[i2];
38231
38264
  if (group.id !== UNASSIGNED) {
38232
- const pr_result = await pr_status(group.id);
38265
+ let pr_result = pr_lookup[group.id];
38233
38266
  if (pr_result && pr_result.state !== "CLOSED") {
38234
38267
  group.pr = pr_result;
38235
- pr_lookup[group.id] = pr_result;
38236
38268
  }
38237
38269
  }
38238
38270
  if (group.id === UNASSIGNED) {
@@ -38315,9 +38347,8 @@ function lines(value) {
38315
38347
  var UNASSIGNED = "unassigned";
38316
38348
 
38317
38349
  // src/core/GitReviseTodo.ts
38318
- import fs9 from "node:fs/promises";
38319
- import os3 from "node:os";
38320
- import path6 from "node:path";
38350
+ import fs10 from "node:fs/promises";
38351
+ import path7 from "node:path";
38321
38352
  function GitReviseTodo(args) {
38322
38353
  const commit_list = [];
38323
38354
  const group_list = args.commit_range.group_list;
@@ -38353,7 +38384,7 @@ GitReviseTodo.todo = function todo(args) {
38353
38384
  return todo2;
38354
38385
  };
38355
38386
  GitReviseTodo.execute = async function grt_execute(args) {
38356
- const tmp_git_sequence_editor_path = path6.join(os3.tmpdir(), "git-sequence-editor.sh");
38387
+ const tmp_git_sequence_editor_path = path7.join(await get_tmp_dir(), "git-sequence-editor.sh");
38357
38388
  const GIT_SEQUENCE_EDITOR_SCRIPT = `#!/bin/sh
38358
38389
 
38359
38390
  # Example
@@ -38391,8 +38422,8 @@ echo "------ END ------"
38391
38422
  echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
38392
38423
  `;
38393
38424
  invariant(GIT_SEQUENCE_EDITOR_SCRIPT, "GIT_SEQUENCE_EDITOR_SCRIPT must exist");
38394
- await fs9.writeFile(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
38395
- await fs9.chmod(tmp_git_sequence_editor_path, "755");
38425
+ await fs10.writeFile(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
38426
+ await fs10.chmod(tmp_git_sequence_editor_path, "755");
38396
38427
  const git_revise_todo = GitReviseTodo(args);
38397
38428
  const command = [
38398
38429
  `GIT_EDITOR="${tmp_git_sequence_editor_path}"`,
@@ -38469,7 +38500,7 @@ function DetectInitialPR(props) {
38469
38500
  const branch_name2 = Store.getState().branch_name;
38470
38501
  const commit_range = Store.getState().commit_range;
38471
38502
  invariant(branch_name2, "branch_name must exist");
38472
- invariant(commit_range, "branch_name must exist");
38503
+ invariant(commit_range, "commit_range must exist");
38473
38504
  try {
38474
38505
  let has_existing_metadata = false;
38475
38506
  for (const commit2 of commit_range.commit_list) {
@@ -38501,7 +38532,7 @@ function DetectInitialPR(props) {
38501
38532
  const branch_name2 = Store.getState().branch_name;
38502
38533
  const commit_range = import_cloneDeep.default(Store.getState().commit_range);
38503
38534
  invariant(branch_name2, "branch_name must exist");
38504
- invariant(commit_range, "branch_name must exist");
38535
+ invariant(commit_range, "commit_range must exist");
38505
38536
  for (const group of commit_range.group_list) {
38506
38537
  group.id = branch_name2;
38507
38538
  group.title = state.pr?.title || "-";
@@ -38833,16 +38864,16 @@ var React32 = __toESM(require_react(), 1);
38833
38864
 
38834
38865
  // src/commands/Rebase.tsx
38835
38866
  var React31 = __toESM(require_react(), 1);
38836
- import fs10 from "node:fs";
38867
+ import fs11 from "node:fs";
38837
38868
 
38838
38869
  // src/core/short_id.ts
38839
- import crypto from "node:crypto";
38870
+ import crypto2 from "node:crypto";
38840
38871
  function short_id() {
38841
38872
  const timestamp = Date.now();
38842
38873
  const js_max_bits = 53;
38843
38874
  const timestamp_bits = Math.floor(Math.log2(timestamp)) + 1;
38844
38875
  const padding_bits = js_max_bits - timestamp_bits;
38845
- const random = crypto.randomInt(0, Math.pow(2, padding_bits));
38876
+ const random = crypto2.randomInt(0, Math.pow(2, padding_bits));
38846
38877
  const combined = interleave_bits(timestamp, random);
38847
38878
  return encode(combined);
38848
38879
  }
@@ -38986,7 +39017,7 @@ Rebase.run = async function run4() {
38986
39017
  cli.sync(`git clean -df`, spawn_options);
38987
39018
  cli.sync(`git checkout ${branch_name}`, spawn_options);
38988
39019
  cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
38989
- if (fs10.existsSync(cwd2)) {
39020
+ if (fs11.existsSync(cwd2)) {
38990
39021
  process.chdir(cwd2);
38991
39022
  }
38992
39023
  cli.sync(`pwd`, spawn_options);
@@ -39009,7 +39040,7 @@ function LocalMergeRebase() {
39009
39040
 
39010
39041
  // src/app/ManualRebase.tsx
39011
39042
  var React33 = __toESM(require_react(), 1);
39012
- import fs11 from "node:fs";
39043
+ import fs12 from "node:fs";
39013
39044
  function ManualRebase() {
39014
39045
  return /* @__PURE__ */ React33.createElement(Await, {
39015
39046
  fallback: /* @__PURE__ */ React33.createElement(Text, {
@@ -39109,7 +39140,7 @@ async function run5() {
39109
39140
  cli.sync(`git clean -df`, spawn_options);
39110
39141
  cli.sync(`git checkout ${branch_name}`, spawn_options);
39111
39142
  cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
39112
- if (fs11.existsSync(cwd2)) {
39143
+ if (fs12.existsSync(cwd2)) {
39113
39144
  process.chdir(cwd2);
39114
39145
  }
39115
39146
  cli.sync(`pwd`, spawn_options);
@@ -39368,8 +39399,8 @@ function PreLocalMergeRebase() {
39368
39399
 
39369
39400
  // src/app/PreManualRebase.tsx
39370
39401
  var React38 = __toESM(require_react(), 1);
39371
- import fs12 from "node:fs/promises";
39372
- import path7 from "node:path";
39402
+ import fs13 from "node:fs/promises";
39403
+ import path8 from "node:path";
39373
39404
  function PreManualRebase() {
39374
39405
  return /* @__PURE__ */ React38.createElement(Await, {
39375
39406
  fallback: null,
@@ -39391,7 +39422,7 @@ async function run7() {
39391
39422
  for (const key of PR_TEMPLATE_KEY_LIST) {
39392
39423
  const pr_template_fn = PR_TEMPLATE[key];
39393
39424
  if (await safe_exists(pr_template_fn(repo_root))) {
39394
- pr_template_body = await fs12.readFile(pr_template_fn(repo_root), "utf-8");
39425
+ pr_template_body = await fs13.readFile(pr_template_fn(repo_root), "utf-8");
39395
39426
  actions.output(/* @__PURE__ */ React38.createElement(FormatText, {
39396
39427
  wrapper: /* @__PURE__ */ React38.createElement(Text, {
39397
39428
  color: colors.yellow
@@ -39406,7 +39437,7 @@ async function run7() {
39406
39437
  }
39407
39438
  let pr_templates = [];
39408
39439
  if (await safe_exists(PR_TEMPLATE.TemplateDir(repo_root))) {
39409
- pr_templates = await fs12.readdir(PR_TEMPLATE.TemplateDir(repo_root));
39440
+ pr_templates = await fs13.readdir(PR_TEMPLATE.TemplateDir(repo_root));
39410
39441
  }
39411
39442
  actions.set((state2) => {
39412
39443
  state2.pr_template_body = pr_template_body;
@@ -39429,10 +39460,10 @@ async function run7() {
39429
39460
  });
39430
39461
  }
39431
39462
  var PR_TEMPLATE = Object.freeze({
39432
- Github: (root) => path7.join(root, ".github", "pull_request_template.md"),
39433
- Root: (root) => path7.join(root, "pull_request_template.md"),
39434
- Docs: (root) => path7.join(root, "docs", "pull_request_template.md"),
39435
- TemplateDir: (root) => path7.join(root, ".github", "PULL_REQUEST_TEMPLATE")
39463
+ Github: (root) => path8.join(root, ".github", "pull_request_template.md"),
39464
+ Root: (root) => path8.join(root, "pull_request_template.md"),
39465
+ Docs: (root) => path8.join(root, "docs", "pull_request_template.md"),
39466
+ TemplateDir: (root) => path8.join(root, ".github", "PULL_REQUEST_TEMPLATE")
39436
39467
  });
39437
39468
  var PR_TEMPLATE_KEY_LIST = Object.keys(PR_TEMPLATE);
39438
39469
 
@@ -40414,7 +40445,7 @@ function Providers(props) {
40414
40445
 
40415
40446
  // src/app/RebaseCheck.tsx
40416
40447
  var React48 = __toESM(require_react(), 1);
40417
- import path8 from "node:path";
40448
+ import path9 from "node:path";
40418
40449
  function reducer5(state, patch) {
40419
40450
  return { ...state, ...patch };
40420
40451
  }
@@ -40452,8 +40483,8 @@ function RebaseCheck(props) {
40452
40483
  try {
40453
40484
  const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
40454
40485
  let is_rebase = false;
40455
- is_rebase ||= await safe_exists(path8.join(git_dir, "rebase-apply"));
40456
- is_rebase ||= await safe_exists(path8.join(git_dir, "rebase-merge"));
40486
+ is_rebase ||= await safe_exists(path9.join(git_dir, "rebase-apply"));
40487
+ is_rebase ||= await safe_exists(path9.join(git_dir, "rebase-merge"));
40457
40488
  const status = is_rebase ? "prompt" : "done";
40458
40489
  patch({ status });
40459
40490
  } catch (err) {
@@ -42009,9 +42040,9 @@ var parser = new YargsParser({
42009
42040
  format,
42010
42041
  normalize,
42011
42042
  resolve: resolve2,
42012
- require: (path9) => {
42043
+ require: (path10) => {
42013
42044
  if (true) {
42014
- return __require(path9);
42045
+ return __require(path10);
42015
42046
  } else
42016
42047
  ;
42017
42048
  }
@@ -45594,7 +45625,7 @@ var yargs_default = Yargs;
45594
45625
 
45595
45626
  // src/command.ts
45596
45627
  async function command2() {
45597
- return yargs_default(hideBin(process.argv)).usage("Usage: git stack [command] [options]").command("$0", "Sync commit ranges to Github", (yargs) => yargs.options(DefaultOptions)).command("fixup [commit]", "Amend staged changes to a specific commit in history", (yargs) => yargs.positional("commit", FixupOptions.commit)).command("log [args...]", "Print an abbreviated log with numbered commits, useful for git stack fixup", (yargs) => yargs.strict(false)).command("rebase", "Update local branch via rebase with latest changes from origin master branch", (yargs) => yargs).option("verbose", GlobalOptions.verbose).wrap(123).strict().version("2.0.1-beta").showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`").help("help", "Show usage via `git stack help`").argv;
45628
+ return yargs_default(hideBin(process.argv)).usage("Usage: git stack [command] [options]").command("$0", "Sync commit ranges to Github", (yargs) => yargs.options(DefaultOptions)).command("fixup [commit]", "Amend staged changes to a specific commit in history", (yargs) => yargs.positional("commit", FixupOptions.commit)).command("log [args...]", "Print an abbreviated log with numbered commits, useful for git stack fixup", (yargs) => yargs.strict(false)).command("rebase", "Update local branch via rebase with latest changes from origin master branch", (yargs) => yargs).option("verbose", GlobalOptions.verbose).wrap(123).strict().version("2.1.1-beta").showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`").help("help", "Show usage via `git stack help`").argv;
45598
45629
  }
45599
45630
  var GlobalOptions = {
45600
45631
  verbose: {
@@ -45703,6 +45734,8 @@ var FixupOptions = {
45703
45734
  maybe_verbose_help();
45704
45735
  process.exit(238);
45705
45736
  });
45737
+ const tmp_dir = await get_tmp_dir();
45738
+ await fs14.rm(tmp_dir, { recursive: true });
45706
45739
  const ink = render_default(/* @__PURE__ */ React55.createElement(App2, null), {
45707
45740
  exitOnCtrlC: false
45708
45741
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-stack-cli",
3
- "version": "2.0.1-beta",
3
+ "version": "2.1.1-beta",
4
4
  "description": "",
5
5
  "author": "magus",
6
6
  "license": "MIT",
@@ -52,6 +52,7 @@
52
52
  "zustand": "^4.4.4"
53
53
  },
54
54
  "devDependencies": {
55
+ "@oven/bun-darwin-aarch64": "1.1.42",
55
56
  "@types/chalk": "^2.2.0",
56
57
  "@types/lodash": "^4.17.7",
57
58
  "@types/luxon": "^3.4.2",
@@ -25,7 +25,9 @@ const previous_formula_path = path.join(HOMEBREW_DIR, "Formula", "git-stack.rb")
25
25
  // version = "1.0.4"
26
26
  //
27
27
  let previous_formula = await file.read_text(previous_formula_path);
28
- const re_version = /version(?: =)? "(?<version>\d+\.\d+\.\d+)"/m;
28
+
29
+ // https://regex101.com/r/BnvdqK/1
30
+ const re_version = /version(?: =)? "(?<version>\d+\.\d+\.\d+(?:-.+)?)"/m;
29
31
  const previous_version_match = previous_formula.match(re_version);
30
32
 
31
33
  if (!previous_version_match?.groups) {
@@ -108,7 +108,7 @@ export function DetectInitialPR(props: Props) {
108
108
  const commit_range = Store.getState().commit_range;
109
109
 
110
110
  invariant(branch_name, "branch_name must exist");
111
- invariant(commit_range, "branch_name must exist");
111
+ invariant(commit_range, "commit_range must exist");
112
112
 
113
113
  try {
114
114
  let has_existing_metadata = false;
@@ -149,7 +149,7 @@ export function DetectInitialPR(props: Props) {
149
149
  const commit_range = cloneDeep(Store.getState().commit_range);
150
150
 
151
151
  invariant(branch_name, "branch_name must exist");
152
- invariant(commit_range, "branch_name must exist");
152
+ invariant(commit_range, "commit_range must exist");
153
153
 
154
154
  for (const group of commit_range.group_list) {
155
155
  group.id = branch_name;
@@ -6,7 +6,8 @@ import * as github from "~/core/github";
6
6
  export type CommitMetadata = Awaited<ReturnType<typeof commit>>;
7
7
  export type CommitRange = Awaited<ReturnType<typeof range>>;
8
8
 
9
- type PullRequest = NonNullable<Awaited<ReturnType<typeof github.pr_status>>>;
9
+ type GithubPRStatus = ReturnType<typeof github.pr_status>;
10
+ type PullRequest = NonNullable<Awaited<GithubPRStatus>>;
10
11
 
11
12
  type CommitGroup = {
12
13
  id: string;
@@ -93,15 +94,31 @@ export async function range(commit_group_map?: CommitGroupMap) {
93
94
  const group_list = [];
94
95
  let unassigned_group;
95
96
 
97
+ // collect github pr status in parallel
98
+ const pr_status_promise_list: Record<string, GithubPRStatus> = {};
99
+ for (const group of group_value_list) {
100
+ if (group.id !== UNASSIGNED) {
101
+ pr_status_promise_list[group.id] = github.pr_status(group.id);
102
+ }
103
+ }
104
+
105
+ await Promise.all(Array.from(Object.values(pr_status_promise_list)));
106
+
107
+ for (const [group_id, pr_status_promise] of Object.entries(pr_status_promise_list)) {
108
+ const pr_status = await pr_status_promise;
109
+ if (pr_status) {
110
+ pr_lookup[group_id] = pr_status;
111
+ }
112
+ }
113
+
96
114
  for (let i = 0; i < group_value_list.length; i++) {
97
115
  const group = group_value_list[i];
98
116
 
99
117
  if (group.id !== UNASSIGNED) {
100
- const pr_result = await github.pr_status(group.id);
118
+ let pr_result = pr_lookup[group.id];
101
119
 
102
120
  if (pr_result && pr_result.state !== "CLOSED") {
103
121
  group.pr = pr_result;
104
- pr_lookup[group.id] = pr_result;
105
122
  }
106
123
  }
107
124
 
@@ -1,9 +1,9 @@
1
1
  import fs from "node:fs/promises";
2
- import os from "node:os";
3
2
  import path from "node:path";
4
3
 
5
4
  import * as Metadata from "~/core/Metadata";
6
5
  import { cli } from "~/core/cli";
6
+ import { get_tmp_dir } from "~/core/get_tmp_dir";
7
7
  import { invariant } from "~/core/invariant";
8
8
  import { safe_rm } from "~/core/safe_rm";
9
9
 
@@ -109,7 +109,7 @@ GitReviseTodo.todo = function todo(args: CommitListArgs) {
109
109
 
110
110
  GitReviseTodo.execute = async function grt_execute(args: ExecuteArgs) {
111
111
  // generate temporary directory and drop sequence editor script
112
- const tmp_git_sequence_editor_path = path.join(os.tmpdir(), "git-sequence-editor.sh");
112
+ const tmp_git_sequence_editor_path = path.join(await get_tmp_dir(), "git-sequence-editor.sh");
113
113
 
114
114
  // replaced at build time with literal contents of `scripts/git-sequence-editor.sh`
115
115
  const GIT_SEQUENCE_EDITOR_SCRIPT = process.env.GIT_SEQUENCE_EDITOR_SCRIPT;
@@ -0,0 +1,12 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+
5
+ export async function get_tmp_dir(): Promise<string> {
6
+ const dir = path.join(os.tmpdir(), "git-stack-cli");
7
+
8
+ // ensure tmp directory exists
9
+ await fs.mkdir(dir, { recursive: true });
10
+
11
+ return dir;
12
+ }
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
 
3
+ import crypto from "node:crypto";
3
4
  import fs from "node:fs/promises";
4
- import os from "node:os";
5
5
  import path from "node:path";
6
6
 
7
7
  import * as Ink from "ink-cjs";
@@ -10,6 +10,7 @@ import { Brackets } from "~/app/Brackets";
10
10
  import { Store } from "~/app/Store";
11
11
  import { cli } from "~/core/cli";
12
12
  import { colors } from "~/core/colors";
13
+ import { get_tmp_dir } from "~/core/get_tmp_dir";
13
14
  import { invariant } from "~/core/invariant";
14
15
  import { safe_quote } from "~/core/safe_quote";
15
16
  import { safe_rm } from "~/core/safe_rm";
@@ -68,7 +69,7 @@ export async function pr_status(branch: string): Promise<null | PullRequest> {
68
69
 
69
70
  if (cache) {
70
71
  if (actions.isDebug()) {
71
- actions.output(
72
+ actions.debug(
72
73
  <Ink.Text>
73
74
  <Ink.Text dimColor>Github pr_status cache</Ink.Text>
74
75
  <Ink.Text> </Ink.Text>
@@ -85,7 +86,7 @@ export async function pr_status(branch: string): Promise<null | PullRequest> {
85
86
  }
86
87
 
87
88
  if (actions.isDebug()) {
88
- actions.output(
89
+ actions.debug(
89
90
  <Ink.Text>
90
91
  <Ink.Text dimColor>Github pr_status cache</Ink.Text>
91
92
  <Ink.Text> </Ink.Text>
@@ -228,7 +229,10 @@ const JSON_FIELDS = "--json id,number,state,baseRefName,headRefName,commits,titl
228
229
  // consistent handle gh cli commands returning json
229
230
  // redirect to tmp file to avoid scrollback overflow causing scrollback to be cleared
230
231
  async function gh_json<T>(command: string): Promise<T | Error> {
231
- const tmp_pr_json = path.join(os.tmpdir(), "git-stack-gh.json");
232
+ // hash command for unique short string
233
+ let hash = crypto.createHash("md5").update(command).digest("hex");
234
+ let tmp_filename = safe_filename(`gh_json-${hash}`);
235
+ const tmp_pr_json = path.join(await get_tmp_dir(), `${tmp_filename}.json`);
232
236
 
233
237
  const options = { ignoreExitCode: true };
234
238
  const cli_result = await cli(`gh ${command} > ${tmp_pr_json}`, options);
@@ -238,9 +242,13 @@ async function gh_json<T>(command: string): Promise<T | Error> {
238
242
  }
239
243
 
240
244
  // read from file
241
- const json_str = await fs.readFile(tmp_pr_json, "utf-8");
242
- const json = JSON.parse(json_str);
243
- return json;
245
+ const json_str = String(await fs.readFile(tmp_pr_json));
246
+ try {
247
+ const json = JSON.parse(json_str);
248
+ return json;
249
+ } catch (error) {
250
+ return new Error(`gh_json JSON.parse: ${error}`);
251
+ }
244
252
  }
245
253
 
246
254
  function handle_error(output: string): never {
@@ -258,15 +266,12 @@ function handle_error(output: string): never {
258
266
  async function write_body_file(args: EditPullRequestArgs) {
259
267
  invariant(args.body, "args.body must exist");
260
268
 
261
- const temp_dir = os.tmpdir();
262
-
263
269
  // ensure unique filename is safe for filesystem
264
270
  // base (group id) might contain slashes, e.g. dev/magus/gs-3cmrMBSUj
265
271
  // the flashes would mess up the filesystem path to this file
266
- let temp_filename = `git-stack-body-${args.base}`;
267
- temp_filename = temp_filename.replace(RE.non_alphanumeric_dash, "-");
272
+ let tmp_filename = safe_filename(`git-stack-body-${args.base}`);
268
273
 
269
- const temp_path = path.join(temp_dir, temp_filename);
274
+ const temp_path = path.join(await get_tmp_dir(), tmp_filename);
270
275
 
271
276
  await safe_rm(temp_path);
272
277
 
@@ -275,6 +280,10 @@ async function write_body_file(args: EditPullRequestArgs) {
275
280
  return temp_path;
276
281
  }
277
282
 
283
+ function safe_filename(value: string): string {
284
+ return value.replace(RE.non_alphanumeric_dash, "-");
285
+ }
286
+
278
287
  type Commit = {
279
288
  authoredDate: string; // "2023-10-22T23:13:35Z"
280
289
  authors: [
package/src/index.tsx CHANGED
@@ -4,11 +4,14 @@
4
4
 
5
5
  import * as React from "react";
6
6
 
7
+ import fs from "node:fs/promises";
8
+
7
9
  import * as Ink from "ink-cjs";
8
10
 
9
11
  import { App } from "~/app/App";
10
12
  import { Store } from "~/app/Store";
11
13
  import { command } from "~/command";
14
+ import { get_tmp_dir } from "~/core/get_tmp_dir";
12
15
  import { pretty_json } from "~/core/pretty_json";
13
16
 
14
17
  (async function main() {
@@ -33,6 +36,10 @@ import { pretty_json } from "~/core/pretty_json";
33
36
  process.exit(238);
34
37
  });
35
38
 
39
+ // cleanup leftover temporary files from previous run
40
+ const tmp_dir = await get_tmp_dir();
41
+ await fs.rm(tmp_dir, { recursive: true });
42
+
36
43
  const ink = Ink.render(<App />, {
37
44
  // If true, each update will be rendered as a separate output, without replacing the previous one.
38
45
  // debug: true,