@gavinc-cn/touchstone-dsh 0.0.0-stage → 0.1.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +335 -2
  3. package/README.zh.md +317 -0
  4. package/agents.py +247 -0
  5. package/auth.py +86 -0
  6. package/board.py +4229 -0
  7. package/builtin_assets.py +808 -0
  8. package/builtin_prompts/free_style/flow.md +301 -0
  9. package/builtin_prompts/free_style/load_test.md +114 -0
  10. package/builtin_prompts/free_style/templates/bug_report_template.md +41 -0
  11. package/builtin_prompts/free_style/templates/case_template.md +23 -0
  12. package/builtin_prompts/free_style/templates/index_template.md +41 -0
  13. package/builtin_prompts/free_style/templates/load_charts_template.md +104 -0
  14. package/builtin_prompts/free_style/templates/load_index_template.md +5 -0
  15. package/builtin_prompts/free_style/templates/load_plan_template.md +76 -0
  16. package/builtin_prompts/free_style/templates/load_scenario_template.md +49 -0
  17. package/builtin_prompts/free_style/templates/status_template.md +18 -0
  18. package/chat.py +616 -0
  19. package/db.py +1407 -0
  20. package/dsh-plugin/cordis.patch.yml +21 -0
  21. package/dsh-plugin/install.sh +79 -0
  22. package/dsh-plugin/lib/agent-driver.js +1888 -0
  23. package/dsh-plugin/lib/client.bundle.js +397 -0
  24. package/dsh-plugin/lib/index.js +284 -0
  25. package/dsh-plugin/scripts/build.mjs +37 -0
  26. package/dsh-plugin/scripts/prepack-check.mjs +61 -0
  27. package/dsh-plugin/scripts/select-bundle.mjs +51 -0
  28. package/dsh-plugin/src/client.js +384 -0
  29. package/dshdriver.py +702 -0
  30. package/dshevents.py +438 -0
  31. package/export_cases.py +160 -0
  32. package/extensions/dsh-autocommit/asset.json +18 -0
  33. package/extensions/dsh-autocommit/pkg/lib/index.mjs +361 -0
  34. package/extensions/dsh-autocommit/pkg/package.json +10 -0
  35. package/feishu.py +2139 -0
  36. package/lib.py +245 -0
  37. package/lifecycle.py +417 -0
  38. package/loadcase.py +558 -0
  39. package/loadgen.py +678 -0
  40. package/localbus.py +91 -0
  41. package/migrate_p7b.py +191 -0
  42. package/package.json +74 -4
  43. package/platcompat.py +272 -0
  44. package/prompts.py +666 -0
  45. package/rag.py +553 -0
  46. package/requirements.txt +9 -0
  47. package/runner.py +2471 -0
  48. package/server.py +5337 -0
  49. package/sessparse.py +638 -0
  50. package/touchstone.py +512 -0
  51. package/waitq.py +1319 -0
  52. package/webui/dist-plugin/assets/index-B0WoP1Qy.css +1 -0
  53. package/webui/dist-plugin/assets/index-eHpxBfP6.js +473 -0
  54. package/webui/dist-plugin/index.html +18 -0
  55. package/worktree.py +293 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Touchstone contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,336 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # Touchstone
4
+
5
+ **An AI-agent-driven automated testing platform.** Point it at a repository; it explores the code, writes and runs test cases, files what breaks, fixes it, and re-verifies the fix.
6
+
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
+ [![Python 3.12+](https://img.shields.io/badge/Python-3.12%2B-3776AB.svg)](https://www.python.org/)
9
+ [![Node 22.19+ | 24+](https://img.shields.io/badge/Node-22.19%2B%20%7C%2024%2B-339933.svg)](https://nodejs.org/)
10
+ [![DeepSeek Harness plugin](https://img.shields.io/badge/DeepSeek%20Harness-plugin-4D6BFE.svg)](https://github.com/deepseek-ai/deepseek-harness)
11
+
12
+ English | [中文](README.zh.md)
13
+
14
+ <img src="docs/images/board.png" alt="Touchstone development board" width="920">
15
+
16
+ </div>
17
+
18
+ ## What is Touchstone?
19
+
20
+ Touchstone turns "we really should test more" into a running loop. You register a project — its source
21
+ directory, a working directory, an environment label, and the house rules the agent must follow — and
22
+ Touchstone drives an AI agent through [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
23
+ (`dsh`) to **generate test cases, execute them, report failures as bug reports, fix the code, and
24
+ re-verify the fix**. Every artifact lands on disk in a reviewable form: a case library of Markdown case
25
+ files, a `bug_report/` directory, and per-round logs.
26
+
27
+ It is not a one-shot "run my test suite" CLI. Touchstone is built around **long-lived, multi-round agent
28
+ sessions**: a task runs round after round in the same session with its context intact, so the agent
29
+ remembers what it already tried. A unified queue keeps exactly one writer per project (no two agents
30
+ editing the same checkout at once), and the whole thing is observable — live round logs, a rendered
31
+ session window, and an SSE-backed board.
32
+
33
+ Touchstone runs **locally**. It is a Python web site with a SQLite database and a file-system workspace;
34
+ no data leaves your machine except for the model calls your `dsh` host makes.
35
+
36
+ ## Highlights
37
+
38
+ - **Six task types** covering the whole QA loop — exploration, regression, stress, fix, retest, and case
39
+ revision — each following a seven-stage lifecycle (generate cases → execute → report → analyze → fix →
40
+ deploy → retest).
41
+ - **A case library, not a test log.** Cases are human-readable Markdown (`case.md` + `status.md` per
42
+ case, plus an `INDEX.md` per directory). Agents read and extend them across tasks; you can fix a bad
43
+ case by editing a file.
44
+ - **Bug reports as first-class artifacts.** Failures are written up as structured reports (severity,
45
+ reproduction steps, log evidence, related cases) and can be routed back into fix / retest / case-revision
46
+ tasks from the UI.
47
+ - **Unified per-project queue.** Tasks, board cards, and chat messages all take the same serial slot per
48
+ project; queue position, the current holder, and evidence are queryable rather than guessed.
49
+ - **A board for agent-driven development.** Kanban cards start, queue, block, and complete agent sessions;
50
+ cards can run in an isolated `git worktree` so exploratory work never touches your main checkout.
51
+ - **Observable sessions.** Render the full transcript of any agent session (messages, reasoning, tool
52
+ calls, results), reply to it, inject into the running turn, compact it, fork it, or rewind to an earlier
53
+ point through a fork.
54
+ - **Stress testing built in.** A stress task asks the agent for a scenario + script; the platform then
55
+ drives the load itself, N runs per task, with per-run metrics, charts, and Markdown/JSON reports.
56
+ - **Optional integrations.** Feishu (Lark) push notifications with two-way answering from chat cards, and
57
+ RAG-based semantic search over the case library.
58
+ - **Self-contained stack.** Backend: Python standard library plus four small dependencies. Frontend: React
59
+ + Vite. Storage: SQLite + plain files. Runs on Linux and Windows.
60
+
61
+ ## Screenshots
62
+
63
+ The development board — cards per column, task entries inline, per-project queue badges:
64
+
65
+ ![Development board](docs/images/board.png)
66
+
67
+ Test tasks — six task types, round counts, statuses, and per-task actions:
68
+
69
+ ![Test tasks](docs/images/tasks.png)
70
+
71
+ The session window — the full agent transcript rendered from the `dsh` session store, with reply,
72
+ approval, and model controls:
73
+
74
+ ![Session window](docs/images/session.png)
75
+
76
+ Card detail — description, scheduling, dependent cards, bound sessions, and comments:
77
+
78
+ ![Card detail](docs/images/card-detail.png)
79
+
80
+ ## How it works
81
+
82
+ ```mermaid
83
+ flowchart LR
84
+ U[Browser] -->|REST + SSE| S["Touchstone server<br/>Python stdlib · SQLite · files"]
85
+ S -->|"/touchstone-agent<br/>resident sessions"| D["dsh host<br/>DeepSeek Harness"]
86
+ D -->|"read / edit / bash"| R["Your repository"]
87
+ D --> C[("Case library<br/>free_style/")]
88
+ D --> B[("Bug reports<br/>bug_report/")]
89
+ S --- C
90
+ S --- B
91
+ ```
92
+
93
+ 1. **You create a project.** Touchstone stores the repository path, a work directory, the environment
94
+ label, optional project skills, and free-form guidance that is injected into every first-round prompt.
95
+ 2. **You create a task.** Pick a type (say, *Exploration*) and an end stage (say, *report*), and Touchstone
96
+ queues it for that project.
97
+ 3. **Rounds run in a resident agent session.** Touchstone asks the `dsh` plugin to create or resume a
98
+ session and sends the round prompt. Rounds stream back to the UI and to
99
+ `<work_dir>/.web/task_<id>_round_<n>.log` as they happen.
100
+ 4. **Artifacts land in your work directory.** New cases under `free_style/`, bug reports under
101
+ `bug_report/`, monitoring state under `.live/`. You review them like code.
102
+ 5. **Follow-up tasks close the loop.** A report can spawn a fix task, a fix can spawn a retest, and a
103
+ rejected report can spawn a case-revision task. When a task's end stage goes past "report", the
104
+ platform appends the downstream stages as a follow-up task automatically.
105
+
106
+ ### Task types
107
+
108
+ | Type | What the agent does | Typical end stage |
109
+ |------|---------------------|-------------------|
110
+ | Exploration | Reads the code and writes new test cases into the case library | Report |
111
+ | Regression | Re-runs existing cases (optionally limited to a commit date range) | Report |
112
+ | Stress | Produces a load scenario + driver script, then the platform runs the load | Report |
113
+ | Fix | Analyzes a bug report, patches the code, deploys, and re-tests | Fix / Deploy / Retest |
114
+ | Retest | Re-verifies one bug report (retest only, deploy + retest, or deploy only) | Retest |
115
+ | Case revision | Rejects a bug report as a bad case and rewrites the case instead | Revision |
116
+
117
+ ### Core concepts
118
+
119
+ | Concept | Meaning |
120
+ |---------|---------|
121
+ | Project | A repository plus its work directory, agent binding, environment label, and guidance |
122
+ | Task | One queued unit of work: a task type, a stage range, a stop condition, and a round history |
123
+ | Round | One prompt/response cycle in the task's agent session |
124
+ | Case library | `<work_dir>/free_style/` — Markdown cases, status files, and per-directory indexes |
125
+ | Bug report | `<work_dir>/bug_report/<timestamp>_FS_<title>/` — the failure dossier for a case |
126
+ | Card | A board item that can start, queue, and drive its own agent session |
127
+ | Queue | The per-project serial slot shared by tasks, cards, and chat messages |
128
+
129
+ ## Quick start
130
+
131
+ ### Prerequisites
132
+
133
+ | Requirement | Version | Needed for |
134
+ |-------------|---------|------------|
135
+ | Python | 3.12+ | The server (verified on 3.12) |
136
+ | Node.js | 22.19+ or 24+ | Running the `dsh` host (the front-end build alone needs Node 18+) |
137
+ | DeepSeek Harness (`dsh`) | current release | Agent execution — required for plugin mode |
138
+
139
+ ### 1. Clone and install
140
+
141
+ ```bash
142
+ git clone https://github.com/gavinc-cn/touchstone-dsh.git
143
+ cd touchstone-dsh
144
+ python3 -m pip install -r requirements.txt
145
+ ```
146
+
147
+ ### 2. Start the site (standalone mode)
148
+
149
+ ```bash
150
+ ./touchstone.sh start # builds the front end on first run, then serves 127.0.0.1:4601
151
+ ./touchstone.sh status # PID and the actual port
152
+ ./touchstone.sh stop
153
+ ```
154
+
155
+ Then open <http://127.0.0.1:4601>.
156
+
157
+ The first start seeds an `admin` account. If `TS_ADMIN_PASSWORD` is not set, a random one-time password
158
+ is generated and printed **once** in the startup banner:
159
+
160
+ ```bash
161
+ grep '一次性初始口令' .run/server.log # or: ./touchstone.sh status
162
+ ```
163
+
164
+ You will be asked to change it on first login. Set `TS_ADMIN_PASSWORD=<your-password>` before the first
165
+ start to skip the one-time password (and the forced change).
166
+
167
+ > Standalone mode gives you the full site — projects, case library, bug reports, board, queue, monitoring —
168
+ > but **agent execution needs plugin mode** (below), because the agent runs inside the `dsh` host process.
169
+
170
+ ### 3. Run as a `dsh` plugin (recommended: enables agent execution)
171
+
172
+ The plugin embeds Touchstone in the `dsh` Web UI as a sidebar entry and panel, and lets Touchstone drive
173
+ resident agent sessions in the host process.
174
+
175
+ **Option A — from npm (self-contained package: whole platform + prebuilt front end):**
176
+
177
+ ```bash
178
+ npx @deepseek-ai/dsh web # 1) start the dsh host once (creates ~/.dsh/profiles/web)
179
+ dsh plugin --profile web add @gavinc-cn/touchstone-dsh # 2) install the plugin package
180
+ # 3) select the bundle in the profile manifest (the Plugins panel toggle does the same thing):
181
+ node ~/.dsh/profiles/web/node_modules/@gavinc-cn/touchstone-dsh/dsh-plugin/scripts/select-bundle.mjs \
182
+ ~/.dsh/profiles/web/package.json
183
+ # 4) restart the dsh web UI, open http://127.0.0.1:3080, use the Touchstone entry (Alt+T toggles the panel)
184
+ ```
185
+
186
+ The platform's own Python dependencies are installed with pip, not npm:
187
+
188
+ ```bash
189
+ pip install -r ~/.dsh/profiles/web/node_modules/@gavinc-cn/touchstone-dsh/requirements.txt
190
+ ```
191
+
192
+ No `repoDir` is needed: the package carries `server.py` and `webui/dist-plugin`, so the plugin falls back to
193
+ its own directory.
194
+
195
+ **Option B — from a checkout (development):**
196
+
197
+ ```bash
198
+ cd touchstone-dsh
199
+ ./dsh-plugin/install.sh # idempotent install of this checkout into the profile
200
+ ```
201
+
202
+ The installer prints the optional profile patch for pointing the plugin at your working copy (or picking a
203
+ specific interpreter); skip it to use the package's own directory:
204
+
205
+ ```yaml
206
+ - id: touchstone
207
+ config: { repoDir: /path/to/touchstone-dsh, pythonPath: /path/to/python3 }
208
+ ```
209
+
210
+ Both run modes share one database (`~/.touchstone/touchstone.db` by default) and are mutually exclusive
211
+ while running; the second instance refuses to start and tells you who holds the lock.
212
+
213
+ ### Windows
214
+
215
+ A cross-platform launcher offers the same commands:
216
+
217
+ ```bash
218
+ python touchstone.py start | stop | restart | status | build | test
219
+ ```
220
+
221
+ ### First steps in the UI
222
+
223
+ 1. Sign in and open **Settings → Change password** if you used the one-time password.
224
+ 2. **Add project** — source directory, work directory (defaults to `<project>/.touchstone`), environment
225
+ label, and the guidance the agent should follow. The case library and bug report directories are
226
+ derived and created for you.
227
+ 3. Create a task (or a board card) and let the queue pick it up. Round logs stream live; the session window
228
+ shows the transcript as it grows.
229
+
230
+ ## Configuration
231
+
232
+ | Variable | Default | Purpose |
233
+ |----------|---------|---------|
234
+ | `TS_PORT` / `TS_HOST` | `4601` / `127.0.0.1` | Listen address. Use `TS_HOST=0.0.0.0` to expose the site on your LAN |
235
+ | `TS_PYTHON` | `python3` | Interpreter used by the launcher (must have the runtime dependencies) |
236
+ | `TOUCHSTONE_DB` | `~/.touchstone/touchstone.db` | SQLite database. Must live on a local disk — file locking does not work on CIFS/network shares |
237
+ | `TS_ADMIN_PASSWORD` | *(random, printed once)* | Initial `admin` password; setting it skips the forced change |
238
+ | `TS_WEB_DIR` | `webui/dist` | Static front-end directory the server serves |
239
+ | `TOUCHSTONE_RUN_DIR` | `.run/` in the repository | PID / log / port files |
240
+ | `TS_EXT_DIR` | `extensions` | Root of the built-in asset manifests |
241
+ | `TS_ARCHIVE_SYNC` | `1` | Keep board "Done" and `dsh` session archive in sync (set `0` to disable) |
242
+ | `TS_DSH_PROFILE` / `TS_DSH_PYTHON` | `web` / auto-detected | `dsh` profile and interpreter used by the plugin installer |
243
+
244
+ Runtime paths inside a project's work directory:
245
+
246
+ | Path | Contents |
247
+ |------|----------|
248
+ | `free_style/` | Case library (cases, status files, indexes) |
249
+ | `bug_report/` | Bug reports, one directory per report |
250
+ | `.web/` | Round logs, chat logs, stress metrics and reports |
251
+ | `.live/live.json` | Agent live state used by the monitoring page |
252
+ | `board_media/` | Attachments pasted onto board cards |
253
+
254
+ ## Capabilities and limits
255
+
256
+ | Area | Supported |
257
+ |------|-----------|
258
+ | Agent sessions | Create, resume, reply, inject into the running turn, cancel, compact, fork, rewind-by-fork, model and permission-preset switching |
259
+ | Session observability | Full transcript rendering, archive state, attachment preview, live status stream (no polling) |
260
+ | Tasks | Six types, seven stages, stop conditions, date-range scoping, per-round logs, restart, continue |
261
+ | Board | Cards across five columns, drag & drop, queue position, parent dependencies, scheduled start, trash, isolated worktrees |
262
+ | Case library | Derived indexes, change-based retest triage, optional semantic (RAG) search |
263
+ | Stress testing | Scenario validation, concurrent load, second-by-second metrics, charts, Markdown/JSON reports per run |
264
+ | Notifications | Feishu (Lark) outbound push, inbound commands, and answering questions from chat cards |
265
+ | Multi-user | Login, admin/user roles, per-project ownership checks on every project-scoped endpoint |
266
+
267
+ Known limitations, stated plainly:
268
+
269
+ - **The UI is currently Chinese-only.**
270
+ - **Agent execution requires plugin mode**; standalone mode is the site without the agent.
271
+ - **Rewind and "compact into a new session" are approximations** — rewind starts a new branch at an
272
+ earlier point (the original session is kept), rather than truncating in place.
273
+ - **No error banner for failed model requests** — `dsh` has no event for it, so the session window shows
274
+ what the host reported and nothing more.
275
+ - **The Windows launcher is implemented but `dsh` itself has not been verified on Windows yet.**
276
+ - **End-to-end test scripts are not distributed** in this repository (see below), so `test-full` and
277
+ `test-ui` report a skip rather than running.
278
+
279
+ ## Repository layout
280
+
281
+ ```
282
+ touchstone-dsh/
283
+ ├── server.py HTTP site: routing, auth, REST, SSE, static front end
284
+ ├── runner.py Task execution engine and per-project scheduling
285
+ ├── waitq.py Unified queue model (the single source of truth for "who runs next")
286
+ ├── board.py Development board: cards, gates, agent sessions, archive sync
287
+ ├── chat.py Session chat: queued messages and injection
288
+ ├── prompts.py Per-round prompt templates (per task type, per stage)
289
+ ├── sessparse.py Reads the dsh session store into a renderable transcript
290
+ ├── dshdriver.py Client for the in-process dsh agent driver
291
+ ├── dshevents.py Folds the dsh state stream into an in-process registry
292
+ ├── rag.py Optional semantic search over the case library
293
+ ├── loadgen.py Built-in stress engine (scenarios, metrics, reports)
294
+ ├── feishu.py Feishu (Lark) integration
295
+ ├── db.py SQLite data layer
296
+ ├── builtin_prompts/ Prompt assets injected into first-round prompts
297
+ ├── dsh-plugin/ The dsh plugin package (thin Node shell + driver + client bundle)
298
+ ├── extensions/ Built-in assets installable from the settings page
299
+ ├── webui/ React + Vite front end
300
+ ├── tests/ pytest / vitest suites and the isolated-instance harness
301
+ └── touchstone.sh|py|cmd Launchers (Linux / cross-platform / Windows)
302
+ ```
303
+
304
+ ## Development
305
+
306
+ ```bash
307
+ ./touchstone.sh build # install front-end deps and build webui/dist
308
+ ./touchstone.sh test # backend pytest + front-end vitest
309
+ ./touchstone.sh test-full # + isolated end-to-end scripts (scripts are not distributed here)
310
+ ./touchstone.sh test-ui # Playwright end-to-end (needs a running site; scripts not distributed)
311
+ cd webui && npm run dev # front-end dev server on :5173, /api proxied to :4601
312
+ ```
313
+
314
+ Optional commit gate:
315
+
316
+ ```bash
317
+ git config core.hooksPath githooks # pre-commit runs the fast test layer (SKIP_TS_TESTS=1 to skip once)
318
+ ```
319
+
320
+ See [tests/README.md](tests/README.md) for the test matrix and prerequisites.
321
+
322
+ ## Security notes
323
+
324
+ - The site listens on `127.0.0.1` by default and requires a login. Exposing it (`TS_HOST=0.0.0.0`) puts it
325
+ on your network — do that deliberately.
326
+ - Every project-scoped endpoint checks ownership before returning data; the `admin` account is the only
327
+ administrator and cannot be renamed or deleted.
328
+ - The agent runs with the permission preset you configure. The default is the most permissive one (no
329
+ approval prompts), which is convenient and sharp-edged: **review the project guidance and the preset
330
+ before pointing it at a repository you care about.**
331
+ - Passwords are stored with the hashing scheme the project was specified against (unsalted MD5 for new
332
+ passwords, PBKDF2-SHA256 for legacy seed accounts). Treat this as a local-development-grade store.
333
+
334
+ ## License
335
+
336
+ [MIT](LICENSE) © Touchstone contributors
package/README.zh.md ADDED
@@ -0,0 +1,317 @@
1
+ <div align="center">
2
+
3
+ # Touchstone(试金石)
4
+
5
+ **AI agent 驱动的自动化测试平台。** 把它指向一个代码仓库,它会读代码、写用例、跑用例,
6
+ 把失败沉淀成 bug 报告,修完再复测一遍。
7
+
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
9
+ [![Python 3.12+](https://img.shields.io/badge/Python-3.12%2B-3776AB.svg)](https://www.python.org/)
10
+ [![Node 22.19+ | 24+](https://img.shields.io/badge/Node-22.19%2B%20%7C%2024%2B-339933.svg)](https://nodejs.org/)
11
+ [![DeepSeek Harness plugin](https://img.shields.io/badge/DeepSeek%20Harness-plugin-4D6BFE.svg)](https://github.com/deepseek-ai/deepseek-harness)
12
+
13
+ [English](README.md) | 中文
14
+
15
+ <img src="docs/images/board.png" alt="Touchstone 开发看板" width="920">
16
+
17
+ </div>
18
+
19
+ ## Touchstone 是什么
20
+
21
+ Touchstone 把「我们真该多测一点」变成一条持续转动的流水线。你登记一个项目——源码目录、
22
+ 工作目录、环境标签、以及要求 agent 遵守的项目约定——Touchstone 就会通过
23
+ [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh`)驱动 AI agent:
24
+ **生成测试用例 → 执行 → 把失败写成 bug 报告 → 修代码 → 再复测**。所有产物都以可直接审阅的形式
25
+ 落在磁盘上:Markdown 写的案例库、`bug_report/` 目录、以及逐轮日志。
26
+
27
+ 它不是「跑一遍我的测试」的一次性 CLI。Touchstone 的核心是**多轮常驻 agent 会话**:一个任务在同一
28
+ 会话里一轮接一轮地跑,上下文不断档,agent 记得自己试过什么。统一队列保证同一个项目同一时刻只有
29
+ 一个写者(不会有两个 agent 同时改同一份检出),并且全流程可观测——逐轮实时日志、可渲染的会话窗口、
30
+ 以及基于 SSE 的看板。
31
+
32
+ Touchstone 是**本地运行**的:Python 站点 + SQLite + 文件系统工作区。除了你的 `dsh` 宿主发起的模型
33
+ 调用之外,数据不出本机。
34
+
35
+ ## 主要特性
36
+
37
+ - **六类任务**覆盖完整测试闭环:探索 / 回归 / 压测 / 修复 / 复测 / 修例,每类都走七阶段生命周期
38
+ (生成用例 → 测试 → 生成报告 → 报告分析 → 问题修复 → 重新部署 → 复测)。
39
+ - **案例库而不是测试日志**。用例是可读的 Markdown(每个用例 `case.md` + `status.md`,每层目录一个
40
+ `INDEX.md`)。agent 跨任务读写同一份案例库;用例写错了,你直接改文件就能修。
41
+ - **bug 报告是一等产物**。失败会写成结构化报告(严重程度、复现步骤、日志证据、关联用例),并可在
42
+ 界面上直接派生成修复 / 复测 / 修例任务。
43
+ - **按项目的统一队列**。任务、看板卡片、会话消息共用同一个项目级串行位;排队位次、当前占用者与
44
+ 判定证据都可查,不靠猜。
45
+ - **面向 agent 开发的看板**。卡片可以起跑、排队、阻塞、完成各自的 agent 会话;需要时在独立的
46
+ `git worktree` 里跑,探索性改动不碰你的主检出。
47
+ - **会话可观测**。完整渲染任意 agent 会话的消息、思考、工具调用与返回;可续聊、可往当前轮注入、
48
+ 可压缩、可 fork、也可通过 fork 回退到更早的节点。
49
+ - **内置压测**。压测任务先让 agent 产出场景与脚本,之后由平台自己发压,一个任务可跑 N 次,每次都有
50
+ 指标、图表与 Markdown/JSON 报告。
51
+ - **可选集成**。飞书(Lark)推送通知与卡片双向作答;案例库的可选语义检索(RAG)。
52
+ - **自包含技术栈**。后端:Python 标准库 + 4 个小依赖;前端:React + Vite;存储:SQLite + 普通文件。
53
+ Linux 与 Windows 均可运行。
54
+
55
+ ## 界面截图
56
+
57
+ 开发看板——五列卡片、任务条目内联展示、项目级排队徽标:
58
+
59
+ ![开发看板](docs/images/board.png)
60
+
61
+ 测试任务——六类任务、轮次、状态与逐任务操作:
62
+
63
+ ![测试任务](docs/images/tasks.png)
64
+
65
+ 会话窗口——从 `dsh` 会话存储渲染出的完整对话(消息、思考、工具调用),带回复、审批与模型控件:
66
+
67
+ ![会话窗口](docs/images/session.png)
68
+
69
+ 卡片详情——描述、定时开工、父任务依赖、绑定会话与评论:
70
+
71
+ ![卡片详情](docs/images/card-detail.png)
72
+
73
+ ## 工作原理
74
+
75
+ ```mermaid
76
+ flowchart LR
77
+ U[浏览器] -->|REST + SSE| S["Touchstone 站点<br/>Python 标准库 · SQLite · 文件"]
78
+ S -->|"/touchstone-agent<br/>常驻会话"| D["dsh 宿主<br/>DeepSeek Harness"]
79
+ D -->|"读 / 改 / 执行"| R["你的代码仓库"]
80
+ D --> C[("案例库<br/>free_style/")]
81
+ D --> B[("bug 报告<br/>bug_report/")]
82
+ S --- C
83
+ S --- B
84
+ ```
85
+
86
+ 1. **建项目**:Touchstone 记录仓库路径、工作目录、环境标签、可选的项目能力 skill,以及每轮首轮
87
+ 提示词都会注入的自由文本约定。
88
+ 2. **建任务**:选类型(例如「探索」)与终点阶段(例如「生成报告」),入该项目的队列。
89
+ 3. **多轮会话执行**:Touchstone 经 `dsh` 插件新建或续接一个常驻会话,下发本轮提示词;过程实时回流
90
+ 到界面,并写入 `<工作目录>/.web/task_<id>_round_<n>.log`。
91
+ 4. **产物落到工作目录**:新用例进 `free_style/`,bug 报告进 `bug_report/`,监控状态进 `.live/`——
92
+ 你像审代码一样审它们。
93
+ 5. **后段任务闭环**:报告可派生修复任务,修复可派生复测任务,被否决的报告可派生修例任务;当任务的
94
+ 终点越过「生成报告」时,平台会自动追加后段阶段任务。
95
+
96
+ ### 任务类型
97
+
98
+ | 类型 | agent 做什么 | 常见终点 |
99
+ |------|--------------|----------|
100
+ | 探索 | 读代码并把新用例写进案例库 | 生成报告 |
101
+ | 回归 | 重跑已有用例(可限定提交日期范围) | 生成报告 |
102
+ | 压测 | 产出压测场景 + 驱动脚本,随后由平台发压 | 生成报告 |
103
+ | 修复 | 分析 bug 报告、改代码、部署并复测 | 问题修复 / 重新部署 / 复测 |
104
+ | 复测 | 针对一份 bug 报告复验(仅复测 / 部署后复测 / 仅部署) | 复测 |
105
+ | 修例 | 判定报告对应的用例本身有误,改写用例 | 修订用例 |
106
+
107
+ ### 核心概念
108
+
109
+ | 概念 | 含义 |
110
+ |------|------|
111
+ | 项目 | 一个仓库 + 工作目录 + 智能体绑定 + 环境标签 + 项目约定 |
112
+ | 任务 | 一个排队单元:任务类型、阶段范围、停止条件与轮次历史 |
113
+ | 轮次 | 任务会话里的一次「提示词 → agent 执行」循环 |
114
+ | 案例库 | `<工作目录>/free_style/`:Markdown 用例、状态文件与逐层索引 |
115
+ | bug 报告 | `<工作目录>/bug_report/<时间戳>_FS_<标题>/`:一条用例的失败档案 |
116
+ | 卡片 | 看板条目,可起跑、排队并驱动自己的 agent 会话 |
117
+ | 队列 | 任务 / 卡片 / 会话消息共享的项目级串行位 |
118
+
119
+ ## 快速开始
120
+
121
+ ### 环境要求
122
+
123
+ | 依赖 | 版本 | 用途 |
124
+ |------|------|------|
125
+ | Python | 3.12+ | 运行站点(实测 3.12) |
126
+ | Node.js | 22.19+ 或 24+ | 运行 `dsh` 宿主(仅构建前端时 Node 18+ 即可) |
127
+ | DeepSeek Harness(`dsh`) | 当前版本 | agent 执行——插件形态必需 |
128
+
129
+ ### 1. 克隆并安装
130
+
131
+ ```bash
132
+ git clone https://github.com/gavinc-cn/touchstone-dsh.git
133
+ cd touchstone-dsh
134
+ python3 -m pip install -r requirements.txt
135
+ ```
136
+
137
+ ### 2. 启动站点(独立形态)
138
+
139
+ ```bash
140
+ ./touchstone.sh start # 首次启动会自动构建前端,然后监听 127.0.0.1:4601
141
+ ./touchstone.sh status # 查看 PID 与实际端口
142
+ ./touchstone.sh stop
143
+ ```
144
+
145
+ 浏览器打开 <http://127.0.0.1:4601>。
146
+
147
+ 首次启动会种子一个 `admin` 账号。若未设置 `TS_ADMIN_PASSWORD`,平台会随机生成一次性初始口令,
148
+ **只在启动横幅打印一次**:
149
+
150
+ ```bash
151
+ grep '一次性初始口令' .run/server.log # 或:./touchstone.sh status
152
+ ```
153
+
154
+ 首次登录会被要求改密。想跳过一次性口令(以及强制改密),在首次启动前设置
155
+ `TS_ADMIN_PASSWORD=<你的口令>` 即可。
156
+
157
+ > 独立形态给的是完整站点——项目、案例库、bug 报告、看板、队列、监控都能用;但**agent 执行需要
158
+ > 插件形态**(见下),因为 agent 跑在 `dsh` 宿主进程里。
159
+
160
+ ### 3. 以 `dsh` 插件形态运行(推荐:启用 agent 执行)
161
+
162
+ 插件把 Touchstone 嵌进 `dsh` Web 界面(侧栏入口 + 面板),并让 Touchstone 能驱动宿主进程内的常驻
163
+ agent 会话。
164
+
165
+ **方式 A —— 从 npm 安装(自包含包:整个平台 + 预构建前端都在包里):**
166
+
167
+ ```bash
168
+ npx @deepseek-ai/dsh web # 1) 先启动一次 dsh 宿主(会创建 ~/.dsh/profiles/web)
169
+ dsh plugin --profile web add @gavinc-cn/touchstone-dsh # 2) 装插件包
170
+ # 3) 把包名选进 profile 清单(等同 Plugins 面板里那一行的开关):
171
+ node ~/.dsh/profiles/web/node_modules/@gavinc-cn/touchstone-dsh/dsh-plugin/scripts/select-bundle.mjs \
172
+ ~/.dsh/profiles/web/package.json
173
+ # 4) 重启 dsh web,打开 http://127.0.0.1:3080,用侧栏里的 Touchstone 入口(Alt+T 开关面板)
174
+ ```
175
+
176
+ 平台自身的 Python 依赖走 pip,npm 不管:
177
+
178
+ ```bash
179
+ pip install -r ~/.dsh/profiles/web/node_modules/@gavinc-cn/touchstone-dsh/requirements.txt
180
+ ```
181
+
182
+ **不需要配 `repoDir`**:包里带着 `server.py` 与 `webui/dist-plugin`,插件缺省就用包自身目录。
183
+
184
+ **方式 B —— 从检出安装(开发用):**
185
+
186
+ ```bash
187
+ cd touchstone-dsh
188
+ ./dsh-plugin/install.sh # 幂等安装本检出到 profile
189
+ ```
190
+
191
+ 安装脚本会打印**可选**的 profile 覆盖(指向本机工作副本、或指定解释器);不写就用包自身目录:
192
+
193
+ ```yaml
194
+ - id: touchstone
195
+ config: { repoDir: /path/to/touchstone-dsh, pythonPath: /path/to/python3 }
196
+ ```
197
+
198
+ 两种形态默认共用同一个数据库(`~/.touchstone/touchstone.db`),运行时互斥:第二个实例会拒绝启动,
199
+ 并打印当前占用者。
200
+
201
+ ### Windows
202
+
203
+ 跨平台启停器提供同一套命令:
204
+
205
+ ```bash
206
+ python touchstone.py start | stop | restart | status | build | test
207
+ ```
208
+
209
+ ### 界面里的第一步
210
+
211
+ 1. 登录;若用的是一次性口令,先去 **设置 → 修改密码**。
212
+ 2. **添加项目**——源码目录、工作目录(默认 `<项目目录>/.touchstone`)、环境标签,以及要求 agent
213
+ 遵守的约定。案例库与 bug 报告目录由平台派生并自动创建。
214
+ 3. 新建任务(或建一张看板卡),等队列调度。逐轮日志实时刷新,会话窗口随对话增长即时渲染。
215
+
216
+ ## 配置
217
+
218
+ | 环境变量 | 默认值 | 作用 |
219
+ |----------|--------|------|
220
+ | `TS_PORT` / `TS_HOST` | `4601` / `127.0.0.1` | 监听地址;`TS_HOST=0.0.0.0` 可对局域网开放 |
221
+ | `TS_PYTHON` | `python3` | 启停器使用的解释器(需装好运行依赖) |
222
+ | `TOUCHSTONE_DB` | `~/.touchstone/touchstone.db` | SQLite 数据库,必须放本地盘——文件锁在 CIFS/网盘上不可用 |
223
+ | `TS_ADMIN_PASSWORD` | *(随机,打印一次)* | `admin` 初始口令;设了就跳过强制改密 |
224
+ | `TS_WEB_DIR` | `webui/dist` | 站点托管的前端静态目录 |
225
+ | `TOUCHSTONE_RUN_DIR` | 仓库内 `.run/` | PID / 日志 / 端口标记文件目录 |
226
+ | `TS_EXT_DIR` | `extensions` | 内置资产清单根目录 |
227
+ | `TS_ARCHIVE_SYNC` | `1` | 看板「已完成」与 `dsh` 会话归档双向同步(置 `0` 关闭) |
228
+ | `TS_DSH_PROFILE` / `TS_DSH_PYTHON` | `web` / 自动探测 | 插件安装脚本使用的 `dsh` profile 与解释器 |
229
+
230
+ 项目工作目录下的运行路径:
231
+
232
+ | 路径 | 内容 |
233
+ |------|------|
234
+ | `free_style/` | 案例库(用例、状态文件、逐层索引) |
235
+ | `bug_report/` | bug 报告,一份报告一个目录 |
236
+ | `.web/` | 逐轮日志、对话日志、压测指标与报告 |
237
+ | `.live/live.json` | 监控页数据源(agent 运行状态) |
238
+ | `board_media/` | 粘贴到看板卡片的附件 |
239
+
240
+ ## 能力与边界
241
+
242
+ | 领域 | 支持情况 |
243
+ |------|----------|
244
+ | agent 会话 | 新建、续接、回复、往当前轮注入、中断、compact 压缩、fork、按 fork 回退、模型与权限档切换 |
245
+ | 会话可观测 | 完整对话渲染、归档状态、附件预览、实时状态流(零状态轮询) |
246
+ | 任务 | 六类型、七阶段、停止条件、日期范围限定、逐轮日志、重启、继续 |
247
+ | 看板 | 五列卡片、拖拽、排队位次、父任务依赖、定时开工、回收站、独立 worktree |
248
+ | 案例库 | 派生索引、按变更文件做复测粗筛、可选语义检索(RAG) |
249
+ | 压测 | 场景校验、并发发压、秒级指标、图表、每次运行独立的 Markdown/JSON 报告 |
250
+ | 通知 | 飞书推送、入站指令、在聊天卡片上直接作答 |
251
+ | 多用户 | 登录、admin/普通用户、所有按项目进入的接口都做归属校验 |
252
+
253
+ 如实说明的已知限制:
254
+
255
+ - **界面目前只有中文。**
256
+ - **agent 执行必须走插件形态**;独立形态是「没有 agent 的站点」。
257
+ - **回退与「压缩并新建」是语义近似**——回退是从更早的节点另起一支(原会话保留),不是原地截断。
258
+ - **模型请求失败没有错误横幅**——`dsh` 没有对应事件通道,会话窗只能显示宿主真实回报的内容。
259
+ - **Windows 启停器已实现,但 `dsh` 在 Windows 上尚未实机验证。**
260
+ - **端到端测试脚本不随本仓分发**(见下),因此 `test-full` 与 `test-ui` 只会提示跳过。
261
+
262
+ ## 仓库结构
263
+
264
+ ```
265
+ touchstone-dsh/
266
+ ├── server.py HTTP 站点:路由、鉴权、REST、SSE、静态前端
267
+ ├── runner.py 任务执行引擎与按项目调度
268
+ ├── waitq.py 统一队列模型(「下一个谁跑」的唯一权威)
269
+ ├── board.py 开发看板:卡片、门禁、agent 会话、归档同步
270
+ ├── chat.py 会话对话:排队消息与注入
271
+ ├── prompts.py 逐轮提示词模板(按任务类型与阶段)
272
+ ├── sessparse.py 读取 dsh 会话存储,还原成可渲染的对话
273
+ ├── dshdriver.py dsh 进程内 agent 驱动的客户端
274
+ ├── dshevents.py 把 dsh 状态流折进进程内注册表
275
+ ├── rag.py 案例库可选语义检索
276
+ ├── loadgen.py 内置压测引擎(场景、指标、报告)
277
+ ├── feishu.py 飞书集成
278
+ ├── db.py SQLite 数据层
279
+ ├── builtin_prompts/ 注入首轮提示词的提示词资产
280
+ ├── dsh-plugin/ dsh 插件包(Node 薄壳 + 驱动 + 客户端 bundle)
281
+ ├── extensions/ 设置页可一键安装的内置资产
282
+ ├── webui/ React + Vite 前端
283
+ ├── tests/ pytest / vitest 套件与隔离实例夹具
284
+ └── touchstone.sh|py|cmd 启停入口(Linux / 跨平台 / Windows)
285
+ ```
286
+
287
+ ## 开发
288
+
289
+ ```bash
290
+ ./touchstone.sh build # 安装前端依赖并构建 webui/dist
291
+ ./touchstone.sh test # 后端 pytest + 前端 vitest
292
+ ./touchstone.sh test-full # 追加隔离实例 e2e(本仓不随附这些脚本)
293
+ ./touchstone.sh test-ui # Playwright e2e(需站点在跑;本仓不随附这些脚本)
294
+ cd webui && npm run dev # 前端开发服务器 :5173,/api 代理到 :4601
295
+ ```
296
+
297
+ 可选的提交门禁:
298
+
299
+ ```bash
300
+ git config core.hooksPath githooks # pre-commit 跑测试快层(SKIP_TS_TESTS=1 单次跳过)
301
+ ```
302
+
303
+ 测试矩阵与前置条件见 [tests/README.md](tests/README.md)。
304
+
305
+ ## 安全说明
306
+
307
+ - 站点默认只监听 `127.0.0.1` 并要求登录。用 `TS_HOST=0.0.0.0` 对外暴露等于把它放进你的网络里,
308
+ 请有意为之。
309
+ - 所有按项目进入的接口先做归属校验;`admin` 是唯一管理员,不可改名或删除。
310
+ - agent 以你配置的权限档运行,默认是限制最松的一档(免审批)。方便,但也锋利:**把它指向你在意的
311
+ 仓库之前,请先看清项目约定与权限档。**
312
+ - 口令存储沿用本项目既定的算法(新口令为无盐 MD5,历史种子账号为 PBKDF2-SHA256)。请把它当作
313
+ 本地开发级别的口令存储来对待。
314
+
315
+ ## 许可证
316
+
317
+ [MIT](LICENSE) © Touchstone contributors