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:
@@ -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.')
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user