@deepstorm/cli 0.11.0 → 0.11.1

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 (123) hide show
  1. package/README.md +8 -8
  2. package/dist/build-registry.js +11 -5
  3. package/dist/cli.js +839 -585
  4. package/dist/mcp/code-hosting/github.json +14 -1
  5. package/dist/mcp/docs-reference/context7.json +1 -10
  6. package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-read/SKILL.md +8 -5
  7. package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-write/SKILL.md +10 -8
  8. package/dist/mcp-skills/deepstorm-mcp-figma-read/SKILL.md +21 -20
  9. package/dist/mcp-skills/deepstorm-mcp-github-read/SKILL.md +17 -17
  10. package/dist/mcp-skills/deepstorm-mcp-github-write/SKILL.md +20 -20
  11. package/dist/mcp-skills/deepstorm-mcp-jira-read/SKILL.md +8 -8
  12. package/dist/mcp-skills/deepstorm-mcp-jira-write/SKILL.md +13 -12
  13. package/dist/mcp-skills/deepstorm-mcp-playwright-read/SKILL.md +10 -10
  14. package/dist/skills/atoll-ops/SKILL.md +4 -0
  15. package/dist/skills/reef-commit/SKILL.md +9 -5
  16. package/dist/skills/reef-commit/scripts/branch-check.mjs +5 -11
  17. package/dist/skills/reef-commit/scripts/check-openspec-status.mjs +6 -12
  18. package/dist/skills/reef-commit/scripts/collect-git-context.mjs +13 -11
  19. package/dist/skills/reef-gen-backend/variants/java/steps.md +7 -7
  20. package/dist/skills/reef-gen-backend/variants/nodejs/steps.md +7 -7
  21. package/dist/skills/reef-gen-backend/variants/python/steps.md +7 -7
  22. package/dist/skills/reef-gen-frontend/variants/angular/steps.md +5 -5
  23. package/dist/skills/reef-gen-frontend/variants/react/steps.md +6 -6
  24. package/dist/skills/reef-gen-frontend/variants/vue/steps.md +6 -6
  25. package/dist/skills/reef-harden/EXAMPLES.md +12 -10
  26. package/dist/skills/reef-harden/SKILL.md +6 -0
  27. package/dist/skills/reef-harden/scripts/find-change-dir.mjs +13 -13
  28. package/dist/skills/reef-pr/SKILL.md +7 -0
  29. package/dist/skills/reef-pr/scripts/create-pr.mjs +31 -29
  30. package/dist/skills/reef-scope/SKILL.md +6 -6
  31. package/dist/skills/reef-start/references/jira-start-subagent.md +7 -7
  32. package/dist/skills/reef-start/references/risk-routing-card.md +28 -25
  33. package/dist/skills/reef-start/references/stage-4-implementation.md +33 -21
  34. package/dist/skills/reef-start/references/superpowers-gate.md +9 -9
  35. package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/structured-output.md +2 -2
  36. package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/quick-reference.md +11 -0
  37. package/dist/skills/reef-style-backend/fragments/java/api-spec/jackson-polymorphism.md +36 -40
  38. package/dist/skills/reef-style-backend/fragments/java/api-spec/quick-reference.md +11 -10
  39. package/dist/skills/reef-style-backend/fragments/java/db-migration/liquibase/examples/database-migration.md +7 -7
  40. package/dist/skills/reef-style-backend/fragments/java/dependency-management/quick-reference.md +24 -21
  41. package/dist/skills/reef-style-backend/fragments/java/exception-handling/examples/error-code-enum.md +7 -7
  42. package/dist/skills/reef-style-backend/fragments/java/exception-handling/quick-reference.md +10 -8
  43. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/dto-mapper.md +2 -2
  44. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/service-entity.md +5 -5
  45. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/testing.md +1 -0
  46. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/quick-reference.md +12 -12
  47. package/dist/skills/reef-style-backend/fragments/java/orm/hibernate/quick-reference.md +13 -12
  48. package/dist/skills/reef-style-backend/fragments/java/security-redlines/quick-reference.md +11 -9
  49. package/dist/skills/reef-style-backend/fragments/java/test/data-jpa-test/quick-reference.md +7 -7
  50. package/dist/skills/reef-style-backend/fragments/java/test/junit5/quick-reference.md +6 -6
  51. package/dist/skills/reef-style-backend/fragments/java/test/spring-mvc-test/quick-reference.md +8 -8
  52. package/dist/skills/reef-style-backend/fragments/java/test/spring-service-test/quick-reference.md +8 -7
  53. package/dist/skills/reef-style-backend/fragments/nodejs/eslint-config.json +1 -4
  54. package/dist/skills/reef-style-backend/fragments/nodejs/nestjs-structure.md +9 -9
  55. package/dist/skills/reef-style-backend/fragments/python/alembic-migration/quick-reference.md +2 -1
  56. package/dist/skills/reef-style-backend/fragments/python/api-spec/quick-reference.md +10 -10
  57. package/dist/skills/reef-style-backend/fragments/python/dependency-management/quick-reference.md +24 -22
  58. package/dist/skills/reef-style-backend/fragments/python/exception-handling/quick-reference.md +10 -9
  59. package/dist/skills/reef-style-backend/fragments/python/fastapi-quick-reference/quick-reference.md +3 -0
  60. package/dist/skills/reef-style-backend/fragments/python/langchain/quick-reference.md +10 -7
  61. package/dist/skills/reef-style-backend/fragments/python/pytest-testing/quick-reference.md +2 -0
  62. package/dist/skills/reef-style-backend/fragments/python/ruff-mypy-toolchain/quick-reference.md +2 -0
  63. package/dist/skills/reef-style-backend/fragments/python/security-redlines/quick-reference.md +11 -9
  64. package/dist/skills/reef-style-backend/fragments/python/sqlalchemy-orm/quick-reference.md +3 -0
  65. package/dist/skills/reef-style-backend/variants/java/examples/code-wrapping.md +3 -4
  66. package/dist/skills/reef-style-backend/variants/java/quick-reference.md +31 -29
  67. package/dist/skills/reef-style-backend/variants/nodejs/examples/module-example.md +2 -8
  68. package/dist/skills/reef-style-backend/variants/nodejs/quick-reference.md +35 -36
  69. package/dist/skills/reef-style-backend/variants/python/quick-reference.md +32 -31
  70. package/dist/skills/reef-style-frontend/fragments/css/tailwind/quick-reference.md +9 -7
  71. package/dist/skills/reef-style-frontend/fragments/test/vitest/examples/testing.md +9 -4
  72. package/dist/skills/reef-style-frontend/fragments/test/vitest/quick-reference.md +4 -4
  73. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/examples/testing.md +135 -140
  74. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/quick-reference.md +32 -32
  75. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/examples/testing.md +161 -162
  76. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/quick-reference.md +42 -42
  77. package/dist/skills/reef-style-frontend/fragments/ts-config/strict/quick-reference.md +16 -10
  78. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/examples/ui-components.md +72 -87
  79. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/quick-reference.md +14 -10
  80. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/examples/ui-components.md +93 -111
  81. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/quick-reference.md +29 -33
  82. package/dist/skills/reef-style-frontend/fragments/ui-lib/primeng/examples/ui-components.md +14 -23
  83. package/dist/skills/reef-style-frontend/variants/angular/examples/code-wrapping.md +15 -17
  84. package/dist/skills/reef-style-frontend/variants/angular/examples/component-types-pipes.md +22 -5
  85. package/dist/skills/reef-style-frontend/variants/angular/examples/entity-types.md +52 -22
  86. package/dist/skills/reef-style-frontend/variants/angular/examples/forms-layer.md +17 -20
  87. package/dist/skills/reef-style-frontend/variants/angular/examples/service-routing.md +8 -11
  88. package/dist/skills/reef-style-frontend/variants/angular/quick-reference.md +27 -27
  89. package/dist/skills/reef-style-frontend/variants/react/examples/code-wrapping.md +14 -27
  90. package/dist/skills/reef-style-frontend/variants/react/examples/component-types-pipes.md +45 -52
  91. package/dist/skills/reef-style-frontend/variants/react/examples/entity-types.md +44 -44
  92. package/dist/skills/reef-style-frontend/variants/react/examples/forms-layer.md +56 -85
  93. package/dist/skills/reef-style-frontend/variants/react/examples/service-routing.md +114 -88
  94. package/dist/skills/reef-style-frontend/variants/react/quick-reference.md +48 -42
  95. package/dist/skills/reef-style-frontend/variants/vue/examples/code-wrapping.md +24 -43
  96. package/dist/skills/reef-style-frontend/variants/vue/examples/component-types-pipes.md +48 -49
  97. package/dist/skills/reef-style-frontend/variants/vue/examples/entity-types.md +45 -45
  98. package/dist/skills/reef-style-frontend/variants/vue/examples/forms-layer.md +64 -68
  99. package/dist/skills/reef-style-frontend/variants/vue/examples/service-routing.md +85 -84
  100. package/dist/skills/reef-style-frontend/variants/vue/quick-reference.md +46 -51
  101. package/dist/skills/reef-testcase/SKILL.md +19 -19
  102. package/dist/skills/reef-testcase/references/coverage-dimensions.md +8 -0
  103. package/dist/skills/reef-testcase/references/test-case-template.md +16 -16
  104. package/dist/skills/sweep-explore/SKILL.md +129 -100
  105. package/dist/skills/sweep-explore/references/explore-flow-template.md +9 -9
  106. package/dist/skills/sweep-init/SKILL.md +4 -0
  107. package/dist/skills/sweep-init/scripts/flow-selector.mjs +6 -11
  108. package/dist/skills/sweep-init/scripts/init-project.mjs +68 -51
  109. package/dist/skills/sweep-plan/references/test-flow-template.md +12 -6
  110. package/dist/skills/sweep-record/SKILL.md +38 -15
  111. package/dist/skills/sweep-run/SKILL.md +59 -50
  112. package/dist/skills/sweep-run/scripts/env-manager.mjs +4 -5
  113. package/dist/skills/sweep-run/scripts/flow-parser.mjs +7 -6
  114. package/dist/skills/sweep-run/scripts/flow-selector.mjs +4 -15
  115. package/dist/skills/sweep-run/scripts/generate-report.mjs +1 -2
  116. package/dist/skills/sweep-run/scripts/mcp-manager.mjs +107 -14
  117. package/dist/skills/sweep-run/scripts/spec-compiler.mjs +19 -9
  118. package/dist/skills/tide-discuss/references/checklists.md +32 -32
  119. package/dist/skills/tide-discuss/references/data-format.md +85 -77
  120. package/dist/skills/tide-discuss/references/prd-template.md +21 -19
  121. package/dist/skills/tide-discuss/references/publish-flow.md +30 -11
  122. package/dist/skills/tide-discuss/references/role-prompts.md +5 -5
  123. package/package.json +4 -3
@@ -30,68 +30,88 @@ function writePackageJson(targetDir, framework) {
30
30
  scripts.test = 'playwright test';
31
31
  }
32
32
 
33
- writeFileSync(join(targetDir, 'package.json'), JSON.stringify({
34
- name: 'sweep-e2e',
35
- version: '1.0.0',
36
- private: true,
37
- type: 'module',
38
- scripts,
39
- devDependencies: deps,
40
- }, null, 2) + '\n');
33
+ writeFileSync(
34
+ join(targetDir, 'package.json'),
35
+ JSON.stringify(
36
+ {
37
+ name: 'sweep-e2e',
38
+ version: '1.0.0',
39
+ private: true,
40
+ type: 'module',
41
+ scripts,
42
+ devDependencies: deps,
43
+ },
44
+ null,
45
+ 2,
46
+ ) + '\n',
47
+ );
41
48
  }
42
49
 
43
50
  function writePlaywrightConfig(targetDir) {
44
- writeFileSync(join(targetDir, 'playwright.config.ts'), [
45
- "import { defineConfig } from '@playwright/test';",
46
- '',
47
- 'export default defineConfig({',
48
- ' use: {',
49
- " baseURL: process.env.BASE_URL || 'http://localhost:3000',",
50
- ' },',
51
- ' timeout: 30000,',
52
- ' retries: 0,',
53
- " reporter: [['line'], ['html', { outputFolder: 'flows/reports' }]],",
54
- ' projects: [',
55
- " { name: 'chromium', use: { browserName: 'chromium' } },",
56
- ' ],',
57
- '});',
58
- '',
59
- ].join('\n'));
51
+ writeFileSync(
52
+ join(targetDir, 'playwright.config.ts'),
53
+ [
54
+ "import { defineConfig } from '@playwright/test';",
55
+ '',
56
+ 'export default defineConfig({',
57
+ ' use: {',
58
+ " baseURL: process.env.BASE_URL || 'http://localhost:3000',",
59
+ ' },',
60
+ ' timeout: 30000,',
61
+ ' retries: 0,',
62
+ " reporter: [['line'], ['html', { outputFolder: 'flows/reports' }]],",
63
+ ' projects: [',
64
+ " { name: 'chromium', use: { browserName: 'chromium' } },",
65
+ ' ],',
66
+ '});',
67
+ '',
68
+ ].join('\n'),
69
+ );
60
70
  }
61
71
 
62
72
  function writeTsconfig(targetDir) {
63
- writeFileSync(join(targetDir, 'tsconfig.json'), JSON.stringify({
64
- compilerOptions: {
65
- target: 'ES2022',
66
- module: 'ESNext',
67
- moduleResolution: 'bundler',
68
- strict: true,
69
- esModuleInterop: true,
70
- },
71
- }, null, 2) + '\n');
73
+ writeFileSync(
74
+ join(targetDir, 'tsconfig.json'),
75
+ JSON.stringify(
76
+ {
77
+ compilerOptions: {
78
+ target: 'ES2022',
79
+ module: 'ESNext',
80
+ moduleResolution: 'bundler',
81
+ strict: true,
82
+ esModuleInterop: true,
83
+ },
84
+ },
85
+ null,
86
+ 2,
87
+ ) + '\n',
88
+ );
72
89
  }
73
90
 
74
91
  function writeTopologyYaml(targetDir) {
75
- writeFileSync(join(targetDir, 'flows', 'topology.yaml'), [
76
- '# flows/topology.yaml',
77
- 'name: E2E 测试拓扑',
78
- 'version: 1',
79
- 'modules:',
80
- ' - name: example',
81
- ' description: 示例模块',
82
- ' children:',
83
- ' - name: feature1',
84
- ' description: 功能 1',
85
- ' features: []',
86
- '',
87
- ].join('\n'));
92
+ writeFileSync(
93
+ join(targetDir, 'flows', 'topology.yaml'),
94
+ [
95
+ '# flows/topology.yaml',
96
+ 'name: E2E 测试拓扑',
97
+ 'version: 1',
98
+ 'modules:',
99
+ ' - name: example',
100
+ ' description: 示例模块',
101
+ ' children:',
102
+ ' - name: feature1',
103
+ ' description: 功能 1',
104
+ ' features: []',
105
+ '',
106
+ ].join('\n'),
107
+ );
88
108
  }
89
109
 
90
110
  // ── Main ──────────────────────────────────────────────────────────
91
111
 
92
112
  export function initProject(opts = {}) {
93
113
  const {
94
- framework = null, // 'playwright' | null
114
+ framework = null, // 'playwright' | null
95
115
  dir = '.',
96
116
  } = opts;
97
117
 
@@ -128,10 +148,7 @@ export function initProject(opts = {}) {
128
148
  // npm install 失败不阻塞
129
149
  }
130
150
 
131
- const created = [
132
- 'flows/', 'flows/reports/', 'scripts/',
133
- 'package.json', 'tsconfig.json',
134
- ];
151
+ const created = ['flows/', 'flows/reports/', 'scripts/', 'package.json', 'tsconfig.json'];
135
152
  if (framework === 'playwright') created.push('playwright.config.ts');
136
153
  if (!existsSync(join(flowsDir, 'topology.yaml'))) {
137
154
  created.push('flows/topology.yaml');
@@ -7,27 +7,30 @@
7
7
 
8
8
  ## 场景清单
9
9
 
10
- | ID | 场景 | 类型 | 优先级 |
11
- |----|------|------|--------|
12
- | L01 | {场景标题} | 正常流程 | P0 |
13
- | L02 | {场景标题} | 边界条件 | P1 |
14
- | L03 | {场景标题} | 异常场景 | P1 |
15
- | L04 | {场景标题} | 验收标准验证 | P0 |
10
+ | ID | 场景 | 类型 | 优先级 |
11
+ | --- | ---------- | ------------ | ------ |
12
+ | L01 | {场景标题} | 正常流程 | P0 |
13
+ | L02 | {场景标题} | 边界条件 | P1 |
14
+ | L03 | {场景标题} | 异常场景 | P1 |
15
+ | L04 | {场景标题} | 验收标准验证 | P0 |
16
16
 
17
17
  ---
18
18
 
19
19
  ## Flow: L01 - {场景标题}
20
20
 
21
21
  ### 前置条件
22
+
22
23
  {描述测试开始前必须满足的状态或数据}
23
24
 
24
25
  ### 执行步骤
26
+
25
27
  1. {操作步骤 1}
26
28
  ✅ 验证点:{预期结果 1}
27
29
  2. {操作步骤 2}
28
30
  ✅ 验证点:{预期结果 2}
29
31
 
30
32
  ### 环境要求
33
+
31
34
  - 目标环境:{test / staging / prod}
32
35
  - 所需账号:{账号类型或角色}
33
36
 
@@ -36,11 +39,14 @@
36
39
  ## Flow: L02 - {场景标题}
37
40
 
38
41
  ### 前置条件
42
+
39
43
  {描述测试开始前必须满足的状态或数据}
40
44
 
41
45
  ### 执行步骤
46
+
42
47
  1. {操作步骤 1}
43
48
  ✅ 验证点:{预期结果 1}
44
49
 
45
50
  ### 环境要求
51
+
46
52
  - 目标环境:{test / staging / prod}
@@ -13,22 +13,24 @@ deepstorm:
13
13
  ## 适用场景
14
14
 
15
15
  **何时使用:**
16
+
16
17
  - 已有录制好的 `.recording.json` 文件(通过 `deepstorm record start -u <url>` 录制)
17
18
  - 想将真人操作转化为可重复执行的 E2E 测试
18
19
  - 项目无前端源码或源码结构不标准,无法使用 `/sweep-explore`
19
20
  - 测试工程师能手动操作界面但不熟悉代码编写
20
21
 
21
22
  **何时不使用:**
23
+
22
24
  - 没有进行浏览器操作录制
23
25
  - 需要从源码分析生成测试 → 请使用 `/sweep-explore`
24
26
  - 已有现成需求文档 → 请使用 `/sweep-plan`
25
27
 
26
28
  ## 使用方式
27
29
 
28
- | 方式 | 说明 |
29
- |------|------|
30
+ | 方式 | 说明 |
31
+ | ------------ | -------------------------------------------------------------------- |
30
32
  | **交互选择** | `/sweep-record` → 列出所有未处理的 `.recording.json`,选择后进入分析 |
31
- | **直接指定** | `/sweep-record <name>` → 匹配对应名称的录制文件,跳过选择直接分析 |
33
+ | **直接指定** | `/sweep-record <name>` → 匹配对应名称的录制文件,跳过选择直接分析 |
32
34
 
33
35
  ---
34
36
 
@@ -75,6 +77,7 @@ ls -lt .deepstorm/recordings/*.recording.json 2>/dev/null
75
77
  ```
76
78
 
77
79
  **判断规则:**
80
+
78
81
  - 已处理:对应名称的 `.flow.md` 已存在于 `test-flows/` 中
79
82
  - 未处理:无同名 `.flow.md`
80
83
  - 标题展示:优先显示文件名;文件名无语义时显示 `?untitled`
@@ -82,6 +85,7 @@ ls -lt .deepstorm/recordings/*.recording.json 2>/dev/null
82
85
  ### 1.3 直接指定
83
86
 
84
87
  `/sweep-record <name>` 时:
88
+
85
89
  - 在 `.deepstorm/recordings/` 中匹配文件名包含 `<name>` 的 `.recording.json`
86
90
  - 唯一匹配 → 直接进入分析
87
91
  - 多匹配 → 展示匹配列表让用户选择
@@ -106,6 +110,7 @@ ls -lt .deepstorm/recordings/*.recording.json 2>/dev/null
106
110
  使用 AI 对原始事件执行:
107
111
 
108
112
  **去重规则:**
113
+
109
114
  - 同一元素 <500ms 内的多次 click → 合并为一次
110
115
  - focus + input + blur → 聚合为一个 input 步骤(保留最终值)
111
116
  - 连续 mousemove/scroll 事件已在 CLI 阶段过滤,此处检查残留
@@ -117,18 +122,19 @@ ls -lt .deepstorm/recordings/*.recording.json 2>/dev/null
117
122
  ```markdown
118
123
  将以下原始事件序列:
119
124
 
120
- click on <input#username> → input value="admin" → click on <input#password> →
121
- input value="****" → click on <button#login> → navigation to /dashboard
125
+ click on <input#username> → input value="admin" → click on <input#password> →
126
+ input value="****" → click on <button#login> → navigation to /dashboard
122
127
 
123
128
  分组为语义步骤:
124
129
 
125
- 1. 填写用户名(admin)
126
- 2. 填写密码
127
- 3. 点击"登录"按钮
128
- 4. 验证跳转到仪表盘页面
130
+ 1. 填写用户名(admin)
131
+ 2. 填写密码
132
+ 3. 点击"登录"按钮
133
+ 4. 验证跳转到仪表盘页面
129
134
  ```
130
135
 
131
136
  **分组策略:**
137
+
132
138
  - 连续输入在同一区域 → 合并为"填写 {表单名}"分组
133
139
  - click + input + blur → 合并为"填写 {字段名} 为 {值}"
134
140
  - 下拉选择 → "选择 {选项名}"
@@ -140,21 +146,25 @@ ls -lt .deepstorm/recordings/*.recording.json 2>/dev/null
140
146
  基于以下数据源自动推断断言:
141
147
 
142
148
  **网络响应断言(优先级高):**
149
+
143
150
  - 从 `type: "network"` 事件中提取 URL 和 statusCode
144
151
  - statusCode 200 → ✅ 验证点:接口 {path} 返回状态码 200
145
152
  - statusCode 4xx/5xx → ✅ 验证点:接口 {path} 返回 {code}(错误提示:{摘要})
146
153
  - 响应体摘要有错误信息 → 追加验证点
147
154
 
148
155
  **页面导航断言:**
156
+
149
157
  - 从 `type: "navigation"` 事件提取目标 URL
150
158
  - 完整导航 → ✅ 验证点:页面 URL 跳转到 {url}
151
159
  - SPA 路由变化 → ✅ 验证点:URL 变为 {path}
152
160
 
153
161
  **页面标题/内容断言:**
162
+
154
163
  - 导航后标题变化 → ✅ 验证点:页面标题变为 {新标题}
155
164
  - 如有截图且 AI 可见差异 → ✅ 验证点:{元素名} 可见(视觉确认)
156
165
 
157
166
  **截图辅助分析:**
167
+
158
168
  - 每张截图附带在事件序列中的时间戳
159
169
  - AI 比较操作前后的截图,发现页面变化
160
170
  - 截图内容用于补充断言(如弹窗出现、状态文字变化)
@@ -162,6 +172,7 @@ ls -lt .deepstorm/recordings/*.recording.json 2>/dev/null
162
172
  ### 2.4 流程自动命名
163
173
 
164
174
  **命名策略:**
175
+
165
176
  1. 综合页面标题序列、URL 路径、操作语义 → 推断业务名称
166
177
  2. 使用英文 kebab-case,3-5 个词
167
178
  3. 反映核心操作目的(如 `user-login`、`create-order`、`approve-workflow`)
@@ -179,6 +190,7 @@ URL 路径序列:/ → /login → /users
179
190
  ```
180
191
 
181
192
  **置信度:**
193
+
182
194
  - 页面标题和 URL 包含业务关键词 → 高置信度
183
195
  - 仅能从操作推断 → 中等置信度,名称加 `?` 前缀标记
184
196
  - 完全无法推断 → 推荐 `?untitled-flow`,提示用户手动命名
@@ -220,8 +232,8 @@ URL 路径序列:/ → /login → /users
220
232
 
221
233
  ## 场景清单
222
234
 
223
- | ID | 场景 | 来源 |
224
- |----|------|------|
235
+ | ID | 场景 | 来源 |
236
+ | --- | ---------------- | -------- |
225
237
  | L01 | {操作序列主流程} | 录制分析 |
226
238
 
227
239
  ---
@@ -229,23 +241,28 @@ URL 路径序列:/ → /login → /users
229
241
  ## Flow: L01 - {主流程}
230
242
 
231
243
  ### 前置条件
244
+
232
245
  - 打开目标页面 {url}
233
246
 
234
247
  ### 执行步骤
248
+
235
249
  1. {操作描述(中文)}
236
250
  ✅ 验证点:{预期结果}
237
251
 
238
252
  ### 环境要求
253
+
239
254
  - 目标环境:{从录制 URL 推断,如 test/staging/prod}
240
255
  ```
241
256
 
242
257
  **注意事项:**
258
+
243
259
  - 精确的 Playwright locator 信息不出现在 `.flow.md` 中(保持可读性)
244
260
  - 每个语义分组对应一个 `Flow: L{N} - {标题}` 章节
245
261
  - 文件头部标记来源为 `sweep-record`
246
262
  - 步骤数量超过 15 时考虑拆分为多个 Flow
247
263
 
248
264
  **多流程拆分:**
265
+
249
266
  - 录制包含多个独立语义流程 → 拆分为多个 `Flow:` 章节,共用同一 `.flow.md`
250
267
  - 录制包含完全无关的两组操作 → AI 建议生成多个 `.flow.md` 文件并请求用户确认
251
268
 
@@ -254,6 +271,7 @@ URL 路径序列:/ → /login → /users
254
271
  基于录制数据中的精确 locator 直接生成 Playwright 测试脚本:
255
272
 
256
273
  **生成策略:**
274
+
257
275
  - 使用录制数据中的精确 locator(`getByRole`、`getByText`、`getByPlaceholder`、`getByTestId`、CSS 选择器),优先级同设计文档 D2
258
276
  - 每个步骤前添加中文注释说明操作意图
259
277
  - 操作后添加对应的 `expect()` 断言(从 Step 2.3 推断)
@@ -261,6 +279,7 @@ URL 路径序列:/ → /login → /users
261
279
  - `.spec.ts` 的 `test.describe` 名称 = flow-name
262
280
 
263
281
  **文件命名:**
282
+
264
283
  - `.flow.md` → `test-flows/{flow-name}.flow.md`
265
284
  - `.spec.ts` → `test-flows/{flow-name}.spec.ts`
266
285
 
@@ -281,6 +300,7 @@ URL 路径序列:/ → /login → /users
281
300
  ### 3.4 异常处理
282
301
 
283
302
  **录制为空或无有效事件:**
303
+
284
304
  - 有效事件数 = 0 → 提示"录制文件中无有效事件,无法生成测试",建议重新录制
285
305
  - 有效事件数 < 2 → 提示"录制事件不足,可能无法生成有意义的测试脚本",但仍尝试生成,附带低质量警告
286
306
 
@@ -296,6 +316,7 @@ cat .deepstorm/recordings/{file}.recording.json | python3 -m json.tool > /dev/nu
296
316
  ```
297
317
 
298
318
  若 JSON 解析失败:
319
+
299
320
  - 提示"录制文件可能已损坏"并显示解析错误位置
300
321
  - 建议用户重新录制
301
322
  - 如文件部分可读,尝试提取有效事件片段
@@ -303,6 +324,7 @@ cat .deepstorm/recordings/{file}.recording.json | python3 -m json.tool > /dev/nu
303
324
  ### 4.2 分析失败
304
325
 
305
326
  当 AI 无法合理分组或推断时:
327
+
306
328
  - 输出原始事件序列的直观展示
307
329
  - 提示"AI 无法有效分析该录制内容"
308
330
  - 可能原因:录制内容过于复杂、浏览器崩溃导致数据不完整、页面涉及需要交互的 iframe
@@ -311,6 +333,7 @@ cat .deepstorm/recordings/{file}.recording.json | python3 -m json.tool > /dev/nu
311
333
  ### 4.3 无截图时的断言策略
312
334
 
313
335
  如果录制过程中截图失败或不存在:
336
+
314
337
  - 降级为纯网络响应和导航状态推断断言
315
338
  - 标记缺少截图的步骤为"无截图确认"(降低断言可信度)
316
339
  - 提示用户"部分操作缺少截图,建议补录以获得更好的断言覆盖"
@@ -321,10 +344,10 @@ cat .deepstorm/recordings/{file}.recording.json | python3 -m json.tool > /dev/nu
321
344
 
322
345
  ### 命令速查
323
346
 
324
- | 命令 | 说明 |
325
- |------|------|
326
- | `/sweep-record` | 交互选择录制文件并进入分析 |
327
- | `/sweep-record <name>` | 直接指定录制文件名称 |
347
+ | 命令 | 说明 |
348
+ | ---------------------- | -------------------------- |
349
+ | `/sweep-record` | 交互选择录制文件并进入分析 |
350
+ | `/sweep-record <name>` | 直接指定录制文件名称 |
328
351
 
329
352
  ### 产出物
330
353
 
@@ -28,12 +28,12 @@ deepstorm:
28
28
 
29
29
  ### 执行模式说明
30
30
 
31
- | 模式 | 参数 | MCP 模式 | 说明 | 加速比 |
32
- |------|------|---------|------|--------|
31
+ | 模式 | 参数 | MCP 模式 | 说明 | 加速比 |
32
+ | -------------------- | ----------------- | -------- | -------------------------------------------------------------------------------- | ------- |
33
33
  | **混合执行(默认)** | (无)或 `--fast` | headless | 预编译 `.flow.spec.ts` → 原生 Playwright 执行(`--reporter=line`);失败 AI 自愈 | ~10-20x |
34
- | 纯原生(不自愈) | `--native` | 不启动 | 只用原生 Playwright 执行,失败不自愈 | ~20x |
35
- | 批量(单线程) | `--no-parallel` | headless | 原生执行 + 单线程顺序运行 | ~10x |
36
- | 浏览器调试 | `--browser` | headed | AI 逐步骤 MCP 调用 + 浏览器窗口可见 | 1x |
34
+ | 纯原生(不自愈) | `--native` | 不启动 | 只用原生 Playwright 执行,失败不自愈 | ~20x |
35
+ | 批量(单线程) | `--no-parallel` | headless | 原生执行 + 单线程顺序运行 | ~10x |
36
+ | 浏览器调试 | `--browser` | headed | AI 逐步骤 MCP 调用 + 浏览器窗口可见 | 1x |
37
37
 
38
38
  ---
39
39
 
@@ -48,7 +48,7 @@ node scripts/env-manager.mjs --framework
48
48
  ```
49
49
 
50
50
  ```json
51
- {"framework":"playwright","source":"deepstorm-settings"}
51
+ { "framework": "playwright", "source": "deepstorm-settings" }
52
52
  ```
53
53
 
54
54
  - **playwright** → 通过 Playwright MCP(`deepstorm-playwright`)执行浏览器操作
@@ -98,9 +98,9 @@ node scripts/env-manager.mjs --project-root
98
98
  ```markdown
99
99
  📋 可用测试模块:
100
100
 
101
- 1. user-system/register(3 个用例:L01-L03)
102
- 2. user-system/login(2 个用例:L01-L02)
103
- 3. tasks/crud(4 个用例:T01-T04)
101
+ 1. user-system/register(3 个用例:L01-L03)
102
+ 2. user-system/login(2 个用例:L01-L02)
103
+ 3. tasks/crud(4 个用例:T01-T04)
104
104
 
105
105
  请选择:全部执行 / 输入序号(如 1,3) / 输入模块名
106
106
  ```
@@ -124,19 +124,20 @@ node scripts/env-manager.mjs --project-root
124
124
 
125
125
  #### 2.2 直接参数模式
126
126
 
127
- | 参数 | 行为 | 示例 |
128
- |------|------|------|
129
- | `--all` | 执行 flows/ 下所有 .flow.md | `/sweep-run --all` |
130
- | `--path {module}` | 执行指定模块路径下的所有 .flow | `/sweep-run --path user-system/login` |
131
- | `{file-path}` | 执行指定文件 | `/sweep-run flows/login.flow.md` |
132
- | `{file-path} --flow {ID}` | 只执行文件中的某个 Flow | `/sweep-run login.flow.md --flow L02` |
133
- | `--env {env}` | 切换目标环境 | `/sweep-run --all --env staging` |
134
- | `--browser` | 打开浏览器窗口逐步骤调试 | `/sweep-run --all --browser` |
135
- | `--no-parallel` | 使用批量但不并行 | `/sweep-run --all --no-parallel` |
127
+ | 参数 | 行为 | 示例 |
128
+ | ------------------------- | ------------------------------ | ------------------------------------- |
129
+ | `--all` | 执行 flows/ 下所有 .flow.md | `/sweep-run --all` |
130
+ | `--path {module}` | 执行指定模块路径下的所有 .flow | `/sweep-run --path user-system/login` |
131
+ | `{file-path}` | 执行指定文件 | `/sweep-run flows/login.flow.md` |
132
+ | `{file-path} --flow {ID}` | 只执行文件中的某个 Flow | `/sweep-run login.flow.md --flow L02` |
133
+ | `--env {env}` | 切换目标环境 | `/sweep-run --all --env staging` |
134
+ | `--browser` | 打开浏览器窗口逐步骤调试 | `/sweep-run --all --browser` |
135
+ | `--no-parallel` | 使用批量但不并行 | `/sweep-run --all --no-parallel` |
136
136
 
137
137
  #### 2.3 文件不存在处理
138
138
 
139
139
  如指定的文件或 --path 不存在:
140
+
140
141
  - 提示"指定路径不存在"
141
142
  - 读取 topology.yaml 展示可用模块
142
143
  - 引导用户重新选择
@@ -165,6 +166,7 @@ Flows数组:
165
166
  ```
166
167
 
167
168
  提取每个 Flow 中的:
169
+
168
170
  - 前置条件(描述性文本,用于理解上下文)
169
171
  - 步骤列表(有序操作 + 验证点)
170
172
  - 环境要求(用于 --env 默认值)
@@ -184,10 +186,14 @@ node scripts/env-manager.mjs --env staging
184
186
  输出示例:
185
187
 
186
188
  ```json
187
- {"env":"staging","baseUrl":"https://staging.example.com","availableEnvs":[
188
- {"name":"test","key":"BASE_URL_TEST","url":"https://test.example.com"},
189
- {"name":"staging","key":"BASE_URL_STAGING","url":"https://staging.example.com"}
190
- ]}
189
+ {
190
+ "env": "staging",
191
+ "baseUrl": "https://staging.example.com",
192
+ "availableEnvs": [
193
+ { "name": "test", "key": "BASE_URL_TEST", "url": "https://test.example.com" },
194
+ { "name": "staging", "key": "BASE_URL_STAGING", "url": "https://staging.example.com" }
195
+ ]
196
+ }
191
197
  ```
192
198
 
193
199
  - `--env staging` → 从 `settings.json` 的 `sweep.environments.staging` 读取
@@ -201,6 +207,7 @@ export BASE_URL=$(node scripts/env-manager.mjs --env test --print 2>/dev/null |
201
207
  ```
202
208
 
203
209
  或从 JSON 结果提取:
210
+
204
211
  ```bash
205
212
  BASE_URL=$(node scripts/env-manager.mjs --env test | node -pe "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).baseUrl")
206
213
  ```
@@ -246,8 +253,9 @@ node scripts/mcp-manager.mjs --mode=skip
246
253
  ```
247
254
 
248
255
  输出 JSON:
256
+
249
257
  ```json
250
- {"action":"started","mode":"headless","pid":12345,"port":54321}
258
+ { "action": "started", "mode": "headless", "pid": 12345, "port": 54321 }
251
259
  ```
252
260
 
253
261
  `action` 取值:`started`(新启动)/ `already-ok`(已在正确模式)/ `switched`(切换后重启)/ `skipped`(跳过)。
@@ -333,13 +341,13 @@ flowchart LR
333
341
 
334
342
  **操作类型:**
335
343
 
336
- | 操作 | MCP 调用 | 验证方式 |
337
- |------|---------|---------|
338
- | 导航 | navigate/goto | 检查页面标题/URL |
339
- | 点击 | click | 检查预期元素/状态变化 |
340
- | 输入 | fill | 检查输入回显或后续页面状态 |
341
- | 选择 | select | 检查选项是否生效 |
342
- | 等待 | waitFor | 检查超时或条件满足 |
344
+ | 操作 | MCP 调用 | 验证方式 |
345
+ | ---- | ------------- | -------------------------- |
346
+ | 导航 | navigate/goto | 检查页面标题/URL |
347
+ | 点击 | click | 检查预期元素/状态变化 |
348
+ | 输入 | fill | 检查输入回显或后续页面状态 |
349
+ | 选择 | select | 检查选项是否生效 |
350
+ | 等待 | waitFor | 检查超时或条件满足 |
343
351
 
344
352
  **执行完成后:** 杀掉 headed 进程,以 `--headless` 重启恢复默认模式。
345
353
 
@@ -364,12 +372,12 @@ flowchart LR
364
372
 
365
373
  **判定与处理:**
366
374
 
367
- | 判定结果 | 操作 | 报告中标注 |
368
- |----------|------|-----------|
369
- | **元素选择器失效**(元素存在但 CSS class/data-testid 变化) | 更新定位器;添加 `// auto-repaired: {timestamp} - {old} -> {new}` 注释;**重跑**确认 | 自愈成功 |
370
- | **数据累积**(多次运行导致同名元素重复,`.first()`/`.last()` 选错目标) | 通过 `page.evaluate()` 调用 API 清理历史残留数据后重跑 | 自愈成功 |
371
- | **真 Bug**(元素不存在、页面行为不符合预期) | 不修改 spec 文件 | 确认 Bug |
372
- | **修复无效**(更新后重跑仍然失败) | 放弃修复 | 自愈放弃 |
375
+ | 判定结果 | 操作 | 报告中标注 |
376
+ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ---------- |
377
+ | **元素选择器失效**(元素存在但 CSS class/data-testid 变化) | 更新定位器;添加 `// auto-repaired: {timestamp} - {old} -> {new}` 注释;**重跑**确认 | 自愈成功 |
378
+ | **数据累积**(多次运行导致同名元素重复,`.first()`/`.last()` 选错目标) | 通过 `page.evaluate()` 调用 API 清理历史残留数据后重跑 | 自愈成功 |
379
+ | **真 Bug**(元素不存在、页面行为不符合预期) | 不修改 spec 文件 | 确认 Bug |
380
+ | **修复无效**(更新后重跑仍然失败) | 放弃修复 | 自愈放弃 |
373
381
 
374
382
  **循环保护:** 同一 Flow 最多重试 **3 次**,超限则停止并保留最后一次失败报告。
375
383
 
@@ -417,16 +425,17 @@ Flow: L01 - 正常登录成功
417
425
 
418
426
  ## Flow: L01 - 正常登录成功 X
419
427
 
420
- | 步骤 | 操作 | 验证 | 结果 |
421
- |------|------|------|------|
422
- | 1/4 | 打开登录页面 | 页面加载完成 | OK |
423
- | 2/4 | 输入邮箱 | 输入框显示 | OK |
424
- | 3/4 | 点击登录按钮 | URL 跳转 /dashboard | X |
425
- | 4/4 | (跳过) | - | > |
428
+ | 步骤 | 操作 | 验证 | 结果 |
429
+ | ---- | ------------ | ------------------- | ---- |
430
+ | 1/4 | 打开登录页面 | 页面加载完成 | OK |
431
+ | 2/4 | 输入邮箱 | 输入框显示 | OK |
432
+ | 3/4 | 点击登录按钮 | URL 跳转 /dashboard | X |
433
+ | 4/4 | (跳过) | - | > |
426
434
 
427
435
  ### 失败详情
428
436
 
429
437
  **步骤 3/4:** 点击登录按钮
438
+
430
439
  - 期望:URL 跳转到 /dashboard
431
440
  - 实际:URL 保持在 /login
432
441
  - 可能原因:登录失败或页面未正确响应
@@ -435,14 +444,14 @@ Flow: L01 - 正常登录成功
435
444
 
436
445
  ## 汇总
437
446
 
438
- | 项目 | 值 |
439
- |------|-----|
440
- | 总 Flow 数 | 1 |
441
- | 总步骤数 | 3 |
442
- | 通过 | 2 |
443
- | 失败 | 1 |
444
- | 跳过 | 1 |
445
- | 通过率 | 66% |
447
+ | 项目 | 值 |
448
+ | ---------- | --- |
449
+ | 总 Flow 数 | 1 |
450
+ | 总步骤数 | 3 |
451
+ | 通过 | 2 |
452
+ | 失败 | 1 |
453
+ | 跳过 | 1 |
454
+ | 通过率 | 66% |
446
455
  ```
447
456
 
448
457
  #### 8.3 报告文件名格式
@@ -107,8 +107,7 @@ export function parseDotEnv(content) {
107
107
  const key = trimmed.slice(0, sepIdx).trim();
108
108
  let value = trimmed.slice(sepIdx + 1).trim();
109
109
  // Strip surrounding quotes
110
- if ((value.startsWith('"') && value.endsWith('"')) ||
111
- (value.startsWith("'") && value.endsWith("'"))) {
110
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
112
111
  value = value.slice(1, -1);
113
112
  }
114
113
  env[key] = value;
@@ -306,7 +305,7 @@ if (process.argv[1] === import.meta.filename) {
306
305
  }
307
306
 
308
307
  if (args.includes('--check-mcp')) {
309
- const mcpName = args.find(a => a.startsWith('--mcp='))?.split('=')[1] || 'deepstorm-playwright';
308
+ const mcpName = args.find((a) => a.startsWith('--mcp='))?.split('=')[1] || 'deepstorm-playwright';
310
309
  const result = checkMcpAvailable(mcpName);
311
310
  console.log(JSON.stringify(result));
312
311
  process.exit(0);
@@ -333,7 +332,7 @@ if (process.argv[1] === import.meta.filename) {
333
332
  }
334
333
 
335
334
  // Default: resolve env
336
- const envFlag = args.find(a => a.startsWith('--env='));
335
+ const envFlag = args.find((a) => a.startsWith('--env='));
337
336
  const envName = envFlag ? envFlag.split('=')[1] : undefined;
338
337
  const result = resolveEnv(envName);
339
338
 
@@ -342,7 +341,7 @@ if (process.argv[1] === import.meta.filename) {
342
341
  console.log(`export BASE_URL=${result.baseUrl}`);
343
342
  } else {
344
343
  console.error(`# No base URL found for environment "${result.env}"`);
345
- console.error(`# Available: ${result.availableEnvs.map(e => e.name).join(', ')}`);
344
+ console.error(`# Available: ${result.availableEnvs.map((e) => e.name).join(', ')}`);
346
345
  process.exit(1);
347
346
  }
348
347
  } else {