sillyspec 3.27.5 → 3.27.6
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/.worktrees/8d2d0392/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/8d2d0392/.claude/skills/verify-per-user/SKILL.md +6 -0
- package/.worktrees/8d2d0392/.gitattributes +2 -0
- package/.worktrees/8d2d0392/.husky/pre-push +20 -0
- package/.worktrees/8d2d0392/README.md +203 -0
- package/.worktrees/8d2d0392/SKILL.md +91 -0
- package/.worktrees/8d2d0392/architecture-analysis.md +448 -0
- package/.worktrees/8d2d0392/bin/sillyspec.js +2 -0
- package/.worktrees/8d2d0392/eval/README.md +86 -0
- package/.worktrees/8d2d0392/eval/eval.config.json +28 -0
- package/.worktrees/8d2d0392/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/8d2d0392/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/8d2d0392/eval/lib/config.mjs +82 -0
- package/.worktrees/8d2d0392/eval/lib/db.mjs +76 -0
- package/.worktrees/8d2d0392/eval/lib/report.mjs +120 -0
- package/.worktrees/8d2d0392/eval/lib/runner.mjs +157 -0
- package/.worktrees/8d2d0392/eval/lib/tasks.mjs +73 -0
- package/.worktrees/8d2d0392/eval/lib/util.mjs +107 -0
- package/.worktrees/8d2d0392/eval/lib/workdir.mjs +30 -0
- package/.worktrees/8d2d0392/eval/run.mjs +83 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/8d2d0392/logo.jpg +0 -0
- package/.worktrees/8d2d0392/package-lock.json +977 -0
- package/.worktrees/8d2d0392/package.json +41 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/8d2d0392/packages/dashboard/package.json +25 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/index.js +679 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/8d2d0392/src/agent-session-log.js +803 -0
- package/.worktrees/8d2d0392/src/change-list.js +290 -0
- package/.worktrees/8d2d0392/src/change-risk-profile.js +339 -0
- package/.worktrees/8d2d0392/src/check-primitives.js +65 -0
- package/.worktrees/8d2d0392/src/classify-change.js +109 -0
- package/.worktrees/8d2d0392/src/commit-suggest.js +202 -0
- package/.worktrees/8d2d0392/src/config-cat.js +88 -0
- package/.worktrees/8d2d0392/src/config-schema.js +328 -0
- package/.worktrees/8d2d0392/src/constants.js +97 -0
- package/.worktrees/8d2d0392/src/contract-matrix.js +533 -0
- package/.worktrees/8d2d0392/src/datetime.js +20 -0
- package/.worktrees/8d2d0392/src/db-engine.js +55 -0
- package/.worktrees/8d2d0392/src/db.js +381 -0
- package/.worktrees/8d2d0392/src/decision-distill.js +517 -0
- package/.worktrees/8d2d0392/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/8d2d0392/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/8d2d0392/src/dispatch/probe.js +246 -0
- package/.worktrees/8d2d0392/src/dispatch/strategy.js +121 -0
- package/.worktrees/8d2d0392/src/docs-check.js +825 -0
- package/.worktrees/8d2d0392/src/docs-debt.js +393 -0
- package/.worktrees/8d2d0392/src/docs-gate.js +107 -0
- package/.worktrees/8d2d0392/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/8d2d0392/src/endpoint-extractor.js +409 -0
- package/.worktrees/8d2d0392/src/foreign-declared.js +78 -0
- package/.worktrees/8d2d0392/src/fs-atomic.js +73 -0
- package/.worktrees/8d2d0392/src/git-helper.js +150 -0
- package/.worktrees/8d2d0392/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/8d2d0392/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/8d2d0392/src/index.js +2854 -0
- package/.worktrees/8d2d0392/src/init.js +626 -0
- package/.worktrees/8d2d0392/src/knowledge-match.js +231 -0
- package/.worktrees/8d2d0392/src/local-detect.js +128 -0
- package/.worktrees/8d2d0392/src/local-register.js +104 -0
- package/.worktrees/8d2d0392/src/machine-interface.js +543 -0
- package/.worktrees/8d2d0392/src/migrate.js +127 -0
- package/.worktrees/8d2d0392/src/module-impact.js +166 -0
- package/.worktrees/8d2d0392/src/module-resolve.js +222 -0
- package/.worktrees/8d2d0392/src/modules.js +580 -0
- package/.worktrees/8d2d0392/src/plan-adopt-waves.js +126 -0
- package/.worktrees/8d2d0392/src/progress/change-registry.js +336 -0
- package/.worktrees/8d2d0392/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/8d2d0392/src/progress/shared.js +36 -0
- package/.worktrees/8d2d0392/src/progress/stage-machine.js +594 -0
- package/.worktrees/8d2d0392/src/progress/step-store.js +265 -0
- package/.worktrees/8d2d0392/src/progress.js +1304 -0
- package/.worktrees/8d2d0392/src/quick-recommend.js +115 -0
- package/.worktrees/8d2d0392/src/quicklog.js +883 -0
- package/.worktrees/8d2d0392/src/review-tier.js +77 -0
- package/.worktrees/8d2d0392/src/run/command.js +1641 -0
- package/.worktrees/8d2d0392/src/run/complete-handlers.js +1552 -0
- package/.worktrees/8d2d0392/src/run/complete.js +1259 -0
- package/.worktrees/8d2d0392/src/run/concurrent-detect.js +156 -0
- package/.worktrees/8d2d0392/src/run/gates.js +1094 -0
- package/.worktrees/8d2d0392/src/run/multi-repo-context.js +208 -0
- package/.worktrees/8d2d0392/src/run/next.js +128 -0
- package/.worktrees/8d2d0392/src/run/prompt.js +843 -0
- package/.worktrees/8d2d0392/src/run/quick-audit.js +186 -0
- package/.worktrees/8d2d0392/src/run/scan-profile.js +269 -0
- package/.worktrees/8d2d0392/src/run/shared.js +1562 -0
- package/.worktrees/8d2d0392/src/run/stage.js +587 -0
- package/.worktrees/8d2d0392/src/run.js +23 -0
- package/.worktrees/8d2d0392/src/scan-diff.js +388 -0
- package/.worktrees/8d2d0392/src/scan-postcheck.js +524 -0
- package/.worktrees/8d2d0392/src/scan-staleness.js +95 -0
- package/.worktrees/8d2d0392/src/setup.js +414 -0
- package/.worktrees/8d2d0392/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/8d2d0392/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/8d2d0392/src/spec-dir-typo.js +50 -0
- package/.worktrees/8d2d0392/src/spec-sync.js +358 -0
- package/.worktrees/8d2d0392/src/stage-contract-engine.js +171 -0
- package/.worktrees/8d2d0392/src/stage-contract-spec.js +551 -0
- package/.worktrees/8d2d0392/src/stage-contract.js +948 -0
- package/.worktrees/8d2d0392/src/stage-review.js +597 -0
- package/.worktrees/8d2d0392/src/stages/archive.js +199 -0
- package/.worktrees/8d2d0392/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/8d2d0392/src/stages/brainstorm.js +624 -0
- package/.worktrees/8d2d0392/src/stages/cmd-existence.js +145 -0
- package/.worktrees/8d2d0392/src/stages/doctor.js +540 -0
- package/.worktrees/8d2d0392/src/stages/execute.js +1277 -0
- package/.worktrees/8d2d0392/src/stages/explore.js +43 -0
- package/.worktrees/8d2d0392/src/stages/index.js +29 -0
- package/.worktrees/8d2d0392/src/stages/knowledge.js +514 -0
- package/.worktrees/8d2d0392/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/8d2d0392/src/stages/plan.js +651 -0
- package/.worktrees/8d2d0392/src/stages/quick.js +167 -0
- package/.worktrees/8d2d0392/src/stages/scan.js +608 -0
- package/.worktrees/8d2d0392/src/stages/status.js +64 -0
- package/.worktrees/8d2d0392/src/stages/verify.js +246 -0
- package/.worktrees/8d2d0392/src/sync.js +1470 -0
- package/.worktrees/8d2d0392/src/task-review.js +1498 -0
- package/.worktrees/8d2d0392/src/taskcard-placeholders.js +21 -0
- package/.worktrees/8d2d0392/src/taskcard.js +217 -0
- package/.worktrees/8d2d0392/src/verify-postcheck.js +1718 -0
- package/.worktrees/8d2d0392/src/verify-probes.js +327 -0
- package/.worktrees/8d2d0392/src/version.js +19 -0
- package/.worktrees/8d2d0392/src/workflow.js +600 -0
- package/.worktrees/8d2d0392/src/workspace.js +125 -0
- package/.worktrees/8d2d0392/src/worktree-apply.js +1611 -0
- package/.worktrees/8d2d0392/src/worktree-deps.js +576 -0
- package/.worktrees/8d2d0392/src/worktree.js +1838 -0
- package/.worktrees/8d2d0392/templates/claude-instruction.md +23 -0
- package/.worktrees/8d2d0392/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/8d2d0392/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/8d2d0392/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/8d2d0392/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/8d2d0392/templates/workflows/scan-docs.yaml +132 -0
- package/architecture-analysis.md +448 -0
- package/package.json +1 -1
- package/src/contract-matrix.js +1 -1
- package/src/endpoint-extractor.js +41 -52
- package/src/foreign-declared.js +78 -1
- package/src/index.js +9 -7
- package/src/run/command.js +2 -1
- package/src/run/gates.js +17 -0
- package/src/run/stage.js +8 -5
- package/src/stage-contract-spec.js +1 -1
- package/src/stages/brainstorm-auto.js +43 -1
- package/src/stages/brainstorm.js +2 -0
- package/src/stages/plan.js +8 -4
- package/src/stages/verify.js +1 -1
- package/src/taskcard.js +33 -0
- package/src/verify-probes.js +27 -6
- package/src/worktree-apply.js +451 -286
- package/src/worktree-deps.js +93 -1
- package/src/worktree.js +84 -19
- package/templates/prompts/taskcard-rules.md +1 -1
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
# SillySpec 项目架构分析报告
|
|
2
|
+
|
|
3
|
+
> 分析时间:2026-08-25
|
|
4
|
+
> 项目版本:3.27.5
|
|
5
|
+
> 分析范围:全量代码库
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 项目定位与概述
|
|
10
|
+
|
|
11
|
+
SillySpec 是一个**给 AI Agent 调用的 CLI 流程状态机**,让 AI 严格按步骤来执行文档驱动开发。它不是给人类直接使用的产品,而是 Agent(如 Claude Code、Cursor)的流程控制器——Agent 通过 CLI 告诉它"我在哪",它告诉 Agent"下一步做什么";Agent 执行步骤,它校验产出、推进状态,人类只在关键决策点介入审批。
|
|
12
|
+
|
|
13
|
+
核心理念:**Spec-Driven Development(规范驱动开发)**——先有文档(brainstorm → design → plan),再写代码(execute),再验证(verify),最后归档(archive)。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. 整体架构设计
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
21
|
+
│ CLI Entry (bin/sillyspec.js) │
|
|
22
|
+
│ → src/index.js (主路由) │
|
|
23
|
+
└──────────────┬──────────────────────────────┬───────────────────┘
|
|
24
|
+
│ │
|
|
25
|
+
┌──────────▼──────────┐ ┌───────────▼──────────┐
|
|
26
|
+
│ 阶段执行引擎 │ │ 子命令路由 │
|
|
27
|
+
│ src/run/ │ │ progress / worktree │
|
|
28
|
+
│ command→stage→ │ │ gate / derive / │
|
|
29
|
+
│ prompt→complete │ │ docs / knowledge / │
|
|
30
|
+
└──────────┬───────────┘ │ workspace / dashboard │
|
|
31
|
+
│ └───────────┬───────────┘
|
|
32
|
+
┌──────────▼───────────┐ ┌───────────▼───────────┐
|
|
33
|
+
│ 阶段定义层 │ │ 状态管理层 │
|
|
34
|
+
│ src/stages/*.js │ │ src/progress.js │
|
|
35
|
+
│ (10 个阶段) │ │ src/progress/*.js │
|
|
36
|
+
└──────────┬───────────┘ │ (facade + 4 submod) │
|
|
37
|
+
│ └───────────┬───────────┘
|
|
38
|
+
│ │
|
|
39
|
+
┌──────────▼───────────────────────────────▼───────────┐
|
|
40
|
+
│ 数据层 │
|
|
41
|
+
│ src/db.js (node:sqlite) → sillyspec.db │
|
|
42
|
+
│ src/db-engine.js (引擎抽象) │
|
|
43
|
+
│ .sillyspec/.runtime/sillyspec.db (SQLite WAL) │
|
|
44
|
+
└──────────────────────────────────────────────────────┘
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2.1 架构分层(自顶向下)
|
|
48
|
+
|
|
49
|
+
| 层级 | 职责 | 关键文件 |
|
|
50
|
+
|------|------|---------|
|
|
51
|
+
| **CLI 入口层** | 参数解析、路由分发、全局 flag 处理 | `bin/sillyspec.js`, `src/index.js` |
|
|
52
|
+
| **命令分发层** | runCommand 主入口、auto 模式、stage 路由 | `src/run/command.js` |
|
|
53
|
+
| **阶段执行层** | step prompt 渲染、complete 校验、wait/continue | `src/run/stage.js`, `src/run/prompt.js`, `src/run/complete.js` |
|
|
54
|
+
| **阶段定义层** | 10 个阶段的 steps/prompt/校验器 | `src/stages/*.js` |
|
|
55
|
+
| **协议校验层** | StageContract 状态机、gate/derive 机器接口 | `src/stage-contract.js`, `src/machine-interface.js` |
|
|
56
|
+
| **状态管理层** | ProgressManager facade + 4 个子模块 | `src/progress.js`, `src/progress/*.js` |
|
|
57
|
+
| **数据持久化层** | SQLite WAL 数据库、原子写、备份恢复 | `src/db.js`, `src/db-engine.js`, `src/fs-atomic.js` |
|
|
58
|
+
| **辅助基础设施** | git 操作、平台同步、worktree 隔离、dashboard | `src/git-helper.js`, `src/sync.js`, `src/worktree*.js` |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 3. 技术栈选择
|
|
63
|
+
|
|
64
|
+
### 3.1 运行时
|
|
65
|
+
|
|
66
|
+
| 技术 | 版本要求 | 选型理由 |
|
|
67
|
+
|------|---------|---------|
|
|
68
|
+
| **Node.js** | ≥ 22.13.0 | 使用 `node:sqlite` 内置模块(22.5+ stable),无需 WASM/sql.js;原生 SQLite 性能 + 真 WAL |
|
|
69
|
+
| **ES Modules** | `"type": "module"` | 全量 ESM,动态 import 实现懒加载优化(E22 启动性能) |
|
|
70
|
+
|
|
71
|
+
### 3.2 数据库
|
|
72
|
+
|
|
73
|
+
| 技术 | 选型理由 |
|
|
74
|
+
|------|---------|
|
|
75
|
+
| **node:sqlite (DatabaseSync)** | Node 22 内置原生 SQLite 绑定,同步 API 简化状态管理;真 WAL 支持并发读写;.bak 损坏自动回退 |
|
|
76
|
+
| **WAL 模式** | `journal_mode=WAL` + `busy_timeout=5000` + `synchronous=NORMAL`,兼顾性能与安全 |
|
|
77
|
+
| **Schema 版本管理** | `DB_SCHEMA_VERSION=5` + `.schema-version` 戳,避免每次启动重建表 |
|
|
78
|
+
|
|
79
|
+
历史:v1/v2 使用 `progress.json` 文件,v3 全量迁移至 SQLite。
|
|
80
|
+
|
|
81
|
+
### 3.3 外部依赖(7 个,极度精简)
|
|
82
|
+
|
|
83
|
+
| 依赖 | 用途 | 选型理由 |
|
|
84
|
+
|------|------|---------|
|
|
85
|
+
| `@inquirer/prompts` | 交互式用户输入 | 标准 Node 交互 prompt 库 |
|
|
86
|
+
| `chalk` | 终端彩色输出 | CLI 美化 |
|
|
87
|
+
| `chokidar` | 文件系统监控 | dashboard 实时更新 |
|
|
88
|
+
| `js-yaml` | YAML 解析/序列化 | local.yaml / 项目配置 / module-map |
|
|
89
|
+
| `open` | 打开浏览器 | dashboard 自动打开 |
|
|
90
|
+
| `ora` | 终端 spinner | 长操作进度提示 |
|
|
91
|
+
| `ws` | WebSocket | dashboard 实时通信 |
|
|
92
|
+
|
|
93
|
+
### 3.4 测试/构建
|
|
94
|
+
|
|
95
|
+
| 技术 | 说明 |
|
|
96
|
+
|------|------|
|
|
97
|
+
| 自研测试运行器 | `test/run-tests.mjs`(无 jest/vitest 依赖,自研轻量 runner) |
|
|
98
|
+
| 自研 lint | `test/check-syntax.mjs`(自研语法检查,非 eslint) |
|
|
99
|
+
| 零构建步骤 | 纯 ESM 直接运行,无 tsc/webpack/rollup |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 4. 核心功能模块划分
|
|
104
|
+
|
|
105
|
+
### 4.1 阶段系统(Stage System)— 核心流程引擎
|
|
106
|
+
|
|
107
|
+
10 个阶段注册在 `src/stages/index.js`,分为两类:
|
|
108
|
+
|
|
109
|
+
#### 主流程阶段(必须按序)
|
|
110
|
+
| 阶段 | 文件 | 职责 |
|
|
111
|
+
|------|------|------|
|
|
112
|
+
| **brainstorm** | `brainstorm.js` | 需求澄清 → 产出 proposal/design/tasks |
|
|
113
|
+
| **plan** | `plan.js` | 任务拆解 → 产出 plan.md + tasks.md(Wave 分组) |
|
|
114
|
+
| **execute** | `execute.js` | 按 plan 执行代码 → 产出 per-task review.json |
|
|
115
|
+
| **verify** | `verify.js` | 验证实现符合 design → 产出 verify-result.md |
|
|
116
|
+
| **brainstorm-auto** | `brainstorm-auto.js` | brainstorm 自动模式变体 |
|
|
117
|
+
|
|
118
|
+
#### 辅助阶段(可在无活跃变更时执行)
|
|
119
|
+
| 阶段 | 文件 | 职责 |
|
|
120
|
+
|------|------|------|
|
|
121
|
+
| **quick** | `quick.js` | 快速任务(≤3 文件),跳过完整流程 |
|
|
122
|
+
| **scan** | `scan.js` | 代码库扫描 → 产出架构/约定/结构文档 |
|
|
123
|
+
| **explore** | `explore.js` | 自由讨论/调研,不修改文件 |
|
|
124
|
+
| **archive** | `archive.js` | 归档已完成变更 → archive 目录 |
|
|
125
|
+
| **status** | `status.js` | 查看当前进度 |
|
|
126
|
+
| **doctor** | `doctor.js` | 进度库健康检查 + 修复 |
|
|
127
|
+
|
|
128
|
+
### 4.2 状态管理子系统
|
|
129
|
+
|
|
130
|
+
**ProgressManager**(`src/progress.js`)是 facade,委托 4 个子模块:
|
|
131
|
+
|
|
132
|
+
| 子模块 | 文件 | 职责 |
|
|
133
|
+
|--------|------|------|
|
|
134
|
+
| `ChangeRegistry` | `progress/change-registry.js` | 变更注册/查询/归档(active/archived 状态管理) |
|
|
135
|
+
| `StageMachine` | `progress/stage-machine.js` | 阶段状态机(pending→in_progress→completed 转换规则) |
|
|
136
|
+
| `StepStore` | `progress/step-store.js` | 步骤级 CRUD(每个阶段的 steps 状态) |
|
|
137
|
+
| `ConsistencyDoctor` | `progress/consistency-doctor.js` | 一致性检查与修复 |
|
|
138
|
+
|
|
139
|
+
### 4.3 运行时子系统(src/run/)
|
|
140
|
+
|
|
141
|
+
| 模块 | 文件 | 职责 |
|
|
142
|
+
|------|------|------|
|
|
143
|
+
| **command** | `command.js` | runCommand 主入口、flag 解析、stage 路由、auto 模式 |
|
|
144
|
+
| **prompt** | `prompt.js` | prompt 渲染引擎(persona/铁律/占位符替换/完成后命令模板) |
|
|
145
|
+
| **stage** | `stage.js` | 单阶段执行器(遍历 steps → outputStep) |
|
|
146
|
+
| **complete** | `complete.js` | 步骤完成处理(--done/--skip/--wait/--continue) |
|
|
147
|
+
| **complete-handlers** | `complete-handlers.js` | 各阶段特化的完成处理器 |
|
|
148
|
+
| **gates** | `gates.js` | 门控引擎(Stage Review Gate / Task Review Gate / symbol-impact) |
|
|
149
|
+
| **shared** | `shared.js` | 共享工具(resolveSpecDir / git / worktree drift 检测等) |
|
|
150
|
+
| **quick-audit** | `quick-audit.js` | quick 完成审计(边界文件检测/归属) |
|
|
151
|
+
| **scan-profile** | `scan-profile.js` | scan 规模判定(quick/standard/deep 三档) |
|
|
152
|
+
| **concurrent-detect** | `concurrent-detect.js` | 并发变更检测 |
|
|
153
|
+
| **multi-repo-context** | `multi-repo-context.js` | 跨仓上下文构造 |
|
|
154
|
+
| **next** | `next.js` | 项目状态探测(下一步命令建议) |
|
|
155
|
+
|
|
156
|
+
### 4.4 协议与门控子系统
|
|
157
|
+
|
|
158
|
+
| 模块 | 文件 | 职责 |
|
|
159
|
+
|------|------|------|
|
|
160
|
+
| **StageContract** | `stage-contract.js` | 阶段合约(前置条件/产出校验/状态转换) |
|
|
161
|
+
| **stage-contract-engine** | `stage-contract-engine.js` | 合约规则引擎 |
|
|
162
|
+
| **stage-contract-spec** | `stage-contract-spec.js` | 合约规则定义 |
|
|
163
|
+
| **MachineInterface** | `machine-interface.js` | 机器接口 v1(gate/derive JSON envelope) |
|
|
164
|
+
| **task-review** | `task-review.js` | per-task review.json 生成/校验/adopt |
|
|
165
|
+
| **stage-review** | `stage-review.js` | stage 级 review.json 注册/刷新 |
|
|
166
|
+
|
|
167
|
+
### 4.5 Worktree 隔离子系统
|
|
168
|
+
|
|
169
|
+
| 模块 | 文件 | 职责 |
|
|
170
|
+
|------|------|------|
|
|
171
|
+
| **WorktreeManager** | `worktree.js` | worktree 创建/清理/doctor |
|
|
172
|
+
| **worktree-apply** | `worktree-apply.js` | 校验 + 应用变更到主工作区(含 merge fallback) |
|
|
173
|
+
| **worktree-guard** | `hooks/worktree-guard.js` | pre-push hook 拦截未合并 worktree |
|
|
174
|
+
|
|
175
|
+
### 4.6 平台集成(SillyHub)
|
|
176
|
+
|
|
177
|
+
| 模块 | 文件 | 职责 |
|
|
178
|
+
|------|------|------|
|
|
179
|
+
| **sync** | `sync.js` | 进度库 ↔ 平台双向同步 |
|
|
180
|
+
| **dispatch** | `dispatch/` | SillyHub MCP 派发(probe + strategy) |
|
|
181
|
+
| **sillyhub-mcp** | `sillyhub-mcp/` | MCP client/config |
|
|
182
|
+
| **platform-pointer** | (in progress.js) | 平台指针管理(fail-closed 设计) |
|
|
183
|
+
|
|
184
|
+
### 4.7 辅助工具集
|
|
185
|
+
|
|
186
|
+
| 模块 | 文件 | 职责 |
|
|
187
|
+
|------|------|------|
|
|
188
|
+
| **docs-check** | `docs-check.js` | 文档 file:line 引用校验 + 自动重锚 |
|
|
189
|
+
| **docs-gate** | `docs-gate.js` | 文档质量门控(pre-push 第三道关) |
|
|
190
|
+
| **knowledge** | `stages/knowledge.js` + `knowledge-match.js` | 知识库搜索/校验/提议 |
|
|
191
|
+
| **commit-suggest** | `commit-suggest.js` | 智能提交建议(conventional commit) |
|
|
192
|
+
| **module-impact** | `module-impact.js` | 模块影响矩阵骨架生成 |
|
|
193
|
+
| **endpoint-extractor** | `endpoint-extractor.js` | 后端路由静态扫描(FastAPI/Express/Spring) |
|
|
194
|
+
| **quicklog** | `quicklog.js` | QUICKLOG 管理 |
|
|
195
|
+
| **workspace** | `workspace.js` | 多项目工作区管理 |
|
|
196
|
+
| **dashboard** | `packages/dashboard/` | Web Dashboard(Vite + WebSocket 实时) |
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 5. 代码组织结构
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
sillyspec/
|
|
204
|
+
├── bin/sillyspec.js # CLI 入口(2 行,import src/index.js)
|
|
205
|
+
├── src/
|
|
206
|
+
│ ├── index.js # 主路由(~1800 行,CLI arg 解析 + 子命令分发)
|
|
207
|
+
│ ├── run.js # barrel(重导出 run/* 子模块)
|
|
208
|
+
│ ├── run/ # 运行时子系统(12 个文件)
|
|
209
|
+
│ │ ├── command.js # runCommand 主入口
|
|
210
|
+
│ │ ├── prompt.js # prompt 渲染引擎
|
|
211
|
+
│ │ ├── stage.js # 阶段执行器
|
|
212
|
+
│ │ ├── complete.js # 步骤完成处理
|
|
213
|
+
│ │ ├── complete-handlers.js # 阶段特化完成器
|
|
214
|
+
│ │ ├── gates.js # 门控引擎
|
|
215
|
+
│ │ ├── shared.js # 共享工具(最大文件)
|
|
216
|
+
│ │ ├── quick-audit.js # quick 审计
|
|
217
|
+
│ │ ├── scan-profile.js # scan 规模判定
|
|
218
|
+
│ │ ├── concurrent-detect.js # 并发检测
|
|
219
|
+
│ │ ├── multi-repo-context.js # 跨仓上下文
|
|
220
|
+
│ │ └── next.js # 状态探测
|
|
221
|
+
│ ├── stages/ # 阶段定义(10 个)
|
|
222
|
+
│ │ ├── index.js # 阶段注册表
|
|
223
|
+
│ │ ├── brainstorm.js # brainstorm 定义
|
|
224
|
+
│ │ ├── plan.js # plan 定义
|
|
225
|
+
│ │ ├── execute.js # execute 定义
|
|
226
|
+
│ │ ├── verify.js # verify 定义
|
|
227
|
+
│ │ ├── quick.js # quick 定义(最大阶段文件)
|
|
228
|
+
│ │ ├── scan.js # scan 定义
|
|
229
|
+
│ │ ├── explore.js # explore 定义
|
|
230
|
+
│ │ ├── archive.js # archive 定义
|
|
231
|
+
│ │ ├── status.js # status 定义
|
|
232
|
+
│ │ ├── doctor.js # doctor 定义
|
|
233
|
+
│ │ ├── knowledge.js # knowledge 命令
|
|
234
|
+
│ │ ├── plan-postcheck.js # plan 后置校验
|
|
235
|
+
│ │ ├── brainstorm-auto.js # 自动 brainstorm
|
|
236
|
+
│ │ └── cmd-existence.js # 命令存在性校验
|
|
237
|
+
│ ├── progress.js # ProgressManager facade
|
|
238
|
+
│ ├── progress/ # 进度子模块
|
|
239
|
+
│ │ ├── change-registry.js # 变更注册
|
|
240
|
+
│ │ ├── stage-machine.js # 阶段状态机
|
|
241
|
+
│ │ ├── step-store.js # 步骤存储
|
|
242
|
+
│ │ ├── consistency-doctor.js # 一致性修复
|
|
243
|
+
│ │ └── shared.js # 共享常量/类型
|
|
244
|
+
│ ├── db.js # SQLite 数据库管理
|
|
245
|
+
│ ├── db-engine.js # 数据库引擎抽象
|
|
246
|
+
│ ├── stage-contract.js # 阶段合约
|
|
247
|
+
│ ├── stage-contract-engine.js # 合约规则引擎
|
|
248
|
+
│ ├── stage-contract-spec.js # 合约规则定义
|
|
249
|
+
│ ├── machine-interface.js # 机器接口(gate/derive)
|
|
250
|
+
│ ├── worktree.js # worktree 管理
|
|
251
|
+
│ ├── worktree-apply.js # worktree 应用
|
|
252
|
+
│ ├── sync.js # 平台同步
|
|
253
|
+
│ ├── dispatch/ # SillyHub 派发
|
|
254
|
+
│ │ ├── probe.js
|
|
255
|
+
│ │ ├── strategy.js
|
|
256
|
+
│ │ └── backends/
|
|
257
|
+
│ │ ├── local-agent.js
|
|
258
|
+
│ │ └── sillyhub-mcp.js
|
|
259
|
+
│ ├── sillyhub-mcp/ # MCP 集成
|
|
260
|
+
│ ├── hooks/
|
|
261
|
+
│ │ └── worktree-guard.js # pre-push hook
|
|
262
|
+
│ ├── fs-atomic.js # 原子写工具
|
|
263
|
+
│ ├── git-helper.js # git 操作封装
|
|
264
|
+
│ ├── init.js # init 命令
|
|
265
|
+
│ ├── setup.js # setup 命令
|
|
266
|
+
│ ├── quicklog.js # QUICKLOG 管理
|
|
267
|
+
│ ├── commit-suggest.js # 提交建议
|
|
268
|
+
│ ├── docs-check.js # 文档引用校验
|
|
269
|
+
│ ├── docs-gate.js # 文档门控
|
|
270
|
+
│ ├── docs-debt.js # 文档债管理
|
|
271
|
+
│ ├── knowledge-match.js # 知识库匹配
|
|
272
|
+
│ ├── module-impact.js # 模块影响分析
|
|
273
|
+
│ ├── module-resolve.js # 模块解析
|
|
274
|
+
│ ├── modules.js # 模块管理
|
|
275
|
+
│ ├── endpoint-extractor.js # 端点提取
|
|
276
|
+
│ ├── config-cat.js # 配置查看
|
|
277
|
+
│ ├── config-schema.js # 配置 schema
|
|
278
|
+
│ ├── local-detect.js # 本地配置检测
|
|
279
|
+
│ ├── local-register.js # 本地注册
|
|
280
|
+
│ ├── doctor-diagnostics.js # 诊断工具
|
|
281
|
+
│ ├── classify-change.js # 变更分类
|
|
282
|
+
│ ├── change-risk-profile.js # 变更风险分析
|
|
283
|
+
│ ├── change-list.js # 变更文件列表
|
|
284
|
+
│ ├── verify-postcheck.js # verify 后置校验
|
|
285
|
+
│ ├── scan-postcheck.js # scan 后置校验
|
|
286
|
+
│ ├── scan-diff.js # scan 漂移检测
|
|
287
|
+
│ ├── scan-staleness.js # scan 过期检测
|
|
288
|
+
│ ├── plan-adopt-waves.js # plan Wave 重排
|
|
289
|
+
│ ├── task-review.js # task review 管理
|
|
290
|
+
│ ├── stage-review.js # stage review 管理
|
|
291
|
+
│ ├── verify-probes.js # verify 机械探针
|
|
292
|
+
│ ├── machine-interface.js # 机器接口
|
|
293
|
+
│ └── ...
|
|
294
|
+
├── packages/
|
|
295
|
+
│ └── dashboard/ # Web Dashboard
|
|
296
|
+
│ ├── server/ # Node.js 后端(Express + WebSocket)
|
|
297
|
+
│ ├── src/ # Vue.js 前端
|
|
298
|
+
│ └── dist/ # 构建产物
|
|
299
|
+
├── test/ # 测试(~250 个 .test.mjs 文件)
|
|
300
|
+
├── docs/ # 文档
|
|
301
|
+
│ ├── prompt/ # 阶段提示词原文
|
|
302
|
+
│ └── sillyspec/ # 项目文档
|
|
303
|
+
├── templates/ # 模板文件
|
|
304
|
+
├── eval/ # 评估工具
|
|
305
|
+
└── .claude/
|
|
306
|
+
└── skills/ # Claude Code SKILL 定义
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## 6. 关键设计模式与架构决策
|
|
312
|
+
|
|
313
|
+
### 6.1 状态机模式(Stage Machine)
|
|
314
|
+
|
|
315
|
+
核心设计:阶段转换由 `StageContract` 严格控制,不允许跳跃。
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
brainstorm → plan → execute → verify → archive
|
|
319
|
+
↑
|
|
320
|
+
quick (辅助,可随时) ─────────────────┘
|
|
321
|
+
scan (辅助,独立)
|
|
322
|
+
explore (辅助,独立)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
每个阶段有:
|
|
326
|
+
- `allowedFrom`: 允许的前置阶段
|
|
327
|
+
- `validators`: 校验器数组(产出文件存在性、内容完整性等)
|
|
328
|
+
- `steps[]`: 步骤定义(每个 step 有 prompt + outputHint + optional 标记)
|
|
329
|
+
|
|
330
|
+
### 6.2 门控模式(Gate Pattern)
|
|
331
|
+
|
|
332
|
+
**Stage Review Gate**: 每个主流程阶段完成后,检查 stage 级 review.json
|
|
333
|
+
**Task Review Gate**: execute 阶段每个 task 完成后,检查 per-task review.json
|
|
334
|
+
**Docs Gate**: pre-push 时检查文档引用有效性
|
|
335
|
+
|
|
336
|
+
所有 gate 遵循:**fail-closed**(无法判断时拒绝通过)+ **只读语义**(不修改状态)
|
|
337
|
+
|
|
338
|
+
### 6.3 Machine Interface(机器接口)
|
|
339
|
+
|
|
340
|
+
把人类可读的校验输出抽象为机器可消费的 JSON envelope:
|
|
341
|
+
- `runGate(stage, change)` → 判断阶段能否标记完成
|
|
342
|
+
- `runDerive(facet, change)` → 查询特定事实的真实状态
|
|
343
|
+
- 退出码三段:0=通过 / 1=阻断 / 2=无法核验
|
|
344
|
+
|
|
345
|
+
### 6.4 Worktree 隔离(execute 阶段)
|
|
346
|
+
|
|
347
|
+
execute 阶段在独立 git worktree 中运行,避免并行变更冲突:
|
|
348
|
+
- `worktree create` → 创建隔离工作区
|
|
349
|
+
- `worktree apply` → 校验 + 合并回主工作区
|
|
350
|
+
- `worktree cleanup` → 清理
|
|
351
|
+
|
|
352
|
+
支持三种模式:`worktree`(标准 git worktree)/ `native-worktree`(原生)/ `in-place-fallback`(降级就地执行)
|
|
353
|
+
|
|
354
|
+
### 6.5 平台指针(Platform Pointer)
|
|
355
|
+
|
|
356
|
+
fail-closed 设计:平台声明接管时,指针缺失则拒绝回退到本地模式
|
|
357
|
+
- `.sillyspec-platform.json` 平台指针
|
|
358
|
+
- `*-managed` 接管声明文件
|
|
359
|
+
- 成对存在,成对删除
|
|
360
|
+
|
|
361
|
+
### 6.6 懒加载优化(E22)
|
|
362
|
+
|
|
363
|
+
`src/index.js` 对轻路径(--version/help)不做重 import,progress.js 和 run/shared.js 链在 main() 早退后才动态加载,省 ~78ms 启动税。
|
|
364
|
+
|
|
365
|
+
### 6.7 原子写 + 并发安全
|
|
366
|
+
|
|
367
|
+
- `fs-atomic.js`: 写临时文件 → renameSync 覆盖(Windows EPERM 重试机制)
|
|
368
|
+
- `db.js`: WAL 模式 + `busy_timeout=5000` + 应用层 `MAX_BUSY_RETRIES=3` 退避
|
|
369
|
+
- 主仓 apply 互斥锁(`withMainRepoLock`)
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## 7. 数据存储结构
|
|
374
|
+
|
|
375
|
+
```
|
|
376
|
+
.sillyspec/
|
|
377
|
+
├── .runtime/
|
|
378
|
+
│ └── sillyspec.db # SQLite 数据库(权威状态源)
|
|
379
|
+
├── changes/
|
|
380
|
+
│ └── <change-name>/
|
|
381
|
+
│ ├── design.md # 设计文档
|
|
382
|
+
│ ├── plan.md # 实现计划
|
|
383
|
+
│ ├── tasks.md # 任务注册表
|
|
384
|
+
│ ├── verify-result.md # 验证报告
|
|
385
|
+
│ ├── symbol-impact.md # 符号影响分析
|
|
386
|
+
│ ├── module-impact.md # 模块影响矩阵
|
|
387
|
+
│ └── tasks/
|
|
388
|
+
│ └── task-01.md # per-task 卡片
|
|
389
|
+
├── docs/
|
|
390
|
+
│ └── <project>/
|
|
391
|
+
│ ├── scan/ # scan 产出文档
|
|
392
|
+
│ │ ├── ARCHITECTURE.md
|
|
393
|
+
│ │ ├── CONVENTIONS.md
|
|
394
|
+
│ │ ├── STRUCTURE.md
|
|
395
|
+
│ │ ├── INTEGRATIONS.md
|
|
396
|
+
│ │ ├── TESTING.md
|
|
397
|
+
│ │ ├── CONCERNS.md
|
|
398
|
+
│ │ └── PROJECT.md
|
|
399
|
+
│ └── modules/ # 模块文档
|
|
400
|
+
│ ├── _module-map.yaml
|
|
401
|
+
│ └── <module>.md
|
|
402
|
+
├── knowledge/ # 知识库
|
|
403
|
+
├── projects/ # 多项目工作区配置
|
|
404
|
+
├── archive/ # 已归档变更
|
|
405
|
+
├── quicklog/ # QUICKLOG
|
|
406
|
+
├── local.yaml # 本地配置
|
|
407
|
+
└── docs-check-baseline # 文档检查基线
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## 8. 测试架构
|
|
413
|
+
|
|
414
|
+
- **~250 个测试文件**(`.test.mjs`),自研测试运行器 `test/run-tests.mjs`
|
|
415
|
+
- 覆盖面:CLI 端到端(子进程模式)、单元测试、集成测试
|
|
416
|
+
- 测试模式:`seed-real-steps`(CLI 子进程 seed 真实步骤)+ 直接 import 测试
|
|
417
|
+
- 特殊测试:flaky 测试隔离(`--spec-dir` 隔离防文件锁竞争)、跨仓测试、平台同步测试
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## 9. 关键配置文件
|
|
422
|
+
|
|
423
|
+
| 文件 | 用途 |
|
|
424
|
+
|------|------|
|
|
425
|
+
| `package.json` | 项目元数据、依赖、脚本 |
|
|
426
|
+
| `.sillyspec/local.yaml` | 本地配置(构建命令、测试命令、docs-check 路径等) |
|
|
427
|
+
| `.sillyspec/.runtime/sillyspec.db` | 权威状态数据库 |
|
|
428
|
+
| `.sillyspec-platform.json` | 平台指针 |
|
|
429
|
+
| `.claude/skills/` | Claude Code SKILL 定义 |
|
|
430
|
+
| `.husky/pre-push` | Git pre-push hook(worktree guard + docs gate) |
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## 10. 风险与观察
|
|
435
|
+
|
|
436
|
+
1. **src/index.js 过大**:~1800 行的主路由文件,承载了所有子命令的 flag 解析和分发逻辑。虽然已有 W6 重构将 run.js 抽为 barrel,但 index.js 本身仍是单体。
|
|
437
|
+
|
|
438
|
+
2. **自研测试/ lint 工具**:未使用社区标准工具(jest/vitest/eslint),维护成本自担,但换来了零依赖的轻量启动。
|
|
439
|
+
|
|
440
|
+
3. **平台集成复杂度**:SillyHub 集成(sync/dispatch/mcp/pointer)引入了大量 fail-closed 守卫和并发安全逻辑,是 bug 高发区(从 MEMORY.md 的大量 worktree/sync 相关经验可见)。
|
|
441
|
+
|
|
442
|
+
4. **Windows 兼容性**:多个 MEMORY 条目记录了 Windows 特有问题(rename EPERM、CRLF、路径分隔符),代码中已有针对性处理但仍需持续关注。
|
|
443
|
+
|
|
444
|
+
5. **测试覆盖广度**:~250 个测试文件覆盖了极广的功能面,但部分测试有 flaky 问题(worktree/git 操作的时序敏感性)。
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
*报告产出路径:`architecture-analysis.md`(工作区根目录)*
|
package/package.json
CHANGED
package/src/contract-matrix.js
CHANGED
|
@@ -341,7 +341,7 @@ export function buildContractFieldInjection(changeDir, taskName) {
|
|
|
341
341
|
* meta);兼容回退 scanRoot/.sillyspec/.runtime(旧路径)。
|
|
342
342
|
* @returns {{ meta: object, gitDir: string }|null} gitDir = diff/扫描用 git 根(真实 worktree 或 scanRoot)
|
|
343
343
|
*/
|
|
344
|
-
function _readWorktreeMeta(specBase, scanRoot, changeName) {
|
|
344
|
+
export function _readWorktreeMeta(specBase, scanRoot, changeName) {
|
|
345
345
|
if (!changeName) return null
|
|
346
346
|
const candidates = [
|
|
347
347
|
specBase ? join(specBase, '.runtime', 'worktrees', changeName, 'meta.json') : null,
|
|
@@ -13,6 +13,17 @@ import { execSync } from 'child_process'
|
|
|
13
13
|
|
|
14
14
|
// ─── Provider: 扫描后端 router 注册的端点 ───────────────────────────────
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* matchIndex → 装饰器/路由起始行号(全文匹配配套;1-based)。
|
|
18
|
+
* 坑 endpoint-multiline-decorator-miss(2026-08-24 用户实证):三框架提取器原为逐行匹配,
|
|
19
|
+
* 多行装饰器(`@router.get(\n "/path",\n response_model=…)` 等)路径不在装饰器行 → 端点
|
|
20
|
+
* 静默漏 → endpoints.json artifact 与 live 扫描双失真 → probe5 missingBackend 误报(11 个
|
|
21
|
+
* 存量端点)。装饰器匹配改为全文正则(`\s*` 天然跨换行),行号取起始行。
|
|
22
|
+
*/
|
|
23
|
+
function lineOfIndex(content, index) {
|
|
24
|
+
return content.slice(0, index).split('\n').length
|
|
25
|
+
}
|
|
26
|
+
|
|
16
27
|
/**
|
|
17
28
|
* 从单个文件提取 FastAPI router 端点
|
|
18
29
|
* 支持 APIRouter(prefix=...) 和 @router.get/post/put/delete/patch("/path")
|
|
@@ -25,7 +36,7 @@ export function extractFastApiEndpoints(filePath) {
|
|
|
25
36
|
const lines = content.split('\n')
|
|
26
37
|
const endpoints = []
|
|
27
38
|
|
|
28
|
-
// 1. 提取 router prefix
|
|
39
|
+
// 1. 提取 router prefix(逐行,同文件近似——维持原行为)
|
|
29
40
|
let routerPrefix = ''
|
|
30
41
|
for (const line of lines) {
|
|
31
42
|
const prefixMatch = line.match(/(?:APIRouter|router)\s*\(\s*(?:prefix\s*=\s*)?["'`]([^"'`]+)["'`]/)
|
|
@@ -35,40 +46,17 @@ export function extractFastApiEndpoints(filePath) {
|
|
|
35
46
|
}
|
|
36
47
|
}
|
|
37
48
|
|
|
38
|
-
// 2.
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const rawPath = decoratorMatch[2]
|
|
50
|
-
endpoints.push({
|
|
51
|
-
method,
|
|
52
|
-
path: routerPrefix + rawPath,
|
|
53
|
-
source: filePath,
|
|
54
|
-
line: i + 1,
|
|
55
|
-
})
|
|
56
|
-
continue
|
|
57
|
-
}
|
|
58
|
-
// 分散式: @router.get\n ("/path",
|
|
59
|
-
const splitMatch = line.match(/@(?:router|api_router)\.(get|post|put|delete|patch)\s*$/)
|
|
60
|
-
if (splitMatch && i + 1 < lines.length) {
|
|
61
|
-
const nextLine = lines[i + 1]
|
|
62
|
-
const pathMatch = nextLine.match(/\(\s*["'`]([^"'`]+)["'`]/)
|
|
63
|
-
if (pathMatch) {
|
|
64
|
-
endpoints.push({
|
|
65
|
-
method: splitMatch[1].toUpperCase(),
|
|
66
|
-
path: routerPrefix + pathMatch[1],
|
|
67
|
-
source: filePath,
|
|
68
|
-
line: i + 1,
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
}
|
|
49
|
+
// 2. 装饰器全文匹配:单行 `@router.get("/path")`、分散式 `@router.get\n("/path")`、
|
|
50
|
+
// 多行参数 `@router.get(\n "/path",\n response_model=…)` 三态合一(\s* 跨换行)
|
|
51
|
+
const decoratorRe = /@(?:router|api_router)\.(get|post|put|delete|patch)\s*\(\s*["'`]([^"'`]+)["'`]/g
|
|
52
|
+
let m
|
|
53
|
+
while ((m = decoratorRe.exec(content)) !== null) {
|
|
54
|
+
endpoints.push({
|
|
55
|
+
method: m[1].toUpperCase(),
|
|
56
|
+
path: routerPrefix + m[2],
|
|
57
|
+
source: filePath,
|
|
58
|
+
line: lineOfIndex(content, m.index),
|
|
59
|
+
})
|
|
72
60
|
}
|
|
73
61
|
|
|
74
62
|
return endpoints
|
|
@@ -94,16 +82,18 @@ export function extractExpressEndpoints(filePath) {
|
|
|
94
82
|
if (useMatch) routerPrefix = useMatch[1]
|
|
95
83
|
}
|
|
96
84
|
|
|
85
|
+
// 路由全文匹配(坑 endpoint-multiline-decorator-miss:`router.get(\n "/path",\n handler)` 同病)
|
|
86
|
+
const routeRe = /\b(?:app|router)\.(get|post|put|delete|patch)\s*\(\s*["'`]([^"'`]+)["'`]/gi
|
|
87
|
+
let m
|
|
88
|
+
while ((m = routeRe.exec(content)) !== null) {
|
|
89
|
+
endpoints.push({ method: m[1].toUpperCase(), path: routerPrefix + m[2], source: filePath, line: lineOfIndex(content, m.index) })
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 链式 .route(path).get(h).put(h) —— 同行所有 method 配上 path(跨行链式不扩面,维持逐行)
|
|
97
93
|
for (let i = 0; i < lines.length; i++) {
|
|
98
94
|
const line = lines[i]
|
|
99
|
-
const m = line.match(/\b(?:app|router)\.(get|post|put|delete|patch)\s*\(\s*["'`]([^"'`]+)["'`]/i)
|
|
100
|
-
if (m) {
|
|
101
|
-
endpoints.push({ method: m[1].toUpperCase(), path: routerPrefix + m[2], source: filePath, line: i + 1 })
|
|
102
|
-
continue
|
|
103
|
-
}
|
|
104
95
|
const routeChain = line.match(/\.route\s*\(\s*["'`]([^"'`]+)["'`]/)
|
|
105
96
|
if (routeChain) {
|
|
106
|
-
// 链式 .route(path).get(h).put(h) —— 同行所有 method 配上 path
|
|
107
97
|
const chainPath = routerPrefix + routeChain[1]
|
|
108
98
|
for (const mm of line.matchAll(/\.(get|post|put|delete|patch)\s*\(/gi)) {
|
|
109
99
|
endpoints.push({ method: mm[1].toUpperCase(), path: chainPath, source: filePath, line: i + 1 })
|
|
@@ -135,17 +125,16 @@ export function extractSpringEndpoints(filePath) {
|
|
|
135
125
|
|
|
136
126
|
const methodMap = { get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH' }
|
|
137
127
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
128
|
+
// 短形式全文匹配(坑 endpoint-multiline-decorator-miss:`@GetMapping(\n "/path"\n)` 同病)
|
|
129
|
+
const shortRe = /@(Get|Post|Put|Delete|Patch)Mapping\s*\(\s*(?:value\s*=\s*)?["'`]([^"'`]+)["'`]/gi
|
|
130
|
+
let m
|
|
131
|
+
while ((m = shortRe.exec(content)) !== null) {
|
|
132
|
+
endpoints.push({ method: methodMap[m[1].toLowerCase()], path: classPrefix + m[2], source: filePath, line: lineOfIndex(content, m.index) })
|
|
133
|
+
}
|
|
134
|
+
// 旧形式全文匹配([^)]*? 字符类可跨行,`@RequestMapping(\n value="/p",\n method=…)` 随全文化一并覆盖)
|
|
135
|
+
const oldRe = /@RequestMapping\s*\(\s*(?:value\s*=\s*)?["'`]([^"'`]+)["'`][^)]*?method\s*=\s*RequestMethod\.(\w+)/gi
|
|
136
|
+
while ((m = oldRe.exec(content)) !== null) {
|
|
137
|
+
endpoints.push({ method: m[2].toUpperCase(), path: classPrefix + m[1], source: filePath, line: lineOfIndex(content, m.index) })
|
|
149
138
|
}
|
|
150
139
|
|
|
151
140
|
return endpoints
|