Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
550 changes: 282 additions & 268 deletions docs/releases.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/__tests__/cli/services/agent-sessions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { listClaudeSessions } from '../../../cli/services/agent-sessions';

// Mock fs
Expand All @@ -28,7 +29,7 @@ describe('listClaudeSessions', () => {
const projectPath = '/path/to/project';
// encodeClaudeProjectPath: replace all non-alphanumeric with -
const encodedPath = '-path-to-project';
const sessionsDir = `/home/testuser/.claude/projects/${encodedPath}`;
const sessionsDir = path.join('/home/testuser', '.claude', 'projects', encodedPath);

const makeJsonlContent = (
opts: {
Expand Down
51 changes: 28 additions & 23 deletions src/__tests__/cli/services/storage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import type { Group, SessionInfo, HistoryEntry } from '../../../shared/types';

// Store original env values
Expand Down Expand Up @@ -98,7 +99,9 @@ describe('storage service', () => {

const result = getConfigDirectory();

expect(result).toBe('/Users/testuser/Library/Application Support/Maestro');
expect(result).toBe(
path.join('/Users/testuser', 'Library', 'Application Support', 'Maestro')
);
});

it('should return Windows config path with APPDATA', () => {
Expand Down Expand Up @@ -130,7 +133,7 @@ describe('storage service', () => {

const result = getConfigDirectory();

expect(result).toBe('/home/testuser/.custom-config/Maestro');
expect(result).toBe(path.join('/home/testuser/.custom-config', 'Maestro'));
});

it('should return Linux config path fallback without XDG_CONFIG_HOME', () => {
Expand All @@ -140,7 +143,7 @@ describe('storage service', () => {

const result = getConfigDirectory();

expect(result).toBe('/home/testuser/.config/Maestro');
expect(result).toBe(path.join('/home/testuser', '.config', 'Maestro'));
});

it('should use Linux path for unknown platforms', () => {
Expand All @@ -150,7 +153,7 @@ describe('storage service', () => {

const result = getConfigDirectory();

expect(result).toBe('/home/testuser/.config/Maestro');
expect(result).toBe(path.join('/home/testuser', '.config', 'Maestro'));
});
});

Expand Down Expand Up @@ -829,7 +832,9 @@ describe('storage service', () => {

const writeCall = vi.mocked(fs.writeFileSync).mock.calls[0];
expect(writeCall[0]).toContain('maestro-history.json');
expect(writeCall[0]).toContain('/Users/testuser/Library/Application Support/Maestro');
expect(writeCall[0]).toContain(
path.join('/Users/testuser', 'Library', 'Application Support', 'Maestro')
);
});
});

Expand Down Expand Up @@ -919,11 +924,11 @@ describe('storage service', () => {
beforeEach(() => {
// Enable migrated mode by making existsSync return true for migration marker
vi.mocked(fs.existsSync).mockImplementation((filepath: fs.PathLike) => {
const pathStr = String(filepath);
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('history-migrated.json')) {
return true;
}
if (pathStr.includes('/history/')) {
if (pathStr.includes(`${path.sep}history${path.sep}`)) {
// Check specific session file existence
return pathStr.includes('session-123.json') || pathStr.includes('session-456.json');
}
Expand Down Expand Up @@ -971,15 +976,15 @@ describe('storage service', () => {
] as unknown as fs.Dirent[]);

vi.mocked(fs.existsSync).mockImplementation((filepath: fs.PathLike) => {
const pathStr = String(filepath);
if (pathStr.includes('history-migrated.json') || pathStr.includes('/history')) {
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('history-migrated.json') || pathStr.includes(`${path.sep}history`)) {
return true;
}
return false;
});

vi.mocked(fs.readFileSync).mockImplementation((filepath) => {
const pathStr = String(filepath);
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('session-123.json')) {
return JSON.stringify({
version: 1,
Expand Down Expand Up @@ -1016,15 +1021,15 @@ describe('storage service', () => {
] as unknown as fs.Dirent[]);

vi.mocked(fs.existsSync).mockImplementation((filepath: fs.PathLike) => {
const pathStr = String(filepath);
if (pathStr.includes('history-migrated.json') || pathStr.includes('/history')) {
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('history-migrated.json') || pathStr.includes(`${path.sep}history`)) {
return true;
}
return false;
});

vi.mocked(fs.readFileSync).mockImplementation((filepath) => {
const pathStr = String(filepath);
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('session-123.json')) {
return JSON.stringify({
version: 1,
Expand Down Expand Up @@ -1066,14 +1071,14 @@ describe('storage service', () => {

it('should write entry to session-specific file', () => {
vi.mocked(fs.existsSync).mockImplementation((filepath: fs.PathLike) => {
const pathStr = String(filepath);
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('history-migrated.json')) {
return true;
}
if (pathStr.includes('/history/session-123.json')) {
if (pathStr.includes(`${path.sep}history${path.sep}session-123.json`)) {
return true;
}
return pathStr.includes('/history');
return pathStr.includes(`${path.sep}history`);
});

const existingData = {
Expand All @@ -1093,15 +1098,15 @@ describe('storage service', () => {

expect(fs.writeFileSync).toHaveBeenCalled();
const writeCall = vi.mocked(fs.writeFileSync).mock.calls[0];
expect(writeCall[0]).toContain('/history/session-123.json');
expect(writeCall[0]).toContain(path.join('history', 'session-123.json'));
const writtenData = JSON.parse(writeCall[1] as string);
expect(writtenData.entries).toHaveLength(2);
expect(writtenData.entries[0].id).toBe('new-entry'); // New entry at beginning
});

it('should create history directory if it does not exist', () => {
vi.mocked(fs.existsSync).mockImplementation((filepath: fs.PathLike) => {
const pathStr = String(filepath);
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('history-migrated.json')) {
return true;
}
Expand All @@ -1115,18 +1120,18 @@ describe('storage service', () => {
});
addHistoryEntry(newEntry);

expect(fs.mkdirSync).toHaveBeenCalledWith(expect.stringContaining('/history'), {
expect(fs.mkdirSync).toHaveBeenCalledWith(expect.stringContaining(`${path.sep}history`), {
recursive: true,
});
});

it('should skip entries without sessionId', () => {
vi.mocked(fs.existsSync).mockImplementation((filepath: fs.PathLike) => {
const pathStr = String(filepath);
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('history-migrated.json')) {
return true;
}
return pathStr.includes('/history');
return pathStr.includes(`${path.sep}history`);
});

const newEntry = mockHistoryEntry({
Expand All @@ -1143,11 +1148,11 @@ describe('storage service', () => {

it('should enforce max entries limit (5000)', () => {
vi.mocked(fs.existsSync).mockImplementation((filepath: fs.PathLike) => {
const pathStr = String(filepath);
const pathStr = path.normalize(String(filepath));
if (pathStr.includes('history-migrated.json')) {
return true;
}
return pathStr.includes('/history');
return pathStr.includes(`${path.sep}history`);
});

// Create 5000 existing entries
Expand Down
Loading