@akiojin/gwt 9.24.2 → 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/README.ja.md CHANGED
@@ -200,6 +200,14 @@ Managed hooks は user hook を保持しながら、Agent state、workflow guard
200
200
  Board reminders、discussion/plan/build Stop checks、coordination-event summaries
201
201
  を追加します。
202
202
 
203
+ gwt から起動された Agent に live GUI / browser backend がある場合、managed hook
204
+ は local hook-forward bridge も有効にします。この bridge は、その session に
205
+ gwt が注入した loopback endpoint と bearer token だけへ hook event を POST し、
206
+ 既存の live event stream 経由で frontend client へ fan-out します。gwt 外から
207
+ 起動した session には転送先が注入されないため、`gwt hook forward` は silent
208
+ no-op のままです。古い転送先、接続拒否、validation error、delivery timeout は
209
+ fail-open の診断情報として扱われ、Agent の tool call を block しません。
210
+
203
211
  ## ワークスペース基盤
204
212
 
205
213
  Agent session の隔離と再現性のため、gwt は各プロジェクトをワークスペース
package/README.md CHANGED
@@ -205,6 +205,14 @@ Managed hooks preserve user hooks while adding gwt runtime behavior for agent
205
205
  state, workflow guardrails, Board reminders, discussion/plan/build Stop checks,
206
206
  and coordination-event summaries.
207
207
 
208
+ When an agent is launched by gwt with a live GUI/browser backend, managed hooks
209
+ also enable the local hook-forward bridge. The bridge posts hook events only to
210
+ the loopback endpoint and bearer token that gwt injects for that session, then
211
+ fans them out through the existing live event stream. Sessions started outside
212
+ gwt do not receive that target and `gwt hook forward` remains a silent no-op;
213
+ stale targets, refused connections, validation errors, and delivery timeouts are
214
+ fail-open diagnostics and do not block agent tool calls.
215
+
208
216
  ## Workspace Foundation
209
217
 
210
218
  For isolation and repeatable agent sessions, gwt can manage each project as a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akiojin/gwt",
3
- "version": "9.24.2",
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": {
@@ -12,9 +12,9 @@
12
12
  "dev": "cargo run -p gwt --bin gwt",
13
13
  "build": "cargo build --release -p gwt --bin gwt --bin gwtd",
14
14
  "test": "cargo test -p gwt-core -p gwt --all-features",
15
- "test:frontend-bundle": "node --check crates/gwt/web/app.js && node --check crates/gwt/web/branch-cleanup-modal.js && node --check crates/gwt/web/migration-modal.js && node --check crates/gwt/web/board-surface.js && node --check crates/gwt/web/workspace-kanban-surface.js && node --check crates/gwt/web/theme-manager.js && node --check crates/gwt/web/theme-toggle.js && node --check crates/gwt/web/hotkey.js && node --check crates/gwt/web/operator-shell.js && node --check crates/gwt/web/focus-trap.js && node --check crates/gwt/web/window-docking.js && node --check crates/gwt/web/update-cta.js && node --check crates/gwt/web/terminal-context-menu.js",
15
+ "test:frontend-bundle": "node --check crates/gwt/web/app.js && node --check crates/gwt/web/branch-cleanup-modal.js && node --check crates/gwt/web/migration-modal.js && node --check crates/gwt/web/board-surface.js && node --check crates/gwt/web/workspace-kanban-surface.js && node --check crates/gwt/web/theme-manager.js && node --check crates/gwt/web/theme-toggle.js && node --check crates/gwt/web/hotkey.js && node --check crates/gwt/web/operator-shell.js && node --check crates/gwt/web/focus-trap.js && node --check crates/gwt/web/window-docking.js && node --check crates/gwt/web/update-cta.js && node --check crates/gwt/web/terminal-context-menu.js && node --check crates/gwt/web/custom-agent-env-editor.js",
16
16
  "test:frontend-smoke": "node --test crates/gwt/web/__tests__/branch-cleanup.smoke.test.mjs crates/gwt/web/__tests__/migration-modal.smoke.test.mjs",
17
- "test:frontend-unit": "node --test crates/gwt/web/__tests__/contrast.test.mjs crates/gwt/web/__tests__/theme-manager.test.mjs crates/gwt/web/__tests__/theme-segmented.test.mjs crates/gwt/web/__tests__/hotkey.test.mjs crates/gwt/web/__tests__/operator-chrome-structure.test.mjs crates/gwt/web/__tests__/operator-shell-runtime.test.mjs crates/gwt/web/__tests__/operator-shell-hover-reveal.test.mjs crates/gwt/web/__tests__/board-surface.test.mjs crates/gwt/web/__tests__/focus-trap.test.mjs crates/gwt/web/__tests__/kanban-structure.test.mjs crates/gwt/web/__tests__/kanban-dnd.test.mjs crates/gwt/web/__tests__/kanban-drawer.test.mjs crates/gwt/web/__tests__/workspace-kanban-surface.test.mjs crates/gwt/web/__tests__/update-button.test.mjs crates/gwt/web/__tests__/window-docking.test.mjs crates/gwt/web/__tests__/terminal-context-menu.test.mjs",
17
+ "test:frontend-unit": "node --test crates/gwt/web/__tests__/contrast.test.mjs crates/gwt/web/__tests__/theme-manager.test.mjs crates/gwt/web/__tests__/theme-segmented.test.mjs crates/gwt/web/__tests__/hotkey.test.mjs crates/gwt/web/__tests__/index-settings-panel.test.mjs crates/gwt/web/__tests__/index-status-controller.test.mjs crates/gwt/web/__tests__/operator-chrome-structure.test.mjs crates/gwt/web/__tests__/operator-shell-runtime.test.mjs crates/gwt/web/__tests__/operator-shell-hover-reveal.test.mjs crates/gwt/web/__tests__/board-surface.test.mjs crates/gwt/web/__tests__/focus-trap.test.mjs crates/gwt/web/__tests__/kanban-structure.test.mjs crates/gwt/web/__tests__/kanban-dnd.test.mjs crates/gwt/web/__tests__/kanban-drawer.test.mjs crates/gwt/web/__tests__/workspace-kanban-surface.test.mjs crates/gwt/web/__tests__/update-button.test.mjs crates/gwt/web/__tests__/window-docking.test.mjs crates/gwt/web/__tests__/terminal-context-menu.test.mjs crates/gwt/web/__tests__/terminal-viewport-reflow.test.mjs crates/gwt/web/__tests__/custom-agent-env-editor.test.mjs crates/gwt/web/__tests__/settings-system-tab.test.mjs",
18
18
  "test:visual": "playwright test --config crates/gwt/playwright/playwright.config.ts",
19
19
  "test:release-assets": "node scripts/test_release_assets.cjs",
20
20
  "test:release-flow": "bash scripts/check-release-flow.sh",
@@ -47,8 +47,8 @@
47
47
  },
48
48
  "packageManager": "pnpm@10.29.2",
49
49
  "devDependencies": {
50
- "@commitlint/cli": "^20.5.0",
51
- "@commitlint/config-conventional": "^20.5.0",
50
+ "@commitlint/cli": "^21.0.0",
51
+ "@commitlint/config-conventional": "^21.0.0",
52
52
  "@playwright/test": "^1.49.1",
53
53
  "linkedom": "^0.18.12"
54
54
  }
@@ -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
+ });