mirror of https://github.com/buster-so/buster.git
move write file to single and to bun based with separate prompt
This commit is contained in:
parent
cce3eaf009
commit
b1aa4c4363
|
@ -63,5 +63,8 @@
|
|||
"uuid": "^11.1.0",
|
||||
"yaml": "^2.8.1",
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.2.23"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import z from 'zod';
|
|||
import { DEFAULT_ANTHROPIC_OPTIONS } from '../../llm/providers/gateway';
|
||||
import { Sonnet4 } from '../../llm/sonnet-4';
|
||||
import { bashExecute, createIdleTool } from '../../tools';
|
||||
import { createWriteFileTool } from '../../tools/file-tools';
|
||||
import { type AgentContext, repairToolCall } from '../../utils/tool-call-repair';
|
||||
import { getDocsAgentSystemPrompt } from './get-docs-agent-system-prompt';
|
||||
|
||||
|
@ -52,6 +53,10 @@ export function createDocsAgent(docsAgentOptions: DocsAgentOptions) {
|
|||
} as ModelMessage;
|
||||
|
||||
const idleTool = createIdleTool();
|
||||
const writeFileTool = createWriteFileTool({
|
||||
messageId: docsAgentOptions.messageId,
|
||||
projectDirectory: docsAgentOptions.folder_structure,
|
||||
});
|
||||
|
||||
// Create planning tools with simple context
|
||||
async function stream({ messages }: DocsStreamOptions) {
|
||||
|
@ -73,6 +78,7 @@ export function createDocsAgent(docsAgentOptions: DocsAgentOptions) {
|
|||
providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
|
||||
tools: {
|
||||
idleTool,
|
||||
writeFileTool,
|
||||
},
|
||||
messages: [systemMessage, ...messages],
|
||||
stopWhen: STOP_CONDITIONS,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# IMPORTANT
|
||||
|
||||
These tools are used in the CLI docs agent and use the Bun runtime to execute file operations.
|
|
@ -1,54 +0,0 @@
|
|||
import type { Sandbox } from '@buster/sandbox';
|
||||
import { tool } from 'ai';
|
||||
import { z } from 'zod';
|
||||
import { createCreateFilesTool } from './create-files-tool';
|
||||
|
||||
// Re-export schemas and types for backward compatibility
|
||||
const FileCreateParamsSchema = z.object({
|
||||
path: z.string().describe('The relative or absolute path to create the file at'),
|
||||
content: z.string().describe('The content to write to the file'),
|
||||
});
|
||||
|
||||
export const CreateFilesInputSchema = z.object({
|
||||
files: z.array(FileCreateParamsSchema).describe('Array of file creation operations to perform'),
|
||||
});
|
||||
|
||||
const CreateFilesOutputSchema = z.object({
|
||||
results: z.array(
|
||||
z.discriminatedUnion('status', [
|
||||
z.object({
|
||||
status: z.literal('success'),
|
||||
filePath: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
status: z.literal('error'),
|
||||
filePath: z.string(),
|
||||
errorMessage: z.string(),
|
||||
}),
|
||||
])
|
||||
),
|
||||
});
|
||||
|
||||
const CreateFilesContextSchema = z.object({
|
||||
messageId: z.string().describe('The message ID for database updates'),
|
||||
sandbox: z
|
||||
.custom<Sandbox>(
|
||||
(val) => {
|
||||
return val && typeof val === 'object' && 'id' in val && 'fs' in val;
|
||||
},
|
||||
{ message: 'Invalid Sandbox instance' }
|
||||
)
|
||||
.describe('Sandbox instance for file operations'),
|
||||
});
|
||||
|
||||
export type CreateFilesInput = z.infer<typeof CreateFilesInputSchema>;
|
||||
export type CreateFilesOutput = z.infer<typeof CreateFilesOutputSchema>;
|
||||
export type CreateFilesContext = z.infer<typeof CreateFilesContextSchema>;
|
||||
|
||||
// Factory function that creates the tool with context
|
||||
export function createFiles(context: CreateFilesContext) {
|
||||
return createCreateFilesTool(context);
|
||||
}
|
||||
|
||||
// Default export using factory pattern - requires context to be passed
|
||||
export default createFiles;
|
|
@ -1,243 +0,0 @@
|
|||
import { exec } from 'node:child_process';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
// Helper to execute script with clean stderr
|
||||
async function runScript(args: string) {
|
||||
const { stdout, stderr } = await execAsync(
|
||||
`npx tsx ${path.join(__dirname, 'create-files-script.ts')} ${args}`,
|
||||
{ env: { ...process.env, npm_config_loglevel: 'error' } }
|
||||
);
|
||||
|
||||
// Filter out npm warnings
|
||||
const cleanStderr = stderr
|
||||
.split('\n')
|
||||
.filter((line) => !line.includes('npm warn') && line.trim() !== '')
|
||||
.join('\n');
|
||||
|
||||
return { stdout, stderr: cleanStderr };
|
||||
}
|
||||
|
||||
describe('create-files-script integration tests', () => {
|
||||
let tempDir: string;
|
||||
const scriptPath = path.join(__dirname, 'create-files-script.ts');
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create a temporary directory for test files
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'create-files-test-'));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Clean up temporary directory
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('should create single file successfully', async () => {
|
||||
const testFile = path.join(tempDir, 'test.txt');
|
||||
const fileParams = [{ path: testFile, content: 'Hello, World!' }];
|
||||
|
||||
const { stdout, stderr } = await runScript(`'${JSON.stringify(fileParams)}'`);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
const results = JSON.parse(stdout);
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0]).toEqual({
|
||||
success: true,
|
||||
filePath: testFile,
|
||||
});
|
||||
|
||||
// Verify file was actually created
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe('Hello, World!');
|
||||
});
|
||||
|
||||
it('should create multiple files successfully', async () => {
|
||||
const files = [
|
||||
{ path: path.join(tempDir, 'file1.txt'), content: 'Content 1' },
|
||||
{ path: path.join(tempDir, 'file2.txt'), content: 'Content 2' },
|
||||
{ path: path.join(tempDir, 'subdir', 'file3.txt'), content: 'Content 3' },
|
||||
];
|
||||
|
||||
const { stdout, stderr } = await runScript(`'${JSON.stringify(files)}'`);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
const results = JSON.parse(stdout);
|
||||
expect(results).toHaveLength(3);
|
||||
|
||||
// Verify all files were created
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
expect(results[i].success).toBe(true);
|
||||
const content = await fs.readFile(files[i]!.path, 'utf-8');
|
||||
expect(content).toBe(files[i]!.content);
|
||||
}
|
||||
|
||||
// Verify subdirectory was created
|
||||
const subdirStats = await fs.stat(path.join(tempDir, 'subdir'));
|
||||
expect(subdirStats.isDirectory()).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle relative paths correctly', async () => {
|
||||
const originalCwd = process.cwd();
|
||||
process.chdir(tempDir);
|
||||
|
||||
try {
|
||||
const fileParams = [
|
||||
{ path: 'relative.txt', content: 'Relative content' },
|
||||
{ path: './subdir/nested.txt', content: 'Nested content' },
|
||||
];
|
||||
|
||||
const { stdout, stderr } = await runScript(`'${JSON.stringify(fileParams)}'`);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
const results = JSON.parse(stdout);
|
||||
expect(results).toHaveLength(2);
|
||||
expect(results[0].success).toBe(true);
|
||||
expect(results[1].success).toBe(true);
|
||||
|
||||
// Verify files were created at correct locations
|
||||
const relativeContent = await fs.readFile(path.join(tempDir, 'relative.txt'), 'utf-8');
|
||||
expect(relativeContent).toBe('Relative content');
|
||||
|
||||
const nestedContent = await fs.readFile(path.join(tempDir, 'subdir', 'nested.txt'), 'utf-8');
|
||||
expect(nestedContent).toBe('Nested content');
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
|
||||
it('should overwrite existing files', async () => {
|
||||
const testFile = path.join(tempDir, 'existing.txt');
|
||||
await fs.writeFile(testFile, 'Original content');
|
||||
|
||||
const fileParams = [{ path: testFile, content: 'New content' }];
|
||||
|
||||
const { stdout, stderr } = await runScript(`'${JSON.stringify(fileParams)}'`);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
const results = JSON.parse(stdout);
|
||||
expect(results[0].success).toBe(true);
|
||||
|
||||
// Verify file was overwritten
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe('New content');
|
||||
});
|
||||
|
||||
it('should handle special characters in content', async () => {
|
||||
const testFile = path.join(tempDir, 'special.txt');
|
||||
const specialContent = 'Line 1\nLine 2\tTabbed\r\nWindows line\n"Quoted"\nSingle';
|
||||
const fileParams = [{ path: testFile, content: specialContent }];
|
||||
|
||||
const { stdout, stderr } = await runScript(`'${JSON.stringify(fileParams)}'`);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
const results = JSON.parse(stdout);
|
||||
expect(results[0].success).toBe(true);
|
||||
|
||||
// Verify content with special characters
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe(specialContent);
|
||||
});
|
||||
|
||||
it('should handle errors gracefully', async () => {
|
||||
// Try to create a file in a non-existent absolute path
|
||||
const invalidPath = '/this/path/should/not/exist/file.txt';
|
||||
const fileParams = [{ path: invalidPath, content: 'Content' }];
|
||||
|
||||
const { stdout, stderr } = await runScript(`'${JSON.stringify(fileParams)}'`);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
const results = JSON.parse(stdout);
|
||||
expect(results[0].success).toBe(false);
|
||||
expect(results[0].filePath).toBe(invalidPath);
|
||||
expect(results[0].error).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should handle mixed success and failure', async () => {
|
||||
const files = [
|
||||
{ path: path.join(tempDir, 'success1.txt'), content: 'Success 1' },
|
||||
{ path: '/invalid/path/fail.txt', content: 'Will fail' },
|
||||
{ path: path.join(tempDir, 'success2.txt'), content: 'Success 2' },
|
||||
];
|
||||
|
||||
const { stdout, stderr } = await runScript(`'${JSON.stringify(files)}'`);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
const results = JSON.parse(stdout);
|
||||
expect(results).toHaveLength(3);
|
||||
|
||||
expect(results[0].success).toBe(true);
|
||||
expect(results[1].success).toBe(false);
|
||||
expect(results[2].success).toBe(true);
|
||||
|
||||
// Verify successful files were created
|
||||
const content1 = await fs.readFile(files[0]!.path, 'utf-8');
|
||||
expect(content1).toBe('Success 1');
|
||||
|
||||
const content2 = await fs.readFile(files[2]!.path, 'utf-8');
|
||||
expect(content2).toBe('Success 2');
|
||||
});
|
||||
|
||||
it('should error when no arguments provided', async () => {
|
||||
try {
|
||||
const { stdout, stderr } = await execAsync(`npx tsx ${scriptPath}`, {
|
||||
env: { ...process.env, npm_config_loglevel: 'error' },
|
||||
});
|
||||
expect.fail('Should have thrown an error');
|
||||
} catch (error: any) {
|
||||
expect(error.code).toBe(1);
|
||||
const errorOutput = JSON.parse(error.stdout || error.stderr);
|
||||
expect(errorOutput[0].success).toBe(false);
|
||||
expect(errorOutput[0].error).toBe('No arguments provided to script');
|
||||
}
|
||||
});
|
||||
|
||||
it('should error with invalid JSON', async () => {
|
||||
try {
|
||||
const { stdout, stderr } = await execAsync(`npx tsx ${scriptPath} 'not valid json'`, {
|
||||
env: { ...process.env, npm_config_loglevel: 'error' },
|
||||
});
|
||||
expect.fail('Should have thrown an error');
|
||||
} catch (error: any) {
|
||||
expect(error.code).toBe(1);
|
||||
const errorOutput = JSON.parse(error.stdout || error.stderr);
|
||||
expect(errorOutput[0].success).toBe(false);
|
||||
expect(errorOutput[0].error).toContain('Failed to parse arguments');
|
||||
}
|
||||
});
|
||||
|
||||
it('should error with invalid parameter structure', async () => {
|
||||
try {
|
||||
const invalidParams = [{ path: '/test/file.txt' }]; // missing content
|
||||
const { stdout, stderr } = await execAsync(
|
||||
`npx tsx ${scriptPath} '${JSON.stringify(invalidParams)}'`,
|
||||
{ env: { ...process.env, npm_config_loglevel: 'error' } }
|
||||
);
|
||||
expect.fail('Should have thrown an error');
|
||||
} catch (error: any) {
|
||||
expect(error.code).toBe(1);
|
||||
const errorOutput = JSON.parse(error.stdout || error.stderr);
|
||||
expect(errorOutput[0].success).toBe(false);
|
||||
expect(errorOutput[0].error).toContain('must have a content string');
|
||||
}
|
||||
});
|
||||
|
||||
it('should create deeply nested directories', async () => {
|
||||
const deepPath = path.join(tempDir, 'a', 'b', 'c', 'd', 'e', 'file.txt');
|
||||
const fileParams = [{ path: deepPath, content: 'Deep content' }];
|
||||
|
||||
const { stdout, stderr } = await runScript(`'${JSON.stringify(fileParams)}'`);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
const results = JSON.parse(stdout);
|
||||
expect(results[0].success).toBe(true);
|
||||
|
||||
// Verify file and all directories were created
|
||||
const content = await fs.readFile(deepPath, 'utf-8');
|
||||
expect(content).toBe('Deep content');
|
||||
});
|
||||
});
|
|
@ -1,334 +0,0 @@
|
|||
import * as child_process from 'node:child_process';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
|
||||
const exec = promisify(child_process.exec);
|
||||
|
||||
describe('create-files-script', () => {
|
||||
const scriptPath = path.join(__dirname, 'create-files-script.ts');
|
||||
let tempDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create a temporary directory for test files
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'create-files-test-'));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Clean up temporary directory
|
||||
try {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
} catch (error) {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
});
|
||||
|
||||
async function runScript(args: string[]): Promise<{ stdout: string; stderr: string }> {
|
||||
// Properly escape arguments for shell
|
||||
const escapedArgs = args.map((arg) => {
|
||||
// If it contains special characters, wrap in single quotes
|
||||
if (arg.includes(' ') || arg.includes('"') || arg.includes('[') || arg.includes(']')) {
|
||||
return `'${arg.replace(/'/g, "'\"'\"'")}'`;
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
const { stdout, stderr } = await exec(`npx tsx ${scriptPath} ${escapedArgs.join(' ')}`);
|
||||
return { stdout, stderr };
|
||||
}
|
||||
|
||||
describe('functional tests', () => {
|
||||
it('should create a single file successfully', async () => {
|
||||
const testFile = path.join(tempDir, 'test.txt');
|
||||
const fileParams = [
|
||||
{
|
||||
path: testFile,
|
||||
content: 'Hello, world!',
|
||||
},
|
||||
];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results).toEqual([
|
||||
{
|
||||
success: true,
|
||||
filePath: testFile,
|
||||
},
|
||||
]);
|
||||
|
||||
// Verify file was created
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe('Hello, world!');
|
||||
});
|
||||
|
||||
it('should create multiple files', async () => {
|
||||
const fileParams = [
|
||||
{ path: path.join(tempDir, 'file1.txt'), content: 'Content 1' },
|
||||
{ path: path.join(tempDir, 'file2.txt'), content: 'Content 2' },
|
||||
{ path: path.join(tempDir, 'file3.txt'), content: 'Content 3' },
|
||||
];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results).toHaveLength(3);
|
||||
expect(results.every((r: any) => r.success)).toBe(true);
|
||||
|
||||
// Verify all files were created
|
||||
for (const param of fileParams) {
|
||||
const content = await fs.readFile(param.path, 'utf-8');
|
||||
expect(content).toBe(param.content);
|
||||
}
|
||||
});
|
||||
|
||||
it('should create directories if they do not exist', async () => {
|
||||
const nestedFile = path.join(tempDir, 'nested', 'deep', 'file.txt');
|
||||
const fileParams = [
|
||||
{
|
||||
path: nestedFile,
|
||||
content: 'Nested content',
|
||||
},
|
||||
];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results[0].success).toBe(true);
|
||||
|
||||
// Verify file and directories were created
|
||||
const content = await fs.readFile(nestedFile, 'utf-8');
|
||||
expect(content).toBe('Nested content');
|
||||
});
|
||||
|
||||
it('should handle relative paths', async () => {
|
||||
const originalCwd = process.cwd();
|
||||
try {
|
||||
// Change to temp directory
|
||||
process.chdir(tempDir);
|
||||
|
||||
const fileParams = [
|
||||
{ path: 'relative.txt', content: 'Relative content' },
|
||||
{ path: './subdir/file.txt', content: 'Subdir content' },
|
||||
];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results).toHaveLength(2);
|
||||
expect(results[0].success).toBe(true);
|
||||
expect(results[1].success).toBe(true);
|
||||
|
||||
// Verify files were created
|
||||
expect(await fs.readFile('relative.txt', 'utf-8')).toBe('Relative content');
|
||||
expect(await fs.readFile('./subdir/file.txt', 'utf-8')).toBe('Subdir content');
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle base64 encoded input', async () => {
|
||||
const testFile = path.join(tempDir, 'base64.txt');
|
||||
const fileParams = [{ path: testFile, content: 'Base64 content' }];
|
||||
const base64Input = Buffer.from(JSON.stringify(fileParams)).toString('base64');
|
||||
|
||||
const { stdout } = await runScript([base64Input]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results[0].success).toBe(true);
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe('Base64 content');
|
||||
});
|
||||
|
||||
it('should handle empty content', async () => {
|
||||
const testFile = path.join(tempDir, 'empty.txt');
|
||||
const fileParams = [{ path: testFile, content: '' }];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results[0].success).toBe(true);
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe('');
|
||||
});
|
||||
|
||||
it('should handle special characters in content', async () => {
|
||||
const testFile = path.join(tempDir, 'special.txt');
|
||||
const specialContent =
|
||||
'Special chars: @#$%^&*()\n"Quotes"\n\'Apostrophes\'\n\tTabs\n\\Backslashes\\';
|
||||
const fileParams = [{ path: testFile, content: specialContent }];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results[0].success).toBe(true);
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe(specialContent);
|
||||
});
|
||||
|
||||
it('should handle multiline content', async () => {
|
||||
const testFile = path.join(tempDir, 'multiline.txt');
|
||||
const multilineContent = `Line 1
|
||||
Line 2
|
||||
Line 3
|
||||
|
||||
Line 5 (after empty line)`;
|
||||
const fileParams = [{ path: testFile, content: multilineContent }];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results[0].success).toBe(true);
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe(multilineContent);
|
||||
});
|
||||
|
||||
it('should handle files with spaces in names', async () => {
|
||||
const testFile = path.join(tempDir, 'file with spaces.txt');
|
||||
const fileParams = [{ path: testFile, content: 'Content with spaces' }];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results[0].success).toBe(true);
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe('Content with spaces');
|
||||
});
|
||||
|
||||
it('should handle no arguments', async () => {
|
||||
try {
|
||||
await runScript([]);
|
||||
// Should not reach here
|
||||
expect(true).toBe(false);
|
||||
} catch (error: any) {
|
||||
// Script exits with code 1
|
||||
const results = JSON.parse(error.stdout);
|
||||
expect(results).toEqual([
|
||||
{
|
||||
success: false,
|
||||
filePath: '',
|
||||
error: 'No arguments provided to script',
|
||||
},
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle invalid JSON', async () => {
|
||||
try {
|
||||
await runScript(['not valid json']);
|
||||
// Should not reach here
|
||||
expect(true).toBe(false);
|
||||
} catch (error: any) {
|
||||
// Script exits with code 1
|
||||
const results = JSON.parse(error.stdout);
|
||||
expect(results[0].success).toBe(false);
|
||||
expect(results[0].error).toContain('Failed to parse arguments');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle non-array input', async () => {
|
||||
try {
|
||||
await runScript(['{"not": "array"}']);
|
||||
// Should not reach here
|
||||
expect(true).toBe(false);
|
||||
} catch (error: any) {
|
||||
// Script exits with code 1
|
||||
const results = JSON.parse(error.stdout);
|
||||
expect(results[0].success).toBe(false);
|
||||
expect(results[0].error).toContain('File parameters must be an array');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle missing path', async () => {
|
||||
const fileParams = [{ content: 'No path provided' }];
|
||||
try {
|
||||
await runScript([JSON.stringify(fileParams)]);
|
||||
// Should not reach here
|
||||
expect(true).toBe(false);
|
||||
} catch (error: any) {
|
||||
// Script exits with code 1
|
||||
const results = JSON.parse(error.stdout);
|
||||
expect(results[0].success).toBe(false);
|
||||
expect(results[0].error).toContain('must have a valid path string');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle missing content', async () => {
|
||||
const fileParams = [{ path: 'test.txt' }];
|
||||
try {
|
||||
await runScript([JSON.stringify(fileParams)]);
|
||||
// Should not reach here
|
||||
expect(true).toBe(false);
|
||||
} catch (error: any) {
|
||||
// Script exits with code 1
|
||||
const results = JSON.parse(error.stdout);
|
||||
expect(results[0].success).toBe(false);
|
||||
expect(results[0].error).toContain('must have a content string');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle mixed success and failure', async () => {
|
||||
const file1 = path.join(tempDir, 'success.txt');
|
||||
const file2 = path.join(tempDir, 'readonly', 'fail.txt');
|
||||
|
||||
// Create a readonly directory
|
||||
const readonlyDir = path.join(tempDir, 'readonly');
|
||||
await fs.mkdir(readonlyDir);
|
||||
await fs.chmod(readonlyDir, 0o444);
|
||||
|
||||
const fileParams = [
|
||||
{ path: file1, content: 'Success' },
|
||||
{ path: file2, content: 'This will fail' },
|
||||
];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results).toHaveLength(2);
|
||||
expect(results[0].success).toBe(true);
|
||||
expect(results[1].success).toBe(false);
|
||||
|
||||
// Verify successful file was created
|
||||
const content = await fs.readFile(file1, 'utf-8');
|
||||
expect(content).toBe('Success');
|
||||
|
||||
// Clean up
|
||||
await fs.chmod(readonlyDir, 0o755);
|
||||
});
|
||||
|
||||
it('should avoid creating duplicate directories', async () => {
|
||||
// Multiple files in the same directory
|
||||
const fileParams = [
|
||||
{ path: path.join(tempDir, 'same-dir', 'file1.txt'), content: 'File 1' },
|
||||
{ path: path.join(tempDir, 'same-dir', 'file2.txt'), content: 'File 2' },
|
||||
{ path: path.join(tempDir, 'same-dir', 'file3.txt'), content: 'File 3' },
|
||||
];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results).toHaveLength(3);
|
||||
expect(results.every((r: any) => r.success)).toBe(true);
|
||||
|
||||
// Verify all files were created
|
||||
for (const param of fileParams) {
|
||||
const content = await fs.readFile(param.path, 'utf-8');
|
||||
expect(content).toBe(param.content);
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle UTF-8 content', async () => {
|
||||
const testFile = path.join(tempDir, 'utf8.txt');
|
||||
const utf8Content = '你好世界 🌍 Émojis and special chars: €£¥';
|
||||
const fileParams = [{ path: testFile, content: utf8Content }];
|
||||
|
||||
const { stdout } = await runScript([JSON.stringify(fileParams)]);
|
||||
const results = JSON.parse(stdout);
|
||||
|
||||
expect(results[0].success).toBe(true);
|
||||
const content = await fs.readFile(testFile, 'utf-8');
|
||||
expect(content).toBe(utf8Content);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,147 +0,0 @@
|
|||
import * as fs from 'node:fs/promises';
|
||||
import * as path from 'node:path';
|
||||
|
||||
interface FileCreateParams {
|
||||
path: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface FileCreateResult {
|
||||
success: boolean;
|
||||
filePath: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
async function createFiles(fileParams: FileCreateParams[]): Promise<FileCreateResult[]> {
|
||||
const results: FileCreateResult[] = [];
|
||||
const createdDirs = new Set<string>();
|
||||
|
||||
// Process files sequentially to avoid race conditions
|
||||
for (const { path: filePath, content } of fileParams) {
|
||||
try {
|
||||
const resolvedPath = path.isAbsolute(filePath)
|
||||
? filePath
|
||||
: path.join(process.cwd(), filePath);
|
||||
const dirPath = path.dirname(resolvedPath);
|
||||
|
||||
// Only create directory if we haven't already created it
|
||||
if (!createdDirs.has(dirPath)) {
|
||||
try {
|
||||
await fs.mkdir(dirPath, { recursive: true });
|
||||
createdDirs.add(dirPath);
|
||||
} catch (error) {
|
||||
results.push({
|
||||
success: false,
|
||||
filePath,
|
||||
error: `Failed to create directory: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
await fs.writeFile(resolvedPath, content, 'utf-8');
|
||||
|
||||
results.push({
|
||||
success: true,
|
||||
filePath,
|
||||
});
|
||||
} catch (error) {
|
||||
results.push({
|
||||
success: false,
|
||||
filePath,
|
||||
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Script execution
|
||||
async function main() {
|
||||
// Parse command line arguments
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length === 0) {
|
||||
console.log(
|
||||
JSON.stringify([
|
||||
{
|
||||
success: false,
|
||||
filePath: '',
|
||||
error: 'No arguments provided to script',
|
||||
},
|
||||
])
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let fileParams: FileCreateParams[];
|
||||
try {
|
||||
// The script expects file parameters as a JSON string in the first argument (possibly base64 encoded)
|
||||
let fileParamsJson = args[0];
|
||||
if (!fileParamsJson) {
|
||||
throw new Error('No argument provided');
|
||||
}
|
||||
|
||||
// Try to decode from base64 if it looks like base64
|
||||
if (
|
||||
fileParamsJson &&
|
||||
/^[A-Za-z0-9+/]+=*$/.test(fileParamsJson) &&
|
||||
fileParamsJson.length % 4 === 0
|
||||
) {
|
||||
try {
|
||||
fileParamsJson = Buffer.from(fileParamsJson, 'base64').toString('utf-8');
|
||||
} catch {
|
||||
// If base64 decode fails, use as-is
|
||||
}
|
||||
}
|
||||
|
||||
fileParams = JSON.parse(fileParamsJson);
|
||||
|
||||
if (!Array.isArray(fileParams)) {
|
||||
throw new Error('File parameters must be an array');
|
||||
}
|
||||
|
||||
// Validate each file parameter
|
||||
for (const param of fileParams) {
|
||||
if (!param.path || typeof param.path !== 'string') {
|
||||
throw new Error('Each file parameter must have a valid path string');
|
||||
}
|
||||
if (typeof param.content !== 'string') {
|
||||
throw new Error('Each file parameter must have a content string');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Return error information instead of empty array
|
||||
console.log(
|
||||
JSON.stringify([
|
||||
{
|
||||
success: false,
|
||||
filePath: '',
|
||||
error: `Failed to parse arguments: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
},
|
||||
])
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const results = await createFiles(fileParams);
|
||||
|
||||
// Output as JSON to stdout
|
||||
console.log(JSON.stringify(results));
|
||||
}
|
||||
|
||||
// Run the script
|
||||
main().catch((error) => {
|
||||
// Return error information for unexpected errors
|
||||
console.log(
|
||||
JSON.stringify([
|
||||
{
|
||||
success: false,
|
||||
filePath: '',
|
||||
error: `Unexpected error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
},
|
||||
])
|
||||
);
|
||||
process.exit(1);
|
||||
});
|
|
@ -1,148 +0,0 @@
|
|||
import { runTypescript } from '@buster/sandbox';
|
||||
import { wrapTraced } from 'braintrust';
|
||||
import type {
|
||||
CreateFilesToolContext,
|
||||
CreateFilesToolInput,
|
||||
CreateFilesToolOutput,
|
||||
} from './create-files-tool';
|
||||
|
||||
export function createCreateFilesToolExecute(context: CreateFilesToolContext) {
|
||||
return wrapTraced(
|
||||
async (input: CreateFilesToolInput): Promise<CreateFilesToolOutput> => {
|
||||
const { files } = input;
|
||||
|
||||
if (!files || files.length === 0) {
|
||||
return { results: [] };
|
||||
}
|
||||
|
||||
try {
|
||||
const sandbox = context.sandbox;
|
||||
|
||||
if (!sandbox) {
|
||||
return {
|
||||
results: files.map((file) => ({
|
||||
status: 'error' as const,
|
||||
filePath: file.path,
|
||||
errorMessage: 'File creation requires sandbox environment',
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
// Generate CommonJS code for sandbox execution
|
||||
const filesJson = JSON.stringify(files);
|
||||
const sandboxCode = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const filesJson = ${JSON.stringify(filesJson)};
|
||||
const files = JSON.parse(filesJson);
|
||||
const results = [];
|
||||
const createdDirs = new Set();
|
||||
|
||||
// Process files sequentially
|
||||
for (const file of files) {
|
||||
try {
|
||||
const resolvedPath = path.isAbsolute(file.path)
|
||||
? file.path
|
||||
: path.join(process.cwd(), file.path);
|
||||
const dirPath = path.dirname(resolvedPath);
|
||||
|
||||
// Only create directory if we haven't already created it
|
||||
if (!createdDirs.has(dirPath)) {
|
||||
try {
|
||||
fs.mkdirSync(dirPath, { recursive: true });
|
||||
createdDirs.add(dirPath);
|
||||
} catch (error) {
|
||||
results.push({
|
||||
success: false,
|
||||
filePath: file.path,
|
||||
error: 'Failed to create directory: ' + (error instanceof Error ? error.message : String(error))
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(resolvedPath, file.content, 'utf-8');
|
||||
|
||||
results.push({
|
||||
success: true,
|
||||
filePath: file.path
|
||||
});
|
||||
} catch (error) {
|
||||
results.push({
|
||||
success: false,
|
||||
filePath: file.path,
|
||||
error: (error instanceof Error ? error.message : String(error)) || 'Unknown error'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(results));
|
||||
`;
|
||||
|
||||
const result = await runTypescript(sandbox, sandboxCode);
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
console.error('Sandbox execution failed. Exit code:', result.exitCode);
|
||||
console.error('Stderr:', result.stderr);
|
||||
console.error('Result:', result.result);
|
||||
throw new Error(`Sandbox execution failed: ${result.stderr || 'Unknown error'}`);
|
||||
}
|
||||
|
||||
// Debug logging to see what we're getting
|
||||
console.info('Raw sandbox result:', result.result);
|
||||
console.info('Trimmed result:', result.result.trim());
|
||||
console.info('Result type:', typeof result.result);
|
||||
|
||||
let fileResults: Array<{
|
||||
success: boolean;
|
||||
filePath: string;
|
||||
error?: string;
|
||||
}>;
|
||||
try {
|
||||
fileResults = JSON.parse(result.result.trim());
|
||||
|
||||
// Additional validation
|
||||
if (!Array.isArray(fileResults)) {
|
||||
console.error('Parsed result is not an array:', fileResults);
|
||||
throw new Error('Parsed result is not an array');
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('Failed to parse sandbox output:', result.result);
|
||||
throw new Error(
|
||||
`Failed to parse sandbox output: ${parseError instanceof Error ? parseError.message : 'Unknown parse error'}`
|
||||
);
|
||||
}
|
||||
|
||||
const output: CreateFilesToolOutput = {
|
||||
results: fileResults.map((fileResult) => {
|
||||
if (fileResult.success) {
|
||||
return {
|
||||
status: 'success' as const,
|
||||
filePath: fileResult.filePath,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'error' as const,
|
||||
filePath: fileResult.filePath,
|
||||
errorMessage: fileResult.error || 'Unknown error',
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
return output;
|
||||
} catch (error) {
|
||||
const errorOutput: CreateFilesToolOutput = {
|
||||
results: files.map((file) => ({
|
||||
status: 'error' as const,
|
||||
filePath: file.path,
|
||||
errorMessage: `Execution error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
})),
|
||||
};
|
||||
|
||||
return errorOutput;
|
||||
}
|
||||
},
|
||||
{ name: 'create-files' }
|
||||
);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
export { createBashTool, bashExecute } from './bash-tool';
|
||||
export { createListFilesTool } from './list-files-tool/list-files-tool';
|
||||
export { createReadFilesTool } from './read-files-tool/read-files-tool';
|
||||
export { createCreateFilesTool } from './create-files-tool/create-files-tool';
|
||||
export { createWriteFileTool } from './write-file-tool/write-file-tool';
|
||||
export { createEditFilesTool } from './edit-files-tool/edit-files-tool';
|
||||
export { createDeleteFilesTool } from './delete-files-tool/delete-files-tool';
|
||||
export { createGrepSearchTool } from './grep-search-tool/grep-search-tool';
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { WriteFileToolInput } from './write-file-tool';
|
||||
import { createWriteFileToolExecute } from './write-file-tool-execute';
|
||||
|
||||
// Mock Bun global
|
||||
const mockBunFile = vi.fn();
|
||||
const mockBunWrite = vi.fn();
|
||||
|
||||
global.Bun = {
|
||||
file: mockBunFile,
|
||||
write: mockBunWrite,
|
||||
} as unknown as typeof Bun;
|
||||
|
||||
describe('createWriteFileToolExecute', () => {
|
||||
const projectDirectory = '/project';
|
||||
const messageId = 'test-message-id';
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.spyOn(console, 'info').mockImplementation(() => { });
|
||||
vi.spyOn(console, 'error').mockImplementation(() => { });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('successful file creation', () => {
|
||||
it('should create a single new file successfully', async () => {
|
||||
// Setup
|
||||
const mockFile = {
|
||||
exists: vi.fn().mockResolvedValue(false),
|
||||
};
|
||||
mockBunFile.mockReturnValue(mockFile);
|
||||
mockBunWrite.mockResolvedValue(undefined);
|
||||
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{
|
||||
path: 'test.ts',
|
||||
content: 'export const test = "hello";',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]).toEqual({
|
||||
status: 'success',
|
||||
filePath: '/project/test.ts',
|
||||
});
|
||||
|
||||
expect(mockBunFile).toHaveBeenCalledWith('/project/test.ts');
|
||||
expect(mockFile.exists).toHaveBeenCalled();
|
||||
expect(mockBunWrite).toHaveBeenCalledWith('/project/test.ts', 'export const test = "hello";');
|
||||
});
|
||||
|
||||
it('should overwrite an existing file successfully', async () => {
|
||||
// Setup
|
||||
const mockFile = {
|
||||
exists: vi.fn().mockResolvedValue(true),
|
||||
};
|
||||
mockBunFile.mockReturnValue(mockFile);
|
||||
mockBunWrite.mockResolvedValue(undefined);
|
||||
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{
|
||||
path: 'existing.ts',
|
||||
content: 'updated content',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]).toEqual({
|
||||
status: 'success',
|
||||
filePath: '/project/existing.ts',
|
||||
});
|
||||
|
||||
expect(mockBunWrite).toHaveBeenCalledWith('/project/existing.ts', 'updated content');
|
||||
});
|
||||
|
||||
it('should create multiple files in parallel', async () => {
|
||||
// Setup
|
||||
const mockFile = {
|
||||
exists: vi.fn().mockResolvedValue(false),
|
||||
};
|
||||
mockBunFile.mockReturnValue(mockFile);
|
||||
mockBunWrite.mockResolvedValue(undefined);
|
||||
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{ path: 'file1.ts', content: 'content1' },
|
||||
{ path: 'file2.ts', content: 'content2' },
|
||||
{ path: 'file3.ts', content: 'content3' },
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(3);
|
||||
expect(result.results.every((r) => r.status === 'success')).toBe(true);
|
||||
expect(mockBunWrite).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should handle absolute paths correctly', async () => {
|
||||
// Setup
|
||||
const mockFile = {
|
||||
exists: vi.fn().mockResolvedValue(false),
|
||||
};
|
||||
mockBunFile.mockReturnValue(mockFile);
|
||||
mockBunWrite.mockResolvedValue(undefined);
|
||||
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{
|
||||
path: '/project/absolute/path.ts',
|
||||
content: 'absolute content',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]).toEqual({
|
||||
status: 'success',
|
||||
filePath: '/project/absolute/path.ts',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
it('should handle file write errors gracefully', async () => {
|
||||
// Setup
|
||||
const mockFile = {
|
||||
exists: vi.fn().mockResolvedValue(false),
|
||||
};
|
||||
mockBunFile.mockReturnValue(mockFile);
|
||||
mockBunWrite.mockRejectedValue(new Error('Permission denied'));
|
||||
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{
|
||||
path: 'error.ts',
|
||||
content: 'content',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]).toEqual({
|
||||
status: 'error',
|
||||
filePath: 'error.ts',
|
||||
errorMessage: 'Permission denied',
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject paths outside project directory', async () => {
|
||||
// Setup
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{
|
||||
path: '../outside/project.ts',
|
||||
content: 'malicious content',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(1);
|
||||
const firstResult = result.results[0];
|
||||
if (!firstResult) {
|
||||
throw new Error('Expected first result to exist');
|
||||
}
|
||||
expect(firstResult.status).toBe('error');
|
||||
if (firstResult.status === 'error') {
|
||||
expect(firstResult.errorMessage).toContain('not in the current working directory');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle mixed success and failure', async () => {
|
||||
// Setup
|
||||
const mockFile = {
|
||||
exists: vi.fn().mockResolvedValue(false),
|
||||
};
|
||||
mockBunFile.mockReturnValue(mockFile);
|
||||
mockBunWrite
|
||||
.mockResolvedValueOnce(undefined) // First succeeds
|
||||
.mockRejectedValueOnce(new Error('Write failed')) // Second fails
|
||||
.mockResolvedValueOnce(undefined); // Third succeeds
|
||||
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{ path: 'success1.ts', content: 'content1' },
|
||||
{ path: 'failure.ts', content: 'content2' },
|
||||
{ path: 'success2.ts', content: 'content3' },
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(3);
|
||||
if (!result.results[0] || !result.results[1] || !result.results[2]) {
|
||||
throw new Error('Expected all results to exist');
|
||||
}
|
||||
expect(result.results[0].status).toBe('success');
|
||||
expect(result.results[1].status).toBe('error');
|
||||
expect(result.results[2].status).toBe('success');
|
||||
});
|
||||
|
||||
it('should reject absolute paths outside project directory', async () => {
|
||||
// Setup
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{
|
||||
path: '/etc/passwd',
|
||||
content: 'malicious',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(1);
|
||||
const firstResult = result.results[0];
|
||||
if (!firstResult) {
|
||||
throw new Error('Expected first result to exist');
|
||||
}
|
||||
expect(firstResult.status).toBe('error');
|
||||
if (firstResult.status === 'error') {
|
||||
expect(firstResult.errorMessage).toContain('not in the current working directory');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('path handling', () => {
|
||||
it('should handle nested directory paths', async () => {
|
||||
// Setup
|
||||
const mockFile = {
|
||||
exists: vi.fn().mockResolvedValue(false),
|
||||
};
|
||||
mockBunFile.mockReturnValue(mockFile);
|
||||
mockBunWrite.mockResolvedValue(undefined);
|
||||
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{
|
||||
path: 'src/components/Button.tsx',
|
||||
content: 'export const Button = () => {};',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]).toEqual({
|
||||
status: 'success',
|
||||
filePath: '/project/src/components/Button.tsx',
|
||||
});
|
||||
});
|
||||
|
||||
it('should normalize paths correctly', async () => {
|
||||
// Setup
|
||||
const mockFile = {
|
||||
exists: vi.fn().mockResolvedValue(false),
|
||||
};
|
||||
mockBunFile.mockReturnValue(mockFile);
|
||||
mockBunWrite.mockResolvedValue(undefined);
|
||||
|
||||
const execute = createWriteFileToolExecute({ messageId, projectDirectory });
|
||||
const input: WriteFileToolInput = {
|
||||
files: [
|
||||
{
|
||||
path: './src/../lib/utils.ts',
|
||||
content: 'utils',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute
|
||||
const result = await execute(input);
|
||||
|
||||
// Verify
|
||||
const firstResult = result.results[0];
|
||||
if (!firstResult) {
|
||||
throw new Error('Expected first result to exist');
|
||||
}
|
||||
expect(firstResult.status).toBe('success');
|
||||
expect(firstResult.filePath).toBe('/project/lib/utils.ts');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,132 @@
|
|||
import path from 'node:path';
|
||||
import type {
|
||||
WriteFileToolContext,
|
||||
WriteFileToolInput,
|
||||
WriteFileToolOutput,
|
||||
} from './write-file-tool';
|
||||
|
||||
/**
|
||||
* Validates that a file path is safe and within the project directory
|
||||
* @param filePath - The file path to validate
|
||||
* @param projectDirectory - The root directory of the project
|
||||
* @throws Error if the path is unsafe or outside the project
|
||||
*/
|
||||
function validateFilePath(filePath: string, projectDirectory: string): void {
|
||||
// Convert to absolute path if relative
|
||||
const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(projectDirectory, filePath);
|
||||
|
||||
// Normalize to resolve any '..' or '.' components
|
||||
const normalizedPath = path.normalize(absolutePath);
|
||||
const normalizedProject = path.normalize(projectDirectory);
|
||||
|
||||
// Ensure the resolved path is within the project directory
|
||||
if (!normalizedPath.startsWith(normalizedProject)) {
|
||||
throw new Error(`File ${filePath} is not in the current working directory ${projectDirectory}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single file using Bun's filesystem API
|
||||
* @param filePath - The file path to create (absolute or relative)
|
||||
* @param content - The content to write
|
||||
* @param projectDirectory - The root directory of the project
|
||||
* @returns Result object with success status and details
|
||||
*/
|
||||
async function createSingleFile(
|
||||
filePath: string,
|
||||
content: string,
|
||||
projectDirectory: string
|
||||
): Promise<{
|
||||
status: 'success' | 'error';
|
||||
filePath: string;
|
||||
errorMessage?: string;
|
||||
existed?: boolean;
|
||||
}> {
|
||||
try {
|
||||
// Convert to absolute path if relative
|
||||
const absolutePath = path.isAbsolute(filePath)
|
||||
? filePath
|
||||
: path.join(projectDirectory, filePath);
|
||||
|
||||
// Validate the file path is within the project directory
|
||||
validateFilePath(absolutePath, projectDirectory);
|
||||
|
||||
// Check if file already exists
|
||||
const file = Bun.file(absolutePath);
|
||||
const existed = await file.exists();
|
||||
|
||||
if (existed) {
|
||||
console.info(`Overwriting existing file: ${absolutePath}`);
|
||||
} else {
|
||||
console.info(`Creating new file: ${absolutePath}`);
|
||||
}
|
||||
|
||||
// Write the file content (Bun automatically creates parent directories)
|
||||
await Bun.write(absolutePath, content);
|
||||
|
||||
console.info(`Successfully ${existed ? 'updated' : 'created'} file: ${absolutePath}`);
|
||||
|
||||
return {
|
||||
status: 'success',
|
||||
filePath: absolutePath,
|
||||
existed,
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
console.error(`Error creating file ${filePath}:`, errorMessage);
|
||||
|
||||
return {
|
||||
status: 'error',
|
||||
filePath,
|
||||
errorMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the execute function for the create files tool
|
||||
* @param context - The tool context containing messageId and project directory
|
||||
* @returns The execute function
|
||||
*/
|
||||
export function createWriteFileToolExecute(context: WriteFileToolContext) {
|
||||
return async function execute(input: WriteFileToolInput): Promise<WriteFileToolOutput> {
|
||||
const { messageId, projectDirectory } = context;
|
||||
const { files } = input;
|
||||
|
||||
console.info(`Creating ${files.length} file(s) for message ${messageId}`);
|
||||
|
||||
// Process all files in parallel
|
||||
const fileResults = await Promise.all(
|
||||
files.map((file) => createSingleFile(file.path, file.content, projectDirectory))
|
||||
);
|
||||
|
||||
// Format results according to the output schema
|
||||
const results = fileResults.map((result) => {
|
||||
if (result.status === 'success') {
|
||||
return {
|
||||
status: 'success' as const,
|
||||
filePath: result.filePath,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'error' as const,
|
||||
filePath: result.filePath,
|
||||
errorMessage: result.errorMessage || 'Unknown error occurred',
|
||||
};
|
||||
});
|
||||
|
||||
// Log summary
|
||||
const successCount = results.filter((r) => r.status === 'success').length;
|
||||
const errorCount = results.filter((r) => r.status === 'error').length;
|
||||
|
||||
console.info(`File creation complete: ${successCount} succeeded, ${errorCount} failed`);
|
||||
|
||||
if (errorCount > 0) {
|
||||
const errors = results.filter((r) => r.status === 'error');
|
||||
console.error('Failed files:', errors);
|
||||
}
|
||||
|
||||
return { results };
|
||||
};
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
import type { Sandbox } from '@buster/sandbox';
|
||||
import { tool } from 'ai';
|
||||
import { z } from 'zod';
|
||||
import { createCreateFilesToolExecute } from './create-files-tool-execute';
|
||||
import { createWriteFileToolExecute } from './write-file-tool-execute';
|
||||
|
||||
const FileCreateParamsSchema = z.object({
|
||||
path: z.string().describe('The relative or absolute path to create the file at'),
|
||||
content: z.string().describe('The content to write to the file'),
|
||||
});
|
||||
|
||||
export const CreateFilesToolInputSchema = z.object({
|
||||
export const WriteFileToolInputSchema = z.object({
|
||||
files: z.array(FileCreateParamsSchema).describe('Array of file creation operations to perform'),
|
||||
});
|
||||
|
||||
const CreateFilesToolOutputSchema = z.object({
|
||||
const WriteFileToolOutputSchema = z.object({
|
||||
results: z.array(
|
||||
z.discriminatedUnion('status', [
|
||||
z.object({
|
||||
|
@ -28,31 +27,24 @@ const CreateFilesToolOutputSchema = z.object({
|
|||
),
|
||||
});
|
||||
|
||||
const CreateFilesToolContextSchema = z.object({
|
||||
const WriteFileToolContextSchema = z.object({
|
||||
messageId: z.string().describe('The message ID for database updates'),
|
||||
sandbox: z
|
||||
.custom<Sandbox>(
|
||||
(val) => {
|
||||
return val && typeof val === 'object' && 'id' in val && 'fs' in val;
|
||||
},
|
||||
{ message: 'Invalid Sandbox instance' }
|
||||
)
|
||||
.describe('Sandbox instance for file operations'),
|
||||
projectDirectory: z.string().describe('The root directory of the project'),
|
||||
});
|
||||
|
||||
export type CreateFilesToolInput = z.infer<typeof CreateFilesToolInputSchema>;
|
||||
export type CreateFilesToolOutput = z.infer<typeof CreateFilesToolOutputSchema>;
|
||||
export type CreateFilesToolContext = z.infer<typeof CreateFilesToolContextSchema>;
|
||||
export type WriteFileToolInput = z.infer<typeof WriteFileToolInputSchema>;
|
||||
export type WriteFileToolOutput = z.infer<typeof WriteFileToolOutputSchema>;
|
||||
export type WriteFileToolContext = z.infer<typeof WriteFileToolContextSchema>;
|
||||
|
||||
export function createCreateFilesTool<
|
||||
TAgentContext extends CreateFilesToolContext = CreateFilesToolContext,
|
||||
export function createWriteFileTool<
|
||||
TAgentContext extends WriteFileToolContext = WriteFileToolContext,
|
||||
>(context: TAgentContext) {
|
||||
const execute = createCreateFilesToolExecute(context);
|
||||
const execute = createWriteFileToolExecute(context);
|
||||
|
||||
return tool({
|
||||
description: `Create one or more files at specified paths with provided content. Supports both absolute and relative file paths. Creates directories if they don't exist and overwrites existing files. Handles errors gracefully by continuing to process other files even if some fail. Returns both successful operations and failed operations with detailed error messages.`,
|
||||
inputSchema: CreateFilesToolInputSchema,
|
||||
outputSchema: CreateFilesToolOutputSchema,
|
||||
inputSchema: WriteFileToolInputSchema,
|
||||
outputSchema: WriteFileToolOutputSchema,
|
||||
execute,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
Writes a file to the local filesystem.
|
||||
|
||||
Usage:
|
||||
- This tool will overwrite the existing file if there is one at the provided path.
|
||||
- If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.
|
||||
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
|
||||
- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.
|
||||
- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.
|
|
@ -14,7 +14,7 @@ export { executeSqlDocsAgent } from './database-tools/super-execute-sql/super-ex
|
|||
// File tools - factory functions
|
||||
export { createListFilesTool } from './file-tools/list-files-tool/list-files-tool';
|
||||
export { createReadFilesTool } from './file-tools/read-files-tool/read-files-tool';
|
||||
export { createCreateFilesTool } from './file-tools/create-files-tool/create-files-tool';
|
||||
export { createWriteFileTool } from './file-tools/write-file-tool/write-file-tool';
|
||||
export { createEditFilesTool } from './file-tools/edit-files-tool/edit-files-tool';
|
||||
export { createDeleteFilesTool } from './file-tools/delete-files-tool/delete-files-tool';
|
||||
export { createBashTool } from './file-tools/bash-tool';
|
||||
|
|
|
@ -296,7 +296,7 @@ importers:
|
|||
version: 5.0.44(zod@3.25.76)
|
||||
drizzle-orm:
|
||||
specifier: 'catalog:'
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
hono:
|
||||
specifier: 'catalog:'
|
||||
version: 4.9.7
|
||||
|
@ -398,7 +398,7 @@ importers:
|
|||
version: 0.3.7(@aws-sdk/credential-provider-web-identity@3.888.0)(zod@3.25.76)
|
||||
drizzle-orm:
|
||||
specifier: 'catalog:'
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
js-yaml:
|
||||
specifier: 'catalog:'
|
||||
version: 4.1.0
|
||||
|
@ -636,7 +636,7 @@ importers:
|
|||
version: 0.7.0(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.9)
|
||||
'@tanstack/react-form':
|
||||
specifier: ^1.23.0
|
||||
version: 1.23.0(@tanstack/react-start@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9)))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
version: 1.23.0(@tanstack/react-start@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9)))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@tanstack/react-query':
|
||||
specifier: ^5.90.2
|
||||
version: 5.90.2(react@19.1.1)
|
||||
|
@ -660,7 +660,7 @@ importers:
|
|||
version: 1.130.17(@tanstack/react-query@5.90.2(react@19.1.1))(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.50)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@tanstack/react-start':
|
||||
specifier: ^1.131.50
|
||||
version: 1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))
|
||||
version: 1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))
|
||||
'@tanstack/react-store':
|
||||
specifier: ^0.7.7
|
||||
version: 0.7.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
|
@ -1012,7 +1012,7 @@ importers:
|
|||
version: link:../vitest-config
|
||||
drizzle-orm:
|
||||
specifier: 'catalog:'
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
lru-cache:
|
||||
specifier: ^11.1.0
|
||||
version: 11.1.0
|
||||
|
@ -1081,7 +1081,7 @@ importers:
|
|||
version: 0.3.7(@aws-sdk/credential-provider-web-identity@3.888.0)(zod@3.25.76)
|
||||
drizzle-orm:
|
||||
specifier: 'catalog:'
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
glob:
|
||||
specifier: ^11.0.3
|
||||
version: 11.0.3
|
||||
|
@ -1100,6 +1100,10 @@ importers:
|
|||
zod:
|
||||
specifier: 'catalog:'
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@types/bun':
|
||||
specifier: ^1.2.23
|
||||
version: 1.2.23(@types/react@19.1.13)
|
||||
|
||||
packages/data-source:
|
||||
dependencies:
|
||||
|
@ -1184,10 +1188,10 @@ importers:
|
|||
version: 0.31.4
|
||||
drizzle-orm:
|
||||
specifier: 'catalog:'
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
drizzle-zod:
|
||||
specifier: ^0.8.3
|
||||
version: 0.8.3(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(zod@3.25.76)
|
||||
version: 0.8.3(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(zod@3.25.76)
|
||||
lru-cache:
|
||||
specifier: ^11.2.1
|
||||
version: 11.2.1
|
||||
|
@ -6233,6 +6237,9 @@ packages:
|
|||
'@types/bun@1.2.21':
|
||||
resolution: {integrity: sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A==}
|
||||
|
||||
'@types/bun@1.2.23':
|
||||
resolution: {integrity: sha512-le8ueOY5b6VKYf19xT3McVbXqLqmxzPXHsQT/q9JHgikJ2X22wyTW3g3ohz2ZMnp7dod6aduIiq8A14Xyimm0A==}
|
||||
|
||||
'@types/canvas-confetti@1.9.0':
|
||||
resolution: {integrity: sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==}
|
||||
|
||||
|
@ -7040,6 +7047,11 @@ packages:
|
|||
peerDependencies:
|
||||
'@types/react': ^19
|
||||
|
||||
bun-types@1.2.23:
|
||||
resolution: {integrity: sha512-R9f0hKAZXgFU3mlrA0YpE/fiDvwV0FT9rORApt2aQVWSuJDzZOyB5QLc0N/4HF57CS8IXJ6+L5E4W1bW6NS2Aw==}
|
||||
peerDependencies:
|
||||
'@types/react': ^19
|
||||
|
||||
bundle-name@4.1.0:
|
||||
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
|
||||
engines: {node: '>=18'}
|
||||
|
@ -18371,7 +18383,7 @@ snapshots:
|
|||
- solid-js
|
||||
- utf-8-validate
|
||||
|
||||
'@tanstack/react-form@1.23.0(@tanstack/react-start@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9)))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
'@tanstack/react-form@1.23.0(@tanstack/react-start@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9)))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@tanstack/form-core': 1.23.0
|
||||
'@tanstack/react-store': 0.7.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
|
@ -18379,7 +18391,7 @@ snapshots:
|
|||
devalue: 5.3.2
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@tanstack/react-start': 1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))
|
||||
'@tanstack/react-start': 1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))
|
||||
transitivePeerDependencies:
|
||||
- react-dom
|
||||
|
||||
|
@ -18453,9 +18465,9 @@ snapshots:
|
|||
tiny-invariant: 1.3.3
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
'@tanstack/react-start-plugin@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))':
|
||||
'@tanstack/react-start-plugin@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))':
|
||||
dependencies:
|
||||
'@tanstack/start-plugin-core': 1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))
|
||||
'@tanstack/start-plugin-core': 1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))
|
||||
'@vitejs/plugin-react': 5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))
|
||||
pathe: 2.0.3
|
||||
vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)
|
||||
|
@ -18505,10 +18517,10 @@ snapshots:
|
|||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
|
||||
'@tanstack/react-start@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))':
|
||||
'@tanstack/react-start@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))':
|
||||
dependencies:
|
||||
'@tanstack/react-start-client': 1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@tanstack/react-start-plugin': 1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))
|
||||
'@tanstack/react-start-plugin': 1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.3(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))
|
||||
'@tanstack/react-start-server': 1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@tanstack/start-server-functions-client': 1.131.50(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))
|
||||
'@tanstack/start-server-functions-server': 1.131.2(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))
|
||||
|
@ -18672,7 +18684,7 @@ snapshots:
|
|||
tiny-invariant: 1.3.3
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
'@tanstack/start-plugin-core@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))':
|
||||
'@tanstack/start-plugin-core@1.131.50(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(@tanstack/react-router@1.131.50(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(webpack@5.99.9(esbuild@0.25.9))':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.26.2
|
||||
'@babel/core': 7.28.4
|
||||
|
@ -18688,7 +18700,7 @@ snapshots:
|
|||
babel-dead-code-elimination: 1.0.10
|
||||
cheerio: 1.1.2
|
||||
h3: 1.13.0
|
||||
nitropack: 2.12.5(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))
|
||||
nitropack: 2.12.5(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))
|
||||
pathe: 2.0.3
|
||||
ufo: 1.6.1
|
||||
vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.93.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)
|
||||
|
@ -19183,6 +19195,12 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
'@types/bun@1.2.23(@types/react@19.1.13)':
|
||||
dependencies:
|
||||
bun-types: 1.2.23(@types/react@19.1.13)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
'@types/canvas-confetti@1.9.0': {}
|
||||
|
||||
'@types/caseless@0.12.5': {}
|
||||
|
@ -19289,7 +19307,7 @@ snapshots:
|
|||
|
||||
'@types/node-fetch@2.6.12':
|
||||
dependencies:
|
||||
'@types/node': 18.19.124
|
||||
'@types/node': 22.18.1
|
||||
form-data: 4.0.4
|
||||
|
||||
'@types/node@16.9.1': {}
|
||||
|
@ -19356,7 +19374,7 @@ snapshots:
|
|||
'@types/request@2.48.12':
|
||||
dependencies:
|
||||
'@types/caseless': 0.12.5
|
||||
'@types/node': 24.3.1
|
||||
'@types/node': 22.18.1
|
||||
'@types/tough-cookie': 4.0.5
|
||||
form-data: 2.5.3
|
||||
|
||||
|
@ -20214,6 +20232,11 @@ snapshots:
|
|||
'@types/node': 24.3.1
|
||||
'@types/react': 19.1.13
|
||||
|
||||
bun-types@1.2.23(@types/react@19.1.13):
|
||||
dependencies:
|
||||
'@types/node': 22.18.1
|
||||
'@types/react': 19.1.13
|
||||
|
||||
bundle-name@4.1.0:
|
||||
dependencies:
|
||||
run-applescript: 7.0.0
|
||||
|
@ -20730,9 +20753,9 @@ snapshots:
|
|||
|
||||
dayjs@1.11.18: {}
|
||||
|
||||
db0@0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1):
|
||||
db0@0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1):
|
||||
optionalDependencies:
|
||||
drizzle-orm: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
drizzle-orm: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
mysql2: 3.14.1
|
||||
|
||||
debug@2.6.9:
|
||||
|
@ -20907,18 +20930,18 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7):
|
||||
drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7):
|
||||
optionalDependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@types/pg': 8.15.4
|
||||
bun-types: 1.2.21(@types/react@19.1.13)
|
||||
bun-types: 1.2.23(@types/react@19.1.13)
|
||||
mysql2: 3.14.1
|
||||
pg: 8.16.3
|
||||
postgres: 3.4.7
|
||||
|
||||
drizzle-zod@0.8.3(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(zod@3.25.76):
|
||||
drizzle-zod@0.8.3(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(zod@3.25.76):
|
||||
dependencies:
|
||||
drizzle-orm: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
drizzle-orm: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
|
||||
zod: 3.25.76
|
||||
|
||||
dt-sql-parser@4.3.1(antlr4ng-cli@1.0.7):
|
||||
|
@ -23869,7 +23892,7 @@ snapshots:
|
|||
- babel-plugin-macros
|
||||
optional: true
|
||||
|
||||
nitropack@2.12.5(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13)):
|
||||
nitropack@2.12.5(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(encoding@0.1.13)(mysql2@3.14.1)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13)):
|
||||
dependencies:
|
||||
'@cloudflare/kv-asset-handler': 0.4.0
|
||||
'@rollup/plugin-alias': 5.1.1(rollup@4.50.0)
|
||||
|
@ -23890,7 +23913,7 @@ snapshots:
|
|||
cookie-es: 2.0.0
|
||||
croner: 9.1.0
|
||||
crossws: 0.3.5
|
||||
db0: 0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1)
|
||||
db0: 0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1)
|
||||
defu: 6.1.4
|
||||
destr: 2.0.5
|
||||
dot-prop: 9.0.0
|
||||
|
@ -23936,7 +23959,7 @@ snapshots:
|
|||
unenv: 2.0.0-rc.20
|
||||
unimport: 5.2.0
|
||||
unplugin-utils: 0.3.0
|
||||
unstorage: 1.17.1(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(db0@0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1))(ioredis@5.7.0)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))
|
||||
unstorage: 1.17.1(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(db0@0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1))(ioredis@5.7.0)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13))
|
||||
untyped: 2.0.0
|
||||
unwasm: 0.3.11
|
||||
youch: 4.1.0-beta.8
|
||||
|
@ -26473,7 +26496,7 @@ snapshots:
|
|||
picomatch: 4.0.3
|
||||
webpack-virtual-modules: 0.6.2
|
||||
|
||||
unstorage@1.17.1(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(db0@0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1))(ioredis@5.7.0)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13)):
|
||||
unstorage@1.17.1(@azure/identity@4.10.2)(@azure/storage-blob@12.26.0)(db0@0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1))(ioredis@5.7.0)(uploadthing@7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13)):
|
||||
dependencies:
|
||||
anymatch: 3.1.3
|
||||
chokidar: 4.0.3
|
||||
|
@ -26486,7 +26509,7 @@ snapshots:
|
|||
optionalDependencies:
|
||||
'@azure/identity': 4.10.2
|
||||
'@azure/storage-blob': 12.26.0
|
||||
db0: 0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.21(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1)
|
||||
db0: 0.3.2(drizzle-orm@0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7))(mysql2@3.14.1)
|
||||
ioredis: 5.7.0
|
||||
uploadthing: 7.7.4(express@5.1.0)(h3@1.15.4)(next@14.2.30(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.93.1))(tailwindcss@4.1.13)
|
||||
|
||||
|
|
Loading…
Reference in New Issue