Skip to content

Commit d09a5e1

Browse files
committed
feat: add local gui console
1 parent 2ebeb76 commit d09a5e1

20 files changed

Lines changed: 1873 additions & 1 deletion

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@
44

55
### Added
66

7+
- `web-tools gui` local-only management console for setup status, provider/env management, smoke tests, diagnostics export, and Agent handoff commands.
8+
- `web-tools setup --check --json` readiness report with non-sensitive repair suggestions for CLI and GUI consumers.
79
- `web-tools setup` for one-command Agent setup, optional provider configuration, skill install, and doctor checks.
810
- User env file auto-loading from `~/.config/web-tools/.env`, with `WEB_TOOLS_ENV` override support.
911
- `web-tools setup --set-env KEY=value` with `--env-file` and `--force-env` for non-interactive env file setup.
1012
- `doctor` env file diagnostics without exposing secret values.
1113

14+
### Security
15+
16+
- GUI and setup diagnostics expose `auth_env` and configured booleans only; token values are never returned.
17+
- GUI binds to `127.0.0.1` by default.
18+
1219
## v1.4.1 - 2026-06-15
1320

1421
Patch release for Agent setup ergonomics and documentation.

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ web-tools doctor --json
133133

134134
# Install/update the Agent skill from the CLI
135135
web-tools setup
136+
137+
# Inspect setup readiness without changing files
138+
web-tools setup --check
139+
web-tools setup --check --json
140+
141+
# Start the local GUI console for human setup
142+
web-tools gui --no-open
136143
```
137144

138145
## Test
@@ -152,6 +159,25 @@ browser.
152159

153160
Use `web-tools doctor` to check local configuration and optional dependencies. Missing optional tools such as SearXNG, MarkItDown, or agent-browser are reported as warnings; invalid config or an unwritable cache directory is reported as an error.
154161

162+
## Local GUI
163+
164+
`web-tools gui` starts a local-only management console for human setup and diagnostics:
165+
166+
```bash
167+
web-tools gui
168+
web-tools gui --no-open --port 0
169+
```
170+
171+
The GUI binds to `127.0.0.1` by default. It can inspect setup readiness, configure the BigModel provider, write `~/.config/web-tools/.env`, run basic search/reader smoke tests, export non-sensitive diagnostics, and generate Agent handoff commands. It never displays or returns secret values; `config.json` stores only environment variable names such as `ZHIPU_APIKEY`.
172+
173+
For agents and scripts, prefer the non-interactive CLI:
174+
175+
```bash
176+
web-tools setup --check --json
177+
web-tools setup --provider bigmodel --auth-env ZHIPU_APIKEY --set-env ZHIPU_APIKEY=...
178+
web-tools skill install --force
179+
```
180+
155181
## Configuration
156182

157183
Config file (optional): `~/.config/web-tools/config.json` or `./web-tools.json`

README.zh-CN.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ web-tools doctor --json
135135

136136
# 从 CLI 安装或更新 Agent skill
137137
web-tools setup
138+
139+
# 只检查 setup 状态,不改文件
140+
web-tools setup --check
141+
web-tools setup --check --json
142+
143+
# 启动本地 GUI 控制台,适合人类配置和排障
144+
web-tools gui --no-open
138145
```
139146

140147
## 测试
@@ -151,6 +158,27 @@ go test ./...
151158

152159
`web-tools doctor` 检查本地配置和可选依赖。缺少 SearXNG、MarkItDown 或 agent-browser 等可选工具时会报告 warning;配置无效或缓存目录不可写会报告 error。
153160

161+
## 本地 GUI
162+
163+
`web-tools gui` 会启动一个只监听本机的管理控制台,用于人类配置和排障:
164+
165+
```bash
166+
web-tools gui
167+
web-tools gui --no-open --port 0
168+
```
169+
170+
GUI 默认绑定 `127.0.0.1`。它可以检查 setup 状态、配置 BigModel provider、写入 `~/.config/web-tools/.env`、运行基础 search/reader smoke test、导出非敏感诊断 JSON,并生成给 Agent 使用的 handoff 命令。
171+
172+
GUI 不展示、不返回 secret 明文;`config.json` 只保存 `ZHIPU_APIKEY` 这样的环境变量名,不保存 token 值。
173+
174+
Agent 和脚本默认仍然应该使用非交互 CLI:
175+
176+
```bash
177+
web-tools setup --check --json
178+
web-tools setup --provider bigmodel --auth-env ZHIPU_APIKEY --set-env ZHIPU_APIKEY=...
179+
web-tools skill install --force
180+
```
181+
154182
## 配置
155183

156184
配置文件可选,默认位置为 `~/.config/web-tools/config.json`,当前目录也可放 `./web-tools.json`

cli_integration_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ func runCLI(t *testing.T, bin string, args []string, env map[string]string) (str
324324
t.Helper()
325325

326326
cmd := exec.Command(bin, args...)
327-
cmd.Env = append(os.Environ(), "WEB_READER_NO_BROWSER=1")
327+
cmd.Env = isolatedCLIEnv(t)
328328
for k, v := range env {
329329
cmd.Env = append(cmd.Env, k+"="+v)
330330
}
@@ -337,3 +337,25 @@ func runCLI(t *testing.T, bin string, args []string, env map[string]string) (str
337337
require.NoError(t, err, "stderr:\n%s\nstdout:\n%s", stderr.String(), stdout.String())
338338
return stdout.String(), stderr.String()
339339
}
340+
341+
func isolatedCLIEnv(t *testing.T) []string {
342+
t.Helper()
343+
blocked := map[string]bool{
344+
"HOME": true,
345+
"WEB_TOOLS_CONFIG": true,
346+
"WEB_TOOLS_ENV": true,
347+
"ZHIPU_APIKEY": true,
348+
"WEB_READER_NO_BROWSER": true,
349+
}
350+
out := make([]string, 0, len(os.Environ())+1)
351+
for _, entry := range os.Environ() {
352+
key, _, _ := strings.Cut(entry, "=")
353+
if blocked[key] {
354+
continue
355+
}
356+
out = append(out, entry)
357+
}
358+
out = append(out, "HOME="+t.TempDir())
359+
out = append(out, "WEB_READER_NO_BROWSER=1")
360+
return out
361+
}

cmd/gui/main.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package guicmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"os/signal"
8+
"syscall"
9+
"time"
10+
11+
"github.com/koda-claw/web-tools/internal/gui"
12+
"github.com/spf13/cobra"
13+
)
14+
15+
// Cmd returns the local GUI command.
16+
func Cmd(version string) *cobra.Command {
17+
var (
18+
flagHost string
19+
flagPort int
20+
flagNoOpen bool
21+
flagSkillDir string
22+
)
23+
24+
cmd := &cobra.Command{
25+
Use: "gui",
26+
Short: "Start the local web-tools GUI",
27+
Long: `Start a local-only management console for checking setup, configuring providers,
28+
writing the user env file, running smoke tests, exporting diagnostics, and
29+
copying Agent handoff commands.`,
30+
Args: cobra.NoArgs,
31+
Run: func(cmd *cobra.Command, args []string) {
32+
server := gui.NewServer(gui.Options{
33+
Version: version,
34+
Host: flagHost,
35+
Port: flagPort,
36+
NoOpen: flagNoOpen,
37+
SkillDir: flagSkillDir,
38+
})
39+
if err := server.Start(); err != nil {
40+
fmt.Fprintf(os.Stderr, "failed to start GUI: %v\n", err)
41+
os.Exit(1)
42+
}
43+
fmt.Fprintf(os.Stdout, "web-tools GUI: %s\n", server.URL())
44+
if err := server.OpenBrowser(); err != nil {
45+
fmt.Fprintf(os.Stderr, "could not open browser automatically: %v\n", err)
46+
}
47+
48+
waitForShutdown(server)
49+
},
50+
}
51+
52+
cmd.Flags().StringVar(&flagHost, "host", "127.0.0.1", "Host to bind; default is local-only")
53+
cmd.Flags().IntVar(&flagPort, "port", 0, "Port to bind; 0 chooses a free port")
54+
cmd.Flags().BoolVar(&flagNoOpen, "no-open", false, "Do not open the browser automatically")
55+
cmd.Flags().StringVar(&flagSkillDir, "skill-dir", "~/.codex/skills", "Skill root directory")
56+
return cmd
57+
}
58+
59+
func waitForShutdown(server *gui.Server) {
60+
signals := make(chan os.Signal, 1)
61+
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
62+
<-signals
63+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
64+
defer cancel()
65+
_ = server.Shutdown(ctx)
66+
}

cmd/setup/main.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package setupcmd
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"os"
67
"strings"
@@ -10,6 +11,7 @@ import (
1011
skillcmd "github.com/koda-claw/web-tools/cmd/skill"
1112
"github.com/koda-claw/web-tools/internal/config"
1213
apperrors "github.com/koda-claw/web-tools/internal/errors"
14+
"github.com/koda-claw/web-tools/internal/setupcheck"
1315
"github.com/spf13/cobra"
1416
)
1517

@@ -29,6 +31,8 @@ func Cmd(version string) *cobra.Command {
2931
flagSetEnv string
3032
flagForceEnv bool
3133
flagSkipDoctor bool
34+
flagCheck bool
35+
flagJSON bool
3236
)
3337

3438
cmd := &cobra.Command{
@@ -43,6 +47,24 @@ what still needs attention.`,
4347
web-tools setup --provider bigmodel --enable-search-auto --install-skill`,
4448
Args: cobra.NoArgs,
4549
Run: func(cmd *cobra.Command, args []string) {
50+
if flagCheck {
51+
report := setupcheck.Run(setupcheck.Options{
52+
Version: version,
53+
SkillDir: flagSkillDir,
54+
Provider: flagProvider,
55+
AuthEnv: flagAuthEnv,
56+
})
57+
if flagJSON {
58+
data, _ := json.MarshalIndent(report, "", " ")
59+
fmt.Println(string(data))
60+
} else {
61+
fmt.Print(report.RenderText())
62+
}
63+
if !report.OK {
64+
os.Exit(1)
65+
}
66+
return
67+
}
4668
opts := Options{
4769
Version: version,
4870
Provider: flagProvider,
@@ -78,6 +100,8 @@ what still needs attention.`,
78100
cmd.Flags().StringVar(&flagSetEnv, "set-env", "", "Write KEY=value to env file without printing the value")
79101
cmd.Flags().BoolVar(&flagForceEnv, "force-env", false, "Overwrite an existing key in env file")
80102
cmd.Flags().BoolVar(&flagSkipDoctor, "skip-doctor", false, "Skip final doctor check")
103+
cmd.Flags().BoolVar(&flagCheck, "check", false, "Check setup readiness without modifying files")
104+
cmd.Flags().BoolVar(&flagJSON, "json", false, "JSON structured output for --check")
81105
return cmd
82106
}
83107

cmd/setup/main_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,36 @@ func TestRunSetupEnvFileOverwriteRequiresForce(t *testing.T) {
8787
assert.Equal(t, "new", values["ZHIPU_APIKEY"])
8888
}
8989

90+
func TestCmdSetupCheckJSON(t *testing.T) {
91+
dir := t.TempDir()
92+
origHome := os.Getenv("HOME")
93+
origConfig := os.Getenv("WEB_TOOLS_CONFIG")
94+
origAuth := os.Getenv("ZHIPU_APIKEY")
95+
t.Setenv("HOME", dir)
96+
t.Setenv("WEB_TOOLS_CONFIG", "")
97+
require.NoError(t, os.Unsetenv("ZHIPU_APIKEY"))
98+
t.Cleanup(func() {
99+
_ = os.Setenv("HOME", origHome)
100+
_ = os.Setenv("WEB_TOOLS_CONFIG", origConfig)
101+
if origAuth == "" {
102+
_ = os.Unsetenv("ZHIPU_APIKEY")
103+
} else {
104+
_ = os.Setenv("ZHIPU_APIKEY", origAuth)
105+
}
106+
})
107+
108+
cmd := Cmd("test")
109+
cmd.SetArgs([]string{"--check", "--json", "--skill-dir", filepath.Join(dir, "skills")})
110+
output := captureStdout(t, func() {
111+
require.NoError(t, cmd.Execute())
112+
})
113+
114+
assert.Contains(t, output, `"ok": true`)
115+
assert.Contains(t, output, `"install_skill"`)
116+
assert.Contains(t, output, `"configure_provider"`)
117+
assert.NotContains(t, output, "super-secret-token")
118+
}
119+
90120
func captureStdout(t *testing.T, fn func()) string {
91121
t.Helper()
92122
orig := os.Stdout

docs/gui-iteration-plan.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ MVP 先使用 Go `embed` 内嵌静态 HTML/CSS/JS,避免引入 Node 构建链
8282

8383
本轮不再拆多个 tag。`setup --check`、repair suggestions、GUI MVP、诊断导出和 Agent Guide 都归入 `v1.5.0`,按内部里程碑顺序推进,全部验收通过后统一发布。人类交互式配置由 GUI 承担,CLI `setup --interactive` 暂不进入本轮。
8484

85+
当前实现状态:
86+
87+
- Milestone 1 已实现:`setup --check``--json`、repair suggestions、setupcheck 单元测试和 smoke 覆盖。
88+
- Milestone 2 已实现:`web-tools gui`、本地 server、`/healthz`、status/provider/env/test API、静态 GUI 页面。
89+
- Milestone 3 已实现:诊断导出、Agent Guide、reader auto 显式确认提示和动态建议。
90+
- 发布前仍需执行统一验收:`go test ./...``go vet ./...``./scripts/smoke.sh``git diff --check`,并完成本地 GUI 冒烟。
91+
8592
### Milestone 1: Setup Check / Repair API
8693

8794
目标:先把 GUI 需要的状态诊断抽成可复用能力,CLI 和 GUI 共用。

docs/setup-env-iteration-plan.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ WEB_TOOLS_ENV=~/.config/web-tools/.env web-tools web-search "Go readability libr
259259

260260
目标:让用户和 Agent 更容易知道“缺什么、下一步做什么”。这部分不再单独发布,而是并入 `v1.5.0 Local GUI 管理台` 的 Milestone 1。
261261

262+
实现状态:已并入 `v1.5.0`,由 `web-tools setup --check``web-tools setup --check --json` 和 GUI `/api/status` 共同消费同一套 `internal/setupcheck` 报告。
263+
262264
#### Task 22: setup --check
263265

264266
**实现**
@@ -299,6 +301,8 @@ Run: web-tools setup --provider bigmodel --set-env ZHIPU_APIKEY=<redacted>
299301

300302
目标:为人类本地首次配置提供安全交互式体验。`v1.5.0` 明确由 GUI 承担这部分能力,CLI `setup --interactive` 暂不进入本轮;CLI 保持非交互,继续服务 Agent 和脚本。
301303

304+
实现状态:已由 `web-tools gui` 承担。CLI 继续提供非交互命令给 Agent 和脚本使用。
305+
302306
#### Task 24: GUI interactive setup
303307

304308
**交互流程**

0 commit comments

Comments
 (0)