hamster-wheel-cli 0.2.0 → 0.3.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.
@@ -1,6 +1,15 @@
1
1
  import assert from 'node:assert/strict';
2
2
  import { test } from 'node:test';
3
- import { applyShortcutArgv, parseAliasEntries, parseGlobalConfig, splitCommandArgs, updateAliasContent } from '../src/global-config';
3
+ import {
4
+ applyShortcutArgv,
5
+ parseAgentEntries,
6
+ parseAliasEntries,
7
+ parseGlobalConfig,
8
+ removeAgentContent,
9
+ splitCommandArgs,
10
+ updateAgentContent,
11
+ updateAliasContent
12
+ } from '../src/global-config';
4
13
 
5
14
  test('parseGlobalConfig 读取 shortcut 配置', () => {
6
15
  const content = `
@@ -101,3 +110,82 @@ command = "--run-e2e"
101
110
  assert.ok(result.includes('daily = "--task \\"新命令\\""'));
102
111
  assert.ok(result.includes('[shortcut]'));
103
112
  });
113
+
114
+ test('parseAgentEntries 读取 agent 配置', () => {
115
+ const content = `
116
+ [agent]
117
+ claude = "claude --model sonnet"
118
+ `;
119
+ const entries = parseAgentEntries(content);
120
+ assert.deepEqual(entries, [
121
+ {
122
+ name: 'claude',
123
+ command: 'claude --model sonnet'
124
+ }
125
+ ]);
126
+ });
127
+
128
+ test('parseAgentEntries 支持 agents 并忽略重复', () => {
129
+ const content = `
130
+ [agents]
131
+ daily = "cmd-a"
132
+
133
+ [agent]
134
+ daily = "cmd-b"
135
+ weekly = "cmd-c"
136
+ `;
137
+ const entries = parseAgentEntries(content);
138
+ assert.deepEqual(entries, [
139
+ {
140
+ name: 'daily',
141
+ command: 'cmd-a'
142
+ },
143
+ {
144
+ name: 'weekly',
145
+ command: 'cmd-c'
146
+ }
147
+ ]);
148
+ });
149
+
150
+ test('updateAgentContent 会在空文件中写入 agent', () => {
151
+ const result = updateAgentContent('', 'daily', 'claude --model sonnet');
152
+ assert.ok(result.includes('[agent]'));
153
+ assert.ok(result.includes('daily = "claude --model sonnet"'));
154
+ assert.ok(result.endsWith('\n'));
155
+ });
156
+
157
+ test('updateAgentContent 会更新已有 agent 并保留其他配置', () => {
158
+ const content = `
159
+ [agent]
160
+ daily = "cmd-a"
161
+
162
+ [shortcut]
163
+ name = "quick"
164
+ command = "--run-e2e"
165
+ `;
166
+ const result = updateAgentContent(content, 'daily', 'cmd-b');
167
+ assert.ok(result.includes('daily = "cmd-b"'));
168
+ assert.ok(result.includes('[shortcut]'));
169
+ });
170
+
171
+ test('removeAgentContent 会删除指定 agent', () => {
172
+ const content = `
173
+ [agent]
174
+ daily = "cmd-a"
175
+ weekly = "cmd-b"
176
+ `;
177
+ const { removed, nextContent } = removeAgentContent(content, 'daily');
178
+ assert.equal(removed, true);
179
+ assert.ok(!nextContent.includes('daily = "cmd-a"'));
180
+ assert.ok(nextContent.includes('weekly = "cmd-b"'));
181
+ });
182
+
183
+ test('removeAgentContent 未命中时保持原内容', () => {
184
+ const content = `
185
+ [agent]
186
+ weekly = "cmd-b"
187
+ `;
188
+ const { removed, nextContent } = removeAgentContent(content, 'daily');
189
+ assert.equal(removed, false);
190
+ assert.ok(nextContent.includes('weekly = "cmd-b"'));
191
+ });
@@ -8,17 +8,20 @@ test('normalizeWebhookUrls 会去除空值并裁剪空白', () => {
8
8
  assert.deepEqual(urls, ['https://example.com', 'http://a.local']);
9
9
  });
10
10
 
11
- test('buildWebhookPayload 会补齐时间戳', () => {
11
+ test('buildWebhookPayload 会补齐本地时间戳', () => {
12
12
  const payload = buildWebhookPayload({
13
13
  event: 'task_start',
14
14
  task: 'demo',
15
15
  iteration: 0,
16
- stage: '任务开始'
16
+ stage: '任务开始',
17
+ project: 'wheel-ai'
17
18
  });
18
19
  assert.equal(payload.event, 'task_start');
19
20
  assert.equal(payload.task, 'demo');
20
21
  assert.equal(payload.iteration, 0);
21
- assert.ok(payload.timestamp.length > 0);
22
+ assert.match(payload.timestamp, /^\d{8}-\d{6}$/);
23
+ assert.equal(payload.commit, '');
24
+ assert.equal(payload.pr, '');
22
25
  });
23
26
 
24
27
  test('sendWebhookNotifications 在无配置时直接跳过', async () => {
@@ -34,6 +37,7 @@ test('sendWebhookNotifications 在无配置时直接跳过', async () => {
34
37
  task: 'demo',
35
38
  iteration: 0,
36
39
  stage: '任务开始',
40
+ project: 'wheel-ai',
37
41
  timestamp: '2024-01-01T00:00:00.000Z'
38
42
  });
39
43
 
@@ -55,10 +59,10 @@ test('sendWebhookNotifications 会向多个地址发送', async () => {
55
59
 
56
60
  const payload = buildWebhookPayload({
57
61
  event: 'iteration_start',
58
- task: 'demo',
59
62
  branch: 'feat/demo',
60
63
  iteration: 2,
61
64
  stage: '开始第 2 轮迭代',
65
+ project: 'wheel-ai',
62
66
  timestamp: '2024-01-01T00:00:00.000Z'
63
67
  });
64
68
 
@@ -67,17 +71,17 @@ test('sendWebhookNotifications 会向多个地址发送', async () => {
67
71
  assert.equal(calls.length, 2);
68
72
  assert.equal(calls[0].contentType, 'application/json');
69
73
  const decoded = JSON.parse(calls[0].body) as typeof payload;
70
- assert.equal(decoded.task, 'demo');
71
74
  assert.equal(decoded.branch, 'feat/demo');
75
+ assert.ok(!('task' in decoded));
72
76
  });
73
77
 
74
78
  test('sendWebhookNotifications 捕获异常并不中断', async () => {
75
79
  const logger = new Logger({ verbose: false });
76
80
  const payload = buildWebhookPayload({
77
81
  event: 'task_end',
78
- task: 'demo',
79
82
  iteration: 1,
80
83
  stage: '任务结束',
84
+ project: 'wheel-ai',
81
85
  timestamp: '2024-01-01T00:00:00.000Z'
82
86
  });
83
87