@akiojin/gwt 9.11.10 → 9.11.12

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/README.ja.md CHANGED
@@ -12,7 +12,7 @@ gwt は Git worktree の管理と、`Claude Code` / `Codex` / `Gemini` /
12
12
 
13
13
  - GUI 向けの主配布物: `gwt-macos-universal.dmg`
14
14
  - マウントした DMG から `GWT.app` を開くとネイティブ GUI をそのまま起動できます
15
- - `PATH` に `gwtd` CLI を入れたい場合は install script を使います
15
+ - `PATH` に `gwt` / `gwtd` CLI を入れたい場合は install script を使います
16
16
 
17
17
  ```bash
18
18
  curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash
package/README.md CHANGED
@@ -14,7 +14,7 @@ Download the release asset for your platform from
14
14
 
15
15
  - GUI-first installer: `gwt-macos-universal.dmg`
16
16
  - Open `GWT.app` from the mounted DMG for the native desktop launch surface
17
- - Use the install script when you want the `gwtd` CLI in your `PATH`
17
+ - Use the install script when you want the `gwt` and `gwtd` CLIs in your `PATH`
18
18
 
19
19
  ```bash
20
20
  curl -fsSL https://raw.githubusercontent.com/akiojin/gwt/main/installers/macos/install.sh | bash
package/bin/gwt.cjs CHANGED
@@ -5,84 +5,20 @@
5
5
  * it will be downloaded on-demand from GitHub Releases.
6
6
  */
7
7
 
8
- const { spawn } = require("child_process");
9
- const path = require("path");
10
- const fs = require("fs");
8
+ const { binaryNameForPlatform } = require("../scripts/release-assets.cjs");
9
+ const { createLauncher } = require("./launcher.cjs");
11
10
 
12
- const {
13
- bundleBinaryNamesForPlatform,
11
+ const launcher = createLauncher({
12
+ commandName: "gwt",
14
13
  binaryNameForPlatform,
15
- installReleaseBinary,
16
- releaseAssetUrl,
17
- } = require("../scripts/release-assets.cjs");
18
-
19
- const REPO = "akiojin/gwt";
20
- const BIN_DIR = __dirname;
21
- const BIN_NAME = binaryNameForPlatform(process.platform);
22
- const BIN_PATH = path.join(BIN_DIR, BIN_NAME);
23
- const BUNDLE_BINARIES = bundleBinaryNamesForPlatform(process.platform);
24
-
25
- function readVersion() {
26
- const pkg = path.join(__dirname, "..", "package.json");
27
- return JSON.parse(fs.readFileSync(pkg, "utf8")).version;
28
- }
29
-
30
- async function ensureBinary() {
31
- if (BUNDLE_BINARIES.every((name) => fs.existsSync(path.join(BIN_DIR, name)))) {
32
- return;
33
- }
34
-
35
- const version = readVersion();
36
- const { url } = releaseAssetUrl(REPO, version, process.platform, process.arch);
37
-
38
- console.log(`Downloading gwt bundle for ${process.platform}-${process.arch}...`);
39
- console.log(`Downloading from: ${url}`);
40
-
41
- await installReleaseBinary({
42
- repo: REPO,
43
- version,
44
- binDir: BIN_DIR,
45
- platform: process.platform,
46
- arch: process.arch,
47
- });
48
-
49
- console.log(`gwt bundle installed successfully: ${BUNDLE_BINARIES.join(", ")}`);
50
- }
51
-
52
- async function main() {
53
- try {
54
- await ensureBinary();
55
- } catch (err) {
56
- console.error(`Failed to download gwt binary: ${err.message}`);
57
- console.error(`https://github.com/${REPO}/releases`);
58
- process.exit(1);
59
- }
60
-
61
- const child = spawn(BIN_PATH, process.argv.slice(2), {
62
- stdio: "inherit",
63
- env: process.env,
64
- });
65
-
66
- child.on("error", (err) => {
67
- console.error(`Failed to start gwt: ${err.message}`);
68
- process.exit(1);
69
- });
70
-
71
- child.on("exit", (code, signal) => {
72
- if (signal) {
73
- process.kill(process.pid, signal);
74
- } else {
75
- process.exit(code ?? 0);
76
- }
77
- });
78
- }
14
+ });
79
15
 
80
16
  if (require.main === module) {
81
- main();
17
+ launcher.main();
82
18
  }
83
19
 
84
20
  module.exports = {
85
- ensureBinary,
86
- main,
87
- readVersion,
21
+ ensureBinary: launcher.ensureBinary,
22
+ main: launcher.main,
23
+ readVersion: launcher.readVersion,
88
24
  };
package/bin/gwtd.cjs ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Wrapper script to execute the gwtd Rust binary.
4
+ * If the bundle is not found (e.g., bunx skips postinstall),
5
+ * it will be downloaded on-demand from GitHub Releases.
6
+ */
7
+
8
+ const { daemonBinaryNameForPlatform } = require("../scripts/release-assets.cjs");
9
+ const { createLauncher } = require("./launcher.cjs");
10
+
11
+ const launcher = createLauncher({
12
+ commandName: "gwtd",
13
+ binaryNameForPlatform: daemonBinaryNameForPlatform,
14
+ });
15
+
16
+ if (require.main === module) {
17
+ launcher.main();
18
+ }
19
+
20
+ module.exports = {
21
+ ensureBinary: launcher.ensureBinary,
22
+ main: launcher.main,
23
+ readVersion: launcher.readVersion,
24
+ };
@@ -0,0 +1,84 @@
1
+ const { spawn } = require("child_process");
2
+ const path = require("path");
3
+ const fs = require("fs");
4
+
5
+ const {
6
+ bundleBinaryNamesForPlatform,
7
+ installReleaseBinary,
8
+ releaseAssetUrl,
9
+ } = require("../scripts/release-assets.cjs");
10
+
11
+ const REPO = "akiojin/gwt";
12
+ const BIN_DIR = __dirname;
13
+
14
+ function readVersion() {
15
+ const pkg = path.join(__dirname, "..", "package.json");
16
+ return JSON.parse(fs.readFileSync(pkg, "utf8")).version;
17
+ }
18
+
19
+ function createLauncher({ commandName, binaryNameForPlatform }) {
20
+ const binName = binaryNameForPlatform(process.platform);
21
+ const binPath = path.join(BIN_DIR, binName);
22
+ const bundleBinaries = bundleBinaryNamesForPlatform(process.platform);
23
+
24
+ async function ensureBinary() {
25
+ if (bundleBinaries.every((name) => fs.existsSync(path.join(BIN_DIR, name)))) {
26
+ return;
27
+ }
28
+
29
+ const version = readVersion();
30
+ const { url } = releaseAssetUrl(REPO, version, process.platform, process.arch);
31
+
32
+ console.log(`Downloading gwt bundle for ${process.platform}-${process.arch}...`);
33
+ console.log(`Downloading from: ${url}`);
34
+
35
+ await installReleaseBinary({
36
+ repo: REPO,
37
+ version,
38
+ binDir: BIN_DIR,
39
+ platform: process.platform,
40
+ arch: process.arch,
41
+ });
42
+
43
+ console.log(`gwt bundle installed successfully: ${bundleBinaries.join(", ")}`);
44
+ }
45
+
46
+ async function main() {
47
+ try {
48
+ await ensureBinary();
49
+ } catch (err) {
50
+ console.error(`Failed to download gwt binary: ${err.message}`);
51
+ console.error(`https://github.com/${REPO}/releases`);
52
+ process.exit(1);
53
+ }
54
+
55
+ const child = spawn(binPath, process.argv.slice(2), {
56
+ stdio: "inherit",
57
+ env: process.env,
58
+ });
59
+
60
+ child.on("error", (err) => {
61
+ console.error(`Failed to start ${commandName}: ${err.message}`);
62
+ process.exit(1);
63
+ });
64
+
65
+ child.on("exit", (code, signal) => {
66
+ if (signal) {
67
+ process.kill(process.pid, signal);
68
+ } else {
69
+ process.exit(code ?? 0);
70
+ }
71
+ });
72
+ }
73
+
74
+ return {
75
+ ensureBinary,
76
+ main,
77
+ readVersion,
78
+ };
79
+ }
80
+
81
+ module.exports = {
82
+ createLauncher,
83
+ readVersion,
84
+ };
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ REPO="akiojin/gwt"
5
+ INSTALL_DIR="${GWT_INSTALL_DIR:-$HOME/.local/bin}"
6
+ VERSION="latest"
7
+
8
+ usage() {
9
+ cat <<'USAGE'
10
+ Usage: install.sh [--version <version>] [--dir <install-dir>]
11
+
12
+ Installs both gwt and gwtd into the target directory.
13
+ Defaults:
14
+ version: latest GitHub Release
15
+ dir: $GWT_INSTALL_DIR or $HOME/.local/bin
16
+ USAGE
17
+ }
18
+
19
+ while [ "$#" -gt 0 ]; do
20
+ case "$1" in
21
+ --version)
22
+ VERSION="${2:?missing value for --version}"
23
+ shift 2
24
+ ;;
25
+ --dir)
26
+ INSTALL_DIR="${2:?missing value for --dir}"
27
+ shift 2
28
+ ;;
29
+ -h|--help)
30
+ usage
31
+ exit 0
32
+ ;;
33
+ *)
34
+ echo "Unknown argument: $1" >&2
35
+ usage >&2
36
+ exit 2
37
+ ;;
38
+ esac
39
+ done
40
+
41
+ case "$(uname -m)" in
42
+ arm64|aarch64)
43
+ ARCH="arm64"
44
+ ;;
45
+ x86_64|amd64)
46
+ ARCH="x86_64"
47
+ ;;
48
+ *)
49
+ echo "Unsupported macOS architecture: $(uname -m)" >&2
50
+ exit 1
51
+ ;;
52
+ esac
53
+
54
+ ASSET="gwt-macos-${ARCH}.tar.gz"
55
+ if [ "$VERSION" = "latest" ]; then
56
+ URL="https://github.com/${REPO}/releases/latest/download/${ASSET}"
57
+ else
58
+ TAG="v${VERSION#v}"
59
+ URL="https://github.com/${REPO}/releases/download/${TAG}/${ASSET}"
60
+ fi
61
+
62
+ TMPDIR="$(mktemp -d)"
63
+ trap 'rm -rf "$TMPDIR"' EXIT
64
+
65
+ mkdir -p "$INSTALL_DIR"
66
+ curl -fsSL "$URL" -o "$TMPDIR/$ASSET"
67
+ tar -xzf "$TMPDIR/$ASSET" -C "$TMPDIR"
68
+
69
+ for BIN in gwt gwtd; do
70
+ SOURCE="$(find "$TMPDIR" -type f -name "$BIN" | head -n 1)"
71
+ if [ -z "$SOURCE" ]; then
72
+ echo "Downloaded archive does not contain $BIN" >&2
73
+ exit 1
74
+ fi
75
+ cp "$SOURCE" "$INSTALL_DIR/$BIN"
76
+ chmod +x "$INSTALL_DIR/$BIN"
77
+ done
78
+
79
+ case ":$PATH:" in
80
+ *":$INSTALL_DIR:"*) ;;
81
+ *)
82
+ echo "Warning: $INSTALL_DIR is not in PATH." >&2
83
+ echo "Add it to your shell profile before running gwt or gwtd by name." >&2
84
+ ;;
85
+ esac
86
+
87
+ echo "Installed gwt and gwtd into $INSTALL_DIR"
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ INSTALL_DIR="${GWT_INSTALL_DIR:-$HOME/.local/bin}"
5
+
6
+ usage() {
7
+ cat <<'USAGE'
8
+ Usage: uninstall.sh [--dir <install-dir>]
9
+
10
+ Removes both gwt and gwtd from the target directory.
11
+ Defaults:
12
+ dir: $GWT_INSTALL_DIR or $HOME/.local/bin
13
+ USAGE
14
+ }
15
+
16
+ while [ "$#" -gt 0 ]; do
17
+ case "$1" in
18
+ --dir)
19
+ INSTALL_DIR="${2:?missing value for --dir}"
20
+ shift 2
21
+ ;;
22
+ -h|--help)
23
+ usage
24
+ exit 0
25
+ ;;
26
+ *)
27
+ echo "Unknown argument: $1" >&2
28
+ usage >&2
29
+ exit 2
30
+ ;;
31
+ esac
32
+ done
33
+
34
+ for BIN in gwt gwtd; do
35
+ rm -f "$INSTALL_DIR/$BIN"
36
+ done
37
+
38
+ echo "Removed gwt and gwtd from $INSTALL_DIR"
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@akiojin/gwt",
3
- "version": "9.11.10",
3
+ "version": "9.11.12",
4
4
  "description": "Desktop GUI for Git worktree management and coding agent launch",
5
5
  "type": "module",
6
6
  "bin": {
7
- "gwt": "bin/gwt.cjs"
7
+ "gwt": "bin/gwt.cjs",
8
+ "gwtd": "bin/gwtd.cjs"
8
9
  },
9
10
  "scripts": {
10
11
  "postinstall": "node scripts/postinstall.cjs",
@@ -7,6 +7,7 @@ const { execFileSync } = require("child_process");
7
7
  const {
8
8
  binaryNameForPlatform,
9
9
  bundleBinaryNamesForPlatform,
10
+ daemonBinaryNameForPlatform,
10
11
  installBundleFromArchive,
11
12
  primaryReleaseAssetName,
12
13
  releaseAssetName,
@@ -47,6 +48,9 @@ run("release helper keeps platform binary names stable", () => {
47
48
  assert.equal(binaryNameForPlatform("win32"), "gwt.exe");
48
49
  assert.equal(binaryNameForPlatform("linux"), "gwt");
49
50
  assert.equal(binaryNameForPlatform("darwin"), "gwt");
51
+ assert.equal(daemonBinaryNameForPlatform("win32"), "gwtd.exe");
52
+ assert.equal(daemonBinaryNameForPlatform("linux"), "gwtd");
53
+ assert.equal(daemonBinaryNameForPlatform("darwin"), "gwtd");
50
54
  });
51
55
 
52
56
  run("release helper keeps bundle binary names stable", () => {
@@ -56,8 +60,12 @@ run("release helper keeps bundle binary names stable", () => {
56
60
  });
57
61
 
58
62
  run("installer entrypoints are loadable under package type module", () => {
63
+ const daemonLauncher = require("../bin/gwtd.cjs");
64
+
59
65
  assert.equal(typeof postinstall.main, "function");
60
66
  assert.equal(typeof launcher.main, "function");
67
+ assert.equal(typeof daemonLauncher.main, "function");
68
+ assert.equal(typeof daemonLauncher.readVersion, "function");
61
69
  });
62
70
 
63
71
  run("windows installer definition includes the gwtd companion binary", () => {
@@ -78,6 +86,8 @@ run("release workflow packages gwtd alongside gwt", () => {
78
86
 
79
87
  run("package scripts keep the GUI front door and release contract explicit", () => {
80
88
  const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
89
+ assert.equal(pkg.bin.gwt, "bin/gwt.cjs");
90
+ assert.equal(pkg.bin.gwtd, "bin/gwtd.cjs");
81
91
  assert.equal(pkg.scripts["test:release-assets"], "node scripts/test_release_assets.cjs");
82
92
  assert.equal(
83
93
  pkg.scripts["test:frontend-bundle"],
@@ -88,6 +98,23 @@ run("package scripts keep the GUI front door and release contract explicit", ()
88
98
  assert.equal(pkg.scripts.build, "cargo build --release -p gwt --bin gwt --bin gwtd");
89
99
  });
90
100
 
101
+ run("macos install scripts install and remove both public command shims", () => {
102
+ const install = fs.readFileSync(
103
+ path.join(__dirname, "..", "installers", "macos", "install.sh"),
104
+ "utf8"
105
+ );
106
+ const uninstall = fs.readFileSync(
107
+ path.join(__dirname, "..", "installers", "macos", "uninstall.sh"),
108
+ "utf8"
109
+ );
110
+
111
+ assert.match(install, /gwt-macos-\$\{ARCH\}\.tar\.gz/);
112
+ assert.match(install, /for BIN in gwt gwtd/);
113
+ assert.match(install, /chmod \+x "\$INSTALL_DIR\/\$BIN"/);
114
+ assert.match(uninstall, /for BIN in gwt gwtd/);
115
+ assert.match(uninstall, /rm -f "\$INSTALL_DIR\/\$BIN"/);
116
+ });
117
+
91
118
  run("test all script keeps rust tests plus frontend release checks", () => {
92
119
  const testAll = fs.readFileSync(path.join(__dirname, "test-all.sh"), "utf8");
93
120
  assert.match(testAll, /test -p gwt-core -p gwt --all-features/);