@akiojin/gwt 9.25.0 → 9.26.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akiojin/gwt",
3
- "version": "9.25.0",
3
+ "version": "9.26.0",
4
4
  "description": "Desktop GUI for Git worktree management and coding agent launch",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SPEC-2041 Phase 19 Gate 2 mock smoke server.
4
+ *
5
+ * Drives the update-modal flow against a synthetic GitHub Releases endpoint
6
+ * so the post-click flow (downloading -> ready -> Restart now / Later) can be
7
+ * exercised without publishing real releases. Combine with the
8
+ * `GWT_UPDATE_API_BASE_URL` env override that landed alongside this script.
9
+ *
10
+ * Usage:
11
+ * node scripts/mock-update-server.cjs --port 18080 --version 99.99.0 \
12
+ * [--asset path/to/gwt-macos-arm64.tar.gz]
13
+ *
14
+ * Then in another shell:
15
+ * GWT_UPDATE_API_BASE_URL=http://127.0.0.1:18080 ./target/release/gwt
16
+ *
17
+ * The server returns a synthetic release at
18
+ * GET /repos/akiojin/gwt/releases/latest
19
+ * that points `browser_download_url` at the mock's own /assets/<filename>
20
+ * endpoint so the prepare path can both observe progress and (when --asset is
21
+ * a real tarball) succeed the restart-now path. Without --asset the download
22
+ * still completes but extraction fails — useful for smoking the failure
23
+ * modal (`update_apply_error` with stage="Download asset" or
24
+ * stage="Persist pending").
25
+ */
26
+
27
+ const http = require("http");
28
+ const fs = require("fs");
29
+ const path = require("path");
30
+
31
+ const args = process.argv.slice(2);
32
+ const opts = {
33
+ port: 18080,
34
+ version: "99.99.0",
35
+ asset: null,
36
+ };
37
+ for (let i = 0; i < args.length; i++) {
38
+ const flag = args[i];
39
+ const value = args[i + 1];
40
+ if (flag === "--port") {
41
+ opts.port = parseInt(value, 10);
42
+ i += 1;
43
+ } else if (flag === "--version") {
44
+ opts.version = value;
45
+ i += 1;
46
+ } else if (flag === "--asset") {
47
+ opts.asset = value;
48
+ i += 1;
49
+ } else if (flag === "--help" || flag === "-h") {
50
+ printUsage();
51
+ process.exit(0);
52
+ }
53
+ }
54
+
55
+ function printUsage() {
56
+ console.log(`SPEC-2041 Phase 19 Gate 2 mock smoke server
57
+
58
+ Usage:
59
+ node scripts/mock-update-server.cjs [--port PORT] [--version VERSION] [--asset PATH]
60
+
61
+ Options:
62
+ --port TCP port to bind on 127.0.0.1 (default: 18080)
63
+ --version Tag name to advertise as the latest release (default: 99.99.0)
64
+ --asset Local path to a real tarball/zip to serve as the asset.
65
+ When omitted, the server returns a 32-byte payload so the
66
+ download stage succeeds and extraction surfaces a failure
67
+ modal -- handy for smoking the failure UX.
68
+
69
+ Then run gwt with:
70
+ GWT_UPDATE_API_BASE_URL=http://127.0.0.1:PORT ./target/release/gwt
71
+ `);
72
+ }
73
+
74
+ let assetBuffer;
75
+ // Always advertise the canonical asset name for this platform so the updater's
76
+ // release-contract matcher (`scripts/release-assets.cjs::releaseAssetName`)
77
+ // finds the asset regardless of the local file the operator points at.
78
+ const assetName = pickAssetName(process.platform, process.arch);
79
+ if (opts.asset) {
80
+ if (!fs.existsSync(opts.asset)) {
81
+ console.error(`[mock] --asset path does not exist: ${opts.asset}`);
82
+ process.exit(1);
83
+ }
84
+ assetBuffer = fs.readFileSync(opts.asset);
85
+ } else {
86
+ // 32 bytes of random payload so the download progress callback fires at
87
+ // least once and the persist path runs. The eventual extract_archive will
88
+ // fail with `Invalid gzip` / `not a tar archive`, exercising the failure
89
+ // modal.
90
+ assetBuffer = Buffer.alloc(32, 0x5a);
91
+ }
92
+
93
+ function pickAssetName(platform, arch) {
94
+ if (platform === "darwin" && arch === "arm64") return "gwt-macos-arm64.tar.gz";
95
+ if (platform === "darwin" && (arch === "x64" || arch === "x86_64"))
96
+ return "gwt-macos-x86_64.tar.gz";
97
+ if (platform === "linux" && arch === "x64") return "gwt-linux-x86_64.tar.gz";
98
+ if (platform === "linux" && arch === "arm64")
99
+ return "gwt-linux-aarch64.tar.gz";
100
+ if (platform === "win32") return "gwt-windows-x86_64.zip";
101
+ return "gwt-update.tar.gz";
102
+ }
103
+
104
+ const server = http.createServer((req, res) => {
105
+ const url = new URL(req.url, `http://${req.headers.host}`);
106
+ console.log(`[mock] ${req.method} ${url.pathname}`);
107
+
108
+ if (
109
+ url.pathname.startsWith("/repos/") &&
110
+ url.pathname.endsWith("/releases/latest")
111
+ ) {
112
+ const baseUrl = `http://127.0.0.1:${opts.port}`;
113
+ // Strip a single leading `v` from --version so passing either `9.26.0` or
114
+ // `v9.26.0` yields the canonical `vN.N.N` tag the updater's
115
+ // `parse_tag_version` accepts (it tolerates exactly one `v` prefix).
116
+ const normalizedVersion = String(opts.version).replace(/^v/, "");
117
+ const release = {
118
+ tag_name: `v${normalizedVersion}`,
119
+ html_url: `${baseUrl}/release-page`,
120
+ assets: [
121
+ {
122
+ name: assetName,
123
+ browser_download_url: `${baseUrl}/assets/${assetName}`,
124
+ },
125
+ ],
126
+ };
127
+ res.writeHead(200, { "Content-Type": "application/json" });
128
+ res.end(JSON.stringify(release));
129
+ return;
130
+ }
131
+
132
+ if (url.pathname.startsWith("/assets/")) {
133
+ res.writeHead(200, {
134
+ "Content-Type": "application/octet-stream",
135
+ "Content-Length": String(assetBuffer.length),
136
+ });
137
+ res.end(assetBuffer);
138
+ return;
139
+ }
140
+
141
+ res.writeHead(404, { "Content-Type": "text/plain" });
142
+ res.end("Not Found");
143
+ });
144
+
145
+ server.listen(opts.port, "127.0.0.1", () => {
146
+ const advertisedTag = `v${String(opts.version).replace(/^v/, "")}`;
147
+ console.log(
148
+ `[mock] update server listening on http://127.0.0.1:${opts.port}`,
149
+ );
150
+ console.log(`[mock] advertising tag ${advertisedTag} (asset: ${assetName})`);
151
+ console.log("[mock] run gwt with:");
152
+ console.log(
153
+ ` GWT_UPDATE_API_BASE_URL=http://127.0.0.1:${opts.port} ./target/release/gwt`,
154
+ );
155
+ console.log("[mock] press ctrl-c to stop.");
156
+ });