@kkeve/suite 0.0.1 → 0.0.2

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 (152) hide show
  1. package/README.md +53 -0
  2. package/dist/bin/keve.d.ts +13 -0
  3. package/dist/bin/keve.js +164 -0
  4. package/dist/commands/auth-update.d.ts +16 -0
  5. package/dist/commands/auth-update.js +88 -0
  6. package/dist/commands/clean.d.ts +10 -0
  7. package/dist/commands/clean.js +78 -0
  8. package/dist/commands/config.d.ts +17 -0
  9. package/dist/commands/config.js +99 -0
  10. package/dist/commands/init.d.ts +15 -0
  11. package/dist/commands/init.js +292 -0
  12. package/dist/commands/report.d.ts +12 -0
  13. package/dist/commands/report.js +159 -0
  14. package/dist/commands/run.d.ts +29 -0
  15. package/dist/commands/run.js +417 -0
  16. package/dist/commands/test.d.ts +12 -0
  17. package/dist/commands/test.js +102 -0
  18. package/dist/commands/vitest.d.ts +14 -0
  19. package/dist/commands/vitest.js +166 -0
  20. package/dist/config.d.ts +109 -0
  21. package/dist/config.js +291 -0
  22. package/dist/core/action-log-writer.d.ts +47 -0
  23. package/dist/{tools/write-file.js → core/action-log-writer.js} +42 -26
  24. package/dist/core/auth.d.ts +17 -0
  25. package/dist/core/auth.js +224 -0
  26. package/dist/core/cdp-resolver.d.ts +5 -0
  27. package/dist/core/cdp-resolver.js +93 -0
  28. package/dist/core/generateReport/report.d.ts +19 -0
  29. package/dist/core/generateReport/report.js +91 -0
  30. package/dist/core/generateReport/reportData.d.ts +215 -0
  31. package/dist/core/generateReport/reportData.js +735 -0
  32. package/dist/core/global-setup.d.ts +6 -0
  33. package/dist/core/global-setup.js +113 -0
  34. package/dist/core/keve-aspect.d.ts +54 -0
  35. package/dist/core/keve-aspect.js +52 -0
  36. package/dist/core/keve-decorators.d.ts +51 -0
  37. package/dist/core/keve-decorators.js +95 -0
  38. package/dist/core/keve-registry.d.ts +38 -0
  39. package/dist/core/keve-registry.js +25 -0
  40. package/dist/core/keve-report.d.ts +27 -0
  41. package/dist/core/keve-report.js +357 -0
  42. package/dist/core/keve-test.d.ts +36 -0
  43. package/dist/core/keve-test.js +364 -0
  44. package/dist/core/learned-actions.d.ts +24 -0
  45. package/dist/core/learned-actions.js +65 -0
  46. package/dist/core/pw-config.d.ts +19 -0
  47. package/dist/core/pw-config.js +180 -0
  48. package/dist/index.d.ts +8 -23
  49. package/dist/index.js +36 -43
  50. package/dist/page-agent/agent.d.ts +129 -0
  51. package/dist/page-agent/agent.js +585 -0
  52. package/dist/page-agent/hooks.d.ts +13 -0
  53. package/dist/page-agent/hooks.js +218 -0
  54. package/dist/page-agent/tools.d.ts +29 -0
  55. package/dist/page-agent/tools.js +297 -0
  56. package/doc/README.md +124 -0
  57. package/doc/agents/keve-dev-test-agent.md +140 -0
  58. package/doc/agents/keve-test-agent.md +178 -0
  59. package/doc/asserts//346/265/213/350/257/225/345/220/204/351/230/266/346/256/265/350/257/264/346/230/216.png +0 -0
  60. package/doc/keve-agent-demo.html +370 -0
  61. package/doc/skills/keve-bddcase-gen/SKILL.md +332 -0
  62. package/doc/skills/keve-bddcase-gen/references/test-case-rules.md +91 -0
  63. package/doc/skills/keve-bddcase-gen/references/test-cases-example.md +103 -0
  64. package/doc/skills/keve-component-gen/SKILL.md +255 -0
  65. package/doc/skills/keve-component-gen/references/component-mock-strategy.md +74 -0
  66. package/doc/skills/keve-component-gen/references/component-model-template.md +98 -0
  67. package/doc/skills/keve-component-gen/references/component-test-template.md +100 -0
  68. package/doc/skills/keve-component-gen/references/vue-test-utils-guide.md +91 -0
  69. package/doc/skills/keve-e2e-gen/SKILL.md +179 -0
  70. package/doc/skills/keve-e2e-gen/references/code-analysis-guide.md +208 -0
  71. package/doc/skills/keve-e2e-gen/references/decisions.md +36 -0
  72. package/doc/skills/keve-e2e-gen/references/pom-generation-guide.md +140 -0
  73. package/doc/skills/keve-e2e-gen/references/script-generation-guide.md +236 -0
  74. package/doc/skills/keve-e2e-gen/references/test-auditor-guide.md +189 -0
  75. package/doc/skills/keve-e2e-gen/scripts/extract-components.sh +85 -0
  76. package/doc/skills/keve-e2e-gen/scripts/inject-testids.sh +95 -0
  77. package/doc/skills/keve-static-analysis/SKILL.md +362 -0
  78. package/doc/skills/keve-static-analysis/references/codegraph-analysis-guide.md +108 -0
  79. package/doc/skills/keve-static-analysis/references/git-impact-analysis.md +81 -0
  80. package/doc/skills/keve-static-analysis/references/lint-fix-guide.md +69 -0
  81. package/doc/skills/keve-static-analysis/references/runtime-risk-patterns.md +92 -0
  82. package/doc/skills/keve-static-analysis/references/security-scan-guide.md +32 -0
  83. package/doc/skills/keve-static-analysis/references/ts-error-patterns.md +98 -0
  84. package/doc/skills/keve-static-analysis/references/vue-security-guide.md +72 -0
  85. package/doc/skills/keve-test-eval/SKILL.md +78 -0
  86. package/doc/skills/keve-test-eval/references/common-fix-guide.md +166 -0
  87. package/doc/skills/keve-test-eval/references/confidence-data-guide.md +78 -0
  88. package/doc/skills/keve-test-eval/references/fix-loop-guide.md +67 -0
  89. package/doc/skills/keve-unit-gen/SKILL.md +203 -0
  90. package/doc/skills/keve-unit-gen/references/boundary-conditions.md +78 -0
  91. package/doc/skills/keve-unit-gen/references/unit-mock-strategy.md +71 -0
  92. package/doc/skills/keve-unit-gen/references/unit-test-template.md +105 -0
  93. package/package.json +47 -25
  94. package/dist/agent/factory.d.ts +0 -25
  95. package/dist/agent/factory.js +0 -99
  96. package/dist/agent/index.d.ts +0 -3
  97. package/dist/agent/index.js +0 -7
  98. package/dist/agent/loader.d.ts +0 -22
  99. package/dist/agent/loader.js +0 -117
  100. package/dist/agent/types.d.ts +0 -9
  101. package/dist/agent/types.js +0 -2
  102. package/dist/agent-loop/complete-task.d.ts +0 -28
  103. package/dist/agent-loop/complete-task.js +0 -70
  104. package/dist/agent-loop/index.d.ts +0 -16
  105. package/dist/agent-loop/index.js +0 -26
  106. package/dist/agent-loop/loop.d.ts +0 -42
  107. package/dist/agent-loop/loop.js +0 -282
  108. package/dist/agent-loop/runtime.d.ts +0 -40
  109. package/dist/agent-loop/runtime.js +0 -163
  110. package/dist/agent-loop/types.d.ts +0 -161
  111. package/dist/agent-loop/types.js +0 -105
  112. package/dist/context/index.d.ts +0 -8
  113. package/dist/context/index.js +0 -29
  114. package/dist/context/tokenCalculation.d.ts +0 -55
  115. package/dist/context/tokenCalculation.js +0 -95
  116. package/dist/context/truncation.d.ts +0 -67
  117. package/dist/context/truncation.js +0 -142
  118. package/dist/context/types.d.ts +0 -7
  119. package/dist/context/types.js +0 -27
  120. package/dist/llm/OpenAIClient.d.ts +0 -31
  121. package/dist/llm/OpenAIClient.js +0 -455
  122. package/dist/llm/constants.d.ts +0 -2
  123. package/dist/llm/constants.js +0 -6
  124. package/dist/llm/errors.d.ts +0 -25
  125. package/dist/llm/errors.js +0 -51
  126. package/dist/llm/index.d.ts +0 -49
  127. package/dist/llm/index.js +0 -158
  128. package/dist/llm/types.d.ts +0 -124
  129. package/dist/llm/types.js +0 -2
  130. package/dist/llm/utils.d.ts +0 -29
  131. package/dist/llm/utils.js +0 -284
  132. package/dist/skill/frontmatter-parser.d.ts +0 -50
  133. package/dist/skill/frontmatter-parser.js +0 -152
  134. package/dist/skill/index.d.ts +0 -12
  135. package/dist/skill/index.js +0 -17
  136. package/dist/skill/loader.d.ts +0 -96
  137. package/dist/skill/loader.js +0 -256
  138. package/dist/tools/ask-user.d.ts +0 -8
  139. package/dist/tools/ask-user.js +0 -47
  140. package/dist/tools/bash.d.ts +0 -47
  141. package/dist/tools/bash.js +0 -213
  142. package/dist/tools/edit-file.d.ts +0 -9
  143. package/dist/tools/edit-file.js +0 -76
  144. package/dist/tools/glob.d.ts +0 -8
  145. package/dist/tools/glob.js +0 -101
  146. package/dist/tools/grep.d.ts +0 -10
  147. package/dist/tools/grep.js +0 -76
  148. package/dist/tools/index.d.ts +0 -24
  149. package/dist/tools/index.js +0 -47
  150. package/dist/tools/read-files.d.ts +0 -8
  151. package/dist/tools/read-files.js +0 -81
  152. package/dist/tools/write-file.d.ts +0 -8
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: keve-unit-gen
3
+ description: 从源码导出函数自动生成 Vitest 单元测试。扫描 src/utils/、src/hooks/、src/store/ 中的纯函数和 composable,分析函数签名、边界条件和异常路径,生成 describe + it 测试文件,执行验证后输出覆盖索引。
4
+ allowed-tools: Bash(shell:*) Bash(npx:*) Bash(npm:*) Bash(node:*) Bash(git:*) Bash(pnpm:*) Bash(yarn:*)
5
+ ---
6
+
7
+ # keve-unit-gen
8
+
9
+ ## 定位
10
+
11
+ **本技能负责**:从源码导出函数自动生成单元测试(不负责组件测试、E2E 测试)。
12
+
13
+ 单元测试覆盖测试金字塔最底层:纯函数、hooks、store 模块。
14
+ 运行环境为 Node.js,不需要浏览器/DOM/jsdom,毫秒级执行。
15
+
16
+ ***
17
+
18
+ ## 触发条件
19
+
20
+ | 触发方式 | 场景 | 说明 |
21
+ |----------|------|------|
22
+ | `use_skill("keve-unit-gen")` | 开发阶段测试流水线 | 由 keve-dev-test-agent 调度 |
23
+ | `/keve-unit-gen` 指令 | 用户主动要求生成单测 | 手动触发 |
24
+
25
+ ***
26
+
27
+ ## 输入
28
+
29
+ - 项目源码中的工具函数、composable、store 模块等(由 Step 1 自动扫描识别)
30
+ - 不硬编码目录路径,根据项目实际结构分析
31
+
32
+ **排除**:
33
+ - `.vue` 组件文件(由 keve-component-gen 负责)
34
+ - `.spec.ts` / `.test.ts` 已有测试文件
35
+ - 类型定义文件(`*.d.ts`)
36
+ - 配置文件(`vite.config.*` / `tsconfig.*` / `*.config.*`)
37
+ - `index.ts` 纯导出聚合文件
38
+
39
+ ***
40
+
41
+ ## 流程
42
+
43
+ ### Step 1: 扫描目标文件
44
+
45
+ 从项目 `src/` 目录扫描,识别导出函数的目标文件:
46
+
47
+ ```
48
+ 扫描路径:
49
+ - src/utils/**/*.ts
50
+ - src/hooks/**/*.ts
51
+ - src/store/**/*.ts
52
+ - src/helpers/**/*.ts
53
+ - src/composables/**/*.ts
54
+
55
+ 排除:
56
+ - *.vue, *.spec.ts, *.test.ts
57
+ - *.d.ts, *.config.ts, *.config.js
58
+ - index.ts (纯导出聚合)
59
+ - types/ 或 types.ts 目录/文件
60
+ ```
61
+
62
+ 输出:目标文件列表 + 每个文件的导出符号列表。
63
+
64
+ ### Step 2: 分析每个导出符号
65
+
66
+ 对每个导出函数/类/composable 分析:
67
+
68
+ | 分析维度 | 识别方式 | 生成用例 |
69
+ |---------|---------|---------|
70
+ | 函数签名 | 参数类型 + 返回类型 | 正常路径 1 test |
71
+ | 必填参数 | 无默认值的参数 | 缺失必填参数 1 test |
72
+ | 可选参数 | 有 `?` 或默认值 | 有/无可选参数各 1 test |
73
+ | 边界条件 | number → 0/-1/NaN/Infinity; string → ''/超长; array → 空数组 | 每个边界 1 test |
74
+ | null/undefined | 参数类型含 `null | undefined` | null/undefined 输入各 1 test |
75
+ | 异常路径 | `throw` / `reject` / `try-catch` | 异常触发 1 test |
76
+ | 异步路径 | `async` / `Promise` | 异步正常 + 异步异常 |
77
+
78
+ ### Step 3: 生成测试文件
79
+
80
+ **生成路径**:`keve_test_spec/util/__test__/{sourceFilename}.test.ts`
81
+
82
+ **生成结构**:
83
+
84
+ ```typescript
85
+ // keve_test_spec/util/__test__/format.test.ts
86
+ import { describe, it, expect, vi } from 'vitest';
87
+ import { truncate, formatCurrency } from '@/utils/format';
88
+
89
+ describe('format', () => {
90
+ describe('truncate', () => {
91
+ it('短字符串不截断', () => {
92
+ expect(truncate('hello', 10)).toBe('hello');
93
+ });
94
+ it('长字符串截断加...', () => {
95
+ expect(truncate('hello world', 5)).toBe('he...');
96
+ });
97
+ it('刚好等于 maxLen', () => {
98
+ expect(truncate('hello', 5)).toBe('hello');
99
+ });
100
+ it('空字符串', () => {
101
+ expect(truncate('', 5)).toBe('');
102
+ });
103
+ });
104
+
105
+ describe('formatCurrency', () => {
106
+ it('正整数', () => {
107
+ expect(formatCurrency(1000)).toBe('¥1,000');
108
+ });
109
+ it('小数保留两位', () => {
110
+ expect(formatCurrency(1000.5)).toBe('¥1,000.50');
111
+ });
112
+ });
113
+ });
114
+ ```
115
+
116
+ **命名规则**:
117
+ - 文件名与源文件同名,后缀 `.test.ts`
118
+ - `describe` 第一层 = 源文件模块名
119
+ - `describe` 第二层 = 函数名
120
+ - `it` 描述 = 中文场景描述
121
+
122
+ ### Step 4: 执行验证
123
+
124
+ ```bash
125
+ npx vitest run keve_test_spec/util/__test__/format.test.ts --coverage
126
+ ```
127
+
128
+ - 如果通过 → 继续
129
+ - 如果失败 → AI 分析错误,修复测试(≤2 轮)
130
+ - 超过 2 轮仍失败 → 跳过该用例,标记为 `pending`(加 `it.todo`)
131
+
132
+ ### Step 5: 生成覆盖索引
133
+
134
+ 从 Vitest 覆盖率输出 + 测试文件分析反向生成 `keve_test_spec/util/coverage.yaml`:
135
+
136
+ ```yaml
137
+ generated_at: 2026-06-16T16:05:00
138
+ total_exports: 15
139
+ tested_exports: 13
140
+ untested_exports: 2
141
+ overall_coverage: 87%
142
+
143
+ files:
144
+ - source: src/utils/format.ts
145
+ test: __test__/format.test.ts
146
+ exports:
147
+ - fn: truncate
148
+ scenarios: [短字符串不截断, 长字符串截断加..., 刚好等于maxLen, 空字符串]
149
+ coverage: 100%
150
+ - fn: formatCurrency
151
+ scenarios: [正整数, 小数两位]
152
+ coverage: 85%
153
+ missing: [NaN输入, 超大数值]
154
+
155
+ - source: src/utils/validator.ts
156
+ test: null
157
+ exports:
158
+ - fn: validateEmail
159
+ - fn: validatePhone
160
+ missing: [全部场景]
161
+ ```
162
+
163
+ ***
164
+
165
+ ## 产出
166
+
167
+ | 产出 | 路径 |
168
+ |------|------|
169
+ | 测试脚本 | `keve_test_spec/util/__test__/*.test.ts` |
170
+ | 覆盖索引 | `keve_test_spec/util/coverage.yaml` |
171
+ | 覆盖率报告 | `coverage/`(Vitest 生成) |
172
+
173
+ ***
174
+
175
+ ## 硬性约束
176
+
177
+ - **不生成 .vue 组件测试**(由 keve-component-gen 负责)
178
+ - **不需要 DOM / jsdom / 浏览器**(纯 Node.js 环境运行)
179
+ - **优先使用 `vi.mock`**,而非 `vi.spyOn`
180
+ - **不修改源码**(只生成测试文件)
181
+ - **测试文件放在 `keve_test_spec/util/__test__/`**,不放在源码旁
182
+ - **每轮修复后重新执行验证**
183
+ - **失败的用例用 `it.todo` 标记**,不删除
184
+
185
+ ***
186
+
187
+ ## Key Decisions
188
+
189
+ | ID | 决策 | 说明 |
190
+ |----|------|------|
191
+ | UG01 | 测试文件放在 keve_test_spec/util/ | 长期资产,跨 MR 复用(D12) |
192
+ | UG02 | 不修改源码 | 只生成测试,不修改被测代码 |
193
+ | UG03 | 最多 2 轮修复 | 单测修复通常简单,2 轮足够 |
194
+ | UG04 | 失败用例用 it.todo | 保留场景信息,不删除 |
195
+ | UG05 | 覆盖索引反向汇总 | 保证和代码一致(D09) |
196
+
197
+ ***
198
+
199
+ ## References
200
+
201
+ - [unit-test-template.md](references/unit-test-template.md) — 单测生成模板
202
+ - [unit-mock-strategy.md](references/unit-mock-strategy.md) — vi.mock 使用策略
203
+ - [boundary-conditions.md](references/boundary-conditions.md) — 边界条件识别规则
@@ -0,0 +1,78 @@
1
+ # 边界条件识别规则
2
+
3
+ > AI 分析函数签名时识别边界条件的参考
4
+
5
+ ---
6
+
7
+ ## 按参数类型的边界条件
8
+
9
+ ### number
10
+
11
+ | 边界值 | 示例 |
12
+ |--------|------|
13
+ | 0 | `calculate(0)` |
14
+ | -1 | `calculate(-1)` |
15
+ | NaN | `calculate(NaN)` |
16
+ | Infinity | `calculate(Infinity)` |
17
+ | 超大数值 | `calculate(Number.MAX_VALUE)` |
18
+ | 小数精度 | `calculate(0.1 + 0.2)` |
19
+
20
+ ### string
21
+
22
+ | 边界值 | 示例 |
23
+ |--------|------|
24
+ | 空字符串 | `parse('')` |
25
+ | 超长字符串 | `parse('a'.repeat(10000))` |
26
+ | 特殊字符 | `parse('<script>alert("xss")</script>')` |
27
+ | Unicode | `parse('你好世界🎉')` |
28
+ | null 字符 | `parse('\0')` |
29
+
30
+ ### Array
31
+
32
+ | 边界值 | 示例 |
33
+ |--------|------|
34
+ | 空数组 | `filter([])` |
35
+ | 单元素 | `filter([1])` |
36
+ | 重复元素 | `filter([1, 1, 1])` |
37
+ | 混合类型 | `filter([1, 'a', null])` |
38
+
39
+ ### Object
40
+
41
+ | 边界值 | 示例 |
42
+ |--------|------|
43
+ | 空对象 | `merge({})` |
44
+ | 嵌套深对象 | `merge({ a: { b: { c: 1 } } })` |
45
+ | 含 undefined 属性 | `merge({ a: undefined })` |
46
+
47
+ ### null / undefined
48
+
49
+ | 边界值 | 示例 |
50
+ |--------|------|
51
+ | null | `parse(null)` |
52
+ | undefined | `parse(undefined)` |
53
+
54
+ ---
55
+
56
+ ## 按返回类型的边界条件
57
+
58
+ | 返回类型 | 应验证 |
59
+ |---------|--------|
60
+ | string | 空字符串、非空字符串 |
61
+ | number | 0、正数、负数 |
62
+ | boolean | true、false |
63
+ | Array | 空数组、非空数组 |
64
+ | Promise | resolve、reject |
65
+ | void | 函数执行无异常 |
66
+
67
+ ---
68
+
69
+ ## 特殊场景
70
+
71
+ | 场景 | 识别方式 | 测试 |
72
+ |------|---------|------|
73
+ | 必填参数缺失 | 无默认值 | 缺失时是否抛错 |
74
+ | 可选参数 | `param?: T` | 有/无各 1 test |
75
+ | 函数重载 | 多个签名 | 每个重载 1 test |
76
+ | 泛型函数 | `<T>(x: T)` | 不同类型参数各 1 test |
77
+ | 抛出异常 | `throw new Error()` | 异常类型 + 消息 |
78
+ | 异步拒绝 | `reject()` | `await expect(fn()).rejects.toThrow()` |
@@ -0,0 +1,71 @@
1
+ # 单元测试 Mock 策略
2
+
3
+ > AI 生成单元测试时的 vi.mock 使用指南
4
+
5
+ ---
6
+
7
+ ## Mock 优先级
8
+
9
+ | 优先级 | 方式 | 适用场景 |
10
+ |--------|------|---------|
11
+ | 1 | `vi.mock` 整个模块 | 外部依赖(API、Store、第三方库) |
12
+ | 2 | `vi.fn` 创建假函数 | 回调函数、事件处理器 |
13
+ | 3 | `vi.spyOn` 监视真实方法 | 需要保留部分真实行为时 |
14
+ | 4 | 传入测试数据 | 无外部依赖的纯函数(不需要 mock) |
15
+
16
+ ---
17
+
18
+ ## 常见 Mock 场景
19
+
20
+ ### Mock API 模块
21
+
22
+ ```typescript
23
+ vi.mock('@/api/client', () => ({
24
+ get: vi.fn().mockResolvedValue({ data: [] }),
25
+ post: vi.fn().mockResolvedValue({ success: true }),
26
+ }));
27
+ ```
28
+
29
+ ### Mock Store
30
+
31
+ ```typescript
32
+ vi.mock('@/store/user', () => ({
33
+ useUserStore: vi.fn(() => ({
34
+ userInfo: { name: 'test' },
35
+ isLoggedIn: true,
36
+ login: vi.fn(),
37
+ logout: vi.fn(),
38
+ })),
39
+ }));
40
+ ```
41
+
42
+ ### Mock 第三方库
43
+
44
+ ```typescript
45
+ vi.mock('lodash/debounce', () => ({
46
+ default: (fn: Function) => fn, // debounce 立即执行
47
+ }));
48
+
49
+ vi.mock('dayjs', () => ({
50
+ default: (date?: string) => ({
51
+ format: (fmt: string) => '2026-01-01',
52
+ }),
53
+ }));
54
+ ```
55
+
56
+ ### Mock 环境变量
57
+
58
+ ```typescript
59
+ vi.stubEnv('VITE_API_URL', 'http://localhost:3000');
60
+ ```
61
+
62
+ ---
63
+
64
+ ## 禁止做法
65
+
66
+ | 禁止 | 原因 |
67
+ |------|------|
68
+ | Mock 被测函数本身 | 失去测试意义 |
69
+ | Mock 纯函数 | 纯函数无副作用,直接调用 |
70
+ | `vi.spyOn` 后 `mockRestore` 不调用 | 影响其他测试 |
71
+ | 在 describe 顶层写 `vi.mock` 外的副作用 | 执行顺序不确定 |
@@ -0,0 +1,105 @@
1
+ # 单元测试生成模板
2
+
3
+ > AI 生成 Vitest 单元测试时的参考模板
4
+
5
+ ---
6
+
7
+ ## 基本结构
8
+
9
+ ```typescript
10
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
11
+ import { functionName } from '@/utils/module';
12
+
13
+ describe('module', () => {
14
+ describe('functionName', () => {
15
+ it('正常路径描述', () => {
16
+ // Arrange
17
+ const input = validInput;
18
+ // Act
19
+ const result = functionName(input);
20
+ // Assert
21
+ expect(result).toBe(expectedValue);
22
+ });
23
+
24
+ it('边界条件描述', () => {
25
+ expect(functionName(boundaryInput)).toBe(expectedValue);
26
+ });
27
+
28
+ it('异常路径描述', () => {
29
+ expect(() => functionName(invalidInput)).toThrow(ErrorType);
30
+ });
31
+ });
32
+ });
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 纯函数模板
38
+
39
+ ```typescript
40
+ describe('format', () => {
41
+ describe('truncate', () => {
42
+ it('短字符串不截断', () => {
43
+ expect(truncate('hello', 10)).toBe('hello');
44
+ });
45
+ it('长字符串截断加省略号', () => {
46
+ expect(truncate('hello world', 5)).toBe('he...');
47
+ });
48
+ it('空字符串', () => {
49
+ expect(truncate('', 5)).toBe('');
50
+ });
51
+ });
52
+ });
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Composable Hook 模板
58
+
59
+ ```typescript
60
+ import { describe, it, expect, vi } from 'vitest';
61
+ import { useSearch } from '@/hooks/useSearch';
62
+
63
+ // 需要 @vue/test-utils 的 mountWithVitest 或 @vueuse/core 的试用
64
+ describe('useSearch', () => {
65
+ it('初始化状态', () => {
66
+ // composable 测试需要在 setup 上下文中调用
67
+ // 方案1: 使用 @vue/test-utils 的 mount
68
+ // 方案2: 使用 vitest 的 withSetup helper
69
+ });
70
+ });
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 异步函数模板
76
+
77
+ ```typescript
78
+ describe('fetchData', () => {
79
+ it('成功返回数据', async () => {
80
+ const mockData = { id: 1, name: 'test' };
81
+ vi.mock('@/api/client', () => ({
82
+ get: vi.fn().mockResolvedValue(mockData),
83
+ }));
84
+ const result = await fetchData(1);
85
+ expect(result).toEqual(mockData);
86
+ });
87
+
88
+ it('网络错误抛出异常', async () => {
89
+ vi.mock('@/api/client', () => ({
90
+ get: vi.fn().mockRejectedValue(new Error('Network error')),
91
+ }));
92
+ await expect(fetchData(1)).rejects.toThrow('Network error');
93
+ });
94
+ });
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 失败用例处理
100
+
101
+ ```typescript
102
+ // 修复 2 轮后仍失败 → 改为 it.todo
103
+ it.todo('NaN输入时的行为');
104
+ it.todo('超大数值溢出');
105
+ ```
package/package.json CHANGED
@@ -1,59 +1,81 @@
1
1
  {
2
2
  "name": "@kkeve/suite",
3
- "version": "0.0.1",
4
- "description": "EVE agent core runtime infrastructure — LLM client, agent loop, skill loader, context management",
3
+ "version": "0.0.2",
4
+ "description": "AI-powered full-stack test agent CLI - static analysis, unit test, component test, E2E test, execute, evaluate, and report",
5
5
  "license": "MIT",
6
+ "bin": {
7
+ "keve": "./dist/bin/keve.js"
8
+ },
6
9
  "main": "./dist/index.js",
7
10
  "exports": {
8
11
  ".": {
9
12
  "types": "./dist/index.d.ts",
10
13
  "default": "./dist/index.js"
11
14
  },
12
- "./llm": {
13
- "types": "./dist/llm/index.d.ts",
14
- "default": "./dist/llm/index.js"
15
+ "./global-setup": {
16
+ "types": "./dist/core/global-setup.d.ts",
17
+ "default": "./dist/core/global-setup.js"
18
+ },
19
+ "./keve-report": {
20
+ "types": "./dist/core/keve-report.d.ts",
21
+ "default": "./dist/core/keve-report.js"
22
+ },
23
+ "./keve-test": {
24
+ "types": "./dist/core/keve-test.d.ts",
25
+ "default": "./dist/core/keve-test.js"
15
26
  },
16
- "./context": {
17
- "types": "./dist/context/index.d.ts",
18
- "default": "./dist/context/index.js"
27
+ "./page-agent": {
28
+ "types": "./dist/page-agent/agent.d.ts",
29
+ "default": "./dist/page-agent/agent.js"
19
30
  },
20
- "./agent-loop": {
21
- "types": "./dist/agent-loop/index.d.ts",
22
- "default": "./dist/agent-loop/index.js"
31
+ "./keve-aspect": {
32
+ "types": "./dist/core/keve-aspect.d.ts",
33
+ "default": "./dist/core/keve-aspect.js"
23
34
  },
24
- "./skill": {
25
- "types": "./dist/skill/index.d.ts",
26
- "default": "./dist/skill/index.js"
35
+ "./action-log": {
36
+ "types": "./dist/core/action-log-writer.d.ts",
37
+ "default": "./dist/core/action-log-writer.js"
27
38
  },
28
- "./agent": {
29
- "types": "./dist/agent/index.d.ts",
30
- "default": "./dist/agent/index.js"
39
+ "./learned-actions": {
40
+ "types": "./dist/core/learned-actions.d.ts",
41
+ "default": "./dist/core/learned-actions.js"
31
42
  },
32
- "./tools": {
33
- "types": "./dist/tools/index.d.ts",
34
- "default": "./dist/tools/index.js"
43
+ "./spec/keve-read-doc": {
44
+ "types": "./dist/spec/keve-read-doc.d.ts",
45
+ "default": "./dist/spec/keve-read-doc.js"
35
46
  }
36
47
  },
37
48
  "files": [
38
- "dist"
49
+ "dist",
50
+ "doc",
51
+ "README.md"
39
52
  ],
40
53
  "scripts": {
41
- "build": "tsc -p tsconfig.json",
54
+ "build": "rm -rf dist && tsc && chmod +x dist/bin/keve.js && cp src/page-agent/system_prompt.md dist/page-agent/",
55
+ "dev": "tsc --watch",
42
56
  "typecheck": "tsc --noEmit",
43
- "prepublishOnly": "pnpm build"
57
+ "keve": "node dist/bin/keve.js",
58
+ "prepublishOnly": ""
44
59
  },
45
60
  "repository": {
46
61
  "type": "git",
47
62
  "url": "https://github.com/bubblem1029-tech/EVE.git"
48
63
  },
49
64
  "dependencies": {
50
- "glob": "^13.0.6",
51
- "jsonrepair": "^3.14.0",
65
+ "@kkeve/core": "0.0.2",
66
+ "@vitest/coverage-v8": "^4.1.9",
67
+ "@vue/test-utils": "^2.4.6",
68
+ "chalk": "^4.1.0",
69
+ "commander": "^13.1.0",
70
+ "jsdom": "^26.1.0",
71
+ "vitest": "^4.1.9",
52
72
  "yaml": "^2.9.0",
53
73
  "zod": "^4.4.3"
54
74
  },
55
75
  "devDependencies": {
76
+ "@playwright/test": "^1.60.0",
56
77
  "@types/node": "^25.6.0",
78
+ "tsx": "^4.19.0",
57
79
  "typescript": "^6.0.2"
58
80
  }
59
81
  }
@@ -1,25 +0,0 @@
1
- /**
2
- * AgentFactory — creates execution resources for AgentLoop
3
- *
4
- * - Creates LLM, ToolRegistry, RuntimeEnvironment
5
- * - Provides AgentLoader for agent discovery
6
- * - Creates sub-agent ToolRegistry with configurable allowed/blocked tools
7
- */
8
- import type { LLMConfig } from '../llm/types';
9
- import type { RuntimeEnvironment } from '../agent-loop/runtime';
10
- import { ToolRegistry } from '../agent-loop/types';
11
- import { LLM } from '../llm/index';
12
- import { AgentLoader } from './loader';
13
- export declare class AgentFactory {
14
- private llm;
15
- private runtime;
16
- private toolRegistry;
17
- private agentLoader;
18
- constructor(llmConfig: LLMConfig, workspaceDir?: string);
19
- init(agentsDir: string): Promise<void>;
20
- getLLM(): LLM;
21
- getToolRegistry(): ToolRegistry;
22
- getRuntime(): RuntimeEnvironment;
23
- getAgentLoader(): AgentLoader;
24
- createSubAgentToolRegistry(allowedTools?: string[], blockedTools?: string[]): ToolRegistry;
25
- }
@@ -1,99 +0,0 @@
1
- "use strict";
2
- /**
3
- * AgentFactory — creates execution resources for AgentLoop
4
- *
5
- * - Creates LLM, ToolRegistry, RuntimeEnvironment
6
- * - Provides AgentLoader for agent discovery
7
- * - Creates sub-agent ToolRegistry with configurable allowed/blocked tools
8
- */
9
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- var desc = Object.getOwnPropertyDescriptor(m, k);
12
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
- desc = { enumerable: true, get: function() { return m[k]; } };
14
- }
15
- Object.defineProperty(o, k2, desc);
16
- }) : (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- o[k2] = m[k];
19
- }));
20
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
- Object.defineProperty(o, "default", { enumerable: true, value: v });
22
- }) : function(o, v) {
23
- o["default"] = v;
24
- });
25
- var __importStar = (this && this.__importStar) || (function () {
26
- var ownKeys = function(o) {
27
- ownKeys = Object.getOwnPropertyNames || function (o) {
28
- var ar = [];
29
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
- return ar;
31
- };
32
- return ownKeys(o);
33
- };
34
- return function (mod) {
35
- if (mod && mod.__esModule) return mod;
36
- var result = {};
37
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
- __setModuleDefault(result, mod);
39
- return result;
40
- };
41
- })();
42
- Object.defineProperty(exports, "__esModule", { value: true });
43
- exports.AgentFactory = void 0;
44
- const path = __importStar(require("node:path"));
45
- const types_1 = require("../agent-loop/types");
46
- const index_1 = require("../llm/index");
47
- const runtime_1 = require("../agent-loop/runtime");
48
- const index_2 = require("../tools/index");
49
- const loader_1 = require("./loader");
50
- class AgentFactory {
51
- llm;
52
- runtime;
53
- toolRegistry;
54
- agentLoader;
55
- constructor(llmConfig, workspaceDir) {
56
- this.llm = new index_1.LLM({
57
- ...llmConfig,
58
- baseURL: llmConfig.baseURL || process.env.LLM_BASE_URL || '',
59
- model: llmConfig.model || process.env.LLM_MODEL_NAME || process.env.LLM_MODEL || '',
60
- apiKey: llmConfig.apiKey || process.env.LLM_API_KEY || '',
61
- });
62
- this.runtime = (0, runtime_1.detectRuntimeEnvironment)(process.cwd(), workspaceDir || path.join(process.cwd(), 'workspace'));
63
- this.toolRegistry = (0, index_2.createDefaultToolRegistry)(this.runtime);
64
- }
65
- async init(agentsDir) {
66
- this.agentLoader = new loader_1.AgentLoader(agentsDir);
67
- await this.agentLoader.discover();
68
- }
69
- getLLM() {
70
- return this.llm;
71
- }
72
- getToolRegistry() {
73
- return this.toolRegistry;
74
- }
75
- getRuntime() {
76
- return this.runtime;
77
- }
78
- getAgentLoader() {
79
- return this.agentLoader;
80
- }
81
- createSubAgentToolRegistry(allowedTools, blockedTools) {
82
- const subRegistry = new types_1.ToolRegistry();
83
- const toolFilter = (allowedTools && allowedTools.length > 0)
84
- ? new Set(allowedTools)
85
- : null;
86
- const blocked = new Set(blockedTools ?? []);
87
- for (const name of this.toolRegistry.getAllToolNames()) {
88
- if (blocked.has(name))
89
- continue;
90
- if (toolFilter && !toolFilter.has(name))
91
- continue;
92
- const tool = this.toolRegistry.get(name);
93
- if (tool)
94
- subRegistry.register(tool);
95
- }
96
- return subRegistry;
97
- }
98
- }
99
- exports.AgentFactory = AgentFactory;
@@ -1,3 +0,0 @@
1
- export { AgentLoader } from './loader';
2
- export { AgentFactory } from './factory';
3
- export type { AgentRegistryDefinition } from './types';