feat: Claude Code AI SDK v5 Integration (#1114)

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
This commit is contained in:
tommy-ca
2025-09-24 22:57:04 +02:00
committed by Ralph Khreish
parent 0079b7defd
commit 18aa416035
31 changed files with 1590 additions and 2515 deletions

View File

@@ -31,36 +31,30 @@ import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
import { flattenTasksWithSubtasks, findProjectRoot } from '../utils.js';
// --- Zod Schemas (Keep from previous step) ---
const subtaskSchema = z
.object({
id: z
.number()
.int()
.positive()
.describe('Sequential subtask ID starting from 1'),
title: z.string().min(5).describe('Clear, specific title for the subtask'),
description: z
.string()
.min(10)
.describe('Detailed description of the subtask'),
dependencies: z
.array(z.string())
.describe(
'Array of subtask dependencies within the same parent task. Use format ["parentTaskId.1", "parentTaskId.2"]. Subtasks can only depend on siblings, not external tasks.'
),
details: z.string().min(20).describe('Implementation details and guidance'),
status: z
.string()
.describe(
'The current status of the subtask (should be pending initially)'
),
testStrategy: z
.string()
.nullable()
.describe('Approach for testing this subtask')
.default('')
})
.strict();
const subtaskSchema = z.strictObject({
id: z.int().positive().describe('Sequential subtask ID starting from 1'),
title: z.string().min(5).describe('Clear, specific title for the subtask'),
description: z
.string()
.min(10)
.describe('Detailed description of the subtask'),
dependencies: z
.array(z.string())
.describe(
'Array of subtask dependencies within the same parent task. Use format ["parentTaskId.1", "parentTaskId.2"]. Subtasks can only depend on siblings, not external tasks.'
),
details: z.string().min(20).describe('Implementation details and guidance'),
status: z
.string()
.describe(
'The current status of the subtask (should be pending initially)'
),
testStrategy: z
.string()
.nullable()
.describe('Approach for testing this subtask')
.prefault('')
});
const subtaskArraySchema = z.array(subtaskSchema);
const subtaskWrapperSchema = z.object({
subtasks: subtaskArraySchema.describe('The array of generated subtasks.')

View File

@@ -355,7 +355,7 @@ Ensure the JSON is valid and properly formatted.`;
const subtaskSchema = z.object({
subtasks: z.array(
z.object({
id: z.number().int().positive(),
id: z.int().positive(),
title: z.string().min(5),
description: z.string().min(10),
dependencies: z.array(z.string()),
@@ -386,8 +386,21 @@ Ensure the JSON is valid and properly formatted.`;
testStrategy: subtask.testStrategy || ''
}));
// Ensure new subtasks have unique sequential IDs after the preserved ones
const maxPreservedId = preservedSubtasks.reduce(
(max, st) => Math.max(max, st.id || 0),
0
);
let nextId = maxPreservedId + 1;
const normalizedGeneratedSubtasks = processedGeneratedSubtasks.map(
(st) => ({
...st,
id: nextId++
})
);
// Update task with preserved subtasks + newly generated ones
task.subtasks = [...preservedSubtasks, ...processedGeneratedSubtasks];
task.subtasks = [...preservedSubtasks, ...normalizedGeneratedSubtasks];
return {
updatedTask: task,

View File

@@ -33,36 +33,33 @@ import { ContextGatherer } from '../utils/contextGatherer.js';
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
// Zod schema for post-parsing validation of the updated task object
const updatedTaskSchema = z
.object({
id: z.number().int(),
title: z.string(), // Title should be preserved, but check it exists
description: z.string(),
status: z.string(),
dependencies: z.array(z.union([z.number().int(), z.string()])),
priority: z.string().nullable().default('medium'),
details: z.string().nullable().default(''),
testStrategy: z.string().nullable().default(''),
subtasks: z
.array(
z.object({
id: z
.number()
.int()
.positive()
.describe('Sequential subtask ID starting from 1'),
title: z.string(),
description: z.string(),
status: z.string(),
dependencies: z.array(z.number().int()).nullable().default([]),
details: z.string().nullable().default(''),
testStrategy: z.string().nullable().default('')
})
)
.nullable()
.default([])
})
.strip(); // Allows parsing even if AI adds extra fields, but validation focuses on schema
const updatedTaskSchema = z.object({
id: z.int(),
title: z.string(), // Title should be preserved, but check it exists
description: z.string(),
status: z.string(),
dependencies: z.array(z.union([z.int(), z.string()])),
priority: z.string().nullable().prefault('medium'),
details: z.string().nullable().prefault(''),
testStrategy: z.string().nullable().prefault(''),
subtasks: z
.array(
z.object({
id: z
.int()
.positive()
.describe('Sequential subtask ID starting from 1'),
title: z.string(),
description: z.string(),
status: z.string(),
dependencies: z.array(z.int()).nullable().prefault([]),
details: z.string().nullable().prefault(''),
testStrategy: z.string().nullable().prefault('')
})
)
.nullable()
.prefault([])
}); // Allows parsing even if AI adds extra fields, but validation focuses on schema
/**
* Parses a single updated task object from AI's text response.

View File

@@ -29,19 +29,17 @@ import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
import { flattenTasksWithSubtasks, findProjectRoot } from '../utils.js';
// Zod schema for validating the structure of tasks AFTER parsing
const updatedTaskSchema = z
.object({
id: z.number().int(),
title: z.string(),
description: z.string(),
status: z.string(),
dependencies: z.array(z.union([z.number().int(), z.string()])),
priority: z.string().nullable(),
details: z.string().nullable(),
testStrategy: z.string().nullable(),
subtasks: z.array(z.any()).nullable() // Keep subtasks flexible for now
})
.strip(); // Allow potential extra fields during parsing if needed, then validate structure
const updatedTaskSchema = z.object({
id: z.int(),
title: z.string(),
description: z.string(),
status: z.string(),
dependencies: z.array(z.union([z.int(), z.string()])),
priority: z.string().nullable(),
details: z.string().nullable(),
testStrategy: z.string().nullable(),
subtasks: z.array(z.any()).nullable() // Keep subtasks flexible for now
}); // Allow potential extra fields during parsing if needed, then validate structure
// Preprocessing schema that adds defaults before validation
const preprocessTaskSchema = z.preprocess((task) => {