vibeman 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 (71) hide show
  1. package/dist/index.js +5 -7
  2. package/dist/runtime/api/.tsbuildinfo +1 -1
  3. package/dist/runtime/api/agent/agent-service.d.ts +11 -13
  4. package/dist/runtime/api/agent/agent-service.js +25 -31
  5. package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +2 -2
  6. package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +25 -36
  7. package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +48 -14
  8. package/dist/runtime/api/agent/ai-providers/types.d.ts +2 -0
  9. package/dist/runtime/api/agent/codex-cli-provider.test.js +37 -0
  10. package/dist/runtime/api/agent/parsers.d.ts +1 -0
  11. package/dist/runtime/api/agent/parsers.js +75 -8
  12. package/dist/runtime/api/agent/prompt-service.d.ts +14 -1
  13. package/dist/runtime/api/agent/prompt-service.js +123 -14
  14. package/dist/runtime/api/agent/prompt-service.test.d.ts +1 -0
  15. package/dist/runtime/api/agent/prompt-service.test.js +230 -0
  16. package/dist/runtime/api/agent/routing-policy.d.ts +14 -14
  17. package/dist/runtime/api/api/routers/ai.d.ts +6 -6
  18. package/dist/runtime/api/api/routers/ai.js +2 -17
  19. package/dist/runtime/api/api/routers/executions.d.ts +5 -5
  20. package/dist/runtime/api/api/routers/executions.js +12 -21
  21. package/dist/runtime/api/api/routers/provider-config.d.ts +165 -0
  22. package/dist/runtime/api/api/routers/provider-config.js +252 -0
  23. package/dist/runtime/api/api/routers/tasks.d.ts +10 -10
  24. package/dist/runtime/api/api/routers/workflows.d.ts +15 -16
  25. package/dist/runtime/api/api/routers/workflows.js +28 -26
  26. package/dist/runtime/api/api/routers/worktrees.d.ts +4 -5
  27. package/dist/runtime/api/api/routers/worktrees.js +11 -11
  28. package/dist/runtime/api/api/trpc.d.ts +18 -18
  29. package/dist/runtime/api/index.js +2 -10
  30. package/dist/runtime/api/lib/local-config.d.ts +245 -0
  31. package/dist/runtime/api/lib/local-config.js +288 -0
  32. package/dist/runtime/api/lib/provider-detection.d.ts +59 -0
  33. package/dist/runtime/api/lib/provider-detection.js +244 -0
  34. package/dist/runtime/api/lib/server/bootstrap.d.ts +38 -0
  35. package/dist/runtime/api/lib/server/bootstrap.js +197 -0
  36. package/dist/runtime/api/lib/server/project-root.js +24 -1
  37. package/dist/runtime/api/lib/trpc/server.d.ts +124 -31
  38. package/dist/runtime/api/lib/trpc/server.js +8 -8
  39. package/dist/runtime/api/lib/trpc/ws-server.js +2 -2
  40. package/dist/runtime/api/router.d.ts +125 -32
  41. package/dist/runtime/api/router.js +9 -31
  42. package/dist/runtime/api/settings-service.js +2 -0
  43. package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +8 -3
  44. package/dist/runtime/api/workflows/vibing-orchestrator.js +182 -183
  45. package/dist/runtime/web/.next/BUILD_ID +1 -1
  46. package/dist/runtime/web/.next/app-build-manifest.json +2 -2
  47. package/dist/runtime/web/.next/build-manifest.json +2 -2
  48. package/dist/runtime/web/.next/prerender-manifest.json +3 -3
  49. package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  50. package/dist/runtime/web/.next/server/app/_not-found.html +2 -2
  51. package/dist/runtime/web/.next/server/app/_not-found.rsc +5 -5
  52. package/dist/runtime/web/.next/server/app/api/health/route.js +1 -1
  53. package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  54. package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +1 -1
  55. package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +1 -1
  56. package/dist/runtime/web/.next/server/app/index.html +2 -2
  57. package/dist/runtime/web/.next/server/app/index.rsc +6 -6
  58. package/dist/runtime/web/.next/server/app/page.js +3 -3
  59. package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +1 -1
  60. package/dist/runtime/web/.next/server/chunks/458.js +1 -1
  61. package/dist/runtime/web/.next/server/pages/404.html +2 -2
  62. package/dist/runtime/web/.next/server/pages/500.html +1 -1
  63. package/dist/runtime/web/.next/server/pages-manifest.json +1 -1
  64. package/dist/runtime/web/.next/server/server-reference-manifest.json +1 -1
  65. package/dist/runtime/web/.next/static/chunks/app/{layout-dc0cfd29075b2160.js → layout-8435322f09fd0975.js} +1 -1
  66. package/dist/runtime/web/.next/static/chunks/app/page-8c3ba579efc6f918.js +1 -0
  67. package/dist/tsconfig.tsbuildinfo +1 -1
  68. package/package.json +5 -1
  69. package/dist/runtime/web/.next/static/chunks/app/page-f34a8b196b18850b.js +0 -1
  70. /package/dist/runtime/web/.next/static/{1HR8N0rJkCvFRtbTPJMyH → mRpNgPfbYR_0wrODzlg_4}/_buildManifest.js +0 -0
  71. /package/dist/runtime/web/.next/static/{1HR8N0rJkCvFRtbTPJMyH → mRpNgPfbYR_0wrODzlg_4}/_ssgManifest.js +0 -0
@@ -4,13 +4,26 @@ export declare class PromptService {
4
4
  private projectRoot;
5
5
  private taskService;
6
6
  constructor(projectRoot: string, taskService: TaskService);
7
+ /**
8
+ * Generate absolute path to task file
9
+ */
10
+ private generateTaskFilePath;
11
+ /**
12
+ * Validate that task file exists at the given path
13
+ */
14
+ private validateTaskFile;
7
15
  generateImprovementPrompt(task: Task, taskData: {
8
16
  title: string;
9
17
  type: string;
10
18
  priority: string;
11
19
  content: string;
12
20
  }): Promise<string>;
13
- generateTaskPrompt(task: Task): Promise<string>;
21
+ generateTaskPrompt(task: Task, workflowConfig?: import('../types/index.js').VibingConfig): Promise<string>;
22
+ /**
23
+ * Build a prominent, clearly formatted instruction section derived from workflow options.
24
+ * If no options are provided or none apply, returns a minimal guidance line.
25
+ */
26
+ private buildWorkflowInstructions;
14
27
  generateAIMergePrompt(task: Task, worktree: WorktreeInfo, baseBranch?: string): Promise<string>;
15
28
  generateReviewPrompt(task: Task, worktree: WorktreeInfo, reviewContext?: string): Promise<string>;
16
29
  }
@@ -70,8 +70,11 @@ If you recommend changes to type or priority, include them at the top of your re
70
70
  Return a JSON object with:
71
71
  - "type": one of [feature, bug, chore, refactor, test, doc]
72
72
  - "priority": one of [high, medium, low]
73
+ - "title": a concise, descriptive title for the task (optional, but preferred)
73
74
  - "content": the improved task specification in markdown format with proper JSON escaping
74
75
 
76
+ If you include a title in the JSON response, do NOT include an H1 heading at the beginning of the content field to avoid duplication.
77
+
75
78
  ## Project Context
76
79
 
77
80
  <ProjectContext>
@@ -95,6 +98,10 @@ const TASK_TEMPLATE = `## Task Assignment
95
98
 
96
99
  Deliver the following task.
97
100
 
101
+ ## Workflow Instructions
102
+
103
+ {{workflowInstructions}}
104
+
98
105
  ## Responsibilities
99
106
 
100
107
  1. **Analyze requirements** — study the acceptance criteria to clarify what must be delivered.
@@ -132,6 +139,8 @@ Begin by examining the codebase; then proceed with the implementation.
132
139
  - **Status:** {{taskStatus}}
133
140
  - **Tags:** {{tagsList}}
134
141
 
142
+ {{taskFilePathInfo}}
143
+
135
144
  #### Description
136
145
 
137
146
  {{taskContent}}
@@ -155,7 +164,7 @@ If conflicts:
155
164
  `;
156
165
  const REVIEW_TEMPLATE = `## Code Review Task
157
166
 
158
- Review the changes made for this task comprehensively.
167
+ Review the changes made for this task comprehensively. Return a JSON string with Fenced JSON.
159
168
 
160
169
  1. **Analyze the implemented changes** by examining the modified files, some of them might be committed in the recent commits
161
170
  2. **Evaluate code quality** including:
@@ -171,17 +180,17 @@ Review the changes made for this task comprehensively.
171
180
  - Implementation matches the task requirements
172
181
  - No unrelated changes were introduced
173
182
 
174
- 4. **Provide structured feedback** using this JSON structure:
183
+ 4. **Provide structured feedback** using this JSON structure with following fields:
184
+
185
+
186
+ "reviewSummary": "Brief overview of the implementation and overall assessment",
187
+ "recommendations": [
188
+ "Specific recommendation 1",
189
+ "Specific recommendation 2",
190
+ "Specific recommendation 3"
191
+ ],
192
+ "qualityScore": 85
175
193
 
176
- {
177
- "reviewSummary": "Brief overview of the implementation and overall assessment",
178
- "recommendations": [
179
- "Specific recommendation 1",
180
- "Specific recommendation 2",
181
- "Specific recommendation 3"
182
- ],
183
- "qualityScore": 85
184
- }
185
194
 
186
195
  ## Review Guidelines
187
196
 
@@ -194,7 +203,7 @@ Review the changes made for this task comprehensively.
194
203
  - Testing & coverage: 0-20
195
204
  - Security & performance considerations: 0-15
196
205
 
197
- If you identify any critical bugs or potential improvements, provide detailed notes, accpetance criteria, implementation details, todo list, etc. in the Recommendations section and return a score below 70. This will trigger a reimplementation based on your feedback.
206
+ If you identify any critical bugs or potential improvements, provide detailed notes, acceptance criteria, implementation details, todo list, etc. in the Recommendations section and return a score below 70. This will trigger a reimplementation based on your feedback.
198
207
 
199
208
  ---
200
209
 
@@ -258,6 +267,32 @@ export class PromptService {
258
267
  this.projectRoot = projectRoot;
259
268
  this.taskService = taskService;
260
269
  }
270
+ /**
271
+ * Generate absolute path to task file
272
+ */
273
+ generateTaskFilePath(taskId) {
274
+ try {
275
+ const vibeDir = getVibeDir();
276
+ const taskFilePath = path.resolve(vibeDir, 'tasks', `${taskId}.md`);
277
+ return taskFilePath;
278
+ }
279
+ catch (error) {
280
+ log.error(`Failed to generate task file path for ${taskId}`, error, 'prompt-service');
281
+ return null;
282
+ }
283
+ }
284
+ /**
285
+ * Validate that task file exists at the given path
286
+ */
287
+ async validateTaskFile(filePath) {
288
+ try {
289
+ await fs.access(filePath, fs.constants.F_OK);
290
+ return true;
291
+ }
292
+ catch {
293
+ return false;
294
+ }
295
+ }
261
296
  async generateImprovementPrompt(task, taskData) {
262
297
  // Read project context
263
298
  const productOverviewPath = path.join(getVibeDir(), 'product_overview.md');
@@ -268,6 +303,12 @@ export class PromptService {
268
303
  catch {
269
304
  log.warn('Could not read product_overview.md for improvement prompt', undefined, 'prompt-service');
270
305
  }
306
+ // Add task file path to project context for improvement prompts
307
+ const taskFilePath = this.generateTaskFilePath(task.id);
308
+ if (taskFilePath && (await this.validateTaskFile(taskFilePath))) {
309
+ productContext += `\n\n**Current task file location:** ${taskFilePath}`;
310
+ log.info(`Task file path included in improvement prompt`, { taskId: task.id, path: taskFilePath }, 'prompt-service');
311
+ }
271
312
  return render(IMPROVEMENT_TEMPLATE, {
272
313
  projectContext: productContext,
273
314
  taskId: task.id,
@@ -278,8 +319,28 @@ export class PromptService {
278
319
  taskContent: taskData.content,
279
320
  });
280
321
  }
281
- async generateTaskPrompt(task) {
322
+ async generateTaskPrompt(task, workflowConfig) {
282
323
  const tagsList = task.tags.join(', ');
324
+ // Generate and validate task file path
325
+ const taskFilePath = this.generateTaskFilePath(task.id);
326
+ let taskFilePathInfo = '';
327
+ if (taskFilePath) {
328
+ const isValid = await this.validateTaskFile(taskFilePath);
329
+ if (isValid) {
330
+ taskFilePathInfo = `- **Current task file:** ${taskFilePath}`;
331
+ log.info(`Task file path included in prompt`, { taskId: task.id, path: taskFilePath }, 'prompt-service');
332
+ }
333
+ else {
334
+ taskFilePathInfo = `- **Task file:** (not accessible at expected path: ${taskFilePath})`;
335
+ log.warn(`Task file not accessible`, { taskId: task.id, path: taskFilePath }, 'prompt-service');
336
+ }
337
+ }
338
+ else {
339
+ taskFilePathInfo = `- **Task file:** (path could not be resolved)`;
340
+ log.error(`Could not generate task file path`, { taskId: task.id }, 'prompt-service');
341
+ }
342
+ // Build workflow instruction prompts based on workflow configuration
343
+ const workflowInstructions = this.buildWorkflowInstructions(workflowConfig);
283
344
  return render(TASK_TEMPLATE, {
284
345
  taskId: task.id,
285
346
  taskTitle: task.title,
@@ -288,8 +349,50 @@ export class PromptService {
288
349
  taskStatus: task.status,
289
350
  taskContent: task.content,
290
351
  tagsList,
352
+ taskFilePathInfo,
353
+ workflowInstructions,
291
354
  });
292
355
  }
356
+ /**
357
+ * Build a prominent, clearly formatted instruction section derived from workflow options.
358
+ * If no options are provided or none apply, returns a minimal guidance line.
359
+ */
360
+ buildWorkflowInstructions(cfg) {
361
+ const lines = [];
362
+ if (!cfg) {
363
+ // Default lightweight guidance when workflow config is unavailable
364
+ return '- Follow project conventions and ask before destructive actions.';
365
+ }
366
+ // Auto Commit disabled prompt
367
+ if (cfg.autoCommit === false) {
368
+ lines.push('IMPORTANT: AUTO COMMIT IS DISABLED');
369
+ lines.push('- DO NOT commit any changes');
370
+ lines.push('- DO NOT run git commit commands');
371
+ lines.push('- Leave all changes staged for manual review');
372
+ lines.push('');
373
+ }
374
+ // PR creation disabled prompt
375
+ if (cfg.createPR === false) {
376
+ lines.push('IMPORTANT: PR CREATION IS DISABLED');
377
+ lines.push('- DO NOT create pull requests');
378
+ lines.push('- DO NOT run gh pr create commands');
379
+ lines.push('- Prepare changes for manual PR creation');
380
+ lines.push('');
381
+ }
382
+ // Auto merge disabled prompt
383
+ if (cfg.autoMerge === false) {
384
+ lines.push('IMPORTANT: AUTO MERGE IS DISABLED');
385
+ lines.push('- DO NOT merge pull requests automatically');
386
+ lines.push('- DO NOT run git merge commands');
387
+ lines.push('- Prepare changes for manual merge approval');
388
+ lines.push('');
389
+ }
390
+ // If nothing matched, provide a simple fallback
391
+ if (lines.length === 0) {
392
+ return '- No special workflow constraints. Proceed with standard process.';
393
+ }
394
+ return lines.join('\n');
395
+ }
293
396
  async generateAIMergePrompt(task, worktree, baseBranch) {
294
397
  const repoPath = this.projectRoot;
295
398
  const featureBr = worktree.branchName;
@@ -321,7 +424,13 @@ export class PromptService {
321
424
  });
322
425
  }
323
426
  async generateReviewPrompt(task, worktree, reviewContext) {
324
- const additionalContext = reviewContext ? `\n**Additional Context:** ${reviewContext}` : '';
427
+ let additionalContext = reviewContext ? `\n**Additional Context:** ${reviewContext}` : '';
428
+ // Add task file path to additional context
429
+ const taskFilePath = this.generateTaskFilePath(task.id);
430
+ if (taskFilePath && (await this.validateTaskFile(taskFilePath))) {
431
+ additionalContext += `\n**Current task file:** ${taskFilePath}`;
432
+ log.info(`Task file path included in review prompt`, { taskId: task.id, path: taskFilePath }, 'prompt-service');
433
+ }
325
434
  return render(REVIEW_TEMPLATE, {
326
435
  taskId: task.id,
327
436
  taskTitle: task.title,
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,230 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import { PromptService } from './prompt-service.js';
5
+ const TEST_DATA_DIR = path.resolve(process.cwd(), '.test-prompt-service');
6
+ const TEST_TASKS_DIR = path.join(TEST_DATA_DIR, 'tasks');
7
+ // Mock getVibeDir to return test directory
8
+ vi.mock('../lib/server/project-root', () => ({
9
+ getVibeDir: () => TEST_DATA_DIR,
10
+ getProjectRoot: () => TEST_DATA_DIR,
11
+ }));
12
+ // Mock TaskService
13
+ const mockTaskService = {
14
+ getTask: vi.fn(),
15
+ getAllTasks: vi.fn(),
16
+ };
17
+ describe('PromptService Task File Path Integration', () => {
18
+ let promptService;
19
+ beforeEach(async () => {
20
+ promptService = new PromptService(TEST_DATA_DIR, mockTaskService);
21
+ // Create test directories
22
+ await fs.mkdir(TEST_TASKS_DIR, { recursive: true });
23
+ });
24
+ afterEach(async () => {
25
+ // Clean up test data
26
+ try {
27
+ await fs.rm(TEST_DATA_DIR, { recursive: true, force: true });
28
+ }
29
+ catch {
30
+ // Ignore cleanup errors
31
+ }
32
+ });
33
+ describe('generateTaskPrompt', () => {
34
+ it('should include absolute path when task file exists', async () => {
35
+ const mockTask = {
36
+ id: 'TEST-TASK-001',
37
+ title: 'Test Task',
38
+ type: 'feature',
39
+ status: 'in-progress',
40
+ priority: 'high',
41
+ tags: ['test'],
42
+ content: 'Test task content',
43
+ created_at: '2024-09-04T12:00:00.000Z',
44
+ updated_at: '2024-09-04T12:00:00.000Z',
45
+ assignee: [],
46
+ comments: [],
47
+ };
48
+ // Create task file
49
+ const taskFilePath = path.join(TEST_TASKS_DIR, 'TEST-TASK-001.md');
50
+ const taskFileContent = `---
51
+ id: TEST-TASK-001
52
+ title: Test Task
53
+ type: feature
54
+ status: in-progress
55
+ priority: high
56
+ tags: test
57
+ ---
58
+
59
+ Test task content`;
60
+ await fs.writeFile(taskFilePath, taskFileContent, 'utf-8');
61
+ const prompt = await promptService.generateTaskPrompt(mockTask);
62
+ expect(prompt).toContain('Current task file:');
63
+ expect(prompt).toContain(taskFilePath);
64
+ expect(prompt).toContain('TEST-TASK-001');
65
+ expect(prompt).toContain('Test Task');
66
+ expect(prompt).toContain('Test task content');
67
+ });
68
+ it('should handle missing task file gracefully', async () => {
69
+ const mockTask = {
70
+ id: 'NONEXISTENT-TASK',
71
+ title: 'Nonexistent Task',
72
+ type: 'bug',
73
+ status: 'backlog',
74
+ priority: 'medium',
75
+ tags: [],
76
+ content: 'This task file does not exist',
77
+ created_at: '2024-09-04T12:00:00.000Z',
78
+ updated_at: '2024-09-04T12:00:00.000Z',
79
+ assignee: [],
80
+ comments: [],
81
+ };
82
+ const prompt = await promptService.generateTaskPrompt(mockTask);
83
+ expect(prompt).toContain('not accessible at expected path');
84
+ expect(prompt).toContain('NONEXISTENT-TASK.md');
85
+ expect(prompt).toContain('Nonexistent Task');
86
+ expect(prompt).toContain('This task file does not exist');
87
+ });
88
+ it('should handle path resolution errors', async () => {
89
+ // Mock generateTaskFilePath to return null (simulating path resolution error)
90
+ const originalGenerateTaskFilePath = promptService.generateTaskFilePath;
91
+ promptService.generateTaskFilePath = vi.fn().mockReturnValue(null);
92
+ const mockTask = {
93
+ id: 'ERROR-TASK',
94
+ title: 'Error Task',
95
+ type: 'chore',
96
+ status: 'review',
97
+ priority: 'low',
98
+ tags: ['error'],
99
+ content: 'Task with path resolution error',
100
+ created_at: '2024-09-04T12:00:00.000Z',
101
+ updated_at: '2024-09-04T12:00:00.000Z',
102
+ assignee: [],
103
+ comments: [],
104
+ };
105
+ const prompt = await promptService.generateTaskPrompt(mockTask);
106
+ expect(prompt).toContain('path could not be resolved');
107
+ expect(prompt).toContain('ERROR-TASK');
108
+ expect(prompt).toContain('Task with path resolution error');
109
+ // Restore original method
110
+ promptService.generateTaskFilePath = originalGenerateTaskFilePath;
111
+ });
112
+ });
113
+ describe('generateImprovementPrompt', () => {
114
+ it('should include task file path in project context', async () => {
115
+ const mockTask = {
116
+ id: 'IMPROVE-TASK-001',
117
+ title: 'Improvement Task',
118
+ type: 'feature',
119
+ status: 'backlog',
120
+ priority: 'medium',
121
+ tags: [],
122
+ content: 'Original content',
123
+ created_at: '2024-09-04T12:00:00.000Z',
124
+ updated_at: '2024-09-04T12:00:00.000Z',
125
+ assignee: [],
126
+ comments: [],
127
+ };
128
+ const taskData = {
129
+ title: 'Improved Task',
130
+ type: 'feature',
131
+ priority: 'high',
132
+ content: 'Improved content',
133
+ };
134
+ // Create task file
135
+ const taskFilePath = path.join(TEST_TASKS_DIR, 'IMPROVE-TASK-001.md');
136
+ await fs.writeFile(taskFilePath, 'Task file content', 'utf-8');
137
+ const prompt = await promptService.generateImprovementPrompt(mockTask, taskData);
138
+ expect(prompt).toContain('Current task file location:');
139
+ expect(prompt).toContain(taskFilePath);
140
+ expect(prompt).toContain('IMPROVE-TASK-001');
141
+ });
142
+ });
143
+ describe('generateReviewPrompt', () => {
144
+ it('should include task file path in additional context', async () => {
145
+ const mockTask = {
146
+ id: 'REVIEW-TASK-001',
147
+ title: 'Review Task',
148
+ type: 'bug',
149
+ status: 'review',
150
+ priority: 'high',
151
+ tags: [],
152
+ content: 'Task under review',
153
+ created_at: '2024-09-04T12:00:00.000Z',
154
+ updated_at: '2024-09-04T12:00:00.000Z',
155
+ assignee: [],
156
+ comments: [],
157
+ };
158
+ const mockWorktree = {
159
+ taskId: 'REVIEW-TASK-001',
160
+ path: '/test/worktree',
161
+ branchName: 'feature/review-task-001',
162
+ };
163
+ // Create task file
164
+ const taskFilePath = path.join(TEST_TASKS_DIR, 'REVIEW-TASK-001.md');
165
+ await fs.writeFile(taskFilePath, 'Review task content', 'utf-8');
166
+ const prompt = await promptService.generateReviewPrompt(mockTask, mockWorktree, 'Custom review context');
167
+ expect(prompt).toContain('Current task file:');
168
+ expect(prompt).toContain(taskFilePath);
169
+ expect(prompt).toContain('Custom review context');
170
+ expect(prompt).toContain('REVIEW-TASK-001');
171
+ });
172
+ });
173
+ describe('cross-platform path resolution', () => {
174
+ it('should generate valid absolute paths on different platforms', async () => {
175
+ const taskId = 'CROSS-PLATFORM-TEST';
176
+ // Test the private method through a task prompt generation
177
+ const mockTask = {
178
+ id: taskId,
179
+ title: 'Cross Platform Test',
180
+ type: 'test',
181
+ status: 'in-progress',
182
+ priority: 'medium',
183
+ tags: [],
184
+ content: 'Cross platform path test',
185
+ created_at: '2024-09-04T12:00:00.000Z',
186
+ updated_at: '2024-09-04T12:00:00.000Z',
187
+ assignee: [],
188
+ comments: [],
189
+ };
190
+ // Create task file
191
+ const taskFilePath = path.join(TEST_TASKS_DIR, `${taskId}.md`);
192
+ await fs.writeFile(taskFilePath, 'Cross platform test content', 'utf-8');
193
+ const prompt = await promptService.generateTaskPrompt(mockTask);
194
+ // Verify the path is absolute and uses correct separators
195
+ const pathMatch = prompt.match(/- \*\*Current task file:\*\* (.+)/);
196
+ expect(pathMatch).toBeTruthy();
197
+ if (pathMatch) {
198
+ const extractedPath = pathMatch[1];
199
+ expect(path.isAbsolute(extractedPath)).toBe(true);
200
+ expect(extractedPath).toContain(taskId);
201
+ expect(extractedPath.endsWith('.md')).toBe(true);
202
+ }
203
+ });
204
+ });
205
+ describe('error handling', () => {
206
+ it('should handle file system permission errors gracefully', async () => {
207
+ const mockTask = {
208
+ id: 'PERMISSION-TEST',
209
+ title: 'Permission Test',
210
+ type: 'chore',
211
+ status: 'backlog',
212
+ priority: 'low',
213
+ tags: [],
214
+ content: 'Permission test content',
215
+ created_at: '2024-09-04T12:00:00.000Z',
216
+ updated_at: '2024-09-04T12:00:00.000Z',
217
+ assignee: [],
218
+ comments: [],
219
+ };
220
+ // Mock validateTaskFile to simulate permission error
221
+ const originalValidateTaskFile = promptService.validateTaskFile;
222
+ promptService.validateTaskFile = vi.fn().mockResolvedValueOnce(false);
223
+ const prompt = await promptService.generateTaskPrompt(mockTask);
224
+ expect(prompt).toContain('not accessible at expected path');
225
+ expect(prompt).toContain('PERMISSION-TEST');
226
+ // Restore original function
227
+ promptService.validateTaskFile = originalValidateTaskFile;
228
+ });
229
+ });
230
+ });
@@ -15,13 +15,13 @@ export declare const GenerationOptionsSchema: z.ZodObject<{
15
15
  maxTokens: z.ZodOptional<z.ZodNumber>;
16
16
  tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
17
17
  }, "strip", z.ZodTypeAny, {
18
+ temperature?: number | undefined;
18
19
  maxTokens?: number | undefined;
19
20
  tools?: string[] | undefined;
20
- temperature?: number | undefined;
21
21
  }, {
22
+ temperature?: number | undefined;
22
23
  maxTokens?: number | undefined;
23
24
  tools?: string[] | undefined;
24
- temperature?: number | undefined;
25
25
  }>;
26
26
  export type GenerationOptions = z.infer<typeof GenerationOptionsSchema>;
27
27
  /**
@@ -35,30 +35,30 @@ export declare const OperationConfigSchema: z.ZodObject<{
35
35
  maxTokens: z.ZodOptional<z.ZodNumber>;
36
36
  tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
37
37
  }, "strip", z.ZodTypeAny, {
38
+ temperature?: number | undefined;
38
39
  maxTokens?: number | undefined;
39
40
  tools?: string[] | undefined;
40
- temperature?: number | undefined;
41
41
  }, {
42
+ temperature?: number | undefined;
42
43
  maxTokens?: number | undefined;
43
44
  tools?: string[] | undefined;
44
- temperature?: number | undefined;
45
45
  }>>;
46
46
  fallback: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
47
47
  }, "strip", z.ZodTypeAny, {
48
48
  provider: string;
49
49
  options?: {
50
+ temperature?: number | undefined;
50
51
  maxTokens?: number | undefined;
51
52
  tools?: string[] | undefined;
52
- temperature?: number | undefined;
53
53
  } | undefined;
54
54
  model?: string | undefined;
55
55
  fallback?: string[] | undefined;
56
56
  }, {
57
57
  provider: string;
58
58
  options?: {
59
+ temperature?: number | undefined;
59
60
  maxTokens?: number | undefined;
60
61
  tools?: string[] | undefined;
61
- temperature?: number | undefined;
62
62
  } | undefined;
63
63
  model?: string | undefined;
64
64
  fallback?: string[] | undefined;
@@ -77,54 +77,54 @@ export declare const RoutingPolicySchema: z.ZodObject<{
77
77
  maxTokens: z.ZodOptional<z.ZodNumber>;
78
78
  tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
79
79
  }, "strip", z.ZodTypeAny, {
80
+ temperature?: number | undefined;
80
81
  maxTokens?: number | undefined;
81
82
  tools?: string[] | undefined;
82
- temperature?: number | undefined;
83
83
  }, {
84
+ temperature?: number | undefined;
84
85
  maxTokens?: number | undefined;
85
86
  tools?: string[] | undefined;
86
- temperature?: number | undefined;
87
87
  }>>;
88
88
  fallback: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
89
89
  }, "strip", z.ZodTypeAny, {
90
90
  provider: string;
91
91
  options?: {
92
+ temperature?: number | undefined;
92
93
  maxTokens?: number | undefined;
93
94
  tools?: string[] | undefined;
94
- temperature?: number | undefined;
95
95
  } | undefined;
96
96
  model?: string | undefined;
97
97
  fallback?: string[] | undefined;
98
98
  }, {
99
99
  provider: string;
100
100
  options?: {
101
+ temperature?: number | undefined;
101
102
  maxTokens?: number | undefined;
102
103
  tools?: string[] | undefined;
103
- temperature?: number | undefined;
104
104
  } | undefined;
105
105
  model?: string | undefined;
106
106
  fallback?: string[] | undefined;
107
107
  }>>>;
108
108
  }, "strip", z.ZodTypeAny, {
109
109
  defaultProvider: string;
110
- operations?: Partial<Record<"execute_task" | "improve_task" | "ai_codereview" | "ai_merge", {
110
+ operations?: Partial<Record<"execute_task" | "improve_task" | "ai_merge" | "ai_codereview", {
111
111
  provider: string;
112
112
  options?: {
113
+ temperature?: number | undefined;
113
114
  maxTokens?: number | undefined;
114
115
  tools?: string[] | undefined;
115
- temperature?: number | undefined;
116
116
  } | undefined;
117
117
  model?: string | undefined;
118
118
  fallback?: string[] | undefined;
119
119
  }>> | undefined;
120
120
  }, {
121
121
  defaultProvider: string;
122
- operations?: Partial<Record<"execute_task" | "improve_task" | "ai_codereview" | "ai_merge", {
122
+ operations?: Partial<Record<"execute_task" | "improve_task" | "ai_merge" | "ai_codereview", {
123
123
  provider: string;
124
124
  options?: {
125
+ temperature?: number | undefined;
125
126
  maxTokens?: number | undefined;
126
127
  tools?: string[] | undefined;
127
- temperature?: number | undefined;
128
128
  } | undefined;
129
129
  model?: string | undefined;
130
130
  fallback?: string[] | undefined;
@@ -8,7 +8,7 @@ import { type RoutingPolicy, type RoutableOperation } from '../../agent/routing-
8
8
  * Build AI router with required dependencies
9
9
  */
10
10
  export declare function buildAIRoutes(options: {
11
- requireAgentService: () => AgentService;
11
+ agentService: AgentService;
12
12
  }): {
13
13
  /**
14
14
  * List all registered AI providers with health status
@@ -50,12 +50,12 @@ export declare function buildAIRoutes(options: {
50
50
  input: {
51
51
  policy: {
52
52
  defaultProvider?: string | undefined;
53
- operations?: Partial<Record<"execute_task" | "improve_task" | "ai_codereview" | "ai_merge", {
53
+ operations?: Partial<Record<"execute_task" | "improve_task" | "ai_merge" | "ai_codereview", {
54
54
  provider: string;
55
55
  options?: {
56
+ temperature?: number | undefined;
56
57
  maxTokens?: number | undefined;
57
58
  tools?: string[] | undefined;
58
- temperature?: number | undefined;
59
59
  } | undefined;
60
60
  model?: string | undefined;
61
61
  fallback?: string[] | undefined;
@@ -86,17 +86,17 @@ export declare function buildAIRoutes(options: {
86
86
  */
87
87
  setOperationConfig: import("@trpc/server").TRPCMutationProcedure<{
88
88
  input: {
89
+ operation: "execute_task" | "improve_task" | "ai_merge" | "ai_codereview";
89
90
  config: {
90
91
  provider: string;
91
92
  options?: {
93
+ temperature?: number | undefined;
92
94
  maxTokens?: number | undefined;
93
95
  tools?: string[] | undefined;
94
- temperature?: number | undefined;
95
96
  } | undefined;
96
97
  model?: string | undefined;
97
98
  fallback?: string[] | undefined;
98
99
  };
99
- operation: "execute_task" | "improve_task" | "ai_codereview" | "ai_merge";
100
100
  };
101
101
  output: {
102
102
  success: boolean;
@@ -130,7 +130,7 @@ export declare function buildAIRoutes(options: {
130
130
  * Useful for unit tests that call functions directly.
131
131
  */
132
132
  export declare function buildAIRouteHandlers(options: {
133
- requireAgentService: () => AgentService;
133
+ agentService: AgentService;
134
134
  }): {
135
135
  readonly listProviders: () => Promise<{
136
136
  name: string;