mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
## CHANGES
- Refreshed Maestro tagline across README and package metadata for clarity ✨ - Reset-on-completion now writes working copies into `Runs/` folder consistently 📁 - Auto Run working-copy IPC handler updated for new `Runs/` directory naming 🧭 - Working-copy relative paths now return `Runs/...` for downstream consumers 🔗 - Preload API docs updated to reflect `Runs/` working-copy location 🧩 - AutoRunner Help Modal now points users to `Runs/` audit-log folder 🪟 - Batch processor tracking/comments updated for `Runs/` audit log behavior 🧾 - Test suite updated to expect `Runs/` working-copy paths reliably 🧪
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
[](https://github.com/pedramamini/Maestro)
|
||||
[](https://discord.gg/SrBsykvG)
|
||||
|
||||
> Run AI coding agents autonomously for days.
|
||||
> Maestro hones fractured attention into focused intent.
|
||||
|
||||
Maestro is a cross-platform desktop app for orchestrating your fleet of AI agents and projects. It's a high-velocity solution for hackers who are juggling multiple projects in parallel. Designed for power users who live on the keyboard and rarely touch the mouse.
|
||||
|
||||
@@ -459,7 +459,7 @@ Auto Run supports running multiple documents in sequence:
|
||||
2. Click **+ Add Docs** to add more documents to the queue
|
||||
3. Drag to reorder documents as needed
|
||||
4. Configure options per document:
|
||||
- **Reset on Completion** - Creates a working copy in `runs/` subfolder instead of modifying the original. The original document is never touched, and working copies (e.g., `TASK-1735192800000-loop-1.md`) serve as audit logs.
|
||||
- **Reset on Completion** - Creates a working copy in `Runs/` subfolder instead of modifying the original. The original document is never touched, and working copies (e.g., `TASK-1735192800000-loop-1.md`) serve as audit logs.
|
||||
- **Duplicate** - Add the same document multiple times
|
||||
5. Enable **Loop Mode** to cycle back to the first document after completing the last
|
||||
6. Click **Go** to start the batch run
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "maestro",
|
||||
"version": "0.12.1",
|
||||
"description": "Run AI coding agents autonomously for days.",
|
||||
"description": "Maestro hones fractured attention into focused intent.",
|
||||
"main": "dist/main/index.js",
|
||||
"author": {
|
||||
"name": "Pedram Amini",
|
||||
|
||||
@@ -620,7 +620,7 @@ describe('useBatchProcessor hook', () => {
|
||||
// Set up window.maestro mocks
|
||||
mockReadDoc = vi.fn().mockResolvedValue({ success: true, content: '# Tasks\n- [ ] Task 1\n- [ ] Task 2' });
|
||||
mockWriteDoc = vi.fn().mockResolvedValue({ success: true });
|
||||
mockCreateWorkingCopy = vi.fn().mockResolvedValue({ workingCopyPath: 'runs/tasks-run-1.md' });
|
||||
mockCreateWorkingCopy = vi.fn().mockResolvedValue({ workingCopyPath: 'Runs/tasks-run-1.md' });
|
||||
mockStatus = vi.fn().mockResolvedValue({ stdout: '' });
|
||||
mockBranch = vi.fn().mockResolvedValue({ stdout: 'main' });
|
||||
mockBroadcastAutoRunState = vi.fn();
|
||||
@@ -1366,7 +1366,7 @@ describe('useBatchProcessor hook', () => {
|
||||
|
||||
describe('reset on completion', () => {
|
||||
it('should create working copy when resetOnCompletion is enabled', async () => {
|
||||
// Note: Reset-on-completion now uses working copies in /runs/ directory
|
||||
// Note: Reset-on-completion now uses working copies in /Runs/ directory
|
||||
// instead of modifying the original document. This preserves the original
|
||||
// and allows the agent to work on a copy.
|
||||
const sessions = [createMockSession()];
|
||||
@@ -3205,7 +3205,7 @@ describe('useBatchProcessor hook', () => {
|
||||
|
||||
describe('reset-on-completion in loop mode', () => {
|
||||
it('should create working copy when document has resetOnCompletion enabled', async () => {
|
||||
// Note: Reset-on-completion now uses working copies in /runs/ directory
|
||||
// Note: Reset-on-completion now uses working copies in /Runs/ directory
|
||||
// instead of modifying the original document. This preserves the original
|
||||
// and allows the agent to work on a copy each loop iteration.
|
||||
const sessions = [createMockSession()];
|
||||
|
||||
@@ -570,7 +570,7 @@ export function registerAutorunHandlers(deps: {
|
||||
);
|
||||
|
||||
// Create a working copy of a document for reset-on-completion loops
|
||||
// Working copies are stored in /runs/ subdirectory with format: {name}-{timestamp}-loop-{N}.md
|
||||
// Working copies are stored in /Runs/ subdirectory with format: {name}-{timestamp}-loop-{N}.md
|
||||
ipcMain.handle(
|
||||
'autorun:createWorkingCopy',
|
||||
createIpcHandler(
|
||||
@@ -604,10 +604,10 @@ export function registerAutorunHandlers(deps: {
|
||||
throw new Error('Source file not found');
|
||||
}
|
||||
|
||||
// Create runs directory (with subdirectory if needed)
|
||||
// Create Runs directory (with subdirectory if needed)
|
||||
const runsDir = subDir
|
||||
? path.join(folderPath, 'runs', subDir)
|
||||
: path.join(folderPath, 'runs');
|
||||
? path.join(folderPath, 'Runs', subDir)
|
||||
: path.join(folderPath, 'Runs');
|
||||
await fs.mkdir(runsDir, { recursive: true });
|
||||
|
||||
// Generate working copy filename: {name}-{timestamp}-loop-{N}.md
|
||||
@@ -625,8 +625,8 @@ export function registerAutorunHandlers(deps: {
|
||||
|
||||
// Return the relative path (without .md for consistency with other APIs)
|
||||
const relativePath = subDir
|
||||
? `runs/${subDir}/${workingCopyName.slice(0, -3)}`
|
||||
: `runs/${workingCopyName.slice(0, -3)}`;
|
||||
? `Runs/${subDir}/${workingCopyName.slice(0, -3)}`
|
||||
: `Runs/${workingCopyName.slice(0, -3)}`;
|
||||
|
||||
logger.info(`Created Auto Run working copy: ${relativePath}`, LOG_CONTEXT);
|
||||
return { workingCopyPath: relativePath, originalPath: baseName };
|
||||
|
||||
@@ -1050,7 +1050,7 @@ contextBridge.exposeInMainWorld('maestro', {
|
||||
deleteBackups: (folderPath: string) =>
|
||||
ipcRenderer.invoke('autorun:deleteBackups', folderPath),
|
||||
// Working copy operations for reset-on-completion documents (preferred)
|
||||
// Creates a copy in /runs/ subdirectory: {name}-{timestamp}-loop-{N}.md
|
||||
// Creates a copy in /Runs/ subdirectory: {name}-{timestamp}-loop-{N}.md
|
||||
createWorkingCopy: (folderPath: string, filename: string, loopNumber: number): Promise<{ workingCopyPath: string; originalPath: string }> =>
|
||||
ipcRenderer.invoke('autorun:createWorkingCopy', folderPath, filename, loopNumber),
|
||||
},
|
||||
|
||||
@@ -283,7 +283,7 @@ export function AutoRunnerHelpModal({ theme, onClose }: AutoRunnerHelpModalProps
|
||||
<p>
|
||||
Enable the reset toggle (<RotateCcw className="w-3 h-3 inline" />) on any document to
|
||||
keep it available for repeated runs. When enabled, Auto Run creates a <strong style={{ color: theme.colors.textMain }}>working copy</strong> in
|
||||
the <code>runs/</code> subfolder and processes that copy—<em>the original document is never modified</em>.
|
||||
the <code>Runs/</code> subfolder and processes that copy—<em>the original document is never modified</em>.
|
||||
</p>
|
||||
<p>
|
||||
Working copies are named with timestamps (e.g., <code>TASK-1735192800000-loop-1.md</code>) and
|
||||
|
||||
2
src/renderer/global.d.ts
vendored
2
src/renderer/global.d.ts
vendored
@@ -787,7 +787,7 @@ interface MaestroAPI {
|
||||
restoreBackup: (folderPath: string, filename: string) => Promise<{ success: boolean; error?: string }>;
|
||||
deleteBackups: (folderPath: string) => Promise<{ success: boolean; deletedCount?: number; error?: string }>;
|
||||
// Working copy operations for reset-on-completion documents (preferred)
|
||||
// Creates a copy in /runs/ subdirectory: {name}-{timestamp}-loop-{N}.md
|
||||
// Creates a copy in /Runs/ subdirectory: {name}-{timestamp}-loop-{N}.md
|
||||
createWorkingCopy: (folderPath: string, filename: string, loopNumber: number) => Promise<{ workingCopyPath: string; originalPath: string }>;
|
||||
};
|
||||
// Playbooks API (saved batch run configurations)
|
||||
|
||||
@@ -557,7 +557,7 @@ export function useBatchProcessor({
|
||||
const stalledDocuments: Map<string, string> = new Map();
|
||||
|
||||
// Track working copies for reset-on-completion documents (original filename -> working copy path)
|
||||
// Working copies are stored in /runs/ and serve as audit logs
|
||||
// Working copies are stored in /Runs/ and serve as audit logs
|
||||
const workingCopies: Map<string, string> = new Map();
|
||||
|
||||
// Helper to add final loop summary (defined here so it has access to tracking vars)
|
||||
@@ -643,7 +643,7 @@ export function useBatchProcessor({
|
||||
let effectiveFilename = docEntry.filename;
|
||||
|
||||
// Create working copy for reset-on-completion documents
|
||||
// Working copies are stored in /runs/ and the original is never modified
|
||||
// Working copies are stored in /Runs/ and the original is never modified
|
||||
if (docEntry.resetOnCompletion) {
|
||||
try {
|
||||
const { workingCopyPath } = await window.maestro.autorun.createWorkingCopy(
|
||||
@@ -912,7 +912,7 @@ export function useBatchProcessor({
|
||||
|
||||
// Skip document handling if this document stalled (it didn't complete normally)
|
||||
if (stalledDocuments.has(docEntry.filename)) {
|
||||
// Working copy approach: stalled working copy stays in /runs/ as audit log
|
||||
// Working copy approach: stalled working copy stays in /Runs/ as audit log
|
||||
// Original document is untouched, so nothing to restore
|
||||
workingCopies.delete(docEntry.filename);
|
||||
// Reset consecutive no-change counter for next document
|
||||
@@ -921,14 +921,14 @@ export function useBatchProcessor({
|
||||
}
|
||||
|
||||
if (skipCurrentDocumentAfterError) {
|
||||
// Working copy approach: errored working copy stays in /runs/ as audit log
|
||||
// Working copy approach: errored working copy stays in /Runs/ as audit log
|
||||
// Original document is untouched, so nothing to restore
|
||||
workingCopies.delete(docEntry.filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Document complete - for reset-on-completion docs, original is untouched
|
||||
// Working copy in /runs/ serves as the audit log of this loop's work
|
||||
// Working copy in /Runs/ serves as the audit log of this loop's work
|
||||
if (docEntry.resetOnCompletion && docTasksCompleted > 0) {
|
||||
// AUTORUN LOG: Document loop completed
|
||||
window.maestro.logger.autorun(
|
||||
@@ -956,7 +956,7 @@ export function useBatchProcessor({
|
||||
}));
|
||||
}
|
||||
|
||||
// Clear tracking - working copy stays in /runs/ as audit log
|
||||
// Clear tracking - working copy stays in /Runs/ as audit log
|
||||
workingCopies.delete(docEntry.filename);
|
||||
} else if (docEntry.resetOnCompletion) {
|
||||
// Document had reset enabled but no tasks were completed
|
||||
@@ -1104,7 +1104,7 @@ export function useBatchProcessor({
|
||||
|
||||
// Working copy approach: no cleanup needed
|
||||
// - Original documents are never modified
|
||||
// - Working copies in /runs/ serve as audit logs and are kept
|
||||
// - Working copies in /Runs/ serve as audit logs and are kept
|
||||
// - User can delete them manually if desired
|
||||
|
||||
// Create PR if worktree was used, PR creation is enabled, and not stopped
|
||||
|
||||
Reference in New Issue
Block a user