@akiojin/gwt 9.6.0 → 9.8.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/.husky/pre-push CHANGED
@@ -6,7 +6,9 @@ echo "Running CI-equivalent lint checks..."
6
6
 
7
7
  cargo clippy --all-targets --all-features -- -D warnings
8
8
  cargo fmt --all -- --check
9
- bunx --bun markdownlint-cli . --config .markdownlint.json --ignore target --ignore CHANGELOG.md
9
+ cargo llvm-cov -p gwt-core -p gwt --all-features --json --summary-only --output-path target/coverage-summary.json
10
+ node scripts/check-coverage-threshold.mjs target/coverage-summary.json 90
11
+ bunx --bun markdownlint-cli . --config .markdownlint.json --ignore target --ignore CHANGELOG.md --ignore tasks/todo.md
10
12
  pnpm lint:skills
11
13
 
12
14
  echo "All pre-push checks passed."
package/README.ja.md CHANGED
@@ -6,10 +6,14 @@ gwt は Git worktree の管理と、`Claude Code` / `Codex` / `Gemini` /
6
6
  ## インストール
7
7
 
8
8
  [GitHub Releases](https://github.com/akiojin/gwt/releases) からお使いの
9
- プラットフォーム向けバイナリをダウンロードし、`PATH` に配置してください。
9
+ プラットフォーム向け release asset を取得してください。
10
10
 
11
11
  ### macOS
12
12
 
13
+ - GUI 向けの主配布物: `gwt-macos-universal.dmg`
14
+ - マウントした DMG から `GWT.app` を開くとネイティブ GUI をそのまま起動できます
15
+ - `PATH` に `gwt` を入れたい場合は install script を使います
16
+
13
17
  ```bash
14
18
  curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash
15
19
  ```
@@ -17,12 +21,21 @@ curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/i
17
21
  特定バージョンを指定する場合:
18
22
 
19
23
  ```bash
20
- curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash -s -- --version 6.30.3
24
+ curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash -s -- --version <version>
21
25
  ```
22
26
 
23
- ### Windows / Linux
27
+ ### Windows
28
+
29
+ - GUI 向けの主配布物: `gwt-windows-x86_64.msi`
30
+ - portable bundle: `gwt-windows-x86_64.zip`
31
+ - public front door は `gwt.exe` で、`gwtd.exe` は内部 runtime 用の companion binary です
24
32
 
25
- GitHub Releases からバイナリを取得して `PATH` に配置します。
33
+ ### Linux
34
+
35
+ - portable bundle:
36
+ - `gwt-linux-x86_64.tar.gz`
37
+ - `gwt-linux-aarch64.tar.gz`
38
+ - 展開した `gwt` / `gwtd` を `PATH` 上のディレクトリへ配置します
26
39
 
27
40
  ### アンインストール(macOS)
28
41
 
@@ -66,6 +79,9 @@ gwt board show
66
79
  gwt hook workflow-policy
67
80
  ```
68
81
 
82
+ managed hook と runtime 委譲の入口も引き続き `gwt` です。利用者が別の daemon
83
+ コマンドを手動起動する必要はありません。
84
+
69
85
  ## 基本フロー
70
86
 
71
87
  1. リポジトリを開く、または前回のプロジェクトを復元する
@@ -137,13 +153,13 @@ gwt issue spec <number> --section spec|plan|tasks
137
153
  ### ビルド
138
154
 
139
155
  ```bash
140
- cargo build -p gwt
156
+ cargo build -p gwt --bin gwt --bin gwtd
141
157
  ```
142
158
 
143
159
  ### 実行
144
160
 
145
161
  ```bash
146
- cargo run -p gwt
162
+ cargo run -p gwt --bin gwt
147
163
  ```
148
164
 
149
165
  ### macOS 向け `.app` bundle
@@ -159,6 +175,24 @@ cargo bundle -p gwt --format osx
159
175
  cargo test -p gwt-core -p gwt --all-features
160
176
  ```
161
177
 
178
+ ### Release Asset Contract
179
+
180
+ ```bash
181
+ npm run test:release-assets
182
+ ```
183
+
184
+ ### Frontend Bundle Contract
185
+
186
+ ```bash
187
+ npm run test:frontend-bundle
188
+ ```
189
+
190
+ ### Release Flow Checks
191
+
192
+ ```bash
193
+ npm run test:release-flow
194
+ ```
195
+
162
196
  ### Lint
163
197
 
164
198
  ```bash
package/README.md CHANGED
@@ -7,12 +7,15 @@ such as `Claude Code`, `Codex`, `Gemini`, and `OpenCode`.
7
7
 
8
8
  ## Install
9
9
 
10
- Download the binary for your platform from
11
- [GitHub Releases](https://github.com/akiojin/gwt/releases) and place it in
12
- your `PATH`.
10
+ Download the release asset for your platform from
11
+ [GitHub Releases](https://github.com/akiojin/gwt/releases).
13
12
 
14
13
  ### macOS
15
14
 
15
+ - GUI-first installer: `gwt-macos-universal.dmg`
16
+ - Open `GWT.app` from the mounted DMG for the native desktop launch surface
17
+ - Use the install script when you want the `gwt` CLI front door in your `PATH`
18
+
16
19
  ```bash
17
20
  curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash
18
21
  ```
@@ -20,12 +23,21 @@ curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/i
20
23
  Install a specific version:
21
24
 
22
25
  ```bash
23
- curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash -s -- --version 6.30.3
26
+ curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash -s -- --version <version>
24
27
  ```
25
28
 
26
- ### Windows / Linux
29
+ ### Windows
30
+
31
+ - GUI-first installer: `gwt-windows-x86_64.msi`
32
+ - Portable bundle: `gwt-windows-x86_64.zip`
33
+ - The public front door is `gwt.exe`; `gwtd.exe` is bundled for internal runtime use
27
34
 
28
- Download the binary from GitHub Releases and add it to your `PATH`.
35
+ ### Linux
36
+
37
+ - Portable bundles:
38
+ - `gwt-linux-x86_64.tar.gz`
39
+ - `gwt-linux-aarch64.tar.gz`
40
+ - Extract `gwt` and `gwtd` into a directory on your `PATH`
29
41
 
30
42
  ### Uninstall (macOS)
31
43
 
@@ -68,6 +80,9 @@ gwt board show
68
80
  gwt hook workflow-policy
69
81
  ```
70
82
 
83
+ Managed hooks and runtime delegation continue to enter through `gwt`. There is
84
+ no separate operator-facing daemon command to start by hand.
85
+
71
86
  ## Main Workflow
72
87
 
73
88
  1. Open a repository directory or restore the previous project.
@@ -141,13 +156,13 @@ gwt issue spec <number> --section spec|plan|tasks
141
156
  ### Build
142
157
 
143
158
  ```bash
144
- cargo build -p gwt
159
+ cargo build -p gwt --bin gwt --bin gwtd
145
160
  ```
146
161
 
147
162
  ### Run
148
163
 
149
164
  ```bash
150
- cargo run -p gwt
165
+ cargo run -p gwt --bin gwt
151
166
  ```
152
167
 
153
168
  ### Build a macOS app bundle
@@ -163,6 +178,24 @@ cargo bundle -p gwt --format osx
163
178
  cargo test -p gwt-core -p gwt --all-features
164
179
  ```
165
180
 
181
+ ### Release Asset Contract
182
+
183
+ ```bash
184
+ npm run test:release-assets
185
+ ```
186
+
187
+ ### Frontend Bundle Contract
188
+
189
+ ```bash
190
+ npm run test:frontend-bundle
191
+ ```
192
+
193
+ ### Release Flow Checks
194
+
195
+ ```bash
196
+ npm run test:release-flow
197
+ ```
198
+
166
199
  ### Lint
167
200
 
168
201
  ```bash
Binary file
Binary file
Binary file
@@ -0,0 +1,18 @@
1
+ {
2
+ "bundle_binaries": {
3
+ "linux": ["gwt", "gwtd"],
4
+ "macos": ["gwt", "gwtd"],
5
+ "windows": ["gwt.exe", "gwtd.exe"]
6
+ },
7
+ "portable_assets": {
8
+ "linux-x86_64": "gwt-linux-x86_64.tar.gz",
9
+ "linux-aarch64": "gwt-linux-aarch64.tar.gz",
10
+ "macos-x86_64": "gwt-macos-x86_64.tar.gz",
11
+ "macos-aarch64": "gwt-macos-arm64.tar.gz",
12
+ "windows-x86_64": "gwt-windows-x86_64.zip"
13
+ },
14
+ "installer_assets": {
15
+ "macos": "gwt-macos-universal.dmg",
16
+ "windows": "gwt-windows-x86_64.msi"
17
+ }
18
+ }
package/bin/gwt.cjs CHANGED
@@ -10,6 +10,7 @@ const path = require("path");
10
10
  const fs = require("fs");
11
11
 
12
12
  const {
13
+ bundleBinaryNamesForPlatform,
13
14
  binaryNameForPlatform,
14
15
  installReleaseBinary,
15
16
  releaseAssetUrl,
@@ -19,6 +20,7 @@ const REPO = "akiojin/gwt";
19
20
  const BIN_DIR = __dirname;
20
21
  const BIN_NAME = binaryNameForPlatform(process.platform);
21
22
  const BIN_PATH = path.join(BIN_DIR, BIN_NAME);
23
+ const BUNDLE_BINARIES = bundleBinaryNamesForPlatform(process.platform);
22
24
 
23
25
  function readVersion() {
24
26
  const pkg = path.join(__dirname, "..", "package.json");
@@ -26,24 +28,25 @@ function readVersion() {
26
28
  }
27
29
 
28
30
  async function ensureBinary() {
29
- if (fs.existsSync(BIN_PATH)) return;
31
+ if (BUNDLE_BINARIES.every((name) => fs.existsSync(path.join(BIN_DIR, name)))) {
32
+ return;
33
+ }
30
34
 
31
35
  const version = readVersion();
32
36
  const { url } = releaseAssetUrl(REPO, version, process.platform, process.arch);
33
37
 
34
- console.log(`Downloading gwt binary for ${process.platform}-${process.arch}...`);
38
+ console.log(`Downloading gwt bundle for ${process.platform}-${process.arch}...`);
35
39
  console.log(`Downloading from: ${url}`);
36
40
 
37
41
  await installReleaseBinary({
38
42
  repo: REPO,
39
43
  version,
40
44
  binDir: BIN_DIR,
41
- binaryName: BIN_NAME,
42
45
  platform: process.platform,
43
46
  arch: process.arch,
44
47
  });
45
48
 
46
- console.log("gwt binary installed successfully!");
49
+ console.log(`gwt bundle installed successfully: ${BUNDLE_BINARIES.join(", ")}`);
47
50
  }
48
51
 
49
52
  async function main() {
@@ -8,8 +8,8 @@ services:
8
8
  - bash-history:/root/.bash_history_dir
9
9
  - claude-config:/root/.claude
10
10
  - codex-config:/root/.codex
11
- - ${HOME:?HOME must be set}/.claude:/root/.claude-host:ro
12
- - ${HOME:?HOME must be set}/.codex:/root/.codex-host:ro
11
+ - ${HOME:-${USERPROFILE:?HOME or USERPROFILE must be set}}/.claude:/root/.claude-host:ro
12
+ - ${HOME:-${USERPROFILE:?HOME or USERPROFILE must be set}}/.codex:/root/.codex-host:ro
13
13
  ports:
14
14
  - ${PORT:-3000}:3000
15
15
  extra_hosts:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akiojin/gwt",
3
- "version": "9.6.0",
3
+ "version": "9.8.0",
4
4
  "description": "Desktop GUI for Git worktree management and coding agent launch",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,9 +8,12 @@
8
8
  },
9
9
  "scripts": {
10
10
  "postinstall": "node scripts/postinstall.cjs",
11
- "dev": "cargo run -p gwt",
12
- "build": "cargo build --release -p gwt",
11
+ "dev": "cargo run -p gwt --bin gwt",
12
+ "build": "cargo build --release -p gwt --bin gwt --bin gwtd",
13
13
  "test": "cargo test -p gwt-core -p gwt --all-features",
14
+ "test:frontend-bundle": "node --check crates/gwt/web/app.js",
15
+ "test:release-assets": "node scripts/test_release_assets.cjs",
16
+ "test:release-flow": "bash scripts/check-release-flow.sh",
14
17
  "test:all": "bash scripts/test-all.sh",
15
18
  "prepare": "test -n \"$CI\" || bunx husky install",
16
19
  "lint:skills": "bash scripts/validate-skill-frontmatter.sh",
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ const [summaryPath, thresholdArg] = process.argv.slice(2);
7
+
8
+ if (!summaryPath || !thresholdArg) {
9
+ console.error(
10
+ "Usage: node scripts/check-coverage-threshold.mjs <summary-json> <threshold>",
11
+ );
12
+ process.exit(2);
13
+ }
14
+
15
+ const threshold = Number(thresholdArg);
16
+ if (!Number.isFinite(threshold)) {
17
+ console.error(`Invalid threshold: ${thresholdArg}`);
18
+ process.exit(2);
19
+ }
20
+
21
+ const report = JSON.parse(fs.readFileSync(summaryPath, "utf8"));
22
+ const files = report.data?.flatMap((entry) => entry.files ?? []) ?? [];
23
+ const ignoredFilePatterns = [/(^|[\\/])gwt[\\/]src[\\/]main\.rs$/i];
24
+
25
+ let coveredLines = 0;
26
+ let totalLines = 0;
27
+ const excludedFiles = [];
28
+
29
+ for (const file of files) {
30
+ const filename = file.filename ?? "";
31
+ if (ignoredFilePatterns.some((pattern) => pattern.test(filename))) {
32
+ excludedFiles.push(path.relative(process.cwd(), filename));
33
+ continue;
34
+ }
35
+
36
+ const lines = file.summary?.lines;
37
+ if (!lines) {
38
+ continue;
39
+ }
40
+
41
+ coveredLines += lines.covered;
42
+ totalLines += lines.count;
43
+ }
44
+
45
+ if (totalLines === 0) {
46
+ console.error("Coverage report did not contain any line summary data.");
47
+ process.exit(1);
48
+ }
49
+
50
+ const percent = (coveredLines / totalLines) * 100;
51
+ console.log(
52
+ `Filtered line coverage: ${percent.toFixed(2)}% (${coveredLines}/${totalLines})`,
53
+ );
54
+ if (excludedFiles.length > 0) {
55
+ console.log(`Excluded from threshold: ${excludedFiles.join(", ")}`);
56
+ }
57
+
58
+ if (percent + Number.EPSILON < threshold) {
59
+ console.error(
60
+ `Coverage threshold not met: required ${threshold.toFixed(2)}%, got ${percent.toFixed(2)}%`,
61
+ );
62
+ process.exit(1);
63
+ }
64
+
65
+ console.log(`Coverage threshold met: ${threshold.toFixed(2)}%`);
@@ -5,6 +5,8 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
5
  RELEASE="$ROOT/.github/workflows/release.yml"
6
6
  README_EN="$ROOT/README.md"
7
7
  README_JA="$ROOT/README.ja.md"
8
+ INDEX_HTML="$ROOT/crates/gwt/web/index.html"
9
+ APP_JS="$ROOT/crates/gwt/web/app.js"
8
10
 
9
11
  fail=0
10
12
 
@@ -23,6 +25,21 @@ if grep -q "release-guide" "$README_EN" "$README_JA"; then
23
25
  fail=1
24
26
  fi
25
27
 
28
+ if ! grep -q '<script type="module" src="/app.js"></script>' "$INDEX_HTML"; then
29
+ echo "[FAIL] index.html no longer points at the shared /app.js frontend bundle"
30
+ fail=1
31
+ fi
32
+
33
+ if ! node "$ROOT/scripts/test_release_assets.cjs"; then
34
+ echo "[FAIL] release asset contract check failed"
35
+ fail=1
36
+ fi
37
+
38
+ if ! node --check "$APP_JS"; then
39
+ echo "[FAIL] frontend bundle syntax check failed"
40
+ fail=1
41
+ fi
42
+
26
43
  if [ "$fail" -ne 0 ]; then
27
44
  exit 1
28
45
  fi
@@ -5,14 +5,14 @@ const fs = require("fs");
5
5
  const path = require("path");
6
6
 
7
7
  const {
8
- binaryNameForPlatform,
8
+ bundleBinaryNamesForPlatform,
9
9
  installReleaseBinary,
10
10
  releaseAssetUrl,
11
11
  } = require("./release-assets.cjs");
12
12
 
13
13
  const REPO = "akiojin/gwt";
14
14
  const BIN_DIR = path.join(__dirname, "..", "bin");
15
- const BINARY_NAME = binaryNameForPlatform();
15
+ const BUNDLE_BINARIES = bundleBinaryNamesForPlatform();
16
16
 
17
17
  function readVersion() {
18
18
  const pkg = path.join(__dirname, "..", "package.json");
@@ -29,7 +29,7 @@ async function main() {
29
29
  const version = readVersion();
30
30
  const { url } = releaseAssetUrl(REPO, version);
31
31
 
32
- console.log(`Downloading gwt binary for ${process.platform}-${process.arch}...`);
32
+ console.log(`Downloading gwt bundle for ${process.platform}-${process.arch}...`);
33
33
  console.log(`Downloading from: ${url}`);
34
34
 
35
35
  try {
@@ -37,9 +37,8 @@ async function main() {
37
37
  repo: REPO,
38
38
  version,
39
39
  binDir: BIN_DIR,
40
- binaryName: BINARY_NAME,
41
40
  });
42
- console.log("gwt binary installed successfully!");
41
+ console.log(`gwt bundle installed successfully: ${BUNDLE_BINARIES.join(", ")}`);
43
42
  } catch (err) {
44
43
  console.error(`gwt: failed to download binary - ${err.message}`);
45
44
  console.error("gwt: you can build from source with: cargo build --release -p gwt");
@@ -8,6 +8,14 @@ function binaryNameForPlatform(platform = os.platform()) {
8
8
  return platform === "win32" ? "gwt.exe" : "gwt";
9
9
  }
10
10
 
11
+ function daemonBinaryNameForPlatform(platform = os.platform()) {
12
+ return platform === "win32" ? "gwtd.exe" : "gwtd";
13
+ }
14
+
15
+ function bundleBinaryNamesForPlatform(platform = os.platform()) {
16
+ return [binaryNameForPlatform(platform), daemonBinaryNameForPlatform(platform)];
17
+ }
18
+
11
19
  function releaseAssetName(platform = os.platform(), arch = os.arch()) {
12
20
  if (platform === "darwin" && arch === "arm64") {
13
21
  return "gwt-macos-arm64.tar.gz";
@@ -28,6 +36,16 @@ function releaseAssetName(platform = os.platform(), arch = os.arch()) {
28
36
  throw new Error(`Unsupported platform: ${platform}-${arch}`);
29
37
  }
30
38
 
39
+ function primaryReleaseAssetName(platform = os.platform(), arch = os.arch()) {
40
+ if (platform === "darwin" && (arch === "arm64" || arch === "x64")) {
41
+ return "gwt-macos-universal.dmg";
42
+ }
43
+ if (platform === "win32" && arch === "x64") {
44
+ return "gwt-windows-x86_64.msi";
45
+ }
46
+ return releaseAssetName(platform, arch);
47
+ }
48
+
31
49
  function releaseAssetUrl(repo, version, platform = os.platform(), arch = os.arch()) {
32
50
  const asset = releaseAssetName(platform, arch);
33
51
  const tag = `v${version}`;
@@ -120,16 +138,15 @@ function cleanupTempDir(tempRoot) {
120
138
  }
121
139
  }
122
140
 
123
- function installBinaryFromArchive({
141
+ function installBundleFromArchive({
124
142
  archivePath,
125
143
  asset,
126
144
  binDir,
127
- binaryName = binaryNameForPlatform(),
128
145
  platform = os.platform(),
146
+ binaryNames = bundleBinaryNamesForPlatform(platform),
129
147
  }) {
130
148
  const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "gwt-extract-"));
131
149
  const extractDir = path.join(tempRoot, "extract");
132
- const dest = path.join(binDir, binaryName);
133
150
 
134
151
  fs.mkdirSync(binDir, { recursive: true });
135
152
  fs.mkdirSync(extractDir, { recursive: true });
@@ -137,17 +154,22 @@ function installBinaryFromArchive({
137
154
  try {
138
155
  extractArchive(archivePath, extractDir, asset);
139
156
 
140
- const extractedBinary = findFileRecursive(extractDir, binaryName);
141
- if (!extractedBinary) {
142
- throw new Error(`Extracted archive does not contain ${binaryName}`);
143
- }
157
+ const destinations = {};
158
+ for (const binaryName of binaryNames) {
159
+ const extractedBinary = findFileRecursive(extractDir, binaryName);
160
+ if (!extractedBinary) {
161
+ throw new Error(`Extracted archive does not contain ${binaryName}`);
162
+ }
144
163
 
145
- fs.copyFileSync(extractedBinary, dest);
146
- if (platform !== "win32") {
147
- fs.chmodSync(dest, 0o755);
164
+ const dest = path.join(binDir, binaryName);
165
+ fs.copyFileSync(extractedBinary, dest);
166
+ if (platform !== "win32") {
167
+ fs.chmodSync(dest, 0o755);
168
+ }
169
+ destinations[binaryName] = dest;
148
170
  }
149
171
 
150
- return { asset, dest };
172
+ return { asset, destinations };
151
173
  } finally {
152
174
  cleanupTempDir(tempRoot);
153
175
  }
@@ -157,7 +179,6 @@ async function installReleaseBinary({
157
179
  repo,
158
180
  version,
159
181
  binDir,
160
- binaryName = binaryNameForPlatform(),
161
182
  platform = os.platform(),
162
183
  arch = os.arch(),
163
184
  }) {
@@ -167,11 +188,10 @@ async function installReleaseBinary({
167
188
 
168
189
  try {
169
190
  await download(url, archivePath);
170
- return installBinaryFromArchive({
191
+ return installBundleFromArchive({
171
192
  archivePath,
172
193
  asset,
173
194
  binDir,
174
- binaryName,
175
195
  platform,
176
196
  });
177
197
  } finally {
@@ -181,9 +201,13 @@ async function installReleaseBinary({
181
201
 
182
202
  module.exports = {
183
203
  binaryNameForPlatform,
204
+ bundleBinaryNamesForPlatform,
205
+ daemonBinaryNameForPlatform,
184
206
  download,
185
- installBinaryFromArchive,
207
+ installBinaryFromArchive: installBundleFromArchive,
208
+ installBundleFromArchive,
186
209
  installReleaseBinary,
210
+ primaryReleaseAssetName,
187
211
  releaseAssetName,
188
212
  releaseAssetUrl,
189
213
  };
@@ -1,9 +1,23 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- cargo test -p gwt-core -p gwt --all-features &
4
+ cargo_cmd="cargo"
5
+ if ! command -v "$cargo_cmd" >/dev/null 2>&1; then
6
+ if command -v cargo.exe >/dev/null 2>&1; then
7
+ cargo_cmd="cargo.exe"
8
+ else
9
+ echo "[FAIL] cargo or cargo.exe is required on PATH" >&2
10
+ exit 1
11
+ fi
12
+ fi
13
+
14
+ "$cargo_cmd" test -p gwt-core -p gwt --all-features &
5
15
  pid_rust=$!
6
16
 
17
+ bash scripts/check-release-flow.sh &
18
+ pid_release_flow=$!
19
+
7
20
  fail=0
8
21
  wait $pid_rust || fail=1
22
+ wait $pid_release_flow || fail=1
9
23
  exit $fail