86 lines
4 KiB
TypeScript
86 lines
4 KiB
TypeScript
|
|
import { describe, expect, it, vi } from 'vitest'
|
||
|
|
import {
|
||
|
|
detectFileOperation,
|
||
|
|
parseBashFileCreation,
|
||
|
|
type AgentFileCallbacks,
|
||
|
|
} from './aiAgentFileOperations'
|
||
|
|
|
||
|
|
const VAULT = '/Users/luca/Laputa'
|
||
|
|
|
||
|
|
function makeCallbacks() {
|
||
|
|
return {
|
||
|
|
onFileCreated: vi.fn(),
|
||
|
|
onFileModified: vi.fn(),
|
||
|
|
onVaultChanged: vi.fn(),
|
||
|
|
} satisfies AgentFileCallbacks
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('detectFileOperation', () => {
|
||
|
|
it('calls onFileCreated for Write tool with .md in vault', () => {
|
||
|
|
const cb = makeCallbacks()
|
||
|
|
detectFileOperation({ toolName: 'Write', input: JSON.stringify({ file_path: `${VAULT}/note/test.md` }), vaultPath: VAULT, callbacks: cb })
|
||
|
|
expect(cb.onFileCreated).toHaveBeenCalledWith('note/test.md')
|
||
|
|
expect(cb.onFileModified).not.toHaveBeenCalled()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('calls onFileCreated for create_note tool with relative markdown path', () => {
|
||
|
|
const cb = makeCallbacks()
|
||
|
|
detectFileOperation({ toolName: 'create_note', input: JSON.stringify({ path: 'note/generated.md' }), vaultPath: VAULT, callbacks: cb })
|
||
|
|
expect(cb.onFileCreated).toHaveBeenCalledWith('note/generated.md')
|
||
|
|
expect(cb.onVaultChanged).not.toHaveBeenCalled()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('calls onFileCreated for create_note tool with Windows absolute path', () => {
|
||
|
|
const cb = makeCallbacks()
|
||
|
|
detectFileOperation({
|
||
|
|
toolName: 'create_note',
|
||
|
|
input: JSON.stringify({ path: String.raw`D:\Notes\Notas\nota-longa-teste-gerada-2.md` }),
|
||
|
|
vaultPath: String.raw`D:\Notes\Notas`,
|
||
|
|
callbacks: cb,
|
||
|
|
})
|
||
|
|
expect(cb.onFileCreated).toHaveBeenCalledWith('nota-longa-teste-gerada-2.md')
|
||
|
|
expect(cb.onVaultChanged).not.toHaveBeenCalled()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('calls onFileModified for Edit tool with .md in vault', () => {
|
||
|
|
const cb = makeCallbacks()
|
||
|
|
detectFileOperation({ toolName: 'Edit', input: JSON.stringify({ file_path: `${VAULT}/note/test.md` }), vaultPath: VAULT, callbacks: cb })
|
||
|
|
expect(cb.onFileModified).toHaveBeenCalledWith('note/test.md')
|
||
|
|
expect(cb.onFileCreated).not.toHaveBeenCalled()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('refreshes the vault when a writable tool target cannot be resolved', () => {
|
||
|
|
const cb = makeCallbacks()
|
||
|
|
detectFileOperation({ toolName: 'Write', input: 'not-json', vaultPath: VAULT, callbacks: cb })
|
||
|
|
detectFileOperation({ toolName: 'Edit', vaultPath: VAULT, callbacks: cb })
|
||
|
|
expect(cb.onVaultChanged).toHaveBeenCalledTimes(2)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('does not treat path prefixes as files inside the vault', () => {
|
||
|
|
const cb = makeCallbacks()
|
||
|
|
detectFileOperation({ toolName: 'Write', input: JSON.stringify({ file_path: `${VAULT}-old/note.md` }), vaultPath: VAULT, callbacks: cb })
|
||
|
|
expect(cb.onFileCreated).not.toHaveBeenCalled()
|
||
|
|
expect(cb.onVaultChanged).toHaveBeenCalledOnce()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('detects Bash redirects and tee writes for markdown files in the vault', () => {
|
||
|
|
expect(parseBashFileCreation({ input: JSON.stringify({ command: `echo "# Title" > ${VAULT}/note.md` }), vaultPath: VAULT })).toBe('note.md')
|
||
|
|
expect(parseBashFileCreation({ input: JSON.stringify({ command: `echo "line" >> ${VAULT}/sub/note.md` }), vaultPath: VAULT })).toBe('sub/note.md')
|
||
|
|
expect(parseBashFileCreation({ input: JSON.stringify({ command: `echo "data" | tee -a ${VAULT}/new.md` }), vaultPath: VAULT })).toBe('new.md')
|
||
|
|
})
|
||
|
|
|
||
|
|
it('refreshes the vault for Bash when no specific markdown target is found', () => {
|
||
|
|
const cb = makeCallbacks()
|
||
|
|
detectFileOperation({ toolName: 'Bash', input: JSON.stringify({ command: 'ls -la' }), vaultPath: VAULT, callbacks: cb })
|
||
|
|
expect(cb.onFileCreated).not.toHaveBeenCalled()
|
||
|
|
expect(cb.onVaultChanged).toHaveBeenCalledOnce()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('ignores read-only tools and missing callbacks', () => {
|
||
|
|
const cb = makeCallbacks()
|
||
|
|
expect(() => detectFileOperation({ toolName: 'Write', input: JSON.stringify({ file_path: `${VAULT}/note/test.md` }), vaultPath: VAULT })).not.toThrow()
|
||
|
|
detectFileOperation({ toolName: 'Read', input: JSON.stringify({ file_path: `${VAULT}/note/test.md` }), vaultPath: VAULT, callbacks: cb })
|
||
|
|
expect(cb.onFileCreated).not.toHaveBeenCalled()
|
||
|
|
expect(cb.onVaultChanged).not.toHaveBeenCalled()
|
||
|
|
})
|
||
|
|
})
|