@raidou/pi-pm-subagents 0.1.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 (69) hide show
  1. package/.prettierrc +7 -0
  2. package/AGENTS.md +1 -0
  3. package/README.md +85 -0
  4. package/README.zh-CN.md +85 -0
  5. package/agents/explorer.md +10 -0
  6. package/agents/planner.md +16 -0
  7. package/agents/researcher.md +22 -0
  8. package/agents/reviewer.md +10 -0
  9. package/eslint.config.mjs +14 -0
  10. package/example-prompts/coordinator.md +21 -0
  11. package/package.json +48 -0
  12. package/pm-subagents-prompts/coordinator.md +16 -0
  13. package/pnpm-workspace.yaml +5 -0
  14. package/src/bash-readonly.test.ts +331 -0
  15. package/src/bash-readonly.ts +205 -0
  16. package/src/coordinator/coordinator.test.ts +28 -0
  17. package/src/coordinator/coordinator.ts +275 -0
  18. package/src/custom-select.test.ts +91 -0
  19. package/src/custom-select.ts +209 -0
  20. package/src/index.ts +87 -0
  21. package/src/models-config/models-config.test.ts +88 -0
  22. package/src/models-config/models-config.ts +205 -0
  23. package/src/models-config/scoped-models-editor.test.ts +189 -0
  24. package/src/models-config/scoped-models-editor.ts +412 -0
  25. package/src/models-config/subagent-model-constants.ts +2 -0
  26. package/src/models-config/subagent-model-cycle.ts +53 -0
  27. package/src/models-config/subagent-model-utils.test.ts +250 -0
  28. package/src/models-config/subagent-model-utils.ts +52 -0
  29. package/src/pm-mode.test.ts +324 -0
  30. package/src/pm-mode.ts +142 -0
  31. package/src/prompts/mode.test.ts +289 -0
  32. package/src/prompts/mode.ts +31 -0
  33. package/src/prompts/roles.test.ts +724 -0
  34. package/src/prompts/roles.ts +119 -0
  35. package/src/subagent/activity.test.ts +230 -0
  36. package/src/subagent/activity.ts +60 -0
  37. package/src/subagent/batcher.test.ts +198 -0
  38. package/src/subagent/batcher.ts +51 -0
  39. package/src/subagent/consts.ts +1 -0
  40. package/src/subagent/demo.ts +773 -0
  41. package/src/subagent/fleet.test.ts +1758 -0
  42. package/src/subagent/fleet.ts +376 -0
  43. package/src/subagent/identity.test.ts +31 -0
  44. package/src/subagent/identity.ts +16 -0
  45. package/src/subagent/manager.test.ts +392 -0
  46. package/src/subagent/manager.ts +277 -0
  47. package/src/subagent/tools.ts +314 -0
  48. package/src/subagent/viewer.ts +305 -0
  49. package/src/types.ts +15 -0
  50. package/src/ui/border-view.ts +50 -0
  51. package/src/ui/review-pager.ts +146 -0
  52. package/src/ui/scroll-view.test.ts +190 -0
  53. package/src/ui/scroll-view.ts +155 -0
  54. package/src/utils/format.test.ts +76 -0
  55. package/src/utils/format.ts +67 -0
  56. package/src/utils/fs.ts +9 -0
  57. package/src/utils/markdown.test.ts +442 -0
  58. package/src/utils/markdown.ts +79 -0
  59. package/src/utils/messages.test.ts +436 -0
  60. package/src/utils/messages.ts +131 -0
  61. package/src/utils/model-ref.test.ts +42 -0
  62. package/src/utils/model-ref.ts +44 -0
  63. package/src/utils/state.test.ts +98 -0
  64. package/src/utils/state.ts +45 -0
  65. package/src/utils/tools.ts +48 -0
  66. package/src/utils/truncate.test.ts +41 -0
  67. package/src/utils/truncate.ts +59 -0
  68. package/tsconfig.json +24 -0
  69. package/vitest.config.ts +8 -0
@@ -0,0 +1,773 @@
1
+ import type {
2
+ AssistantMessage,
3
+ ImageContent,
4
+ Message,
5
+ TextContent,
6
+ ToolCall,
7
+ ToolResultMessage,
8
+ Usage,
9
+ UserMessage,
10
+ } from '@earendil-works/pi-ai'
11
+ import type {
12
+ AgentSession,
13
+ AgentSessionEventListener,
14
+ ContextUsage,
15
+ PromptOptions,
16
+ } from '@earendil-works/pi-coding-agent'
17
+
18
+ import type { LiveSubagent } from './manager.js'
19
+ import { SubagentManager } from './manager.js'
20
+
21
+ type MockAgentSession = Pick<
22
+ AgentSession,
23
+ 'messages' | 'dispose' | 'abort' | 'steer' | 'subscribe' | 'prompt'
24
+ >
25
+
26
+ export class SubagentManagerDemo extends SubagentManager {
27
+ readonly #subagents: LiveSubagent[] = initialDemoSubagents()
28
+
29
+ override list(): LiveSubagent[] {
30
+ return [...this.#subagents]
31
+ }
32
+
33
+ override get(id: number): LiveSubagent | undefined {
34
+ return this.#subagents.find((w) => w.id === id)
35
+ }
36
+
37
+ override latest(): LiveSubagent | undefined {
38
+ return this.#subagents[this.#subagents.length - 1]
39
+ }
40
+
41
+ override createNewSubagent(): Promise<LiveSubagent> {
42
+ return Promise.reject(
43
+ new Error('spawn is not supported for demo subagents'),
44
+ )
45
+ }
46
+
47
+ override steer(): Promise<boolean> {
48
+ return Promise.resolve(false)
49
+ }
50
+
51
+ override async abort(id: number): Promise<boolean> {
52
+ const subagent = this.get(id)
53
+ if (!subagent || subagent.status !== 'running') return false
54
+ subagent.status = 'killed'
55
+ subagent.completedAt = Date.now()
56
+ return true
57
+ }
58
+
59
+ add(prompt?: string): void {
60
+ this.#subagents.push({
61
+ id: this.#subagents.length + 1,
62
+ title: prompt ?? 'Review and fix authentication flow',
63
+ previousEntries: [],
64
+ prompt: prompt ?? 'Review and fix authentication flow',
65
+ status: 'running',
66
+ startedAt: Date.now() - 600000,
67
+ completedAt: undefined,
68
+ followUpCount: 0,
69
+ activeTools: ['read', 'write', 'bash'],
70
+ session: mockSessionFor('2'),
71
+ role: 'worker',
72
+ contextUsage: normalContextUsage(),
73
+ })
74
+ }
75
+ }
76
+
77
+ function initialDemoSubagents(): LiveSubagent[] {
78
+ const now = Date.now()
79
+ return [
80
+ {
81
+ id: 1,
82
+ title: 'Review and fix authentication flow',
83
+ previousEntries: [
84
+ {
85
+ title: 'Check JWT validation logic',
86
+ status: 'done',
87
+ followUpCount: 1,
88
+ startedAt: now - 3500000,
89
+ completedAt: now - 3000000,
90
+ },
91
+ {
92
+ title: 'Initial authentication review',
93
+ status: 'done',
94
+ followUpCount: 0,
95
+ startedAt: now - 3600000,
96
+ completedAt: now - 3500000,
97
+ },
98
+ ],
99
+ prompt: 'Review and fix authentication flow',
100
+ status: 'done',
101
+ startedAt: now - 3000000,
102
+ completedAt: now - 3000000,
103
+ followUpCount: 2,
104
+ activeTools: ['read', 'edit', 'bash'],
105
+ session: mockSessionFor('1', 6),
106
+ role: 'reviewer',
107
+ contextUsage: normalContextUsage(),
108
+ },
109
+ {
110
+ id: 2,
111
+ title: 'Add unit tests for API endpoints',
112
+ previousEntries: [],
113
+ prompt: 'Add unit tests for API endpoints',
114
+ status: 'running',
115
+ startedAt: now - 600000,
116
+ completedAt: undefined,
117
+ followUpCount: 0,
118
+ activeTools: ['read', 'write', 'bash'],
119
+ session: mockSessionFor('2', 6),
120
+ role: 'tester',
121
+ contextUsage: normalContextUsage(),
122
+ },
123
+ {
124
+ id: 3,
125
+ title: 'Update dependencies and fix breaking changes\nClean local cache',
126
+ previousEntries: [
127
+ {
128
+ title: 'Review React 19 compatibility',
129
+ status: 'done',
130
+ followUpCount: 1,
131
+ startedAt: now - 1100000,
132
+ completedAt: now - 900000,
133
+ },
134
+ {
135
+ title: 'Check for outdated dependencies',
136
+ status: 'done',
137
+ followUpCount: 0,
138
+ startedAt: now - 1200000,
139
+ completedAt: now - 1100000,
140
+ },
141
+ ],
142
+ prompt: 'Update dependencies and fix breaking changes\nClean local cache',
143
+ status: 'failed',
144
+ startedAt: now - 900000,
145
+ completedAt: now - 900000,
146
+ followUpCount: 2,
147
+ activeTools: ['read', 'bash'],
148
+ session: mockSessionFor('3', 6),
149
+ role: 'investigator',
150
+ contextUsage: highContextUsage(),
151
+ },
152
+ {
153
+ id: 4,
154
+ title: 'Optimize database queries for dashboard',
155
+ previousEntries: [
156
+ {
157
+ title: 'Analyze dashboard query performance',
158
+ status: 'done',
159
+ followUpCount: 0,
160
+ startedAt: now - 1700000,
161
+ completedAt: now - 1500000,
162
+ },
163
+ ],
164
+ prompt: 'Optimize database queries for dashboard',
165
+ status: 'killed',
166
+ startedAt: now - 1500000,
167
+ completedAt: now - 1500000,
168
+ followUpCount: 1,
169
+ activeTools: ['read', 'edit'],
170
+ session: mockSessionFor('4', 6),
171
+ role: 'worker',
172
+ contextUsage: unknownTokensContextUsage(),
173
+ },
174
+ {
175
+ id: 5,
176
+ title: 'Write documentation for new features',
177
+ previousEntries: [],
178
+ prompt: 'Write documentation for new features',
179
+ status: 'done',
180
+ startedAt: now - 7200000,
181
+ completedAt: now - 6000000,
182
+ followUpCount: 0,
183
+ activeTools: ['read', 'write'],
184
+ session: mockSessionFor('5', 6),
185
+ role: 'docs',
186
+ },
187
+ {
188
+ id: 6,
189
+ title: 'Migrate legacy config parser to new schema',
190
+ previousEntries: [],
191
+ prompt: 'Migrate legacy config parser to new schema',
192
+ status: 'running',
193
+ startedAt: now - 95000000,
194
+ completedAt: undefined,
195
+ followUpCount: 0,
196
+ activeTools: ['read', 'edit', 'bash'],
197
+ session: mockSessionFor('6', 6),
198
+ role: 'worker',
199
+ contextUsage: nearFullContextUsage(),
200
+ },
201
+ {
202
+ id: 7,
203
+ title:
204
+ 'Investigate flaky integration test in CI pipeline for pull request validation workflow',
205
+ previousEntries: [
206
+ {
207
+ title: 'Re-run failed CI workflow for logs',
208
+ status: 'done',
209
+ followUpCount: 2,
210
+ startedAt: now - 900000,
211
+ completedAt: now - 700000,
212
+ },
213
+ {
214
+ title: 'Collect flaky test reports',
215
+ status: 'done',
216
+ followUpCount: 1,
217
+ startedAt: now - 1000000,
218
+ completedAt: now - 900000,
219
+ },
220
+ ],
221
+ prompt:
222
+ 'Investigate flaky integration test in CI pipeline for pull request validation workflow',
223
+ status: 'running',
224
+ startedAt: now - 240000,
225
+ completedAt: undefined,
226
+ followUpCount: 3,
227
+ activeTools: ['read', 'bash'],
228
+ session: mockSessionFor('7', 6),
229
+ role: 'investigator',
230
+ contextUsage: normalContextUsage(),
231
+ },
232
+ {
233
+ id: 8,
234
+ title: 'Audit repository for hardcoded secrets',
235
+ previousEntries: [
236
+ {
237
+ title: 'Check environment template files',
238
+ status: 'done',
239
+ followUpCount: 3,
240
+ startedAt: now - 108000000,
241
+ completedAt: now - 105000000,
242
+ },
243
+ {
244
+ title: 'Scan git history for leaked keys',
245
+ status: 'done',
246
+ followUpCount: 2,
247
+ startedAt: now - 110000000,
248
+ completedAt: now - 108000000,
249
+ },
250
+ {
251
+ title: 'Initial secrets audit',
252
+ status: 'done',
253
+ followUpCount: 1,
254
+ startedAt: now - 110500000,
255
+ completedAt: now - 110000000,
256
+ },
257
+ ],
258
+ prompt: 'Audit repository for hardcoded secrets',
259
+ status: 'done',
260
+ startedAt: now - 105000000,
261
+ completedAt: now - 96000000,
262
+ followUpCount: 4,
263
+ activeTools: ['read', 'bash'],
264
+ session: mockSessionFor('8', 6),
265
+ role: 'reviewer',
266
+ contextUsage: highContextUsage(),
267
+ },
268
+ {
269
+ id: 9,
270
+ title: 'Verify release checklist for v2.4.0\nCheck changelog entries',
271
+ previousEntries: [
272
+ {
273
+ title: 'Diff package version against tags',
274
+ status: 'done',
275
+ followUpCount: 0,
276
+ startedAt: now - 60000,
277
+ completedAt: now - 45000,
278
+ },
279
+ ],
280
+ prompt: 'Verify release checklist for v2.4.0\nCheck changelog entries',
281
+ status: 'failed',
282
+ startedAt: now - 45000,
283
+ completedAt: now - 30000,
284
+ followUpCount: 1,
285
+ activeTools: ['read', 'bash'],
286
+ session: mockSessionFor('9', 6),
287
+ role: 'tester',
288
+ contextUsage: unknownTokensContextUsage(),
289
+ },
290
+ ]
291
+ }
292
+
293
+ function normalContextUsage(): ContextUsage {
294
+ return { tokens: 60000, contextWindow: 200000, percent: 30.0 }
295
+ }
296
+
297
+ function highContextUsage(): ContextUsage {
298
+ return { tokens: 160000, contextWindow: 200000, percent: 80.0 }
299
+ }
300
+
301
+ function unknownTokensContextUsage(): ContextUsage {
302
+ return { tokens: null, contextWindow: 200000, percent: null }
303
+ }
304
+
305
+ function nearFullContextUsage(): ContextUsage {
306
+ return { tokens: 187000, contextWindow: 200000, percent: 93.5 }
307
+ }
308
+
309
+ const MOCK_USAGE: Usage = {
310
+ input: 1000,
311
+ output: 500,
312
+ cacheRead: 0,
313
+ cacheWrite: 0,
314
+ totalTokens: 1500,
315
+ cost: {
316
+ input: 0.001,
317
+ output: 0.002,
318
+ cacheRead: 0,
319
+ cacheWrite: 0,
320
+ total: 0.003,
321
+ },
322
+ }
323
+
324
+ function userMessage(text: string): UserMessage {
325
+ return {
326
+ role: 'user',
327
+ content: text,
328
+ timestamp: Date.now(),
329
+ }
330
+ }
331
+
332
+ function assistantMessage(
333
+ text: string,
334
+ toolCalls: ToolCall[] = [],
335
+ ): AssistantMessage {
336
+ const content: (TextContent | ToolCall)[] = [
337
+ { type: 'text', text },
338
+ ...toolCalls,
339
+ ]
340
+ return {
341
+ role: 'assistant',
342
+ content,
343
+ api: 'anthropic-messages',
344
+ provider: 'anthropic',
345
+ model: 'claude-sonnet-4-20250514',
346
+ usage: MOCK_USAGE,
347
+ stopReason: 'stop',
348
+ timestamp: Date.now(),
349
+ }
350
+ }
351
+
352
+ function toolResultMessage(
353
+ toolCallId: string,
354
+ toolName: string,
355
+ text: string,
356
+ isError = false,
357
+ ): ToolResultMessage {
358
+ return {
359
+ role: 'toolResult',
360
+ toolCallId,
361
+ toolName,
362
+ content: [{ type: 'text', text }],
363
+ isError,
364
+ timestamp: Date.now(),
365
+ }
366
+ }
367
+
368
+ function mockSessionFor(key: string, repeat: number = 1): AgentSession {
369
+ const baseMessages = MOCK_MESSAGES[key]
370
+ if (!baseMessages) {
371
+ throw new Error(`Unknown mock key: ${key}`)
372
+ }
373
+
374
+ const messages: Message[] = []
375
+
376
+ for (let r = 1; r <= repeat; r++) {
377
+ let isFirstUserOfRound = true
378
+
379
+ for (const msg of baseMessages) {
380
+ if (msg.role === 'user') {
381
+ const userContent =
382
+ typeof msg.content === 'string' && isFirstUserOfRound && r > 1
383
+ ? `${msg.content} (run ${r})`
384
+ : msg.content
385
+ const cloned: UserMessage = {
386
+ role: 'user',
387
+ content: userContent,
388
+ timestamp: msg.timestamp,
389
+ }
390
+ messages.push(cloned)
391
+ isFirstUserOfRound = false
392
+ } else if (msg.role === 'assistant') {
393
+ const content: (TextContent | ToolCall)[] = []
394
+ for (const item of msg.content) {
395
+ if (item.type === 'toolCall') {
396
+ content.push({
397
+ type: 'toolCall',
398
+ id: r > 1 ? `${item.id}_r${r}` : item.id,
399
+ name: item.name,
400
+ arguments: item.arguments,
401
+ })
402
+ } else if (item.type === 'text') {
403
+ content.push({ type: 'text', text: item.text })
404
+ }
405
+ }
406
+
407
+ const cloned: AssistantMessage = {
408
+ role: 'assistant',
409
+ content,
410
+ api: msg.api,
411
+ provider: msg.provider,
412
+ model: msg.model,
413
+ usage: msg.usage,
414
+ stopReason: msg.stopReason,
415
+ timestamp: msg.timestamp,
416
+ }
417
+ messages.push(cloned)
418
+ } else {
419
+ const cloned: ToolResultMessage = {
420
+ role: 'toolResult',
421
+ toolCallId: r > 1 ? `${msg.toolCallId}_r${r}` : msg.toolCallId,
422
+ toolName: msg.toolName,
423
+ content: msg.content.map((block) => {
424
+ if (block.type === 'text') {
425
+ return { type: 'text' as const, text: block.text }
426
+ }
427
+ return {
428
+ type: 'image' as const,
429
+ data: block.data,
430
+ mimeType: block.mimeType,
431
+ }
432
+ }),
433
+ isError: msg.isError,
434
+ timestamp: msg.timestamp,
435
+ }
436
+ messages.push(cloned)
437
+ }
438
+ }
439
+ }
440
+
441
+ const session: MockAgentSession = {
442
+ messages,
443
+ dispose: () => {},
444
+ abort: async () => {},
445
+ steer: async (_text: string, _images?: ImageContent[]) => {
446
+ void _text
447
+ void _images
448
+ },
449
+ subscribe: (_listener: AgentSessionEventListener) => {
450
+ void _listener
451
+ return () => {}
452
+ },
453
+ prompt: async (_text: string, _options?: PromptOptions) => {
454
+ void _text
455
+ void _options
456
+ },
457
+ }
458
+
459
+ return session as AgentSession
460
+ }
461
+
462
+ const MOCK_MESSAGES: Record<string, Message[]> = {
463
+ '1': [
464
+ userMessage('Review and fix authentication flow'),
465
+ assistantMessage(
466
+ 'Looking at the auth code to identify potential issues...',
467
+ ),
468
+ assistantMessage("I'll read the authentication module first.", [
469
+ {
470
+ type: 'toolCall',
471
+ id: 'call_001',
472
+ name: 'read',
473
+ arguments: { path: 'src/auth/jwt.ts' },
474
+ },
475
+ ]),
476
+ toolResultMessage(
477
+ 'call_001',
478
+ 'read',
479
+ `export function validateToken(token: string): boolean {
480
+ try {
481
+ const decoded = jwt.verify(token, SECRET_KEY)
482
+ return decoded.exp > Date.now() / 1000
483
+ } catch (error) {
484
+ console.error('Token validation failed:', error)
485
+ return false
486
+ }
487
+ }
488
+
489
+ // TODO: Add proper error types and logging`,
490
+ ),
491
+ assistantMessage(
492
+ 'Found the issue. The error handling needs improvement and the expiration check should be more explicit. Let me fix it.',
493
+ ),
494
+ assistantMessage('Fixed JWT token validation and updated error handling.'),
495
+ ],
496
+ '2': [
497
+ userMessage('Add unit tests for API endpoints'),
498
+ assistantMessage(
499
+ "I'll write unit tests for the API endpoints. Let me check what's already covered.",
500
+ ),
501
+ assistantMessage(
502
+ 'Running the existing tests to see the current coverage.',
503
+ [
504
+ {
505
+ type: 'toolCall',
506
+ id: 'call_002',
507
+ name: 'bash',
508
+ arguments: {
509
+ command: 'pnpm test -- --coverage',
510
+ },
511
+ },
512
+ ],
513
+ ),
514
+ toolResultMessage(
515
+ 'call_002',
516
+ 'bash',
517
+ `PASS src/api/user.test.ts
518
+ User endpoints
519
+ ✓ GET /api/users (45ms)
520
+ ✓ POST /api/users (62ms)
521
+
522
+ Coverage Report:
523
+ -----------------
524
+ File | % Stmts | % Branch | % Funcs | % Lines
525
+ ------------------------|---------|----------|---------|--------
526
+ src/api/user.ts | 78.95 | 66.67 | 100 | 77.78
527
+ src/api/auth.ts | 45.00 | 0 | 50 | 45.00
528
+ ------------------------|---------|----------|---------|--------
529
+ All files | 61.98 | 33.33 | 75 | 61.38`,
530
+ ),
531
+ assistantMessage(
532
+ "Good coverage on user endpoints but auth tests are missing. I'll add those now...",
533
+ ),
534
+ ],
535
+ '3': [
536
+ userMessage('Update dependencies and fix breaking changes'),
537
+ assistantMessage(
538
+ "I'll update the dependencies to the latest versions and check for breaking changes.",
539
+ ),
540
+ assistantMessage('Running npm update...', [
541
+ {
542
+ type: 'toolCall',
543
+ id: 'call_003',
544
+ name: 'bash',
545
+ arguments: {
546
+ command: 'npm update',
547
+ },
548
+ },
549
+ ]),
550
+ toolResultMessage(
551
+ 'call_003',
552
+ 'bash',
553
+ `npm ERR! code ERESOLVE
554
+ npm ERR! ERESOLVE unable to resolve dependency tree
555
+ npm ERR!
556
+ npm ERR! While resolving: pi-pm-subagents@1.0.0
557
+ npm ERR! Found: react@19.0.0
558
+ npm ERR! node_modules/react
559
+ npm ERR! react@"^19.0.0" from the root project
560
+ npm ERR!
561
+ npm ERR! Could not resolve dependency:
562
+ npm ERR! peer react@"^18.0.0" from some-library@2.5.0
563
+ npm ERR! node_modules/some-library
564
+ npm ERR! some-library@"^2.5.0" from the root project
565
+ npm ERR!
566
+ npm ERR! Fix the upstream dependency conflict, or retry`,
567
+ true,
568
+ ),
569
+ assistantMessage(
570
+ "There's a peer dependency conflict with React 19. The library `some-library` requires React 18 but we're using React 19. We need to either downgrade React or find a compatible version of the library.",
571
+ ),
572
+ ],
573
+ '4': [
574
+ userMessage('Optimize database queries for dashboard'),
575
+ assistantMessage(
576
+ "I'll analyze the database queries used in the dashboard and optimize them for better performance.",
577
+ ),
578
+ assistantMessage(
579
+ 'Reading the query files to identify optimization opportunities.',
580
+ [
581
+ {
582
+ type: 'toolCall',
583
+ id: 'call_004',
584
+ name: 'read',
585
+ arguments: { path: 'src/queries/dashboard.sql' },
586
+ },
587
+ ],
588
+ ),
589
+ toolResultMessage(
590
+ 'call_004',
591
+ 'read',
592
+ `-- Dashboard analytics query
593
+ SELECT
594
+ users.id,
595
+ users.name,
596
+ COUNT(sessions.id) as session_count,
597
+ AVG(sessions.duration) as avg_duration
598
+ FROM users
599
+ LEFT JOIN sessions ON users.id = sessions.user_id
600
+ LEFT JOIN events ON sessions.id = events.session_id
601
+ WHERE users.created_at > NOW() - INTERVAL '30 days'
602
+ GROUP BY users.id
603
+ ORDER BY session_count DESC
604
+ LIMIT 100;`,
605
+ ),
606
+ assistantMessage(
607
+ 'I can see several optimization opportunities here. The query could benefit from proper indexing on user_id and created_at columns, and the LEFT JOIN with events is unnecessary for the current metrics. Let me create an optimized version...',
608
+ ),
609
+ ],
610
+ '5': [
611
+ userMessage('Write documentation for new features'),
612
+ assistantMessage(
613
+ "I'll write comprehensive documentation for the new features, including usage examples and API references.",
614
+ ),
615
+ assistantMessage('Creating the main README file.', [
616
+ {
617
+ type: 'toolCall',
618
+ id: 'call_005',
619
+ name: 'write',
620
+ arguments: {
621
+ path: 'docs/FEATURES.md',
622
+ content: `# New Features
623
+
624
+ ## Subagent Mode
625
+ Subagent mode allows you to delegate complex tasks to autonomous agents.
626
+
627
+ ### Usage
628
+
629
+ \`\`\`typescript
630
+ const subagent = await subagentManager.spawn(
631
+ 'Analyze performance',
632
+ 'Profile the main loop and identify bottlenecks',
633
+ { cwd: '/path/to/project' }
634
+ )
635
+ \`\`\`
636
+
637
+ ### Features
638
+ - Async task execution
639
+ - Real-time progress tracking
640
+ - Automatic tool selection
641
+ - Error handling and retry
642
+
643
+ ## API Reference
644
+
645
+ See [API.md](./API.md) for detailed documentation.
646
+ `,
647
+ },
648
+ },
649
+ ]),
650
+ toolResultMessage('call_005', 'write', 'OK'),
651
+ assistantMessage(
652
+ "Documentation written successfully. I've also updated the README with a quick start guide and added the API reference section.",
653
+ ),
654
+ ],
655
+ '6': [
656
+ userMessage('Migrate legacy config parser to new schema'),
657
+ assistantMessage(
658
+ "I'll port the legacy parser to the new schema while keeping backward compatibility.",
659
+ ),
660
+ assistantMessage('Reading the legacy parser implementation first.', [
661
+ {
662
+ type: 'toolCall',
663
+ id: 'call_006',
664
+ name: 'read',
665
+ arguments: { path: 'src/config/legacy-parser.ts' },
666
+ },
667
+ ]),
668
+ toolResultMessage(
669
+ 'call_006',
670
+ 'read',
671
+ `export function parseLegacyConfig(raw: string): Config {
672
+ const entries = raw.split(';').filter(Boolean)
673
+ const config: Record<string, string> = {}
674
+ for (const entry of entries) {
675
+ const [key, value] = entry.split('=', 2)
676
+ if (!key || value === undefined) continue
677
+ config[key.trim()] = value.trim()
678
+ }
679
+ return config as Config
680
+ }`,
681
+ ),
682
+ assistantMessage(
683
+ 'The legacy parser accepts semicolon-separated key/value pairs and silently drops malformed entries. I will keep that behavior in the new schema loader and add a compatibility shim for old config files.',
684
+ ),
685
+ ],
686
+ '7': [
687
+ userMessage(
688
+ 'Investigate flaky integration test in CI pipeline for pull request validation workflow',
689
+ ),
690
+ assistantMessage(
691
+ "I'll start from the failure logs of the most recent red CI runs.",
692
+ ),
693
+ assistantMessage('Fetching the failed run logs.', [
694
+ {
695
+ type: 'toolCall',
696
+ id: 'call_007',
697
+ name: 'bash',
698
+ arguments: {
699
+ command:
700
+ 'gh run list --status failure --limit 5 && gh run view --log-failed | tail -n 60',
701
+ },
702
+ },
703
+ ]),
704
+ toolResultMessage(
705
+ 'call_007',
706
+ 'bash',
707
+ `integrations/webhook.test.ts > delivers PR validation event (2/10 runs failed)
708
+ Error: Test timed out after 30000ms
709
+ at onWebhookReceived (integrations/webhook.test.ts:84:11)
710
+ at Timeout.callback [as _onTimeout] (node:internal/timers:494:15)
711
+
712
+ Summary: 27 failed runs in the last 14 days, all in integrations/webhook.test.ts,
713
+ all timing out while waiting for the mock registry to answer.`,
714
+ ),
715
+ assistantMessage(
716
+ 'All recent failures are timeouts in integrations/webhook.test.ts while waiting for the mock webhook registry, which only warms up on a cold runner. Next I will add a readiness probe before the test asserts.',
717
+ ),
718
+ ],
719
+ '8': [
720
+ userMessage('Audit repository for hardcoded secrets'),
721
+ assistantMessage(
722
+ "I'll scan tracked files for common credential patterns and report findings.",
723
+ ),
724
+ assistantMessage('Running the pattern scan.', [
725
+ {
726
+ type: 'toolCall',
727
+ id: 'call_008',
728
+ name: 'bash',
729
+ arguments: {
730
+ command:
731
+ "git ls-files | xargs grep -lniE '(api[_-]?key|secret|password)\\s*='",
732
+ },
733
+ },
734
+ ]),
735
+ toolResultMessage(
736
+ 'call_008',
737
+ 'bash',
738
+ `test/fixtures/config.ts
739
+ docs/examples/quickstart.md
740
+ src/__tests__/auth.test.ts
741
+
742
+ grep: 3 files matched`,
743
+ ),
744
+ assistantMessage(
745
+ 'All three matches are test fixtures and documentation examples using placeholder values. No real credentials found — the audit is clean.',
746
+ ),
747
+ ],
748
+ '9': [
749
+ userMessage('Verify release checklist for v2.4.0'),
750
+ assistantMessage(
751
+ "I'll verify the release checklist items against the repository state.",
752
+ ),
753
+ assistantMessage('Checking the changelog for the 2.4.0 section.', [
754
+ {
755
+ type: 'toolCall',
756
+ id: 'call_009',
757
+ name: 'bash',
758
+ arguments: {
759
+ command: "grep -n '^## 2.4.0' CHANGELOG.md",
760
+ },
761
+ },
762
+ ]),
763
+ toolResultMessage(
764
+ 'call_009',
765
+ 'bash',
766
+ 'Error: Command failed with exit code 1\nNo CHANGELOG.md entry found for version 2.4.0',
767
+ true,
768
+ ),
769
+ assistantMessage(
770
+ 'The release checklist check failed: CHANGELOG.md has no 2.4.0 section and package.json still reports 2.3.1. Both need to be updated before tagging the release.',
771
+ ),
772
+ ],
773
+ }