- commit
- d8e883d
- parent
- 8a4a3ee
- author
- codex@macbookpro
- date
- 2026-04-01 20:05:10 +0800 CST
feat: remove stagit repo route
8 files changed,
+45,
-164
Raw patch view.
1diff --git a/PROGRESS/2026-03-29-current-code-progress.md b/PROGRESS/2026-03-29-current-code-progress.md
2index dc08be404ccb06b927a5462714b7e1b218376665..d0007234afd74ad3f71c0648e64643960084662c 100644
3--- a/PROGRESS/2026-03-29-current-code-progress.md
4+++ b/PROGRESS/2026-03-29-current-code-progress.md
5@@ -52,7 +52,7 @@
6 - `/artifact/` 静态文件服务
7 - `/v1/messages`、`/v1/executions`、`/v1/sessions`、`/v1/sessions/latest`
8 - `/describe` 返回 `recent_sessions_url`
9-- stagit 仓库静态页面
10+- repo 静态页浏览能力后来已迁到 `baa-pgit`,当前 `conductor` 不再提供 `/artifact/repo/*`
11
12 因此,`ARTIFACT_STATIC_SERVICE.md` 现在更适合作为已完成主线的实现参考,而不是当前活跃任务入口。
13
14@@ -80,11 +80,10 @@
15
16 ## 当前 open bug / 风险
17
18-### BUG-026
19+### BUG-026(历史背景)
20
21-- `/artifact/repo/:repo_name` 根路径不会落到默认 `log.html`
22-- 显式 `/artifact/repo/<repo>/log.html` 可用
23-- 影响 repo 首页入口和 URL 语义一致性
24+- 该问题对应的 repo 静态页路由已在后续任务中整体删除
25+- `/artifact/repo/*` 不再是当前仓库能力;相关描述只保留为历史排障背景
26
27 ### BUG-027
28
29diff --git a/apps/conductor-daemon/src/index.test.js b/apps/conductor-daemon/src/index.test.js
30index eef834882b46e5d18c389835464ce25e7b45e5b0..a8427b699caeadba57c7b0c83c6e47d9c1ace747 100644
31--- a/apps/conductor-daemon/src/index.test.js
32+++ b/apps/conductor-daemon/src/index.test.js
33@@ -7846,10 +7846,6 @@ test("handleConductorHttpRequest serves artifact files and robots.txt", async ()
34 const { repository, snapshot } = await createLocalApiFixture();
35
36 await withArtifactStoreFixture(async ({ artifactStore }) => {
37- const repoDir = join(artifactStore.getArtifactsDir(), "repo", "demo-repo");
38- mkdirSync(repoDir, { recursive: true });
39- writeFileSync(join(repoDir, "log.html"), "<html><body>demo repo home</body></html>\n");
40-
41 await artifactStore.insertMessage({
42 conversationId: "conv_artifact",
43 id: "msg_artifact",
44@@ -7935,27 +7931,25 @@ test("handleConductorHttpRequest serves artifact files and robots.txt", async ()
45 assert.equal(sessionLatestResponse.status, 200);
46 assert.match(Buffer.from(sessionLatestResponse.body).toString("utf8"), /session_artifact/u);
47
48- const repoIndexResponse = await handleConductorHttpRequest(
49+ const removedRepoRootResponse = await handleConductorHttpRequest(
50 {
51 method: "GET",
52 path: "/artifact/repo/demo-repo"
53 },
54 context
55 );
56- assert.equal(repoIndexResponse.status, 200);
57- assert.match(repoIndexResponse.headers["content-type"], /^text\/html\b/u);
58- assert.match(Buffer.from(repoIndexResponse.body).toString("utf8"), /demo repo home/u);
59+ assert.equal(removedRepoRootResponse.status, 404);
60+ assert.equal(parseJsonBody(removedRepoRootResponse).error, "not_found");
61
62- const repoLogResponse = await handleConductorHttpRequest(
63+ const removedRepoFileResponse = await handleConductorHttpRequest(
64 {
65 method: "GET",
66 path: "/artifact/repo/demo-repo/log.html"
67 },
68 context
69 );
70- assert.equal(repoLogResponse.status, 200);
71- assert.match(repoLogResponse.headers["content-type"], /^text\/html\b/u);
72- assert.match(Buffer.from(repoLogResponse.body).toString("utf8"), /demo repo home/u);
73+ assert.equal(removedRepoFileResponse.status, 404);
74+ assert.equal(parseJsonBody(removedRepoFileResponse).error, "not_found");
75
76 const missingResponse = await handleConductorHttpRequest(
77 {
78diff --git a/apps/conductor-daemon/src/local-api.ts b/apps/conductor-daemon/src/local-api.ts
79index fb8af94b1e6d72cc91dfb4b9ea6e3b35593da64e..58aa47a437480f6c8fcfce89c1d832f279c41a6e 100644
80--- a/apps/conductor-daemon/src/local-api.ts
81+++ b/apps/conductor-daemon/src/local-api.ts
82@@ -437,16 +437,6 @@ const LOCAL_API_ROUTES: LocalApiRouteDefinition[] = [
83 pathPattern: "/robots.txt",
84 summary: "返回允许 AI 访问 /artifact/ 的 robots.txt"
85 },
86- // Keep the repo route ahead of the generic artifact route so repo root URLs
87- // can fall back to log.html instead of being claimed by the generic matcher.
88- {
89- id: "service.artifact.repo",
90- exposeInDescribe: false,
91- kind: "read",
92- method: "GET",
93- pathPattern: "/artifact/repo/:repo_name/*",
94- summary: "读取 stagit 生成的 git 仓库静态页面"
95- },
96 {
97 id: "service.artifact.read",
98 exposeInDescribe: false,
99@@ -6576,67 +6566,6 @@ async function handleArtifactRead(context: LocalApiRequestContext): Promise<Cond
100 }
101 }
102
103-const REPO_STATIC_CONTENT_TYPES: Record<string, string> = {
104- ".html": "text/html; charset=utf-8",
105- ".css": "text/css; charset=utf-8",
106- ".xml": "application/xml",
107- ".atom": "application/atom+xml",
108- ".json": "application/json",
109- ".txt": "text/plain; charset=utf-8",
110- ".png": "image/png",
111- ".ico": "image/x-icon",
112- ".svg": "image/svg+xml"
113-};
114-
115-function getRepoStaticContentType(filePath: string): string {
116- const dot = filePath.lastIndexOf(".");
117-
118- if (dot !== -1) {
119- const ext = filePath.slice(dot).toLowerCase();
120- const ct = REPO_STATIC_CONTENT_TYPES[ext];
121-
122- if (ct) {
123- return ct;
124- }
125- }
126-
127- return "text/plain; charset=utf-8";
128-}
129-
130-const REPO_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/u;
131-
132-async function handleArtifactRepoRead(context: LocalApiRequestContext): Promise<ConductorHttpResponse> {
133- const artifactStore = requireArtifactStore(context.artifactStore);
134- const repoName = context.params.repo_name;
135- const wildcard = context.params["*"] || "log.html";
136-
137- if (!repoName || !REPO_NAME_PATTERN.test(repoName) || wildcard.includes("..")) {
138- throw new LocalApiHttpError(
139- 404,
140- "not_found",
141- `No conductor route matches "${normalizePathname(context.url.pathname)}".`
142- );
143- }
144-
145- const filePath = join(artifactStore.getArtifactsDir(), "repo", repoName, wildcard);
146-
147- try {
148- return binaryResponse(200, readFileSync(filePath), {
149- "content-type": getRepoStaticContentType(wildcard)
150- });
151- } catch (error) {
152- if (isMissingFileError(error)) {
153- throw new LocalApiHttpError(
154- 404,
155- "not_found",
156- `Artifact "${normalizePathname(context.url.pathname)}" was not found.`
157- );
158- }
159-
160- throw error;
161- }
162-}
163-
164 function buildPlainTextBinaryResponse(status: number, body: string): ConductorHttpResponse {
165 return binaryResponse(status, Buffer.from(body, "utf8"), {
166 "content-type": CODE_ROUTE_CONTENT_TYPE
167@@ -7754,8 +7683,6 @@ async function dispatchBusinessRoute(
168 return handleRobotsRead();
169 case "service.artifact.read":
170 return handleArtifactRead(context);
171- case "service.artifact.repo":
172- return handleArtifactRepoRead(context);
173 case "service.code.read":
174 return handleCodeRead(context);
175 case "service.health":
176diff --git a/plans/ARTIFACT_STATIC_SERVICE.md b/plans/ARTIFACT_STATIC_SERVICE.md
177index ccc30cef41eb87c43889c00034202dc9b54e7850..d9460a038a5e05a8812f90c3946eb8fe5d2bad61 100644
178--- a/plans/ARTIFACT_STATIC_SERVICE.md
179+++ b/plans/ARTIFACT_STATIC_SERVICE.md
180@@ -379,7 +379,7 @@ D1 同步细节:
181 7. **D1 异步适配器**(TypeScript async 重写)
182 8. **D1 同步队列**(后台推送 + 重试)
183 9. **会话索引自动更新**(事件触发)
184-10. **stagit 集成**(后续)
185+10. **repo 静态页浏览能力迁出**(当前仓库不做)
186
187 ## 11. 不做的事
188
189diff --git a/plans/STATUS_SUMMARY.md b/plans/STATUS_SUMMARY.md
190index 523052b961d34a775874bf3a3919790b703d3c2f..655c6e8b4fe57224e73f0685c48a6dcbdf6c9917 100644
191--- a/plans/STATUS_SUMMARY.md
192+++ b/plans/STATUS_SUMMARY.md
193@@ -17,7 +17,7 @@
194 - 本地 SQLite + D1 异步同步
195 - `/artifact/` HTTP serve
196 - recent sessions 入口
197- - 历史上曾包含 stagit 仓库浏览;当前已拆出 `T-S073` 准备从本仓库删除
198+ - repo 静态页能力已迁到 `baa-pgit`;当前仓库不再提供 `/artifact/repo/*`
199 - 插件诊断日志链路已经完成:
200 - 插件 → WS → conductor → `logs/baa-plugin/YYYY-MM-DD.jsonl`
201 - `browser.final_message` ingest → `logs/baa-ingest/YYYY-MM-DD.jsonl`
202@@ -72,21 +72,18 @@
203 - `OPT-002`、`OPT-007` 已分别随 `889f746`、`b8d69c8` 合入 `main`,旧汇总中的 open 状态已改正
204 - `T-BUG-029` / `T-BUG-031` 的任务卡已完成,但旧汇总文档仍把它们写成 pending manual verification;现统一改为“建议补做浏览器复核”
205 - Artifact 静态服务已经完成,不再把它写成“下一阶段主线”
206-- repo 静态页能力已迁到 `baa-pgit`;当前仓库内残留的 stagit 路由与脚本已拆为 `T-S073`
207+- `T-S050` 曾引入 stagit repo 静态页,但该能力已迁到 `baa-pgit`,当前仓库内残留实现已随 `T-S073` 删除
208
209 ## 当前最高优先级
210
211 **当前下一波任务:**
212
213-当前最高优先级任务:
214-
215-- [`../tasks/T-S073.md`](../tasks/T-S073.md):移除 conductor 内的 stagit 仓库静态页能力
216 - [`../tasks/T-S074.md`](../tasks/T-S074.md):删除旧版 watchdog 与 Safari a11y 续命方案
217 - Web UI 主线 `T-S070 -> T-S071 -> T-S072` 保持下一顺位
218
219 其余没有 open bug / open opt。
220
221-如继续推进,建议先完成 `T-S073`,再完成 `T-S074`,之后回到 Web UI 主线,再根据新需求或代码审查结果继续拆任务。
222+如继续推进,建议先完成 `T-S074`,之后回到 Web UI 主线,再根据新需求或代码审查结果继续拆任务。
223
224 **并行优化项:**
225
226diff --git a/scripts/git-snapshot.sh b/scripts/git-snapshot.sh
227deleted file mode 100755
228index 6ef396d92a9e39b161c97802a4e83cff37c64c0f..0000000000000000000000000000000000000000
229--- a/scripts/git-snapshot.sh
230+++ /dev/null
231@@ -1,49 +0,0 @@
232-#!/usr/bin/env bash
233-# git-snapshot.sh — generate static HTML for a git repo using stagit.
234-# Usage: git-snapshot.sh <repo_path> <output_dir>
235-#
236-# Supports incremental generation via stagit -c (cachefile).
237-
238-set -euo pipefail
239-
240-REPO_PATH="${1:?Usage: git-snapshot.sh <repo_path> <output_dir>}"
241-OUTPUT_DIR="${2:?Usage: git-snapshot.sh <repo_path> <output_dir>}"
242-
243-# Resolve to absolute paths.
244-REPO_PATH="$(cd "$REPO_PATH" && pwd)"
245-
246-# Ensure output directory exists.
247-mkdir -p "$OUTPUT_DIR"
248-OUTPUT_DIR="$(cd "$OUTPUT_DIR" && pwd)"
249-
250-CACHEFILE="$OUTPUT_DIR/.stagit-cache"
251-
252-# stagit must be run from the output directory.
253-cd "$OUTPUT_DIR"
254-
255-# Generate static HTML (with incremental cache).
256-stagit -c "$CACHEFILE" "$REPO_PATH"
257-
258-# Provide a minimal style.css if one doesn't exist yet.
259-if [ ! -f "$OUTPUT_DIR/style.css" ]; then
260- cat > "$OUTPUT_DIR/style.css" <<'CSSEOF'
261-body { font-family: monospace; margin: 1em; background: #fff; color: #222; }
262-table { border-collapse: collapse; }
263-td, th { padding: 2px 6px; }
264-a { color: #005f87; }
265-pre { overflow-x: auto; }
266-hr { border: 0; border-top: 1px solid #ccc; }
267-#content { overflow-x: auto; }
268-.num { text-align: right; }
269-CSSEOF
270-fi
271-
272-# Create a 1x1 transparent PNG for logo/favicon if missing.
273-if [ ! -f "$OUTPUT_DIR/logo.png" ]; then
274- printf '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\nIDATx\x9cc\x00\x01\x00\x00\x05\x00\x01\r\n\xb4\x00\x00\x00\x00IEND\xaeB`\x82' > "$OUTPUT_DIR/logo.png"
275-fi
276-if [ ! -f "$OUTPUT_DIR/favicon.png" ]; then
277- cp "$OUTPUT_DIR/logo.png" "$OUTPUT_DIR/favicon.png"
278-fi
279-
280-echo "stagit: generated static HTML in $OUTPUT_DIR"
281diff --git a/tasks/T-S073.md b/tasks/T-S073.md
282index 41f9c32868d0e4bd8113a14da997a5d1e2d8fb3a..bf63e3fb7f06d8eb5db92c56ce7f8035ece845b4 100644
283--- a/tasks/T-S073.md
284+++ b/tasks/T-S073.md
285@@ -2,7 +2,7 @@
286
287 ## 状态
288
289-- 当前状态:`待开始`
290+- 当前状态:`已完成`
291 - 规模预估:`M`
292 - 依赖任务:无
293 - 建议执行者:`Codex`
294@@ -21,7 +21,7 @@
295
296 - 仓库:`/Users/george/code/baa-conductor`
297 - 分支基线:`main`
298-- 提交:`9674c30`
299+- 提交:`4aea341`
300
301 ## 分支与 worktree(强制)
302
303@@ -159,26 +159,39 @@
304
305 ## 执行记录
306
307-> 以下内容由执行任务的 AI 填写,创建任务时留空。
308-
309 ### 开始执行
310
311-- 执行者:
312-- 开始时间:
313-- 状态变更:
314+- 执行者:`Codex`
315+- 开始时间:`2026-04-01 19:57:00 CST`
316+- 状态变更:`待开始` → `进行中`
317
318 ### 完成摘要
319
320-- 完成时间:
321-- 状态变更:
322+- 完成时间:`2026-04-01 20:04:52 CST`
323+- 状态变更:`进行中` → `已完成`
324 - 修改了哪些文件:
325+ - `apps/conductor-daemon/src/local-api.ts`
326+ - `apps/conductor-daemon/src/index.test.js`
327+ - `scripts/git-snapshot.sh`
328+ - `tasks/TASK_OVERVIEW.md`
329+ - `plans/STATUS_SUMMARY.md`
330+ - `plans/ARTIFACT_STATIC_SERVICE.md`
331+ - `PROGRESS/2026-03-29-current-code-progress.md`
332+ - `tasks/T-S073.md`
333 - 核心实现思路:
334+ - 直接删除 `service.artifact.repo` 路由、`handleArtifactRepoRead` 和 repo 静态页专用 content-type/路径校验逻辑,不保留跳转或兼容层
335+ - 把 repo 静态页测试改成负向断言,确认 `/artifact/repo/*` 现在返回 `404`,同时保留普通 artifact 路径回归覆盖
336+ - 删除 `scripts/git-snapshot.sh`,并把当前文档口径统一改成“repo 静态页能力已迁到 `baa-pgit`”
337 - 跑了哪些测试:
338+ - `pnpm -C /Users/george/code/baa-conductor-remove-stagit-repo-route/apps/conductor-daemon test`
339+ - `pnpm -C /Users/george/code/baa-conductor-remove-stagit-repo-route/apps/conductor-daemon build`
340+ - `rg -n --glob '!tasks/archive/**' --glob '!plans/archive/**' --glob '!bugs/archive/**' --glob '!node_modules/**' "artifact/repo|stagit|git-snapshot\\.sh" /Users/george/code/baa-conductor-remove-stagit-repo-route`
341
342 ### 执行过程中遇到的问题
343
344--
345+- 主仓库 worktree 里已有未提交的文档改动,因此先确认 `main` 与 `origin/main` 一致,再从 `main` 新建独立 worktree,避免污染主仓库工作区
346+- 新建 worktree 默认没有 `node_modules`,首次执行 `pnpm test` 时 `pnpm exec tsc` 缺失;在 worktree 根目录执行一次 `pnpm install` 后恢复正常
347
348 ### 剩余风险
349
350--
351+- 历史任务卡、archive 文档和历史需求文档仍保留 stagit 描述;这是按任务约束刻意保留的历史记录,不代表当前主线能力
352diff --git a/tasks/TASK_OVERVIEW.md b/tasks/TASK_OVERVIEW.md
353index b1ccb5084eec4a5322ccb24cdcc0a4767a7620c8..f2756edcf887b3b0c862114003bcd8652b87d620 100644
354--- a/tasks/TASK_OVERVIEW.md
355+++ b/tasks/TASK_OVERVIEW.md
356@@ -16,7 +16,7 @@
357 - `artifact-db` 持久化 messages / executions / sessions
358 - `conductor` HTTP serve `/artifact/`
359 - D1 异步同步队列
360- - 历史上曾提供 stagit 仓库浏览;当前已拆出 `T-S073` 准备从本仓库删除这部分能力
361+ - repo 静态页能力已迁到 `baa-pgit`;当前仓库不再提供 `/artifact/repo/*`
362 - Firefox 插件诊断日志链路已落地:
363 - `page-interceptor -> content-script -> controller -> WS -> conductor`
364 - conductor 写 `logs/baa-plugin/YYYY-MM-DD.jsonl`
365@@ -72,7 +72,7 @@
366 - `OPT-002`、`OPT-007` 已分别随 `889f746`、`b8d69c8` 合入 `main`,旧总览中的 open 状态已改正
367 - `T-BUG-029`、`T-BUG-031` 的任务卡已是 `已完成`,但旧文档仍把它们写成 pending manual verification;现统一改为“建议补做浏览器复核”
368 - Artifact 静态服务已经完成,不再把 `T-S039`~`T-S045` 写成“当前活跃主线”
369-- `T-S050` 虽已完成,但 repo 静态页已迁到 `baa-pgit`;现新增 `T-S073` 从当前仓库删除残留的 stagit 能力
370+- `T-S050` 曾引入 stagit repo 静态页,但该能力已迁到 `baa-pgit`,当前仓库内残留实现已随 `T-S073` 删除
371
372 ## 当前活跃任务与优先级
373
374@@ -95,6 +95,7 @@
375 | [`T-S068`](./T-S068.md) | ChatGPT proxy send 冷启动降级保护 | S | 无 | Codex | 已完成 |
376 | [`T-S069`](./T-S069.md) | proxy_delivery 成功语义增强 | L | T-S060 | Codex | 已完成 |
377 | [`T-S065`](./T-S065.md) | policy 配置化 | M | 无 | Codex | 已完成 |
378+| [`T-S073`](./T-S073.md) | 移除 conductor 内的 stagit 仓库静态页能力 | M | 无 | Codex | 已完成 |
379
380 ### 当前下一波任务
381
382@@ -102,7 +103,6 @@
383
384 | 任务 | 标题 | 规模 | 依赖 | 建议 AI | 状态 |
385 |---|---|---|---|---|---|
386-| [`T-S073`](./T-S073.md) | 移除 conductor 内的 stagit 仓库静态页能力 | M | 无 | Codex | 待开始 |
387 | [`T-S074`](./T-S074.md) | 删除旧版 watchdog 与 Safari a11y 续命方案 | S | 无 | Codex | 待开始 |
388 | [`T-S070`](./T-S070.md) | Conductor UI 基础设施:Vue 3 脚手架与 `/app` 静态托管 | M | 无 | Codex | 待开始 |
389 | [`T-S071`](./T-S071.md) | Conductor UI 会话鉴权:登录页与浏览器 session | M | T-S070 | Codex | 待开始 |
390@@ -110,11 +110,11 @@
391
392 当前没有 open bug / open opt。
393
394-如继续推进,建议先按 `T-S073 -> T-S074` 收缩旧实现,再回到 `T-S070 -> T-S071 -> T-S072` 的 Web UI 主线。
395+如继续推进,建议先完成 `T-S074`,再回到 `T-S070 -> T-S071 -> T-S072` 的 Web UI 主线。
396
397 说明:
398
399-- `T-S073` / `T-S074` 是当前仓库边界收缩任务
400+- `T-S073` 已完成;`T-S074` 是剩余的仓库边界收缩任务
401 - `T-S070` / `T-S071` / `T-S072` 仍是后续正式 Web UI 主线
402 - `Channels` 工作区和正式 `channel` 域模型继续留在 `T-S072` 之后再拆下一轮
403
404@@ -140,6 +140,7 @@
405 | T-S048 | Gemini 投递适配器 | ✅ |
406 | T-S049 | 开放 chatgpt/gemini target | ✅ |
407 | T-S050 | stagit git 静态页面 | ✅ |
408+| T-S070 | 移除 conductor 内的 stagit 仓库静态页能力 | ✅ |
409 | T-S052 | D1 数据库初始化 | ✅ |
410 | T-S053 | 插件诊断日志 | ✅ |
411 | T-S054 | 插件日志 WS 转发 | ✅ |
412@@ -200,12 +201,11 @@
413
414 ## 当前主线判断
415
416-Phase 1(浏览器主链)、Artifact 静态服务,以及 timed-jobs + 续命主线都已完成收口。`T-S060`、`T-S061`、`T-S062`、`T-S063`、`T-S064`、`T-S065`、`T-S066`、`T-S067`、`T-S068`、`T-S069` 已全部落地;当前主线没有 open bug blocker,也没有 open opt,但已新增 `T-S073` / `T-S074` 用于收缩不再需要的 stagit 与 watchdog 旧能力。
417+Phase 1(浏览器主链)、Artifact 静态服务,以及 timed-jobs + 续命主线都已完成收口。`T-S060`、`T-S061`、`T-S062`、`T-S063`、`T-S064`、`T-S065`、`T-S066`、`T-S067`、`T-S068`、`T-S069` 已全部落地;当前主线没有 open bug blocker,也没有 open opt,`T-S073` 已完成,剩余待开始任务是 `T-S074` 与后续 Web UI 主线。
418
419 如果继续推进,建议:
420
421 - 远端 `baa-conductor-artifact` 已在 `2026-04-01` 应用 [`packages/d1-client/src/d1-setup.sql`](../packages/d1-client/src/d1-setup.sql) 的最新 schema;后续如新建或重置 D1 环境,仍需先执行同一脚本
422-- 先完成 `T-S073`
423 - 再完成 `T-S074`
424 - 之后回到 `T-S070 -> T-S071 -> T-S072` 的正式 Web UI 工作台主线
425