From bcfb7be3da2ebb5cc3dc84e64f429a3cb89dc10d Mon Sep 17 00:00:00 2001 From: ProaFilippi Date: Mon, 30 Mar 2026 18:38:49 -0500 Subject: [PATCH 01/23] feat: Auto-retry Claude rate limits with exact countdown timer --- package-lock.json | 79 +++++------ .../main/parsers/rate-limit-event.test.ts | 87 +++++++++++++ src/main/parsers/claude-output-parser.ts | 79 ++++++++++- src/main/parsers/error-patterns.ts | 116 ++++++++++++++++- src/main/preload/process.ts | 1 + .../process-manager/handlers/StdoutHandler.ts | 1 + src/main/process-manager/types.ts | 2 + src/renderer/components/AgentErrorModal.tsx | 123 +++++++++++++++++- src/renderer/global.d.ts | 1 + src/renderer/hooks/agent/useAgentListeners.ts | 1 + src/shared/types.ts | 3 + 11 files changed, 443 insertions(+), 50 deletions(-) create mode 100644 src/__tests__/main/parsers/rate-limit-event.test.ts diff --git a/package-lock.json b/package-lock.json index 3f79a06d67..e79c9be0f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "maestro", - "version": "0.16.1-RC", + "version": "0.16.3-RC", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "maestro", - "version": "0.16.1-RC", + "version": "0.16.3-RC", "hasInstallScript": true, "license": "AGPL 3.0", "dependencies": { @@ -274,7 +274,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -678,7 +677,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -722,7 +720,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -2296,7 +2293,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -2318,7 +2314,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.2.0.tgz", "integrity": "sha512-qRkLWiUEZNAmYapZ7KGS5C4OmBLcP/H2foXeOEaowYCR0wi89fHejrfYfbuLVCMLp/dWZXKvQusdbUEZjERfwQ==", "license": "Apache-2.0", - "peer": true, "engines": { "node": "^18.19.0 || >=20.6.0" }, @@ -2331,7 +2326,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz", "integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -2347,7 +2341,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.208.0.tgz", "integrity": "sha512-Eju0L4qWcQS+oXxi6pgh7zvE2byogAkcsVv0OjHF/97iOz1N/aKE6etSGowYkie+YA1uo6DNwdSxaaNnLvcRlA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/api-logs": "0.208.0", "import-in-the-middle": "^2.0.0", @@ -2735,7 +2728,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" @@ -2752,7 +2744,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz", "integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", @@ -2770,7 +2761,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.38.0.tgz", "integrity": "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=14" } @@ -3829,7 +3819,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -4381,7 +4372,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -4393,7 +4383,6 @@ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -4519,7 +4508,6 @@ "integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.50.1", "@typescript-eslint/types": "8.50.1", @@ -4989,7 +4977,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5071,7 +5058,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6087,7 +6073,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -6570,7 +6555,6 @@ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@chevrotain/cst-dts-gen": "11.0.3", "@chevrotain/gast": "11.0.3", @@ -7296,7 +7280,6 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10" } @@ -7706,7 +7689,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -8204,7 +8186,6 @@ "integrity": "sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "24.13.3", "builder-util": "24.13.1", @@ -8300,7 +8281,8 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/dompurify": { "version": "3.3.0", @@ -8444,6 +8426,7 @@ "integrity": "sha512-oHkV0iogWfyK+ah9ZIvMDpei1m9ZRpdXcvde1wTpra2U8AFDNNpqJdnin5z+PM1GbQ5BoaKCWas2HSjtR0HwMg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "24.13.3", "archiver": "^5.3.1", @@ -8457,6 +8440,7 @@ "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.4", @@ -8476,6 +8460,7 @@ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", @@ -8498,6 +8483,7 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -8514,6 +8500,7 @@ "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", @@ -8530,6 +8517,7 @@ "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" @@ -8544,6 +8532,7 @@ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -8559,6 +8548,7 @@ "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -8571,7 +8561,8 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/electron-builder-squirrel-windows/node_modules/string_decoder": { "version": "1.1.1", @@ -8579,6 +8570,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -8589,6 +8581,7 @@ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -8599,6 +8592,7 @@ "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "archiver-utils": "^3.0.4", "compress-commons": "^4.1.2", @@ -8614,6 +8608,7 @@ "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", @@ -9295,7 +9290,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -11215,7 +11209,6 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -12036,7 +12029,6 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -12506,14 +12498,16 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.escaperegexp": { "version": "4.1.2", @@ -12526,7 +12520,8 @@ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.isequal": { "version": "4.5.0", @@ -12540,7 +12535,8 @@ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -12554,7 +12550,8 @@ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/log-symbols": { "version": "4.1.0", @@ -12645,6 +12642,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -14935,7 +14933,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -15156,7 +15153,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -15397,6 +15393,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -15412,6 +15409,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -15756,7 +15754,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -15786,7 +15783,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -15834,7 +15830,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -16033,8 +16028,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -18088,7 +18082,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18462,7 +18455,6 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -18968,7 +18960,6 @@ "integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.15", "@vitest/mocker": "4.0.15", @@ -19559,7 +19550,6 @@ "integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -20157,7 +20147,6 @@ "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/__tests__/main/parsers/rate-limit-event.test.ts b/src/__tests__/main/parsers/rate-limit-event.test.ts new file mode 100644 index 0000000000..fee43ae541 --- /dev/null +++ b/src/__tests__/main/parsers/rate-limit-event.test.ts @@ -0,0 +1,87 @@ +import { describe, it, expect } from 'vitest'; +import { ClaudeOutputParser } from '../../../main/parsers/claude-output-parser'; + +describe('rate_limit_event caching', () => { + it('should cache resetsAt from rate_limit_event and attach to next rate_limited error', () => { + const parser = new ClaudeOutputParser(); + const futureResetEpochSeconds = Math.floor(Date.now() / 1000) + 3600; // 1 hour from now + + // Step 1: Process the rate_limit_event line (arrives BEFORE the error) + const rateLimitEvent = { + type: 'rate_limit_event', + rate_limit_info: { + status: 'rejected', + resetsAt: futureResetEpochSeconds, + rateLimitType: 'five_hour', + overageStatus: 'rejected', + overageDisabledReason: 'org_level_disabled', + isUsingOverage: false, + }, + uuid: '50dbdb0f-6850-4c32-bf93-866c1f59cfd3', + session_id: '1ceebdef-cc2a-4d09-b5ac-1191b7042d09', + }; + + // This should cache the resetsAt + const event1 = parser.parseJsonObject(rateLimitEvent); + expect(event1?.type).toBe('system'); + + // Verify internal cache + expect((parser as any).lastRateLimitResetAt).toBe(futureResetEpochSeconds * 1000); + + // Step 2: Process the assistant error line + const assistantError = { + type: 'assistant', + message: { + id: 'b858a1c7-0823-4e5d-8bd1-c82eb350316d', + model: '', + role: 'assistant', + stop_reason: 'stop_sequence', + stop_sequence: '', + type: 'message', + usage: { + input_tokens: 0, + output_tokens: 0, + cache_creation_input_tokens: 0, + cache_read_input_tokens: 0, + }, + content: [{ type: 'text', text: "You've hit your limit · resets 3pm (America/Winnipeg)" }], + }, + session_id: '1ceebdef-cc2a-4d09-b5ac-1191b7042d09', + uuid: '8b7f641e-799f-4b24-895a-8a66baa75919', + error: 'rate_limit', + }; + + // This should detect the error AND attach rateLimitResetAt + const agentError = parser.detectErrorFromParsed(assistantError); + + expect(agentError).not.toBeNull(); + expect(agentError!.type).toBe('rate_limited'); + expect(agentError!.rateLimitResetAt).toBe(futureResetEpochSeconds * 1000); + + // Cache should be cleared after use + expect((parser as any).lastRateLimitResetAt).toBeNull(); + }); + + it('should fall back to content text parsing if no rate_limit_event was received', () => { + const parser = new ClaudeOutputParser(); + + // No rate_limit_event processed — go straight to assistant error + const assistantError = { + type: 'assistant', + message: { + content: [{ type: 'text', text: "You've hit your limit · resets 3pm (America/Winnipeg)" }], + }, + session_id: 'test', + uuid: 'test', + error: 'rate_limit', + }; + + const agentError = parser.detectErrorFromParsed(assistantError); + + expect(agentError).not.toBeNull(); + expect(agentError!.type).toBe('rate_limited'); + // Should have a reset time from content text parsing + expect(agentError!.rateLimitResetAt).toBeDefined(); + expect(agentError!.rateLimitResetAt).toBeGreaterThan(Date.now() - 86400000); // within last 24h + }); +}); diff --git a/src/main/parsers/claude-output-parser.ts b/src/main/parsers/claude-output-parser.ts index cf7abb6ac2..19139efbc4 100644 --- a/src/main/parsers/claude-output-parser.ts +++ b/src/main/parsers/claude-output-parser.ts @@ -14,7 +14,7 @@ import type { ToolType, AgentError } from '../../shared/types'; import type { AgentOutputParser, ParsedEvent } from './agent-output-parser'; import { aggregateModelUsage, type ModelStats } from './usage-aggregator'; -import { getErrorPatterns, matchErrorPattern } from './error-patterns'; +import { getErrorPatterns, matchErrorPattern, parseRateLimitResetTime } from './error-patterns'; /** * Content block in Claude assistant messages @@ -68,6 +68,13 @@ interface ClaudeRawMessage { export class ClaudeOutputParser implements AgentOutputParser { readonly agentId: ToolType = 'claude-code'; + /** + * Cached rate-limit reset timestamp from a `rate_limit_event` JSON event. + * Claude CLI sends this event (with `resetsAt` as epoch seconds) BEFORE the + * actual error event, so we cache it here and attach it to the next error. + */ + private lastRateLimitResetAt: number | null = null; + /** * Parse a single JSON line from Claude Code output. * Delegates to parseJsonObject after JSON.parse. @@ -189,6 +196,22 @@ export class ClaudeOutputParser implements AgentOutputParser { }; } + // Handle rate_limit_event — cache the reset timestamp for the next error + if (msg.type === 'rate_limit_event') { + const rateLimitInfo = (msg as unknown as Record).rate_limit_info as + | Record + | undefined; + if (rateLimitInfo?.resetsAt && typeof rateLimitInfo.resetsAt === 'number') { + // resetsAt is in epoch seconds — convert to milliseconds + this.lastRateLimitResetAt = rateLimitInfo.resetsAt * 1000; + } + return { + type: 'system', + sessionId: msg.session_id, + raw: msg, + }; + } + // Default: preserve as system event return { type: 'system', @@ -358,7 +381,7 @@ export class ClaudeOutputParser implements AgentOutputParser { const patterns = getErrorPatterns(this.agentId); const match = matchErrorPattern(patterns, errorText); if (match) { - return { + const mixedError: AgentError = { type: match.type, message: match.message, recoverable: match.recoverable, @@ -366,6 +389,16 @@ export class ClaudeOutputParser implements AgentOutputParser { timestamp: Date.now(), raw: { errorLine: line }, }; + + // For rate-limit errors, try to parse the reset time + if (match.type === 'rate_limited') { + const resetAt = parseRateLimitResetTime(errorText); + if (resetAt) { + mixedError.rateLimitResetAt = resetAt; + } + } + + return mixedError; } return null; } @@ -406,7 +439,7 @@ export class ClaudeOutputParser implements AgentOutputParser { const match = matchErrorPattern(patterns, errorText); if (match) { - return { + const error: AgentError = { type: match.type, message: match.message, recoverable: match.recoverable, @@ -414,6 +447,46 @@ export class ClaudeOutputParser implements AgentOutputParser { timestamp: Date.now(), parsedJson, }; + + // For rate-limit errors, attach the reset time. + // Priority: (1) cached rate_limit_event.resetsAt, (2) message.content text, (3) errorText + if (match.type === 'rate_limited') { + let resetAt: number | null = null; + + // Best source: the rate_limit_event that arrived just before this error + if (this.lastRateLimitResetAt && this.lastRateLimitResetAt > Date.now()) { + resetAt = this.lastRateLimitResetAt; + this.lastRateLimitResetAt = null; + } + + // Fallback: parse from message.content text blocks + if (!resetAt && obj) { + const message = (obj as Record).message as + | Record + | undefined; + if (message?.content && Array.isArray(message.content)) { + for (const block of message.content) { + if (typeof block === 'string') { + resetAt = parseRateLimitResetTime(block); + } else if (block && typeof block === 'object' && 'text' in block) { + resetAt = parseRateLimitResetTime((block as { text: string }).text); + } + if (resetAt) break; + } + } + } + + // Last resort: try the error text itself + if (!resetAt && errorText) { + resetAt = parseRateLimitResetTime(errorText); + } + + if (resetAt) { + error.rateLimitResetAt = resetAt; + } + } + + return error; } // Structured error event that didn't match a known pattern — diff --git a/src/main/parsers/error-patterns.ts b/src/main/parsers/error-patterns.ts index b027697dae..582e2b08e8 100644 --- a/src/main/parsers/error-patterns.ts +++ b/src/main/parsers/error-patterns.ts @@ -156,7 +156,7 @@ const CLAUDE_ERROR_PATTERNS: AgentErrorPatterns = { rate_limited: [ { - pattern: /rate limit/i, + pattern: /rate[_ ]limit/i, message: 'Rate limit exceeded. Please wait a moment before trying again.', recoverable: true, }, @@ -1004,3 +1004,117 @@ export function matchSshErrorPattern( export function getSshErrorPatterns(): AgentErrorPatterns { return SSH_ERROR_PATTERNS; } + +// ============================================================================ +// Rate Limit Reset Time Parsing +// ============================================================================ + +/** + * Regex to extract reset time from rate-limit error messages. + * + * Matches patterns like: + * - "resets 3pm (America/Winnipeg)" + * - "resets 3:30pm (America/Chicago)" + * - "resets 15:00 (US/Eastern)" + * - "resets 3:30 PM (America/New_York)" + * + * Capture groups: + * 1: hours (e.g. "3", "15") + * 2: optional ":minutes" (e.g. ":30") + * 3: optional am/pm designator + * 4: IANA timezone (e.g. "America/Winnipeg") + */ +const RATE_LIMIT_RESET_REGEX = /resets?\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\s*\(([A-Za-z_/]+)\)/i; + +/** + * Parse a rate-limit reset time from an error message. + * + * Given text like "You've hit your limit · resets 3pm (America/Winnipeg)", + * returns the epoch-ms timestamp of the next occurrence of that time in + * the specified timezone. Returns null if the text doesn't contain a + * parseable reset time. + * + * Uses Intl.DateTimeFormat for timezone conversion (no external deps). + */ +export function parseRateLimitResetTime(text: string): number | null { + const m = text.match(RATE_LIMIT_RESET_REGEX); + if (!m) return null; + + let hours = parseInt(m[1], 10); + const minutes = m[2] ? parseInt(m[2], 10) : 0; + const ampm = m[3]?.toLowerCase(); + const timezone = m[4]; + + // Convert 12-hour to 24-hour + if (ampm === 'pm' && hours < 12) hours += 12; + if (ampm === 'am' && hours === 12) hours = 0; + + // Validate ranges + if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null; + + // Validate timezone by trying to format a date with it + try { + Intl.DateTimeFormat('en-US', { timeZone: timezone }).format(); + } catch { + return null; + } + + // Get current wall-clock time in the target timezone + const now = new Date(); + const formatter = new Intl.DateTimeFormat('en-US', { + timeZone: timezone, + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hour12: false, + }); + const parts = formatter.formatToParts(now); + const getPart = (type: string) => parseInt(parts.find((p) => p.type === type)?.value || '0', 10); + + const tzYear = getPart('year'); + const tzMonth = getPart('month'); + const tzDay = getPart('day'); + const tzHour = getPart('hour'); + const tzMinute = getPart('minute'); + const tzSecond = getPart('second'); + + // Compute the target date in the target timezone. + // Start with today; if that time has already passed, use tomorrow. + let targetDay = tzDay; + let targetMonth = tzMonth; + let targetYear = tzYear; + + const nowMinutes = tzHour * 60 + tzMinute; + const resetMinutes = hours * 60 + minutes; + + if (resetMinutes <= nowMinutes) { + // Reset time already passed today — advance to tomorrow + const tomorrow = new Date(now.getTime() + 86400000); + const tParts = formatter.formatToParts(tomorrow); + const tGetPart = (type: string) => + parseInt(tParts.find((p) => p.type === type)?.value || '0', 10); + targetDay = tGetPart('day'); + targetMonth = tGetPart('month'); + targetYear = tGetPart('year'); + } + + // Build an ISO-like string for the target time and compute epoch via brute-force offset. + // We know the wall-clock offset from UTC by comparing now.getTime() with the tz wall clock. + // Approach: use a reference point to compute the UTC offset of the timezone at 'now'. + const utcNow = now.getTime(); + // Wall-clock "now" as pseudo-UTC ms (treating tz wall-clock as if it were UTC) + const wallNowMs = Date.UTC(tzYear, tzMonth - 1, tzDay, tzHour, tzMinute, tzSecond); + // Offset = wallNowMs - utcNow (positive = timezone is ahead of UTC) + const tzOffsetMs = wallNowMs - utcNow; + + // Compute target wall-clock as pseudo-UTC ms + const wallTargetMs = Date.UTC(targetYear, targetMonth - 1, targetDay, hours, minutes, 0); + + // Convert back to real UTC by subtracting the offset + const targetUtcMs = wallTargetMs - tzOffsetMs; + + return targetUtcMs; +} diff --git a/src/main/preload/process.ts b/src/main/preload/process.ts index 94bde82334..c324842b55 100644 --- a/src/main/preload/process.ts +++ b/src/main/preload/process.ts @@ -118,6 +118,7 @@ export interface AgentError { agentId: string; sessionId?: string; timestamp: number; + rateLimitResetAt?: number; raw?: { exitCode?: number; stderr?: string; diff --git a/src/main/process-manager/handlers/StdoutHandler.ts b/src/main/process-manager/handlers/StdoutHandler.ts index 3b90331245..9fd30b3057 100644 --- a/src/main/process-manager/handlers/StdoutHandler.ts +++ b/src/main/process-manager/handlers/StdoutHandler.ts @@ -192,6 +192,7 @@ export class StdoutHandler { sessionId, errorType: agentError.type, errorMessage: agentError.message, + rateLimitResetAt: agentError.rateLimitResetAt, isRemote: !!managedProcess.sshRemoteId, }); this.emitter.emit('agent-error', sessionId, agentError); diff --git a/src/main/process-manager/types.ts b/src/main/process-manager/types.ts index 8f0f5f87bd..c54f3991ba 100644 --- a/src/main/process-manager/types.ts +++ b/src/main/process-manager/types.ts @@ -78,6 +78,8 @@ export interface ManagedProcess { sshRemoteHost?: string; dataBuffer?: string; dataBufferTimeout?: NodeJS.Timeout; + /** Pending rate-limit error waiting for stdin probe response with reset time */ + pendingRateLimitError?: AgentError; } export interface UsageTotals { diff --git a/src/renderer/components/AgentErrorModal.tsx b/src/renderer/components/AgentErrorModal.tsx index 77fe58eb6d..b01a51a9bf 100644 --- a/src/renderer/components/AgentErrorModal.tsx +++ b/src/renderer/components/AgentErrorModal.tsx @@ -12,11 +12,12 @@ * - Clear error description with type indicator * - Collapsible JSON details viewer for structured error data * - Recovery action buttons (re-authenticate, start new session, retry, etc.) + * - Rate-limit countdown with auto-retry * - Dismiss option for non-critical errors * - Auto-focus on primary recovery action */ -import React, { useRef, useMemo, useState } from 'react'; +import React, { useRef, useMemo, useState, useEffect, useCallback } from 'react'; import { AlertCircle, RefreshCw, @@ -29,6 +30,7 @@ import { ChevronDown, ChevronRight, Code2, + Timer, } from 'lucide-react'; import type { Theme, AgentError, AgentErrorType } from '../types'; import { MODAL_PRIORITIES } from '../constants/modalPriorities'; @@ -113,6 +115,87 @@ function getErrorColor(error: AgentError, theme: Theme): string { return theme.colors.warning; } +/** + * Format remaining milliseconds as a human-readable countdown string. + */ +function formatCountdown(remainingMs: number): string { + if (remainingMs <= 0) return 'now'; + + const totalSeconds = Math.ceil(remainingMs / 1000); + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + + if (hours > 0) { + return `${hours}h ${minutes}m ${seconds}s`; + } + if (minutes > 0) { + return `${minutes}m ${seconds}s`; + } + return `${seconds}s`; +} + +/** + * RateLimitCountdown - Live countdown until rate limit resets with auto-retry. + * + * Displays a pulsing timer with the remaining time. When the countdown reaches + * zero, it automatically invokes the onComplete callback to trigger a retry. + */ +function RateLimitCountdown({ + resetAt, + theme, + onComplete, +}: { + resetAt: number; + theme: Theme; + onComplete: () => void; +}) { + const [remainingMs, setRemainingMs] = useState(() => Math.max(0, resetAt - Date.now())); + const completedRef = useRef(false); + + useEffect(() => { + // Reset state when resetAt changes + completedRef.current = false; + setRemainingMs(Math.max(0, resetAt - Date.now())); + + const interval = setInterval(() => { + const remaining = Math.max(0, resetAt - Date.now()); + setRemainingMs(remaining); + + if (remaining <= 0 && !completedRef.current) { + completedRef.current = true; + clearInterval(interval); + onComplete(); + } + }, 1000); + + return () => clearInterval(interval); + }, [resetAt, onComplete]); + + const resetDate = new Date(resetAt); + const resetTimeStr = resetDate.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }); + + return ( +
+ +
+
+ {remainingMs > 0 ? `Auto-retrying in ${formatCountdown(remainingMs)}` : 'Retrying now...'} +
+
+ Limit resets at {resetTimeStr} +
+
+
+ ); +} + export function AgentErrorModal({ theme, error, @@ -134,6 +217,35 @@ export function AgentErrorModal({ // Check if we have JSON details to show const hasJsonDetails = error.parsedJson !== undefined; + // Find the retry action from recovery actions for auto-retry + const retryAction = useMemo( + () => recoveryActions.find((a) => a.id === 'retry'), + [recoveryActions] + ); + + // Auto-retry handler: when countdown completes, invoke the "retry" recovery action + const handleCountdownComplete = useCallback(() => { + if (retryAction) { + retryAction.onClick(); + } + }, [retryAction]); + + // For rate-limited errors: use parsed reset time if available, otherwise default to 60s + const DEFAULT_RATE_LIMIT_WAIT_MS = 2 * 60 * 60_000; // 2 hours + const rateLimitResetAt = useMemo(() => { + if (error.type !== 'rate_limited' || !retryAction) return null; + + if (error.rateLimitResetAt && error.rateLimitResetAt > Date.now()) { + return error.rateLimitResetAt; + } + + // Fallback: 60 seconds from when the error occurred + const fallback = error.timestamp + DEFAULT_RATE_LIMIT_WAIT_MS; + return fallback > Date.now() ? fallback : null; + }, [error.type, error.rateLimitResetAt, error.timestamp, retryAction]); + + const showCountdown = rateLimitResetAt !== null; + const errorColor = getErrorColor(error, theme); const errorIcon = getErrorIcon(error.type); const errorTitle = getErrorTitle(error.type); @@ -166,6 +278,15 @@ export function AgentErrorModal({ {error.message}

+ {/* Rate-limit countdown with auto-retry */} + {showCountdown && ( + + )} + {/* Timestamp */}
{new Date(error.timestamp).toLocaleTimeString()} diff --git a/src/renderer/global.d.ts b/src/renderer/global.d.ts index 0499684c10..3967c7604c 100644 --- a/src/renderer/global.d.ts +++ b/src/renderer/global.d.ts @@ -441,6 +441,7 @@ interface MaestroAPI { agentId: string; sessionId?: string; timestamp: number; + rateLimitResetAt?: number; raw?: { exitCode?: number; stderr?: string; diff --git a/src/renderer/hooks/agent/useAgentListeners.ts b/src/renderer/hooks/agent/useAgentListeners.ts index 1bd66c73fa..ab9e8dee58 100644 --- a/src/renderer/hooks/agent/useAgentListeners.ts +++ b/src/renderer/hooks/agent/useAgentListeners.ts @@ -1122,6 +1122,7 @@ export function useAgentListeners(deps: UseAgentListenersDeps): void { agentId: error.agentId, sessionId: error.sessionId, timestamp: error.timestamp, + rateLimitResetAt: error.rateLimitResetAt, raw: error.raw, parsedJson: error.parsedJson, }; diff --git a/src/shared/types.ts b/src/shared/types.ts index 7de98589fb..550671b4a5 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -193,6 +193,9 @@ export interface AgentError { /** Timestamp when the error occurred */ timestamp: number; + /** Epoch ms when rate limit resets (parsed from error text, e.g. "resets 3pm") */ + rateLimitResetAt?: number; + /** Original error data for debugging (stderr, exit code, etc.) */ raw?: { exitCode?: number; From cc95b66d7cabf67e9cf97f909cb0c07fff8f5da6 Mon Sep 17 00:00:00 2001 From: ProaFilippi Date: Mon, 30 Mar 2026 23:57:37 -0500 Subject: [PATCH 02/23] fix(agentStore): implement robust auto-retry loop for rate-limits --- src/renderer/stores/agentStore.ts | 81 +++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/renderer/stores/agentStore.ts b/src/renderer/stores/agentStore.ts index b651724264..605354bba2 100644 --- a/src/renderer/stores/agentStore.ts +++ b/src/renderer/stores/agentStore.ts @@ -30,6 +30,7 @@ import { createTab, getActiveTab } from '../utils/tabHelpers'; import { getStdinFlags } from '../utils/spawnHelpers'; import { generateId } from '../utils/ids'; import { useSessionStore } from './sessionStore'; +import { useSettingsStore } from './settingsStore'; import { DEFAULT_IMAGE_ONLY_PROMPT } from '../hooks/input/useInputProcessing'; import { maestroSystemPrompt } from '../../prompts'; import { substituteTemplateVariables } from '../utils/templateVariables'; @@ -204,7 +205,87 @@ export const useAgentStore = create()((set, get) => ({ }, retryAfterError: (sessionId) => { + const session = getSession(sessionId); + if (!session) return; + + // 1. Clear the error state (sets session to idle) get().clearAgentError(sessionId); + + // 2. Find the target tab so we can grab the last user message + const targetTabId = session.agentErrorTabId; + const targetTab = targetTabId + ? session.aiTabs.find((tab) => tab.id === targetTabId) + : getActiveTab(session); + + if (!targetTab) return; + + // 3. Find the last user string in the logs + const logs = targetTab.logs || []; + const lastUserLog = [...logs].reverse().find((l) => l.source === 'user'); + + if (!lastUserLog || !lastUserLog.text) { + console.warn('[retryAfterError] No user message found to retry.'); + return; + } + + // 4. Re-construct a QueuedItem 'message' to re-dispatch. + // By sending it as a 'message' (even if it originally was a command), + // we avoid double-substituting template variables, as the text in the log + // is already the final rendered prompt. Also, processQueuedItem does not + // push duplicate logs for 'message' types. + const queuedItem: QueuedItem = { + id: generateId(), + timestamp: Date.now(), + tabId: targetTab.id, + type: 'message', + text: lastUserLog.text, + images: lastUserLog.images, + tabName: + targetTab.name || + (targetTab.agentSessionId ? targetTab.agentSessionId.split('-')[0].toUpperCase() : 'New'), + readOnlyMode: targetTab.readOnlyMode, + }; + + // 5. Gather required deps (we only strictly need conductorProfile for plain messages) + const settings = useSettingsStore.getState(); + const deps: ProcessQueuedItemDeps = { + conductorProfile: settings.conductorProfile, + customAICommands: settings.customAICommands, + speckitCommands: [], + openspecCommands: [], + bmadCommands: [], + }; + + // 6. Reset session to busy/thinking state so the UI reflects the retry + useSessionStore.getState().setSessions((prev) => + prev.map((s) => { + if (s.id !== sessionId) return s; + const updatedAiTabs = s.aiTabs?.map((tab) => + tab.id === targetTab.id + ? { + ...tab, + state: 'busy' as const, + thinkingStartTime: Date.now(), + } + : tab + ); + return { + ...s, + state: 'busy' as SessionState, + busySource: 'ai', + aiTabs: updatedAiTabs, + }; + }) + ); + + // 7. Dispatch to agent! + setTimeout(() => { + get() + .processQueuedItem(sessionId, queuedItem, deps) + .catch((err) => { + console.error('[retryAfterError] Failed to retry item:', err); + }); + }, 0); }, restartAgentAfterError: async (sessionId) => { From 6f419e55992ca4f9faa692ed069c38a3c2d05f8b Mon Sep 17 00:00:00 2001 From: ProaFilippi Date: Tue, 31 Mar 2026 08:10:17 -0500 Subject: [PATCH 03/23] fix: address CodeRabbit feedback and migrate rate-limit settings to per-agent config --- .../main/parsers/rate-limit-event.test.ts | 4 +- src/main/agents/definitions.ts | 17 ++++++ src/main/parsers/claude-output-parser.ts | 9 ++- src/main/parsers/error-patterns.ts | 57 +++++++++---------- src/renderer/components/AgentErrorModal.tsx | 46 +++++++++++++-- src/renderer/stores/agentStore.ts | 8 +-- 6 files changed, 100 insertions(+), 41 deletions(-) diff --git a/src/__tests__/main/parsers/rate-limit-event.test.ts b/src/__tests__/main/parsers/rate-limit-event.test.ts index fee43ae541..014d4ac65a 100644 --- a/src/__tests__/main/parsers/rate-limit-event.test.ts +++ b/src/__tests__/main/parsers/rate-limit-event.test.ts @@ -82,6 +82,8 @@ describe('rate_limit_event caching', () => { expect(agentError!.type).toBe('rate_limited'); // Should have a reset time from content text parsing expect(agentError!.rateLimitResetAt).toBeDefined(); - expect(agentError!.rateLimitResetAt).toBeGreaterThan(Date.now() - 86400000); // within last 24h + const now = Date.now(); + expect(agentError!.rateLimitResetAt).toBeGreaterThan(now); + expect(agentError!.rateLimitResetAt).toBeLessThan(now + 86400000); }); }); diff --git a/src/main/agents/definitions.ts b/src/main/agents/definitions.ts index 8ee7aee686..77abc8f78d 100644 --- a/src/main/agents/definitions.ts +++ b/src/main/agents/definitions.ts @@ -139,6 +139,23 @@ export const AGENT_DEFINITIONS: AgentDefinition[] = [ resumeArgs: (sessionId: string) => ['--resume', sessionId], // Resume with session ID readOnlyArgs: ['--permission-mode', 'plan'], // Read-only/plan mode readOnlyCliEnforced: true, // CLI enforces read-only via --permission-mode plan + configOptions: [ + { + key: 'rateLimitAutoRetry', + type: 'checkbox' as const, + label: 'Auto-retry on Rate Limit', + description: 'Automatically pause and retry when encountering a Claude Code rate limit.', + default: true, + }, + { + key: 'rateLimitFallbackHours', + type: 'number' as const, + label: 'Rate Limit Fallback (Hours)', + description: + 'Wait time to use if the exact rate limit reset time cannot be parsed (leave 0 to disable fallback).', + default: 2, + }, + ], }, { id: 'codex', diff --git a/src/main/parsers/claude-output-parser.ts b/src/main/parsers/claude-output-parser.ts index 19139efbc4..acf4f12e3b 100644 --- a/src/main/parsers/claude-output-parser.ts +++ b/src/main/parsers/claude-output-parser.ts @@ -392,7 +392,14 @@ export class ClaudeOutputParser implements AgentOutputParser { // For rate-limit errors, try to parse the reset time if (match.type === 'rate_limited') { - const resetAt = parseRateLimitResetTime(errorText); + let resetAt: number | null = null; + if (this.lastRateLimitResetAt && this.lastRateLimitResetAt > Date.now()) { + resetAt = this.lastRateLimitResetAt; + this.lastRateLimitResetAt = null; + } + if (!resetAt) { + resetAt = parseRateLimitResetTime(errorText); + } if (resetAt) { mixedError.rateLimitResetAt = resetAt; } diff --git a/src/main/parsers/error-patterns.ts b/src/main/parsers/error-patterns.ts index 582e2b08e8..28356484a1 100644 --- a/src/main/parsers/error-patterns.ts +++ b/src/main/parsers/error-patterns.ts @@ -1074,47 +1074,46 @@ export function parseRateLimitResetTime(text: string): number | null { const parts = formatter.formatToParts(now); const getPart = (type: string) => parseInt(parts.find((p) => p.type === type)?.value || '0', 10); - const tzYear = getPart('year'); - const tzMonth = getPart('month'); - const tzDay = getPart('day'); const tzHour = getPart('hour'); const tzMinute = getPart('minute'); - const tzSecond = getPart('second'); // Compute the target date in the target timezone. // Start with today; if that time has already passed, use tomorrow. - let targetDay = tzDay; - let targetMonth = tzMonth; - let targetYear = tzYear; - + let targetDate = now; const nowMinutes = tzHour * 60 + tzMinute; const resetMinutes = hours * 60 + minutes; if (resetMinutes <= nowMinutes) { // Reset time already passed today — advance to tomorrow - const tomorrow = new Date(now.getTime() + 86400000); - const tParts = formatter.formatToParts(tomorrow); - const tGetPart = (type: string) => - parseInt(tParts.find((p) => p.type === type)?.value || '0', 10); - targetDay = tGetPart('day'); - targetMonth = tGetPart('month'); - targetYear = tGetPart('year'); + targetDate = new Date(now.getTime() + 86400000); } - // Build an ISO-like string for the target time and compute epoch via brute-force offset. - // We know the wall-clock offset from UTC by comparing now.getTime() with the tz wall clock. - // Approach: use a reference point to compute the UTC offset of the timezone at 'now'. - const utcNow = now.getTime(); - // Wall-clock "now" as pseudo-UTC ms (treating tz wall-clock as if it were UTC) - const wallNowMs = Date.UTC(tzYear, tzMonth - 1, tzDay, tzHour, tzMinute, tzSecond); - // Offset = wallNowMs - utcNow (positive = timezone is ahead of UTC) - const tzOffsetMs = wallNowMs - utcNow; - - // Compute target wall-clock as pseudo-UTC ms + const targetParts = formatter.formatToParts(targetDate); + const targetGetPart = (type: string) => + parseInt(targetParts.find((p) => p.type === type)?.value || '0', 10); + + const targetDay = targetGetPart('day'); + const targetMonth = targetGetPart('month'); + const targetYear = targetGetPart('year'); + const targetHour = targetGetPart('hour'); + const targetMinute = targetGetPart('minute'); + const targetSecond = targetGetPart('second'); + + // Find the UTC offset exactly at the target instant + const targetUtcMs = targetDate.getTime(); + const targetWallMs = Date.UTC( + targetYear, + targetMonth - 1, + targetDay, + targetHour, + targetMinute, + targetSecond + ); + const targetTzOffsetMs = targetWallMs - targetUtcMs; + + // Build the exact wall-clock reset target as pseudo-UTC const wallTargetMs = Date.UTC(targetYear, targetMonth - 1, targetDay, hours, minutes, 0); - // Convert back to real UTC by subtracting the offset - const targetUtcMs = wallTargetMs - tzOffsetMs; - - return targetUtcMs; + // Revert the offset to get real UTC + return wallTargetMs - targetTzOffsetMs; } diff --git a/src/renderer/components/AgentErrorModal.tsx b/src/renderer/components/AgentErrorModal.tsx index b01a51a9bf..6471e553cd 100644 --- a/src/renderer/components/AgentErrorModal.tsx +++ b/src/renderer/components/AgentErrorModal.tsx @@ -230,19 +230,53 @@ export function AgentErrorModal({ } }, [retryAction]); - // For rate-limited errors: use parsed reset time if available, otherwise default to 60s - const DEFAULT_RATE_LIMIT_WAIT_MS = 2 * 60 * 60_000; // 2 hours + const [autoRetrySettings, setAutoRetrySettings] = useState<{ + enabled: boolean; + fallbackHours: number; + } | null>(null); + + useEffect(() => { + if (error.type === 'rate_limited') { + window.maestro.agents + .getConfig(error.agentId) + .then((config) => { + if (!config) { + setAutoRetrySettings({ enabled: true, fallbackHours: 2 }); + return; + } + + setAutoRetrySettings({ + enabled: config.rateLimitAutoRetry ?? true, + fallbackHours: config.rateLimitFallbackHours ?? 2, + }); + }) + .catch((err) => { + console.error('Failed to load agent config for error modal:', err); + setAutoRetrySettings({ enabled: true, fallbackHours: 2 }); + }); + } + }, [error.type, error.agentId]); + + // For rate-limited errors: use parsed reset time if available, otherwise use configured fallback const rateLimitResetAt = useMemo(() => { - if (error.type !== 'rate_limited' || !retryAction) return null; + if (error.type !== 'rate_limited' || !retryAction || !autoRetrySettings) return null; + + // If auto-retry is explicitly disabled by the user, don't show countdown or auto-retry + if (!autoRetrySettings.enabled) return null; + // Exact parsed reset time is always preferred if (error.rateLimitResetAt && error.rateLimitResetAt > Date.now()) { return error.rateLimitResetAt; } - // Fallback: 60 seconds from when the error occurred - const fallback = error.timestamp + DEFAULT_RATE_LIMIT_WAIT_MS; + // If no fallback is configured or available, don't show countdown + if (autoRetrySettings.fallbackHours <= 0) return null; + + // Configure fallback using the user's preferred wait time + const fallbackWaitMs = autoRetrySettings.fallbackHours * 60 * 60_000; + const fallback = error.timestamp + fallbackWaitMs; return fallback > Date.now() ? fallback : null; - }, [error.type, error.rateLimitResetAt, error.timestamp, retryAction]); + }, [error.type, error.rateLimitResetAt, error.timestamp, retryAction, autoRetrySettings]); const showCountdown = rateLimitResetAt !== null; diff --git a/src/renderer/stores/agentStore.ts b/src/renderer/stores/agentStore.ts index 605354bba2..8d9b8f0744 100644 --- a/src/renderer/stores/agentStore.ts +++ b/src/renderer/stores/agentStore.ts @@ -208,10 +208,7 @@ export const useAgentStore = create()((set, get) => ({ const session = getSession(sessionId); if (!session) return; - // 1. Clear the error state (sets session to idle) - get().clearAgentError(sessionId); - - // 2. Find the target tab so we can grab the last user message + // 1. Find the target tab so we can grab the last user message const targetTabId = session.agentErrorTabId; const targetTab = targetTabId ? session.aiTabs.find((tab) => tab.id === targetTabId) @@ -219,6 +216,9 @@ export const useAgentStore = create()((set, get) => ({ if (!targetTab) return; + // 2. Clear the error state (sets session to idle) + get().clearAgentError(sessionId); + // 3. Find the last user string in the logs const logs = targetTab.logs || []; const lastUserLog = [...logs].reverse().find((l) => l.source === 'user'); From 74ea8a8b796bdd82e83da7601348cfb469460996 Mon Sep 17 00:00:00 2001 From: Pedram Amini Date: Tue, 7 Apr 2026 12:01:37 -0500 Subject: [PATCH 04/23] Added star history --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 0463ec2a57..5ce1574d13 100644 --- a/README.md +++ b/README.md @@ -181,3 +181,13 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, architecture detai ## License [AGPL-3.0 License](LICENSE) + +## Star History + + + + + + Star History Chart + + From 6ebe46cab296b1c6767bc40a497be336dd526ae8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 8 Apr 2026 04:56:32 +0000 Subject: [PATCH 05/23] docs: sync release notes for v0.16.8-RC --- docs/releases.md | 494 +++++++++++++++++++++++------------------------ 1 file changed, 240 insertions(+), 254 deletions(-) diff --git a/docs/releases.md b/docs/releases.md index 36a1f457e7..3b467bc158 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -17,32 +17,32 @@ Maestro can update itself automatically! This feature was introduced in **v0.8.7 **Latest: v0.15.3** | Released April 5, 2026 -# Major 0.15.x Additions - -🎶 **Maestro Symphony** — Contribute to open source with AI assistance! Browse curated issues from projects with the `runmaestro.ai` label, clone repos with one click, and automatically process the relevant Auto Run playbooks. Track your contributions, streaks, and stats. You're contributing CPU and tokens towards your favorite open source projects and features. - -🎬 **Director's Notes** — Aggregates history across all agents into a unified timeline with search, filters, and an activity graph. Includes an AI Overview tab that generates a structured synopsis of recent work. Off by default, gated behind a new "Encore Features" panel under settings. This is a precursor to an eventual plugin system, allowing for extensions and customizations without bloating the core app. - -🏷️ **Conductor Profile** — Available under Settings > General. Provide a short description on how Maestro agents should interface with you. - -🧠 **Three-State Thinking Toggle** — The thinking toggle now cycles through three modes: off, on, and sticky. Sticky mode keeps thinking content visible after the response completes. Cycle with CMD/CTRL+SHIFT+K. - -🤖 **Factory.ai Droid Support** — Added support for the [Factory.ai](https://factory.ai/product/cli) droid agent. Full session management and output parsing integration. - -## Changes in v0.15.3 - -- **CLI settings management:** Full `maestro-cli settings` command suite — list, get, set, and reset any Maestro setting from the command line. Includes per-agent configuration (custom paths, args, env vars, model overrides). Supports category filtering, verbose descriptions, and machine-readable JSON output for scripting -- **Live settings reload:** Settings changes made via the CLI are automatically detected by the running desktop app — no restart required -- **Plan-Mode toggle:** Claude Code and OpenCode agents now show "Plan-Mode" instead of "Read-Only" for the read-only toggle, matching their native terminology -- **Solarized Dark theme:** New Solarized Dark color theme with tuned contrast for tags, code blocks, and pill labels -- **Files pane icon theme:** Choose between default and rich icon themes in the files pane — rich theme adds colorful, language-specific icons for 70+ file types and folder categories. Toggle under Settings > Display -- **Persistent web link:** The web/mobile interface link now persists across app restarts — no need to re-enable it each session -- **OpenCode v1.2+ session support:** Automatically reads OpenCode's new SQLite session storage format alongside the legacy JSONL format -- **Group chat @mentions:** Use `@agent-name` syntax in the prompt composer to direct messages to specific agents in group chat -- **Group chat over SSH:** Group chat synthesis and moderation now run correctly on SSH remote agents instead of always spawning locally -- **Group chat participant management:** Remove button on participant cards lets you remove stale or unwanted participants from a group chat -- **Batch resume/abort:** New controls in the right panel for resuming or aborting batch operations -- **Default worktree directory:** Worktree configuration now defaults to the parent of the agent's working directory instead of blank +# Major 0.15.x Additions + +🎶 **Maestro Symphony** — Contribute to open source with AI assistance! Browse curated issues from projects with the `runmaestro.ai` label, clone repos with one click, and automatically process the relevant Auto Run playbooks. Track your contributions, streaks, and stats. You're contributing CPU and tokens towards your favorite open source projects and features. + +🎬 **Director's Notes** — Aggregates history across all agents into a unified timeline with search, filters, and an activity graph. Includes an AI Overview tab that generates a structured synopsis of recent work. Off by default, gated behind a new "Encore Features" panel under settings. This is a precursor to an eventual plugin system, allowing for extensions and customizations without bloating the core app. + +🏷️ **Conductor Profile** — Available under Settings > General. Provide a short description on how Maestro agents should interface with you. + +🧠 **Three-State Thinking Toggle** — The thinking toggle now cycles through three modes: off, on, and sticky. Sticky mode keeps thinking content visible after the response completes. Cycle with CMD/CTRL+SHIFT+K. + +🤖 **Factory.ai Droid Support** — Added support for the [Factory.ai](https://factory.ai/product/cli) droid agent. Full session management and output parsing integration. + +## Changes in v0.15.3 + +- **CLI settings management:** Full `maestro-cli settings` command suite — list, get, set, and reset any Maestro setting from the command line. Includes per-agent configuration (custom paths, args, env vars, model overrides). Supports category filtering, verbose descriptions, and machine-readable JSON output for scripting +- **Live settings reload:** Settings changes made via the CLI are automatically detected by the running desktop app — no restart required +- **Plan-Mode toggle:** Claude Code and OpenCode agents now show "Plan-Mode" instead of "Read-Only" for the read-only toggle, matching their native terminology +- **Solarized Dark theme:** New Solarized Dark color theme with tuned contrast for tags, code blocks, and pill labels +- **Files pane icon theme:** Choose between default and rich icon themes in the files pane — rich theme adds colorful, language-specific icons for 70+ file types and folder categories. Toggle under Settings > Display +- **Persistent web link:** The web/mobile interface link now persists across app restarts — no need to re-enable it each session +- **OpenCode v1.2+ session support:** Automatically reads OpenCode's new SQLite session storage format alongside the legacy JSONL format +- **Group chat @mentions:** Use `@agent-name` syntax in the prompt composer to direct messages to specific agents in group chat +- **Group chat over SSH:** Group chat synthesis and moderation now run correctly on SSH remote agents instead of always spawning locally +- **Group chat participant management:** Remove button on participant cards lets you remove stale or unwanted participants from a group chat +- **Batch resume/abort:** New controls in the right panel for resuming or aborting batch operations +- **Default worktree directory:** Worktree configuration now defaults to the parent of the agent's working directory instead of blank - **Drawfinity in Symphony:** Added Drawfinity to the Symphony project registry ### Previous Releases in this Series @@ -56,41 +56,41 @@ Maestro can update itself automatically! This feature was introduced in **v0.8.7 **Latest: v0.14.5** | Released January 24, 2026 -Changes in this point release include: - -- Desktop app performance improvements (more to come on this, we want Maestro blazing fast) 🐌 -- Added local manifest feature for custom playbooks 📖 -- Agents are now inherently aware of your activity history as seen in the history panel 📜 (this is built-in cross context memory!) -- Added markdown rendering support for AI responses in mobile view 📱 -- Bugfix in tracking costs from JSONL files that were aged out 🏦 -- Added BlueSky social media handle for leaderboard 🦋 -- Added options to disable GPU rendering and confetti 🎊 -- Better handling of large files in preview 🗄️ -- Bug fix in Claude context calculation 🧮 -- Addressed bug in OpenSpec version reporting 🐛 - -The major contributions to 0.14.x remain: - -🗄️ Document Graphs. Launch from file preview or from the FIle tree panel. Explore relationships between Markdown documents that contain links between documents and to URLs. - -📶 SSH support for agents. Manage a remote agent with feature parity over SSH. Includes support for Git and File tree panels. Manage agents on remote systems or in containers. This even works for Group Chat, which is rad as hell. - -🧙‍♂️ Added an in-tab wizard for generating Auto Run Playbooks via `/wizard` or a new button in the Auto Run panel. - -# Smaller Changes in 014.x - -- Improved User Dashboard, available from hamburger menu, command palette or hotkey 🎛️ -- Leaderboard tracking now works across multiple systems and syncs level from cloud 🏆 -- Agent duplication. Pro tip: Consider a group of unused "Template" agents ✌️ -- New setting to prevent system from going to sleep while agents are active 🛏️ -- The tab menu has a new "Publish as GitHub Gist" option 📝 -- The tab menu has options to move the tab to the first or last position 🔀 -- [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) can now contain non-markdown assets 📙 -- Improved default shell detection 🐚 -- Added logic to prevent overlapping TTS notifications 💬 -- Added "Toggle Bookmark" shortcut (CTRL/CMD+SHIFT+B) ⌨️ -- Gist publishing now shows previous URLs with copy button 📋 - +Changes in this point release include: + +- Desktop app performance improvements (more to come on this, we want Maestro blazing fast) 🐌 +- Added local manifest feature for custom playbooks 📖 +- Agents are now inherently aware of your activity history as seen in the history panel 📜 (this is built-in cross context memory!) +- Added markdown rendering support for AI responses in mobile view 📱 +- Bugfix in tracking costs from JSONL files that were aged out 🏦 +- Added BlueSky social media handle for leaderboard 🦋 +- Added options to disable GPU rendering and confetti 🎊 +- Better handling of large files in preview 🗄️ +- Bug fix in Claude context calculation 🧮 +- Addressed bug in OpenSpec version reporting 🐛 + +The major contributions to 0.14.x remain: + +🗄️ Document Graphs. Launch from file preview or from the FIle tree panel. Explore relationships between Markdown documents that contain links between documents and to URLs. + +📶 SSH support for agents. Manage a remote agent with feature parity over SSH. Includes support for Git and File tree panels. Manage agents on remote systems or in containers. This even works for Group Chat, which is rad as hell. + +🧙‍♂️ Added an in-tab wizard for generating Auto Run Playbooks via `/wizard` or a new button in the Auto Run panel. + +# Smaller Changes in 014.x + +- Improved User Dashboard, available from hamburger menu, command palette or hotkey 🎛️ +- Leaderboard tracking now works across multiple systems and syncs level from cloud 🏆 +- Agent duplication. Pro tip: Consider a group of unused "Template" agents ✌️ +- New setting to prevent system from going to sleep while agents are active 🛏️ +- The tab menu has a new "Publish as GitHub Gist" option 📝 +- The tab menu has options to move the tab to the first or last position 🔀 +- [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) can now contain non-markdown assets 📙 +- Improved default shell detection 🐚 +- Added logic to prevent overlapping TTS notifications 💬 +- Added "Toggle Bookmark" shortcut (CTRL/CMD+SHIFT+B) ⌨️ +- Gist publishing now shows previous URLs with copy button 📋 + Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @deandebeer @shadown @breki @charles-dyfis-net @ronaldeddings @jlengrand @ksylvan ### Previous Releases in this Series @@ -109,22 +109,20 @@ Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @d ### Changes -- TAKE TWO! Fixed Linux ARM64 build architecture contamination issues 🏗️ - -### v0.13.1 Changes - -- Fixed Linux ARM64 build architecture contamination issues 🏗️ -- Enhanced error handling for Auto Run batch processing 🚨 - -### v0.13.0 Changes - -- Added a global usage dashboard, data collection begins with this install 🎛️ -- Added a Playbook Exchange for downloading pre-defined Auto Run playbooks from [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) 📕 -- Bundled OpenSpec commands for structured change proposals 📝 -- Added pre-release channel support for beta/RC updates 🧪 -- Implemented global hands-on time tracking across sessions ⏱️ -- Added new keyboard shortcut for agent settings (Opt+Cmd+, | Ctrl+Alt+,) ⌨️ -- Added directory size calculation with file/folder counts in file explorer 📊 +- TAKE TWO! Fixed Linux ARM64 build architecture contamination issues 🏗️ + +### v0.13.1 Changes +- Fixed Linux ARM64 build architecture contamination issues 🏗️ +- Enhanced error handling for Auto Run batch processing 🚨 + +### v0.13.0 Changes +- Added a global usage dashboard, data collection begins with this install 🎛️ +- Added a Playbook Exchange for downloading pre-defined Auto Run playbooks from [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) 📕 +- Bundled OpenSpec commands for structured change proposals 📝 +- Added pre-release channel support for beta/RC updates 🧪 +- Implemented global hands-on time tracking across sessions ⏱️ +- Added new keyboard shortcut for agent settings (Opt+Cmd+, | Ctrl+Alt+,) ⌨️ +- Added directory size calculation with file/folder counts in file explorer 📊 - Added sleep detection to exclude laptop sleep from time tracking ⏰ ### Previous Releases in this Series @@ -138,26 +136,22 @@ Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @d **Latest: v0.12.3** | Released December 28, 2025 -The big changes in the v0.12.x line are the following three: - -## Show Thinking - -🤔 There is now a toggle to show thinking for the agent, the default for new tabs is off, though this can be changed under Settings > General. The toggle shows next to History and Read-Only. Very similar pattern. This has been the #1 most requested feature, though personally, I don't think I'll use it as I prefer to not see the details of the work, but the results of the work. Just as we work with our colleagues. - -## GitHub Spec-Kit Integration - -🎯 Added [GitHub Spec-Kit](https://github.com/github/spec-kit) commands into Maestro with a built in updater to grab the latest prompts from the repository. We do override `/speckit-implement` (the final step) to create Auto Run docs and guide the user through their execution, which thanks to Wortrees from v0.11.x allows us to run in parallel! - -## Context Management Tools - -📖 Added context management options from tab right-click menu. You can now compress, merge, and transfer contexts between agents. You will received (configurable) warnings at 60% and 80% context consumption with a hint to compact. - -## Changes Specific to v0.12.3: - -- We now have hosted documentation through Mintlify 📚 -- Export any tab conversation as self-contained themed HTML file 📄 -- Publish files as private/public Gists 🌐 -- Added tab hover overlay menu with close operations and export 📋 +The big changes in the v0.12.x line are the following three: + +## Show Thinking +🤔 There is now a toggle to show thinking for the agent, the default for new tabs is off, though this can be changed under Settings > General. The toggle shows next to History and Read-Only. Very similar pattern. This has been the #1 most requested feature, though personally, I don't think I'll use it as I prefer to not see the details of the work, but the results of the work. Just as we work with our colleagues. + +## GitHub Spec-Kit Integration +🎯 Added [GitHub Spec-Kit](https://github.com/github/spec-kit) commands into Maestro with a built in updater to grab the latest prompts from the repository. We do override `/speckit-implement` (the final step) to create Auto Run docs and guide the user through their execution, which thanks to Wortrees from v0.11.x allows us to run in parallel! + +## Context Management Tools +📖 Added context management options from tab right-click menu. You can now compress, merge, and transfer contexts between agents. You will received (configurable) warnings at 60% and 80% context consumption with a hint to compact. + +## Changes Specific to v0.12.3: +- We now have hosted documentation through Mintlify 📚 +- Export any tab conversation as self-contained themed HTML file 📄 +- Publish files as private/public Gists 🌐 +- Added tab hover overlay menu with close operations and export 📋 - Added social handles to achievement share images 🏆 ### Previous Releases in this Series @@ -171,12 +165,12 @@ The big changes in the v0.12.x line are the following three: **Latest: v0.11.0** | Released December 22, 2025 -🌳 Github Worktree support was added. Any agent bound to a Git repository has the option to enable worktrees, each of which show up as a sub-agent with their own write-lock and Auto Run capability. Now you can truly develop in parallel on the same project and issue PRs when you're ready, all from within Maestro. Huge improvement, major thanks to @petersilberman. - -# Other Changes - -- @ file mentions now include documents from your Auto Run folder (which may not live in your agent working directory) 🗄️ -- The wizard is now capable of detecting and continuing on past started projects 🧙 +🌳 Github Worktree support was added. Any agent bound to a Git repository has the option to enable worktrees, each of which show up as a sub-agent with their own write-lock and Auto Run capability. Now you can truly develop in parallel on the same project and issue PRs when you're ready, all from within Maestro. Huge improvement, major thanks to @petersilberman. + +# Other Changes + +- @ file mentions now include documents from your Auto Run folder (which may not live in your agent working directory) 🗄️ +- The wizard is now capable of detecting and continuing on past started projects 🧙 - Bug fixes 🐛🐜🐞 --- @@ -187,14 +181,14 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Export group chats as self-contained HTML ⬇️ -- Enhanced system process viewer now has details view with full process args 💻 -- Update button hides until platform binaries are available in releases. ⏳ -- Added Auto Run stall detection at the loop level, if no documents are updated after a loop 🔁 -- Improved Codex session discovery 🔍 -- Windows compatibility fixes 🐛 -- 64-bit Linux ARM build issue fixed (thanks @LilYoopug) 🐜 -- Addressed session enumeration issues with Codex and OpenCode 🐞 +- Export group chats as self-contained HTML ⬇️ +- Enhanced system process viewer now has details view with full process args 💻 +- Update button hides until platform binaries are available in releases. ⏳ +- Added Auto Run stall detection at the loop level, if no documents are updated after a loop 🔁 +- Improved Codex session discovery 🔍 +- Windows compatibility fixes 🐛 +- 64-bit Linux ARM build issue fixed (thanks @LilYoopug) 🐜 +- Addressed session enumeration issues with Codex and OpenCode 🐞 - Addressed pathing issues around gh command (thanks @oliveiraantoniocc) 🐝 ### Previous Releases in this Series @@ -210,13 +204,13 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Add Sentry crashing reporting monitoring with opt-out 🐛 -- Stability fixes on v0.9.0 along with all the changes it brought along, including... - - Major refactor to enable supporting of multiple providers 👨‍👩‍👧‍👦 - - Added OpenAI Codex support 👨‍💻 - - Added OpenCode support 👩‍💻 - - Error handling system detects and recovers from agent failures 🚨 - - Added option to specify CLI arguments to AI providers ✨ +- Add Sentry crashing reporting monitoring with opt-out 🐛 +- Stability fixes on v0.9.0 along with all the changes it brought along, including... + - Major refactor to enable supporting of multiple providers 👨‍👩‍👧‍👦 + - Added OpenAI Codex support 👨‍💻 + - Added OpenCode support 👩‍💻 + - Error handling system detects and recovers from agent failures 🚨 + - Added option to specify CLI arguments to AI providers ✨ - Bunch of other little tweaks and additions 💎 ### Previous Releases in this Series @@ -231,19 +225,19 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Added "Nudge" messages. Short static copy to include with every interactive message sent, perhaps to remind the agent on how to work 📌 -- Addressed various resource consumption issues to reduce battery cost 📉 -- Implemented fuzzy file search in quick actions for instant navigation 🔍 -- Added "clear" command support to clean terminal shell logs 🧹 -- Simplified search highlighting by integrating into markdown pipeline ✨ -- Enhanced update checker to filter prerelease tags like -rc, -beta 🚀 -- Fixed RPM package compatibility for OpenSUSE Tumbleweed 🐧 (H/T @JOduMonT) -- Added libuuid1 support alongside standard libuuid dependency 📦 -- Introduced Cmd+Shift+U shortcut for tab unread toggle ⌨️ -- Enhanced keyboard navigation for marking tabs unread 🎯 -- Expanded Linux distribution support with smart dependencies 🌐 -- Major underlying code re-structuring for maintainability 🧹 -- Improved stall detection to allow for individual docs to stall out while not affecting the entire playbook 📖 (H/T @mattjay) +- Added "Nudge" messages. Short static copy to include with every interactive message sent, perhaps to remind the agent on how to work 📌 +- Addressed various resource consumption issues to reduce battery cost 📉 +- Implemented fuzzy file search in quick actions for instant navigation 🔍 +- Added "clear" command support to clean terminal shell logs 🧹 +- Simplified search highlighting by integrating into markdown pipeline ✨ +- Enhanced update checker to filter prerelease tags like -rc, -beta 🚀 +- Fixed RPM package compatibility for OpenSUSE Tumbleweed 🐧 (H/T @JOduMonT) +- Added libuuid1 support alongside standard libuuid dependency 📦 +- Introduced Cmd+Shift+U shortcut for tab unread toggle ⌨️ +- Enhanced keyboard navigation for marking tabs unread 🎯 +- Expanded Linux distribution support with smart dependencies 🌐 +- Major underlying code re-structuring for maintainability 🧹 +- Improved stall detection to allow for individual docs to stall out while not affecting the entire playbook 📖 (H/T @mattjay) - Added option to select a static listening port for remote control 🎮 (H/T @b3nw) ### Previous Releases in this Series @@ -263,40 +257,35 @@ The big changes in the v0.12.x line are the following three: **Latest: v0.7.4** | Released December 12, 2025 -Minor bugfixes on top of v0.7.3: - -# Onboarding, Wizard, and Tours - -- Implemented comprehensive onboarding wizard with integrated tour system 🚀 -- Added project-understanding confidence display to wizard UI 🎨 -- Enhanced keyboard navigation across all wizard screens ⌨️ -- Added analytics tracking for wizard and tour completion 📈 -- Added First Run Celebration modal with confetti animation 🎉 - -# UI / UX Enhancements - -- Added expand-to-fullscreen button for Auto Run interface 🖥️ -- Created dedicated modal component and improved modal priority constants for expanded Auto Run view 📐 -- Enhanced user experience with fullscreen editing capabilities ✨ -- Fixed tab name display to correctly show full name for active tabs 🏷️ -- Added performance optimizations with throttling and caching for scrolling ⚡ -- Implemented drag-and-drop reordering for execution queue items 🎯 -- Enhanced toast context with agent name for OS notifications 📢 - -# Auto Run Workflow Improvements - -- Created phase document generation for Auto Run workflow 📄 -- Added real-time log streaming to the LogViewer component 📊 - -# Application Behavior / Core Fixes - -- Added validation to prevent nested worktrees inside the main repository 🚫 -- Fixed process manager to properly emit exit events on errors 🔧 -- Fixed process exit handling to ensure proper cleanup 🧹 - -# Update System - -- Implemented automatic update checking on application startup 🚀 +Minor bugfixes on top of v0.7.3: + +# Onboarding, Wizard, and Tours +- Implemented comprehensive onboarding wizard with integrated tour system 🚀 +- Added project-understanding confidence display to wizard UI 🎨 +- Enhanced keyboard navigation across all wizard screens ⌨️ +- Added analytics tracking for wizard and tour completion 📈 +- Added First Run Celebration modal with confetti animation 🎉 + +# UI / UX Enhancements +- Added expand-to-fullscreen button for Auto Run interface 🖥️ +- Created dedicated modal component and improved modal priority constants for expanded Auto Run view 📐 +- Enhanced user experience with fullscreen editing capabilities ✨ +- Fixed tab name display to correctly show full name for active tabs 🏷️ +- Added performance optimizations with throttling and caching for scrolling ⚡ +- Implemented drag-and-drop reordering for execution queue items 🎯 +- Enhanced toast context with agent name for OS notifications 📢 + +# Auto Run Workflow Improvements +- Created phase document generation for Auto Run workflow 📄 +- Added real-time log streaming to the LogViewer component 📊 + +# Application Behavior / Core Fixes +- Added validation to prevent nested worktrees inside the main repository 🚫 +- Fixed process manager to properly emit exit events on errors 🔧 +- Fixed process exit handling to ensure proper cleanup 🧹 + +# Update System +- Implemented automatic update checking on application startup 🚀 - Added settings toggle for enabling/disabling startup update checks ⚙️ ### Previous Releases in this Series @@ -312,40 +301,38 @@ Minor bugfixes on top of v0.7.3: **Latest: v0.6.1** | Released December 4, 2025 -In this release... - -- Added recursive subfolder support for Auto Run markdown files 🗂️ -- Enhanced document tree display with expandable folder navigation 🌳 -- Enabled creating documents in subfolders with path selection 📁 -- Improved batch runner UI with inline progress bars and loop indicators 📊 -- Fixed execution queue display bug for immediate command processing 🐛 -- Added folder icons and better visual hierarchy for document browser 🎨 -- Implemented dynamic task re-counting for batch run loop iterations 🔄 -- Enhanced create document modal with location selector dropdown 📍 -- Improved progress tracking with per-document completion visualization 📈 -- Added support for nested folder structures in document management 🏗️ - -Plus the pre-release ALPHA... - -- Template vars now set context in default autorun prompt 🚀 -- Added Enter key support for queued message confirmation dialog ⌨️ -- Kill process capability added to System Process Monitor 💀 -- Toggle markdown rendering added to Cmd+K Quick Actions 📝 -- Fixed cloudflared detection in packaged app environments 🔧 -- Added debugging logs for process exit diagnostics 🐛 -- Tab switcher shows last activity timestamps and filters by project 🕐 -- Slash commands now fill text on Tab/Enter instead of executing ⚡ -- Added GitHub Actions workflow for auto-assigning issues/PRs 🤖 -- Graceful handling for playbooks with missing documents implemented ✨ -- Added multi-document batch processing for Auto Run 🚀 -- Introduced Git worktree support for parallel execution 🌳 -- Created playbook system for saving run configurations 📚 -- Implemented document reset-on-completion with loop mode 🔄 -- Added drag-and-drop document reordering interface 🎯 -- Built Auto Run folder selector with file management 📁 -- Enhanced progress tracking with per-document metrics 📊 -- Integrated PR creation after worktree completion 🔀 -- Added undo/redo support in document editor ↩️ +In this release... +- Added recursive subfolder support for Auto Run markdown files 🗂️ +- Enhanced document tree display with expandable folder navigation 🌳 +- Enabled creating documents in subfolders with path selection 📁 +- Improved batch runner UI with inline progress bars and loop indicators 📊 +- Fixed execution queue display bug for immediate command processing 🐛 +- Added folder icons and better visual hierarchy for document browser 🎨 +- Implemented dynamic task re-counting for batch run loop iterations 🔄 +- Enhanced create document modal with location selector dropdown 📍 +- Improved progress tracking with per-document completion visualization 📈 +- Added support for nested folder structures in document management 🏗️ + +Plus the pre-release ALPHA... +- Template vars now set context in default autorun prompt 🚀 +- Added Enter key support for queued message confirmation dialog ⌨️ +- Kill process capability added to System Process Monitor 💀 +- Toggle markdown rendering added to Cmd+K Quick Actions 📝 +- Fixed cloudflared detection in packaged app environments 🔧 +- Added debugging logs for process exit diagnostics 🐛 +- Tab switcher shows last activity timestamps and filters by project 🕐 +- Slash commands now fill text on Tab/Enter instead of executing ⚡ +- Added GitHub Actions workflow for auto-assigning issues/PRs 🤖 +- Graceful handling for playbooks with missing documents implemented ✨ +- Added multi-document batch processing for Auto Run 🚀 +- Introduced Git worktree support for parallel execution 🌳 +- Created playbook system for saving run configurations 📚 +- Implemented document reset-on-completion with loop mode 🔄 +- Added drag-and-drop document reordering interface 🎯 +- Built Auto Run folder selector with file management 📁 +- Enhanced progress tracking with per-document metrics 📊 +- Integrated PR creation after worktree completion 🔀 +- Added undo/redo support in document editor ↩️ - Implemented auto-save with 5-second debounce 💾 ### Previous Releases in this Series @@ -360,15 +347,15 @@ Plus the pre-release ALPHA... ### Changes -- Added "Made with Maestro" badge to README header 🎯 -- Redesigned app icon with darker purple color scheme 🎨 -- Created new SVG badge for project attribution 🏷️ -- Added side-by-side image diff viewer for git changes 🖼️ -- Enhanced confetti animation with realistic cannon-style bursts 🎊 -- Fixed z-index layering for standing ovation overlay 📊 -- Improved tab switcher to show all named sessions 🔍 -- Enhanced batch synopsis prompts for cleaner summaries 📝 -- Added binary file detection in git diff parser 🔧 +- Added "Made with Maestro" badge to README header 🎯 +- Redesigned app icon with darker purple color scheme 🎨 +- Created new SVG badge for project attribution 🏷️ +- Added side-by-side image diff viewer for git changes 🖼️ +- Enhanced confetti animation with realistic cannon-style bursts 🎊 +- Fixed z-index layering for standing ovation overlay 📊 +- Improved tab switcher to show all named sessions 🔍 +- Enhanced batch synopsis prompts for cleaner summaries 📝 +- Added binary file detection in git diff parser 🔧 - Implemented git file reading at specific refs 📁 ### Previous Releases in this Series @@ -383,24 +370,24 @@ Plus the pre-release ALPHA... ### Changes -- Added Tab Switcher modal for quick navigation between AI tabs 🚀 -- Implemented @ mention file completion for AI mode references 📁 -- Added navigation history with back/forward through sessions and tabs ⏮️ -- Introduced tab completion filters for branches, tags, and files 🌳 -- Added unread tab indicators and filtering for better organization 📬 -- Implemented token counting display with human-readable formatting 🔢 -- Added markdown rendering toggle for AI responses in terminal 📝 -- Removed built-in slash commands in favor of custom AI commands 🎯 -- Added context menu for sessions with rename, bookmark, move options 🖱️ -- Enhanced file preview with stats showing size, tokens, timestamps 📊 -- Added token counting with js-tiktoken for file preview stats bar 🔢 -- Implemented Tab Switcher modal for fuzzy-search navigation (Opt+Cmd+T) 🔍 -- Added Save to History toggle (Cmd+S) for automatic work synopsis tracking 💾 -- Enhanced tab completion with @ mentions for file references in AI prompts 📎 -- Implemented navigation history with back/forward shortcuts (Cmd+Shift+,/.) 🔙 -- Added git branches and tags to intelligent tab completion system 🌿 -- Enhanced markdown rendering with syntax highlighting and toggle view 📝 -- Added right-click context menus for session management and organization 🖱️ +- Added Tab Switcher modal for quick navigation between AI tabs 🚀 +- Implemented @ mention file completion for AI mode references 📁 +- Added navigation history with back/forward through sessions and tabs ⏮️ +- Introduced tab completion filters for branches, tags, and files 🌳 +- Added unread tab indicators and filtering for better organization 📬 +- Implemented token counting display with human-readable formatting 🔢 +- Added markdown rendering toggle for AI responses in terminal 📝 +- Removed built-in slash commands in favor of custom AI commands 🎯 +- Added context menu for sessions with rename, bookmark, move options 🖱️ +- Enhanced file preview with stats showing size, tokens, timestamps 📊 +- Added token counting with js-tiktoken for file preview stats bar 🔢 +- Implemented Tab Switcher modal for fuzzy-search navigation (Opt+Cmd+T) 🔍 +- Added Save to History toggle (Cmd+S) for automatic work synopsis tracking 💾 +- Enhanced tab completion with @ mentions for file references in AI prompts 📎 +- Implemented navigation history with back/forward shortcuts (Cmd+Shift+,/.) 🔙 +- Added git branches and tags to intelligent tab completion system 🌿 +- Enhanced markdown rendering with syntax highlighting and toggle view 📝 +- Added right-click context menus for session management and organization 🖱️ - Improved mobile app with better WebSocket reconnection and status badges 📱 ### Previous Releases in this Series @@ -415,15 +402,15 @@ Plus the pre-release ALPHA... ### Changes -- Fixed tab handling requiring explicitly selected Claude session 🔧 -- Added auto-scroll navigation for slash command list selection ⚡ -- Implemented TTS audio feedback for toast notifications speak 🔊 -- Fixed shortcut case sensitivity using lowercase key matching 🔤 -- Added Cmd+Shift+J shortcut to jump to bottom instantly ⬇️ -- Sorted shortcuts alphabetically in help modal for discovery 📑 -- Display full commit message body in git log view 📝 -- Added expand/collapse all buttons to process tree header 🌳 -- Support synopsis process type in process tree parsing 🔍 +- Fixed tab handling requiring explicitly selected Claude session 🔧 +- Added auto-scroll navigation for slash command list selection ⚡ +- Implemented TTS audio feedback for toast notifications speak 🔊 +- Fixed shortcut case sensitivity using lowercase key matching 🔤 +- Added Cmd+Shift+J shortcut to jump to bottom instantly ⬇️ +- Sorted shortcuts alphabetically in help modal for discovery 📑 +- Display full commit message body in git log view 📝 +- Added expand/collapse all buttons to process tree header 🌳 +- Support synopsis process type in process tree parsing 🔍 - Renamed "No Group" to "UNGROUPED" for better clarity ✨ ### Previous Releases in this Series @@ -436,15 +423,15 @@ Plus the pre-release ALPHA... **Latest: v0.2.3** | Released November 29, 2025 -• Enhanced mobile web interface with session sync and history panel 📱 -• Added ThinkingStatusPill showing real-time token counts and elapsed time ⏱️ -• Implemented task count badges and session deduplication for batch runner 📊 -• Added TTS stop control and improved voice synthesis compatibility 🔊 -• Created image lightbox with navigation, clipboard, and delete features 🖼️ -• Fixed UI bugs in search, auto-scroll, and sidebar interactions 🐛 -• Added global Claude stats with streaming updates across projects 📈 -• Improved markdown checkbox styling and collapsed palette hover UX ✨ -• Enhanced scratchpad with search, image paste, and attachment support 🔍 +• Enhanced mobile web interface with session sync and history panel 📱 +• Added ThinkingStatusPill showing real-time token counts and elapsed time ⏱️ +• Implemented task count badges and session deduplication for batch runner 📊 +• Added TTS stop control and improved voice synthesis compatibility 🔊 +• Created image lightbox with navigation, clipboard, and delete features 🖼️ +• Fixed UI bugs in search, auto-scroll, and sidebar interactions 🐛 +• Added global Claude stats with streaming updates across projects 📈 +• Improved markdown checkbox styling and collapsed palette hover UX ✨ +• Enhanced scratchpad with search, image paste, and attachment support 🔍 • Added splash screen with logo and progress bar during startup 🎨 ### Previous Releases in this Series @@ -459,15 +446,15 @@ Plus the pre-release ALPHA... **Latest: v0.1.6** | Released November 27, 2025 -• Added template variables for dynamic AI command customization 🎯 -• Implemented session bookmarking with star icons and dedicated section ⭐ -• Enhanced Git Log Viewer with smarter date formatting 📅 -• Improved GitHub release workflow to handle partial failures gracefully 🔧 -• Added collapsible template documentation in AI Commands panel 📚 -• Updated default commit command with session ID traceability 🔍 -• Added tag indicators for custom-named sessions visually 🏷️ -• Improved Git Log search UX with better focus handling 🎨 -• Fixed input placeholder spacing for better readability 📝 +• Added template variables for dynamic AI command customization 🎯 +• Implemented session bookmarking with star icons and dedicated section ⭐ +• Enhanced Git Log Viewer with smarter date formatting 📅 +• Improved GitHub release workflow to handle partial failures gracefully 🔧 +• Added collapsible template documentation in AI Commands panel 📚 +• Updated default commit command with session ID traceability 🔍 +• Added tag indicators for custom-named sessions visually 🏷️ +• Improved Git Log search UX with better focus handling 🎨 +• Fixed input placeholder spacing for better readability 📝 • Updated documentation with new features and template references 📖 ### Previous Releases in this Series @@ -486,7 +473,6 @@ Plus the pre-release ALPHA... All releases are available on the [GitHub Releases page](https://github.com/RunMaestro/Maestro/releases). Maestro is available for: - - **macOS** - Apple Silicon (arm64) and Intel (x64) - **Windows** - x64 - **Linux** - x64 and arm64, AppImage, deb, and rpm packages From a136d7dbca235a8ab80358cc6b18a9c2b4f70eae Mon Sep 17 00:00:00 2001 From: Jeff Scott Ward Date: Thu, 9 Apr 2026 14:30:28 -0400 Subject: [PATCH 06/23] fix: restore repo git hooks and ignore local worktrees --- .gitignore | 1 + .prettierignore | 1 + docs/releases.md | 494 ++++++++++--------- package.json | 2 +- scripts/setup-git-hooks.mjs | 33 ++ src/__tests__/main/stats/integration.test.ts | 34 +- 6 files changed, 297 insertions(+), 268 deletions(-) create mode 100644 scripts/setup-git-hooks.mjs diff --git a/.gitignore b/.gitignore index 8a66100201..53bf38329b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ TEMP-REFACTORING-PLAN.md TEMP-REFACTORING-PLAN-2.md Auto\ Run\ Docs/ Work\ Trees/ +.worktrees/ community-data/ .mcp.json specs/ diff --git a/.prettierignore b/.prettierignore index a877d7bf84..813476ea02 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,6 +2,7 @@ dist/ release/ node_modules/ coverage/ +.worktrees/ *.min.js .gitignore src/renderer/assets/file-explorer-rich-icons/*.svg diff --git a/docs/releases.md b/docs/releases.md index 3b467bc158..36a1f457e7 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -17,32 +17,32 @@ Maestro can update itself automatically! This feature was introduced in **v0.8.7 **Latest: v0.15.3** | Released April 5, 2026 -# Major 0.15.x Additions - -🎶 **Maestro Symphony** — Contribute to open source with AI assistance! Browse curated issues from projects with the `runmaestro.ai` label, clone repos with one click, and automatically process the relevant Auto Run playbooks. Track your contributions, streaks, and stats. You're contributing CPU and tokens towards your favorite open source projects and features. - -🎬 **Director's Notes** — Aggregates history across all agents into a unified timeline with search, filters, and an activity graph. Includes an AI Overview tab that generates a structured synopsis of recent work. Off by default, gated behind a new "Encore Features" panel under settings. This is a precursor to an eventual plugin system, allowing for extensions and customizations without bloating the core app. - -🏷️ **Conductor Profile** — Available under Settings > General. Provide a short description on how Maestro agents should interface with you. - -🧠 **Three-State Thinking Toggle** — The thinking toggle now cycles through three modes: off, on, and sticky. Sticky mode keeps thinking content visible after the response completes. Cycle with CMD/CTRL+SHIFT+K. - -🤖 **Factory.ai Droid Support** — Added support for the [Factory.ai](https://factory.ai/product/cli) droid agent. Full session management and output parsing integration. - -## Changes in v0.15.3 - -- **CLI settings management:** Full `maestro-cli settings` command suite — list, get, set, and reset any Maestro setting from the command line. Includes per-agent configuration (custom paths, args, env vars, model overrides). Supports category filtering, verbose descriptions, and machine-readable JSON output for scripting -- **Live settings reload:** Settings changes made via the CLI are automatically detected by the running desktop app — no restart required -- **Plan-Mode toggle:** Claude Code and OpenCode agents now show "Plan-Mode" instead of "Read-Only" for the read-only toggle, matching their native terminology -- **Solarized Dark theme:** New Solarized Dark color theme with tuned contrast for tags, code blocks, and pill labels -- **Files pane icon theme:** Choose between default and rich icon themes in the files pane — rich theme adds colorful, language-specific icons for 70+ file types and folder categories. Toggle under Settings > Display -- **Persistent web link:** The web/mobile interface link now persists across app restarts — no need to re-enable it each session -- **OpenCode v1.2+ session support:** Automatically reads OpenCode's new SQLite session storage format alongside the legacy JSONL format -- **Group chat @mentions:** Use `@agent-name` syntax in the prompt composer to direct messages to specific agents in group chat -- **Group chat over SSH:** Group chat synthesis and moderation now run correctly on SSH remote agents instead of always spawning locally -- **Group chat participant management:** Remove button on participant cards lets you remove stale or unwanted participants from a group chat -- **Batch resume/abort:** New controls in the right panel for resuming or aborting batch operations -- **Default worktree directory:** Worktree configuration now defaults to the parent of the agent's working directory instead of blank +# Major 0.15.x Additions + +🎶 **Maestro Symphony** — Contribute to open source with AI assistance! Browse curated issues from projects with the `runmaestro.ai` label, clone repos with one click, and automatically process the relevant Auto Run playbooks. Track your contributions, streaks, and stats. You're contributing CPU and tokens towards your favorite open source projects and features. + +🎬 **Director's Notes** — Aggregates history across all agents into a unified timeline with search, filters, and an activity graph. Includes an AI Overview tab that generates a structured synopsis of recent work. Off by default, gated behind a new "Encore Features" panel under settings. This is a precursor to an eventual plugin system, allowing for extensions and customizations without bloating the core app. + +🏷️ **Conductor Profile** — Available under Settings > General. Provide a short description on how Maestro agents should interface with you. + +🧠 **Three-State Thinking Toggle** — The thinking toggle now cycles through three modes: off, on, and sticky. Sticky mode keeps thinking content visible after the response completes. Cycle with CMD/CTRL+SHIFT+K. + +🤖 **Factory.ai Droid Support** — Added support for the [Factory.ai](https://factory.ai/product/cli) droid agent. Full session management and output parsing integration. + +## Changes in v0.15.3 + +- **CLI settings management:** Full `maestro-cli settings` command suite — list, get, set, and reset any Maestro setting from the command line. Includes per-agent configuration (custom paths, args, env vars, model overrides). Supports category filtering, verbose descriptions, and machine-readable JSON output for scripting +- **Live settings reload:** Settings changes made via the CLI are automatically detected by the running desktop app — no restart required +- **Plan-Mode toggle:** Claude Code and OpenCode agents now show "Plan-Mode" instead of "Read-Only" for the read-only toggle, matching their native terminology +- **Solarized Dark theme:** New Solarized Dark color theme with tuned contrast for tags, code blocks, and pill labels +- **Files pane icon theme:** Choose between default and rich icon themes in the files pane — rich theme adds colorful, language-specific icons for 70+ file types and folder categories. Toggle under Settings > Display +- **Persistent web link:** The web/mobile interface link now persists across app restarts — no need to re-enable it each session +- **OpenCode v1.2+ session support:** Automatically reads OpenCode's new SQLite session storage format alongside the legacy JSONL format +- **Group chat @mentions:** Use `@agent-name` syntax in the prompt composer to direct messages to specific agents in group chat +- **Group chat over SSH:** Group chat synthesis and moderation now run correctly on SSH remote agents instead of always spawning locally +- **Group chat participant management:** Remove button on participant cards lets you remove stale or unwanted participants from a group chat +- **Batch resume/abort:** New controls in the right panel for resuming or aborting batch operations +- **Default worktree directory:** Worktree configuration now defaults to the parent of the agent's working directory instead of blank - **Drawfinity in Symphony:** Added Drawfinity to the Symphony project registry ### Previous Releases in this Series @@ -56,41 +56,41 @@ Maestro can update itself automatically! This feature was introduced in **v0.8.7 **Latest: v0.14.5** | Released January 24, 2026 -Changes in this point release include: - -- Desktop app performance improvements (more to come on this, we want Maestro blazing fast) 🐌 -- Added local manifest feature for custom playbooks 📖 -- Agents are now inherently aware of your activity history as seen in the history panel 📜 (this is built-in cross context memory!) -- Added markdown rendering support for AI responses in mobile view 📱 -- Bugfix in tracking costs from JSONL files that were aged out 🏦 -- Added BlueSky social media handle for leaderboard 🦋 -- Added options to disable GPU rendering and confetti 🎊 -- Better handling of large files in preview 🗄️ -- Bug fix in Claude context calculation 🧮 -- Addressed bug in OpenSpec version reporting 🐛 - -The major contributions to 0.14.x remain: - -🗄️ Document Graphs. Launch from file preview or from the FIle tree panel. Explore relationships between Markdown documents that contain links between documents and to URLs. - -📶 SSH support for agents. Manage a remote agent with feature parity over SSH. Includes support for Git and File tree panels. Manage agents on remote systems or in containers. This even works for Group Chat, which is rad as hell. - -🧙‍♂️ Added an in-tab wizard for generating Auto Run Playbooks via `/wizard` or a new button in the Auto Run panel. - -# Smaller Changes in 014.x - -- Improved User Dashboard, available from hamburger menu, command palette or hotkey 🎛️ -- Leaderboard tracking now works across multiple systems and syncs level from cloud 🏆 -- Agent duplication. Pro tip: Consider a group of unused "Template" agents ✌️ -- New setting to prevent system from going to sleep while agents are active 🛏️ -- The tab menu has a new "Publish as GitHub Gist" option 📝 -- The tab menu has options to move the tab to the first or last position 🔀 -- [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) can now contain non-markdown assets 📙 -- Improved default shell detection 🐚 -- Added logic to prevent overlapping TTS notifications 💬 -- Added "Toggle Bookmark" shortcut (CTRL/CMD+SHIFT+B) ⌨️ -- Gist publishing now shows previous URLs with copy button 📋 - +Changes in this point release include: + +- Desktop app performance improvements (more to come on this, we want Maestro blazing fast) 🐌 +- Added local manifest feature for custom playbooks 📖 +- Agents are now inherently aware of your activity history as seen in the history panel 📜 (this is built-in cross context memory!) +- Added markdown rendering support for AI responses in mobile view 📱 +- Bugfix in tracking costs from JSONL files that were aged out 🏦 +- Added BlueSky social media handle for leaderboard 🦋 +- Added options to disable GPU rendering and confetti 🎊 +- Better handling of large files in preview 🗄️ +- Bug fix in Claude context calculation 🧮 +- Addressed bug in OpenSpec version reporting 🐛 + +The major contributions to 0.14.x remain: + +🗄️ Document Graphs. Launch from file preview or from the FIle tree panel. Explore relationships between Markdown documents that contain links between documents and to URLs. + +📶 SSH support for agents. Manage a remote agent with feature parity over SSH. Includes support for Git and File tree panels. Manage agents on remote systems or in containers. This even works for Group Chat, which is rad as hell. + +🧙‍♂️ Added an in-tab wizard for generating Auto Run Playbooks via `/wizard` or a new button in the Auto Run panel. + +# Smaller Changes in 014.x + +- Improved User Dashboard, available from hamburger menu, command palette or hotkey 🎛️ +- Leaderboard tracking now works across multiple systems and syncs level from cloud 🏆 +- Agent duplication. Pro tip: Consider a group of unused "Template" agents ✌️ +- New setting to prevent system from going to sleep while agents are active 🛏️ +- The tab menu has a new "Publish as GitHub Gist" option 📝 +- The tab menu has options to move the tab to the first or last position 🔀 +- [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) can now contain non-markdown assets 📙 +- Improved default shell detection 🐚 +- Added logic to prevent overlapping TTS notifications 💬 +- Added "Toggle Bookmark" shortcut (CTRL/CMD+SHIFT+B) ⌨️ +- Gist publishing now shows previous URLs with copy button 📋 + Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @deandebeer @shadown @breki @charles-dyfis-net @ronaldeddings @jlengrand @ksylvan ### Previous Releases in this Series @@ -109,20 +109,22 @@ Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @d ### Changes -- TAKE TWO! Fixed Linux ARM64 build architecture contamination issues 🏗️ - -### v0.13.1 Changes -- Fixed Linux ARM64 build architecture contamination issues 🏗️ -- Enhanced error handling for Auto Run batch processing 🚨 - -### v0.13.0 Changes -- Added a global usage dashboard, data collection begins with this install 🎛️ -- Added a Playbook Exchange for downloading pre-defined Auto Run playbooks from [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) 📕 -- Bundled OpenSpec commands for structured change proposals 📝 -- Added pre-release channel support for beta/RC updates 🧪 -- Implemented global hands-on time tracking across sessions ⏱️ -- Added new keyboard shortcut for agent settings (Opt+Cmd+, | Ctrl+Alt+,) ⌨️ -- Added directory size calculation with file/folder counts in file explorer 📊 +- TAKE TWO! Fixed Linux ARM64 build architecture contamination issues 🏗️ + +### v0.13.1 Changes + +- Fixed Linux ARM64 build architecture contamination issues 🏗️ +- Enhanced error handling for Auto Run batch processing 🚨 + +### v0.13.0 Changes + +- Added a global usage dashboard, data collection begins with this install 🎛️ +- Added a Playbook Exchange for downloading pre-defined Auto Run playbooks from [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) 📕 +- Bundled OpenSpec commands for structured change proposals 📝 +- Added pre-release channel support for beta/RC updates 🧪 +- Implemented global hands-on time tracking across sessions ⏱️ +- Added new keyboard shortcut for agent settings (Opt+Cmd+, | Ctrl+Alt+,) ⌨️ +- Added directory size calculation with file/folder counts in file explorer 📊 - Added sleep detection to exclude laptop sleep from time tracking ⏰ ### Previous Releases in this Series @@ -136,22 +138,26 @@ Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @d **Latest: v0.12.3** | Released December 28, 2025 -The big changes in the v0.12.x line are the following three: - -## Show Thinking -🤔 There is now a toggle to show thinking for the agent, the default for new tabs is off, though this can be changed under Settings > General. The toggle shows next to History and Read-Only. Very similar pattern. This has been the #1 most requested feature, though personally, I don't think I'll use it as I prefer to not see the details of the work, but the results of the work. Just as we work with our colleagues. - -## GitHub Spec-Kit Integration -🎯 Added [GitHub Spec-Kit](https://github.com/github/spec-kit) commands into Maestro with a built in updater to grab the latest prompts from the repository. We do override `/speckit-implement` (the final step) to create Auto Run docs and guide the user through their execution, which thanks to Wortrees from v0.11.x allows us to run in parallel! - -## Context Management Tools -📖 Added context management options from tab right-click menu. You can now compress, merge, and transfer contexts between agents. You will received (configurable) warnings at 60% and 80% context consumption with a hint to compact. - -## Changes Specific to v0.12.3: -- We now have hosted documentation through Mintlify 📚 -- Export any tab conversation as self-contained themed HTML file 📄 -- Publish files as private/public Gists 🌐 -- Added tab hover overlay menu with close operations and export 📋 +The big changes in the v0.12.x line are the following three: + +## Show Thinking + +🤔 There is now a toggle to show thinking for the agent, the default for new tabs is off, though this can be changed under Settings > General. The toggle shows next to History and Read-Only. Very similar pattern. This has been the #1 most requested feature, though personally, I don't think I'll use it as I prefer to not see the details of the work, but the results of the work. Just as we work with our colleagues. + +## GitHub Spec-Kit Integration + +🎯 Added [GitHub Spec-Kit](https://github.com/github/spec-kit) commands into Maestro with a built in updater to grab the latest prompts from the repository. We do override `/speckit-implement` (the final step) to create Auto Run docs and guide the user through their execution, which thanks to Wortrees from v0.11.x allows us to run in parallel! + +## Context Management Tools + +📖 Added context management options from tab right-click menu. You can now compress, merge, and transfer contexts between agents. You will received (configurable) warnings at 60% and 80% context consumption with a hint to compact. + +## Changes Specific to v0.12.3: + +- We now have hosted documentation through Mintlify 📚 +- Export any tab conversation as self-contained themed HTML file 📄 +- Publish files as private/public Gists 🌐 +- Added tab hover overlay menu with close operations and export 📋 - Added social handles to achievement share images 🏆 ### Previous Releases in this Series @@ -165,12 +171,12 @@ The big changes in the v0.12.x line are the following three: **Latest: v0.11.0** | Released December 22, 2025 -🌳 Github Worktree support was added. Any agent bound to a Git repository has the option to enable worktrees, each of which show up as a sub-agent with their own write-lock and Auto Run capability. Now you can truly develop in parallel on the same project and issue PRs when you're ready, all from within Maestro. Huge improvement, major thanks to @petersilberman. - -# Other Changes - -- @ file mentions now include documents from your Auto Run folder (which may not live in your agent working directory) 🗄️ -- The wizard is now capable of detecting and continuing on past started projects 🧙 +🌳 Github Worktree support was added. Any agent bound to a Git repository has the option to enable worktrees, each of which show up as a sub-agent with their own write-lock and Auto Run capability. Now you can truly develop in parallel on the same project and issue PRs when you're ready, all from within Maestro. Huge improvement, major thanks to @petersilberman. + +# Other Changes + +- @ file mentions now include documents from your Auto Run folder (which may not live in your agent working directory) 🗄️ +- The wizard is now capable of detecting and continuing on past started projects 🧙 - Bug fixes 🐛🐜🐞 --- @@ -181,14 +187,14 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Export group chats as self-contained HTML ⬇️ -- Enhanced system process viewer now has details view with full process args 💻 -- Update button hides until platform binaries are available in releases. ⏳ -- Added Auto Run stall detection at the loop level, if no documents are updated after a loop 🔁 -- Improved Codex session discovery 🔍 -- Windows compatibility fixes 🐛 -- 64-bit Linux ARM build issue fixed (thanks @LilYoopug) 🐜 -- Addressed session enumeration issues with Codex and OpenCode 🐞 +- Export group chats as self-contained HTML ⬇️ +- Enhanced system process viewer now has details view with full process args 💻 +- Update button hides until platform binaries are available in releases. ⏳ +- Added Auto Run stall detection at the loop level, if no documents are updated after a loop 🔁 +- Improved Codex session discovery 🔍 +- Windows compatibility fixes 🐛 +- 64-bit Linux ARM build issue fixed (thanks @LilYoopug) 🐜 +- Addressed session enumeration issues with Codex and OpenCode 🐞 - Addressed pathing issues around gh command (thanks @oliveiraantoniocc) 🐝 ### Previous Releases in this Series @@ -204,13 +210,13 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Add Sentry crashing reporting monitoring with opt-out 🐛 -- Stability fixes on v0.9.0 along with all the changes it brought along, including... - - Major refactor to enable supporting of multiple providers 👨‍👩‍👧‍👦 - - Added OpenAI Codex support 👨‍💻 - - Added OpenCode support 👩‍💻 - - Error handling system detects and recovers from agent failures 🚨 - - Added option to specify CLI arguments to AI providers ✨ +- Add Sentry crashing reporting monitoring with opt-out 🐛 +- Stability fixes on v0.9.0 along with all the changes it brought along, including... + - Major refactor to enable supporting of multiple providers 👨‍👩‍👧‍👦 + - Added OpenAI Codex support 👨‍💻 + - Added OpenCode support 👩‍💻 + - Error handling system detects and recovers from agent failures 🚨 + - Added option to specify CLI arguments to AI providers ✨ - Bunch of other little tweaks and additions 💎 ### Previous Releases in this Series @@ -225,19 +231,19 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Added "Nudge" messages. Short static copy to include with every interactive message sent, perhaps to remind the agent on how to work 📌 -- Addressed various resource consumption issues to reduce battery cost 📉 -- Implemented fuzzy file search in quick actions for instant navigation 🔍 -- Added "clear" command support to clean terminal shell logs 🧹 -- Simplified search highlighting by integrating into markdown pipeline ✨ -- Enhanced update checker to filter prerelease tags like -rc, -beta 🚀 -- Fixed RPM package compatibility for OpenSUSE Tumbleweed 🐧 (H/T @JOduMonT) -- Added libuuid1 support alongside standard libuuid dependency 📦 -- Introduced Cmd+Shift+U shortcut for tab unread toggle ⌨️ -- Enhanced keyboard navigation for marking tabs unread 🎯 -- Expanded Linux distribution support with smart dependencies 🌐 -- Major underlying code re-structuring for maintainability 🧹 -- Improved stall detection to allow for individual docs to stall out while not affecting the entire playbook 📖 (H/T @mattjay) +- Added "Nudge" messages. Short static copy to include with every interactive message sent, perhaps to remind the agent on how to work 📌 +- Addressed various resource consumption issues to reduce battery cost 📉 +- Implemented fuzzy file search in quick actions for instant navigation 🔍 +- Added "clear" command support to clean terminal shell logs 🧹 +- Simplified search highlighting by integrating into markdown pipeline ✨ +- Enhanced update checker to filter prerelease tags like -rc, -beta 🚀 +- Fixed RPM package compatibility for OpenSUSE Tumbleweed 🐧 (H/T @JOduMonT) +- Added libuuid1 support alongside standard libuuid dependency 📦 +- Introduced Cmd+Shift+U shortcut for tab unread toggle ⌨️ +- Enhanced keyboard navigation for marking tabs unread 🎯 +- Expanded Linux distribution support with smart dependencies 🌐 +- Major underlying code re-structuring for maintainability 🧹 +- Improved stall detection to allow for individual docs to stall out while not affecting the entire playbook 📖 (H/T @mattjay) - Added option to select a static listening port for remote control 🎮 (H/T @b3nw) ### Previous Releases in this Series @@ -257,35 +263,40 @@ The big changes in the v0.12.x line are the following three: **Latest: v0.7.4** | Released December 12, 2025 -Minor bugfixes on top of v0.7.3: - -# Onboarding, Wizard, and Tours -- Implemented comprehensive onboarding wizard with integrated tour system 🚀 -- Added project-understanding confidence display to wizard UI 🎨 -- Enhanced keyboard navigation across all wizard screens ⌨️ -- Added analytics tracking for wizard and tour completion 📈 -- Added First Run Celebration modal with confetti animation 🎉 - -# UI / UX Enhancements -- Added expand-to-fullscreen button for Auto Run interface 🖥️ -- Created dedicated modal component and improved modal priority constants for expanded Auto Run view 📐 -- Enhanced user experience with fullscreen editing capabilities ✨ -- Fixed tab name display to correctly show full name for active tabs 🏷️ -- Added performance optimizations with throttling and caching for scrolling ⚡ -- Implemented drag-and-drop reordering for execution queue items 🎯 -- Enhanced toast context with agent name for OS notifications 📢 - -# Auto Run Workflow Improvements -- Created phase document generation for Auto Run workflow 📄 -- Added real-time log streaming to the LogViewer component 📊 - -# Application Behavior / Core Fixes -- Added validation to prevent nested worktrees inside the main repository 🚫 -- Fixed process manager to properly emit exit events on errors 🔧 -- Fixed process exit handling to ensure proper cleanup 🧹 - -# Update System -- Implemented automatic update checking on application startup 🚀 +Minor bugfixes on top of v0.7.3: + +# Onboarding, Wizard, and Tours + +- Implemented comprehensive onboarding wizard with integrated tour system 🚀 +- Added project-understanding confidence display to wizard UI 🎨 +- Enhanced keyboard navigation across all wizard screens ⌨️ +- Added analytics tracking for wizard and tour completion 📈 +- Added First Run Celebration modal with confetti animation 🎉 + +# UI / UX Enhancements + +- Added expand-to-fullscreen button for Auto Run interface 🖥️ +- Created dedicated modal component and improved modal priority constants for expanded Auto Run view 📐 +- Enhanced user experience with fullscreen editing capabilities ✨ +- Fixed tab name display to correctly show full name for active tabs 🏷️ +- Added performance optimizations with throttling and caching for scrolling ⚡ +- Implemented drag-and-drop reordering for execution queue items 🎯 +- Enhanced toast context with agent name for OS notifications 📢 + +# Auto Run Workflow Improvements + +- Created phase document generation for Auto Run workflow 📄 +- Added real-time log streaming to the LogViewer component 📊 + +# Application Behavior / Core Fixes + +- Added validation to prevent nested worktrees inside the main repository 🚫 +- Fixed process manager to properly emit exit events on errors 🔧 +- Fixed process exit handling to ensure proper cleanup 🧹 + +# Update System + +- Implemented automatic update checking on application startup 🚀 - Added settings toggle for enabling/disabling startup update checks ⚙️ ### Previous Releases in this Series @@ -301,38 +312,40 @@ Minor bugfixes on top of v0.7.3: **Latest: v0.6.1** | Released December 4, 2025 -In this release... -- Added recursive subfolder support for Auto Run markdown files 🗂️ -- Enhanced document tree display with expandable folder navigation 🌳 -- Enabled creating documents in subfolders with path selection 📁 -- Improved batch runner UI with inline progress bars and loop indicators 📊 -- Fixed execution queue display bug for immediate command processing 🐛 -- Added folder icons and better visual hierarchy for document browser 🎨 -- Implemented dynamic task re-counting for batch run loop iterations 🔄 -- Enhanced create document modal with location selector dropdown 📍 -- Improved progress tracking with per-document completion visualization 📈 -- Added support for nested folder structures in document management 🏗️ - -Plus the pre-release ALPHA... -- Template vars now set context in default autorun prompt 🚀 -- Added Enter key support for queued message confirmation dialog ⌨️ -- Kill process capability added to System Process Monitor 💀 -- Toggle markdown rendering added to Cmd+K Quick Actions 📝 -- Fixed cloudflared detection in packaged app environments 🔧 -- Added debugging logs for process exit diagnostics 🐛 -- Tab switcher shows last activity timestamps and filters by project 🕐 -- Slash commands now fill text on Tab/Enter instead of executing ⚡ -- Added GitHub Actions workflow for auto-assigning issues/PRs 🤖 -- Graceful handling for playbooks with missing documents implemented ✨ -- Added multi-document batch processing for Auto Run 🚀 -- Introduced Git worktree support for parallel execution 🌳 -- Created playbook system for saving run configurations 📚 -- Implemented document reset-on-completion with loop mode 🔄 -- Added drag-and-drop document reordering interface 🎯 -- Built Auto Run folder selector with file management 📁 -- Enhanced progress tracking with per-document metrics 📊 -- Integrated PR creation after worktree completion 🔀 -- Added undo/redo support in document editor ↩️ +In this release... + +- Added recursive subfolder support for Auto Run markdown files 🗂️ +- Enhanced document tree display with expandable folder navigation 🌳 +- Enabled creating documents in subfolders with path selection 📁 +- Improved batch runner UI with inline progress bars and loop indicators 📊 +- Fixed execution queue display bug for immediate command processing 🐛 +- Added folder icons and better visual hierarchy for document browser 🎨 +- Implemented dynamic task re-counting for batch run loop iterations 🔄 +- Enhanced create document modal with location selector dropdown 📍 +- Improved progress tracking with per-document completion visualization 📈 +- Added support for nested folder structures in document management 🏗️ + +Plus the pre-release ALPHA... + +- Template vars now set context in default autorun prompt 🚀 +- Added Enter key support for queued message confirmation dialog ⌨️ +- Kill process capability added to System Process Monitor 💀 +- Toggle markdown rendering added to Cmd+K Quick Actions 📝 +- Fixed cloudflared detection in packaged app environments 🔧 +- Added debugging logs for process exit diagnostics 🐛 +- Tab switcher shows last activity timestamps and filters by project 🕐 +- Slash commands now fill text on Tab/Enter instead of executing ⚡ +- Added GitHub Actions workflow for auto-assigning issues/PRs 🤖 +- Graceful handling for playbooks with missing documents implemented ✨ +- Added multi-document batch processing for Auto Run 🚀 +- Introduced Git worktree support for parallel execution 🌳 +- Created playbook system for saving run configurations 📚 +- Implemented document reset-on-completion with loop mode 🔄 +- Added drag-and-drop document reordering interface 🎯 +- Built Auto Run folder selector with file management 📁 +- Enhanced progress tracking with per-document metrics 📊 +- Integrated PR creation after worktree completion 🔀 +- Added undo/redo support in document editor ↩️ - Implemented auto-save with 5-second debounce 💾 ### Previous Releases in this Series @@ -347,15 +360,15 @@ Plus the pre-release ALPHA... ### Changes -- Added "Made with Maestro" badge to README header 🎯 -- Redesigned app icon with darker purple color scheme 🎨 -- Created new SVG badge for project attribution 🏷️ -- Added side-by-side image diff viewer for git changes 🖼️ -- Enhanced confetti animation with realistic cannon-style bursts 🎊 -- Fixed z-index layering for standing ovation overlay 📊 -- Improved tab switcher to show all named sessions 🔍 -- Enhanced batch synopsis prompts for cleaner summaries 📝 -- Added binary file detection in git diff parser 🔧 +- Added "Made with Maestro" badge to README header 🎯 +- Redesigned app icon with darker purple color scheme 🎨 +- Created new SVG badge for project attribution 🏷️ +- Added side-by-side image diff viewer for git changes 🖼️ +- Enhanced confetti animation with realistic cannon-style bursts 🎊 +- Fixed z-index layering for standing ovation overlay 📊 +- Improved tab switcher to show all named sessions 🔍 +- Enhanced batch synopsis prompts for cleaner summaries 📝 +- Added binary file detection in git diff parser 🔧 - Implemented git file reading at specific refs 📁 ### Previous Releases in this Series @@ -370,24 +383,24 @@ Plus the pre-release ALPHA... ### Changes -- Added Tab Switcher modal for quick navigation between AI tabs 🚀 -- Implemented @ mention file completion for AI mode references 📁 -- Added navigation history with back/forward through sessions and tabs ⏮️ -- Introduced tab completion filters for branches, tags, and files 🌳 -- Added unread tab indicators and filtering for better organization 📬 -- Implemented token counting display with human-readable formatting 🔢 -- Added markdown rendering toggle for AI responses in terminal 📝 -- Removed built-in slash commands in favor of custom AI commands 🎯 -- Added context menu for sessions with rename, bookmark, move options 🖱️ -- Enhanced file preview with stats showing size, tokens, timestamps 📊 -- Added token counting with js-tiktoken for file preview stats bar 🔢 -- Implemented Tab Switcher modal for fuzzy-search navigation (Opt+Cmd+T) 🔍 -- Added Save to History toggle (Cmd+S) for automatic work synopsis tracking 💾 -- Enhanced tab completion with @ mentions for file references in AI prompts 📎 -- Implemented navigation history with back/forward shortcuts (Cmd+Shift+,/.) 🔙 -- Added git branches and tags to intelligent tab completion system 🌿 -- Enhanced markdown rendering with syntax highlighting and toggle view 📝 -- Added right-click context menus for session management and organization 🖱️ +- Added Tab Switcher modal for quick navigation between AI tabs 🚀 +- Implemented @ mention file completion for AI mode references 📁 +- Added navigation history with back/forward through sessions and tabs ⏮️ +- Introduced tab completion filters for branches, tags, and files 🌳 +- Added unread tab indicators and filtering for better organization 📬 +- Implemented token counting display with human-readable formatting 🔢 +- Added markdown rendering toggle for AI responses in terminal 📝 +- Removed built-in slash commands in favor of custom AI commands 🎯 +- Added context menu for sessions with rename, bookmark, move options 🖱️ +- Enhanced file preview with stats showing size, tokens, timestamps 📊 +- Added token counting with js-tiktoken for file preview stats bar 🔢 +- Implemented Tab Switcher modal for fuzzy-search navigation (Opt+Cmd+T) 🔍 +- Added Save to History toggle (Cmd+S) for automatic work synopsis tracking 💾 +- Enhanced tab completion with @ mentions for file references in AI prompts 📎 +- Implemented navigation history with back/forward shortcuts (Cmd+Shift+,/.) 🔙 +- Added git branches and tags to intelligent tab completion system 🌿 +- Enhanced markdown rendering with syntax highlighting and toggle view 📝 +- Added right-click context menus for session management and organization 🖱️ - Improved mobile app with better WebSocket reconnection and status badges 📱 ### Previous Releases in this Series @@ -402,15 +415,15 @@ Plus the pre-release ALPHA... ### Changes -- Fixed tab handling requiring explicitly selected Claude session 🔧 -- Added auto-scroll navigation for slash command list selection ⚡ -- Implemented TTS audio feedback for toast notifications speak 🔊 -- Fixed shortcut case sensitivity using lowercase key matching 🔤 -- Added Cmd+Shift+J shortcut to jump to bottom instantly ⬇️ -- Sorted shortcuts alphabetically in help modal for discovery 📑 -- Display full commit message body in git log view 📝 -- Added expand/collapse all buttons to process tree header 🌳 -- Support synopsis process type in process tree parsing 🔍 +- Fixed tab handling requiring explicitly selected Claude session 🔧 +- Added auto-scroll navigation for slash command list selection ⚡ +- Implemented TTS audio feedback for toast notifications speak 🔊 +- Fixed shortcut case sensitivity using lowercase key matching 🔤 +- Added Cmd+Shift+J shortcut to jump to bottom instantly ⬇️ +- Sorted shortcuts alphabetically in help modal for discovery 📑 +- Display full commit message body in git log view 📝 +- Added expand/collapse all buttons to process tree header 🌳 +- Support synopsis process type in process tree parsing 🔍 - Renamed "No Group" to "UNGROUPED" for better clarity ✨ ### Previous Releases in this Series @@ -423,15 +436,15 @@ Plus the pre-release ALPHA... **Latest: v0.2.3** | Released November 29, 2025 -• Enhanced mobile web interface with session sync and history panel 📱 -• Added ThinkingStatusPill showing real-time token counts and elapsed time ⏱️ -• Implemented task count badges and session deduplication for batch runner 📊 -• Added TTS stop control and improved voice synthesis compatibility 🔊 -• Created image lightbox with navigation, clipboard, and delete features 🖼️ -• Fixed UI bugs in search, auto-scroll, and sidebar interactions 🐛 -• Added global Claude stats with streaming updates across projects 📈 -• Improved markdown checkbox styling and collapsed palette hover UX ✨ -• Enhanced scratchpad with search, image paste, and attachment support 🔍 +• Enhanced mobile web interface with session sync and history panel 📱 +• Added ThinkingStatusPill showing real-time token counts and elapsed time ⏱️ +• Implemented task count badges and session deduplication for batch runner 📊 +• Added TTS stop control and improved voice synthesis compatibility 🔊 +• Created image lightbox with navigation, clipboard, and delete features 🖼️ +• Fixed UI bugs in search, auto-scroll, and sidebar interactions 🐛 +• Added global Claude stats with streaming updates across projects 📈 +• Improved markdown checkbox styling and collapsed palette hover UX ✨ +• Enhanced scratchpad with search, image paste, and attachment support 🔍 • Added splash screen with logo and progress bar during startup 🎨 ### Previous Releases in this Series @@ -446,15 +459,15 @@ Plus the pre-release ALPHA... **Latest: v0.1.6** | Released November 27, 2025 -• Added template variables for dynamic AI command customization 🎯 -• Implemented session bookmarking with star icons and dedicated section ⭐ -• Enhanced Git Log Viewer with smarter date formatting 📅 -• Improved GitHub release workflow to handle partial failures gracefully 🔧 -• Added collapsible template documentation in AI Commands panel 📚 -• Updated default commit command with session ID traceability 🔍 -• Added tag indicators for custom-named sessions visually 🏷️ -• Improved Git Log search UX with better focus handling 🎨 -• Fixed input placeholder spacing for better readability 📝 +• Added template variables for dynamic AI command customization 🎯 +• Implemented session bookmarking with star icons and dedicated section ⭐ +• Enhanced Git Log Viewer with smarter date formatting 📅 +• Improved GitHub release workflow to handle partial failures gracefully 🔧 +• Added collapsible template documentation in AI Commands panel 📚 +• Updated default commit command with session ID traceability 🔍 +• Added tag indicators for custom-named sessions visually 🏷️ +• Improved Git Log search UX with better focus handling 🎨 +• Fixed input placeholder spacing for better readability 📝 • Updated documentation with new features and template references 📖 ### Previous Releases in this Series @@ -473,6 +486,7 @@ Plus the pre-release ALPHA... All releases are available on the [GitHub Releases page](https://github.com/RunMaestro/Maestro/releases). Maestro is available for: + - **macOS** - Apple Silicon (arm64) and Intel (x64) - **Windows** - x64 - **Linux** - x64 and arm64, AppImage, deb, and rpm packages diff --git a/package.json b/package.json index 52540c70b7..a1eff877e6 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "package:linux": "node scripts/set-version.mjs npm run build && node scripts/set-version.mjs electron-builder --linux", "start": "electron .", "clean": "rm -rf dist release node_modules/.vite", - "prepare": "husky || true", + "prepare": "node scripts/setup-git-hooks.mjs", "postinstall": "electron-rebuild -f -w node-pty,better-sqlite3", "lint": "tsc -p tsconfig.lint.json && tsc -p tsconfig.main.json --noEmit && tsc -p tsconfig.cli.json --noEmit", "lint:eslint": "eslint src/", diff --git a/scripts/setup-git-hooks.mjs b/scripts/setup-git-hooks.mjs new file mode 100644 index 0000000000..ef8e86c932 --- /dev/null +++ b/scripts/setup-git-hooks.mjs @@ -0,0 +1,33 @@ +import { existsSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; + +function runGit(args) { + const result = spawnSync('git', args, { stdio: 'pipe', encoding: 'utf8' }); + if (result.error) throw result.error; + if (result.status !== 0) { + throw new Error(result.stderr.trim() || `git ${args.join(' ')} failed`); + } + return result.stdout.trim(); +} + +function getGitConfig(key) { + const result = spawnSync('git', ['config', '--get', key], { stdio: 'pipe', encoding: 'utf8' }); + if (result.error) throw result.error; + if (result.status !== 0) return ''; + return result.stdout.trim(); +} + +if (!existsSync('.git')) { + console.log('[setup-git-hooks] Skipping hook installation because .git is not present.'); + process.exit(0); +} + +const desiredHooksPath = '.husky'; +const currentHooksPath = getGitConfig('core.hooksPath'); + +if (currentHooksPath !== desiredHooksPath) { + runGit(['config', 'core.hooksPath', desiredHooksPath]); + console.log(`[setup-git-hooks] Set core.hooksPath=${desiredHooksPath}`); +} else { + console.log(`[setup-git-hooks] core.hooksPath already set to ${desiredHooksPath}`); +} diff --git a/src/__tests__/main/stats/integration.test.ts b/src/__tests__/main/stats/integration.test.ts index ca5a04b3ed..9fd361eada 100644 --- a/src/__tests__/main/stats/integration.test.ts +++ b/src/__tests__/main/stats/integration.test.ts @@ -890,16 +890,12 @@ describe('electron-rebuild verification for better-sqlite3', () => { it('should have better-sqlite3 native binding in expected location', async () => { const fs = await import('node:fs'); const path = await import('node:path'); + const betterSqlitePackagePath = require.resolve('better-sqlite3/package.json'); + const betterSqliteDir = path.dirname(betterSqlitePackagePath); // Check if the native binding exists in build/Release (compiled location) const nativeModulePath = path.join( - __dirname, - '..', - '..', - '..', - '..', - 'node_modules', - 'better-sqlite3', + betterSqliteDir, 'build', 'Release', 'better_sqlite3.node' @@ -912,16 +908,7 @@ describe('electron-rebuild verification for better-sqlite3', () => { // If the native module doesn't exist, check if there's a prebuilt binary if (!exists) { // Check for prebuilt binaries in the bin directory - const binDir = path.join( - __dirname, - '..', - '..', - '..', - '..', - 'node_modules', - 'better-sqlite3', - 'bin' - ); + const binDir = path.join(betterSqliteDir, 'bin'); if (fs.existsSync(binDir)) { const binContents = fs.readdirSync(binDir); @@ -937,17 +924,10 @@ describe('electron-rebuild verification for better-sqlite3', () => { it('should verify binding.gyp exists for native compilation', async () => { const fs = await import('node:fs'); const path = await import('node:path'); + const betterSqlitePackagePath = require.resolve('better-sqlite3/package.json'); + const betterSqliteDir = path.dirname(betterSqlitePackagePath); - const bindingGypPath = path.join( - __dirname, - '..', - '..', - '..', - '..', - 'node_modules', - 'better-sqlite3', - 'binding.gyp' - ); + const bindingGypPath = path.join(betterSqliteDir, 'binding.gyp'); // binding.gyp is required for node-gyp compilation expect(fs.existsSync(bindingGypPath)).toBe(true); From 403148578c72c3d1b00ac4aa8c4dc7a6f4b8b3d1 Mon Sep 17 00:00:00 2001 From: Jeff Scott Ward Date: Thu, 9 Apr 2026 13:57:40 -0400 Subject: [PATCH 07/23] fix: polish slash menu and playbooks ui --- src/renderer/components/AutoRun.tsx | 6 +++--- src/renderer/components/AutoRunExpandedModal.tsx | 6 +++--- src/renderer/components/InputArea.tsx | 8 ++++---- src/renderer/components/SessionList/SessionList.tsx | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/renderer/components/AutoRun.tsx b/src/renderer/components/AutoRun.tsx index 60b80c9f0b..3b9f0dbcc3 100644 --- a/src/renderer/components/AutoRun.tsx +++ b/src/renderer/components/AutoRun.tsx @@ -1761,7 +1761,7 @@ const AutoRunInner = forwardRef(function AutoRunInn Run )} - {/* Playbook Exchange button */} + {/* PlayBooks button */} {onOpenMarketplace && ( )} {/* Launch Wizard button */} diff --git a/src/renderer/components/AutoRunExpandedModal.tsx b/src/renderer/components/AutoRunExpandedModal.tsx index 03139e19dc..c2deaf630e 100644 --- a/src/renderer/components/AutoRunExpandedModal.tsx +++ b/src/renderer/components/AutoRunExpandedModal.tsx @@ -401,7 +401,7 @@ export function AutoRunExpandedModal({ Run )} - {/* Exchange button */} + {/* PlayBooks button */} {onOpenMarketplace && ( )}
diff --git a/src/renderer/components/InputArea.tsx b/src/renderer/components/InputArea.tsx index 12dd502337..7ae2497270 100644 --- a/src/renderer/components/InputArea.tsx +++ b/src/renderer/components/InputArea.tsx @@ -501,7 +501,7 @@ export const InputArea = React.memo(function InputArea(props: InputAreaProps) { style={{ backgroundColor: theme.colors.bgSidebar, borderColor: theme.colors.border }} >
{filteredSlashCommands.map((cmd, idx) => ( @@ -509,7 +509,7 @@ export const InputArea = React.memo(function InputArea(props: InputAreaProps) { type="button" key={cmd.command} ref={(el) => (slashCommandItemRefs.current[idx] = el)} - className={`w-full px-4 py-3 text-left transition-colors ${ + className={`w-full px-3 py-2 text-left transition-colors ${ idx === safeSelectedIndex ? 'font-semibold' : '' }`} style={{ @@ -528,8 +528,8 @@ export const InputArea = React.memo(function InputArea(props: InputAreaProps) { }} onMouseEnter={() => setSelectedSlashCommandIndex(idx)} > -
{cmd.command}
-
{cmd.description}
+
{cmd.command}
+
{cmd.description}
))}
diff --git a/src/renderer/components/SessionList/SessionList.tsx b/src/renderer/components/SessionList/SessionList.tsx index 38ad6fbd2a..4a9da4bd1e 100644 --- a/src/renderer/components/SessionList/SessionList.tsx +++ b/src/renderer/components/SessionList/SessionList.tsx @@ -718,7 +718,7 @@ function SessionListInner(props: SessionListProps) { {/* Hamburger Menu */} -
+
))}
From cbe43f60328c9dd9f97f18f2136154c220b79676 Mon Sep 17 00:00:00 2001 From: Jeff Scott Ward Date: Thu, 9 Apr 2026 19:16:51 -0400 Subject: [PATCH 17/23] fix: clamp fallback context percentages --- src/__tests__/renderer/utils/contextUsage.test.ts | 15 +++++++++++++++ src/renderer/utils/contextUsage.ts | 9 +++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/__tests__/renderer/utils/contextUsage.test.ts b/src/__tests__/renderer/utils/contextUsage.test.ts index 59c6e33b6d..067a825032 100644 --- a/src/__tests__/renderer/utils/contextUsage.test.ts +++ b/src/__tests__/renderer/utils/contextUsage.test.ts @@ -411,6 +411,21 @@ describe('calculateContextDisplay', () => { expect(result.percentage).toBe(100); }); + it('should clamp fallback percentages above 100 before deriving tokens', () => { + const result = calculateContextDisplay( + { + inputTokens: 50000, + cacheReadInputTokens: 758000, + cacheCreationInputTokens: 200000, + }, + 200000, + 'claude-code', + 150 + ); + expect(result.tokens).toBe(200000); + expect(result.percentage).toBe(100); + }); + it('should use Codex semantics (includes output tokens)', () => { const result = calculateContextDisplay( { inputTokens: 50000, outputTokens: 30000, cacheCreationInputTokens: 20000 }, diff --git a/src/renderer/utils/contextUsage.ts b/src/renderer/utils/contextUsage.ts index 6c99afa4f1..ce6a47c2b0 100644 --- a/src/renderer/utils/contextUsage.ts +++ b/src/renderer/utils/contextUsage.ts @@ -168,9 +168,14 @@ export function calculateContextDisplay( let tokens = raw; if (raw > contextWindow) { - if (fallbackPercentage != null && fallbackPercentage >= 0) { + if ( + fallbackPercentage != null && + Number.isFinite(fallbackPercentage) && + fallbackPercentage >= 0 + ) { // Accumulated multi-tool turn: derive tokens from preserved percentage - tokens = Math.round((fallbackPercentage / 100) * contextWindow); + const boundedFallback = Math.min(100, fallbackPercentage); + tokens = Math.round((boundedFallback / 100) * contextWindow); } else { // We don't have a trustworthy fallback percentage yet, so clamp to the // configured window instead of displaying an impossible token total. From 630fa0e29b15f30a123efac08bfc46d1b121cc35 Mon Sep 17 00:00:00 2001 From: Jeff Scott Ward Date: Thu, 9 Apr 2026 20:32:53 -0400 Subject: [PATCH 18/23] fix: serve built web assets for remote control --- .../main/web-server/WebServer.test.ts | 38 +++++++++++++++++++ src/main/web-server/WebServer.ts | 29 ++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/__tests__/main/web-server/WebServer.test.ts diff --git a/src/__tests__/main/web-server/WebServer.test.ts b/src/__tests__/main/web-server/WebServer.test.ts new file mode 100644 index 0000000000..4c14bf7f63 --- /dev/null +++ b/src/__tests__/main/web-server/WebServer.test.ts @@ -0,0 +1,38 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'fs'; +import os from 'os'; +import path from 'path'; +import { WebServer } from '../../../main/web-server/WebServer'; + +describe('WebServer web asset resolution', () => { + let tempRoot: string; + + beforeEach(() => { + tempRoot = mkdtempSync(path.join(os.tmpdir(), 'maestro-web-assets-')); + vi.spyOn(process, 'cwd').mockReturnValue(tempRoot); + }); + + afterEach(() => { + vi.restoreAllMocks(); + rmSync(tempRoot, { recursive: true, force: true }); + }); + + it('prefers built dist/web assets over the source web index', () => { + const distWebDir = path.join(tempRoot, 'dist', 'web'); + mkdirSync(distWebDir, { recursive: true }); + writeFileSync( + path.join(distWebDir, 'index.html'), + '' + ); + + const server = new WebServer(0); + + expect((server as any).webAssetsPath).toBe(distWebDir); + }); + + it('rejects source web assets that still reference /main.tsx when no built bundle exists', () => { + const server = new WebServer(0); + + expect((server as any).webAssetsPath).toBeNull(); + }); +}); diff --git a/src/main/web-server/WebServer.ts b/src/main/web-server/WebServer.ts index ed171bb517..0aa3a0a441 100644 --- a/src/main/web-server/WebServer.ts +++ b/src/main/web-server/WebServer.ts @@ -28,7 +28,7 @@ import fastifyStatic from '@fastify/static'; import { FastifyInstance, FastifyRequest } from 'fastify'; import { randomUUID } from 'crypto'; import path from 'path'; -import { existsSync } from 'fs'; +import { existsSync, readFileSync } from 'fs'; import { getLocalIpAddressSync } from '../utils/networkUtils'; import { logger } from '../utils/logger'; import { WebSocketMessageHandler } from './handlers'; @@ -165,16 +165,16 @@ export class WebServer { private resolveWebAssetsPath(): string | null { // Try multiple locations for the web assets const possiblePaths = [ - // Production: relative to the compiled main process - path.join(__dirname, '..', '..', 'web'), // Development: from project root path.join(process.cwd(), 'dist', 'web'), + // Production: relative to the compiled main process + path.join(__dirname, '..', '..', 'web'), // Alternative: relative to __dirname going up to dist path.join(__dirname, '..', 'web'), ]; for (const p of possiblePaths) { - if (existsSync(path.join(p, 'index.html'))) { + if (this.isServableWebAssetsPath(p)) { logger.debug(`Web assets found at: ${p}`, LOG_CONTEXT); return p; } @@ -187,6 +187,27 @@ export class WebServer { return null; } + /** + * Only serve built web assets. Source `src/web/index.html` references `/main.tsx`, + * which the embedded Fastify server cannot compile or serve. + */ + private isServableWebAssetsPath(candidatePath: string): boolean { + const indexPath = path.join(candidatePath, 'index.html'); + if (!existsSync(indexPath)) { + return false; + } + + try { + const html = readFileSync(indexPath, 'utf-8'); + const referencesDevEntrypoint = + html.includes('src="/main.tsx"') || html.includes("src='/main.tsx'"); + return !referencesDevEntrypoint; + } catch (error) { + logger.warn(`Failed to inspect web assets at ${candidatePath}: ${error}`, LOG_CONTEXT); + return false; + } + } + // ============ Live Session Management (Delegated to LiveSessionManager) ============ /** From 798c01e6b6445bf393995cb72c1ba8399ab01505 Mon Sep 17 00:00:00 2001 From: Jeff Scott Ward Date: Thu, 9 Apr 2026 20:52:16 -0400 Subject: [PATCH 19/23] fix: report unexpected web asset inspection failures --- .../main/web-server/WebServer.test.ts | 22 +++++++++++++++++++ src/main/web-server/WebServer.ts | 16 ++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/__tests__/main/web-server/WebServer.test.ts b/src/__tests__/main/web-server/WebServer.test.ts index 4c14bf7f63..daab2d2ec2 100644 --- a/src/__tests__/main/web-server/WebServer.test.ts +++ b/src/__tests__/main/web-server/WebServer.test.ts @@ -2,8 +2,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'fs'; import os from 'os'; import path from 'path'; +import { captureException } from '../../../main/utils/sentry'; import { WebServer } from '../../../main/web-server/WebServer'; +vi.mock('../../../main/utils/sentry', () => ({ + captureException: vi.fn(), +})); + describe('WebServer web asset resolution', () => { let tempRoot: string; @@ -14,6 +19,7 @@ describe('WebServer web asset resolution', () => { afterEach(() => { vi.restoreAllMocks(); + vi.clearAllMocks(); rmSync(tempRoot, { recursive: true, force: true }); }); @@ -35,4 +41,20 @@ describe('WebServer web asset resolution', () => { expect((server as any).webAssetsPath).toBeNull(); }); + + it('reports and rethrows unexpected asset inspection failures', () => { + const distWebDir = path.join(tempRoot, 'dist', 'web'); + const indexPath = path.join(distWebDir, 'index.html'); + mkdirSync(indexPath, { recursive: true }); + + expect(() => new WebServer(0)).toThrow(); + + const [[capturedError, captureContext]] = vi.mocked(captureException).mock.calls; + expect((capturedError as NodeJS.ErrnoException).code).toBe('EISDIR'); + expect(captureContext).toEqual({ + operation: 'webServer:isServableWebAssetsPath', + candidatePath: distWebDir, + indexPath, + }); + }); }); diff --git a/src/main/web-server/WebServer.ts b/src/main/web-server/WebServer.ts index 0aa3a0a441..24f1e924b2 100644 --- a/src/main/web-server/WebServer.ts +++ b/src/main/web-server/WebServer.ts @@ -31,6 +31,7 @@ import path from 'path'; import { existsSync, readFileSync } from 'fs'; import { getLocalIpAddressSync } from '../utils/networkUtils'; import { logger } from '../utils/logger'; +import { captureException } from '../utils/sentry'; import { WebSocketMessageHandler } from './handlers'; import { BroadcastService } from './services'; import { ApiRoutes, StaticRoutes, WsRoute } from './routes'; @@ -203,8 +204,19 @@ export class WebServer { html.includes('src="/main.tsx"') || html.includes("src='/main.tsx'"); return !referencesDevEntrypoint; } catch (error) { - logger.warn(`Failed to inspect web assets at ${candidatePath}: ${error}`, LOG_CONTEXT); - return false; + const err = error as NodeJS.ErrnoException; + if (err.code === 'ENOENT') { + logger.warn(`Web assets disappeared while inspecting ${candidatePath}`, LOG_CONTEXT); + return false; + } + + logger.error(`Failed to inspect web assets at ${candidatePath}`, LOG_CONTEXT, error); + captureException(error, { + operation: 'webServer:isServableWebAssetsPath', + candidatePath, + indexPath, + }); + throw error; } } From b2872446281072b66a13306679091a101a39178f Mon Sep 17 00:00:00 2001 From: Jonathan Sydorowicz Date: Sat, 11 Apr 2026 18:18:50 -0500 Subject: [PATCH 20/23] fix(ui): restore z-20 on main panel header to prevent popover clipping Commit 4d01c32ec ("fix: remove main header z-index") removed z-20 from the main panel header container, which caused absolute-positioned popovers inside the header (notably the Context Details dropdown) to render behind the main content area instead of above it. The Context Details popover uses `absolute top-full right-0 ... z-50` to drop below the CONTEXT button. Its local z-50 only ranks it within the header's stacking context. With z-20 gone, the header no longer establishes a stacking context elevated above the sibling main content area, so when the popover extends below the header's 64px height it is covered by the chat/AI log view. Symptom: clicking CONTEXT shows only the top strip of 'Context Details' at the bottom edge of the header; the rest of the popover is hidden behind the chat area. Restoring z-20 re-establishes the stacking context and lets the popover escape downward cleanly. No other elements depended on the header being z-auto, and this matches the state that shipped before April 9, 2026. --- src/renderer/components/MainPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/components/MainPanel.tsx b/src/renderer/components/MainPanel.tsx index a54e73ba81..b9595b2a18 100644 --- a/src/renderer/components/MainPanel.tsx +++ b/src/renderer/components/MainPanel.tsx @@ -855,7 +855,7 @@ export const MainPanel = React.memo( {!isMobileLandscape && (
Date: Mon, 13 Apr 2026 06:08:24 +0000 Subject: [PATCH 21/23] docs: sync release notes for v0.16.9-RC --- docs/releases.md | 494 +++++++++++++++++++++++------------------------ 1 file changed, 240 insertions(+), 254 deletions(-) diff --git a/docs/releases.md b/docs/releases.md index 36a1f457e7..3b467bc158 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -17,32 +17,32 @@ Maestro can update itself automatically! This feature was introduced in **v0.8.7 **Latest: v0.15.3** | Released April 5, 2026 -# Major 0.15.x Additions - -🎶 **Maestro Symphony** — Contribute to open source with AI assistance! Browse curated issues from projects with the `runmaestro.ai` label, clone repos with one click, and automatically process the relevant Auto Run playbooks. Track your contributions, streaks, and stats. You're contributing CPU and tokens towards your favorite open source projects and features. - -🎬 **Director's Notes** — Aggregates history across all agents into a unified timeline with search, filters, and an activity graph. Includes an AI Overview tab that generates a structured synopsis of recent work. Off by default, gated behind a new "Encore Features" panel under settings. This is a precursor to an eventual plugin system, allowing for extensions and customizations without bloating the core app. - -🏷️ **Conductor Profile** — Available under Settings > General. Provide a short description on how Maestro agents should interface with you. - -🧠 **Three-State Thinking Toggle** — The thinking toggle now cycles through three modes: off, on, and sticky. Sticky mode keeps thinking content visible after the response completes. Cycle with CMD/CTRL+SHIFT+K. - -🤖 **Factory.ai Droid Support** — Added support for the [Factory.ai](https://factory.ai/product/cli) droid agent. Full session management and output parsing integration. - -## Changes in v0.15.3 - -- **CLI settings management:** Full `maestro-cli settings` command suite — list, get, set, and reset any Maestro setting from the command line. Includes per-agent configuration (custom paths, args, env vars, model overrides). Supports category filtering, verbose descriptions, and machine-readable JSON output for scripting -- **Live settings reload:** Settings changes made via the CLI are automatically detected by the running desktop app — no restart required -- **Plan-Mode toggle:** Claude Code and OpenCode agents now show "Plan-Mode" instead of "Read-Only" for the read-only toggle, matching their native terminology -- **Solarized Dark theme:** New Solarized Dark color theme with tuned contrast for tags, code blocks, and pill labels -- **Files pane icon theme:** Choose between default and rich icon themes in the files pane — rich theme adds colorful, language-specific icons for 70+ file types and folder categories. Toggle under Settings > Display -- **Persistent web link:** The web/mobile interface link now persists across app restarts — no need to re-enable it each session -- **OpenCode v1.2+ session support:** Automatically reads OpenCode's new SQLite session storage format alongside the legacy JSONL format -- **Group chat @mentions:** Use `@agent-name` syntax in the prompt composer to direct messages to specific agents in group chat -- **Group chat over SSH:** Group chat synthesis and moderation now run correctly on SSH remote agents instead of always spawning locally -- **Group chat participant management:** Remove button on participant cards lets you remove stale or unwanted participants from a group chat -- **Batch resume/abort:** New controls in the right panel for resuming or aborting batch operations -- **Default worktree directory:** Worktree configuration now defaults to the parent of the agent's working directory instead of blank +# Major 0.15.x Additions + +🎶 **Maestro Symphony** — Contribute to open source with AI assistance! Browse curated issues from projects with the `runmaestro.ai` label, clone repos with one click, and automatically process the relevant Auto Run playbooks. Track your contributions, streaks, and stats. You're contributing CPU and tokens towards your favorite open source projects and features. + +🎬 **Director's Notes** — Aggregates history across all agents into a unified timeline with search, filters, and an activity graph. Includes an AI Overview tab that generates a structured synopsis of recent work. Off by default, gated behind a new "Encore Features" panel under settings. This is a precursor to an eventual plugin system, allowing for extensions and customizations without bloating the core app. + +🏷️ **Conductor Profile** — Available under Settings > General. Provide a short description on how Maestro agents should interface with you. + +🧠 **Three-State Thinking Toggle** — The thinking toggle now cycles through three modes: off, on, and sticky. Sticky mode keeps thinking content visible after the response completes. Cycle with CMD/CTRL+SHIFT+K. + +🤖 **Factory.ai Droid Support** — Added support for the [Factory.ai](https://factory.ai/product/cli) droid agent. Full session management and output parsing integration. + +## Changes in v0.15.3 + +- **CLI settings management:** Full `maestro-cli settings` command suite — list, get, set, and reset any Maestro setting from the command line. Includes per-agent configuration (custom paths, args, env vars, model overrides). Supports category filtering, verbose descriptions, and machine-readable JSON output for scripting +- **Live settings reload:** Settings changes made via the CLI are automatically detected by the running desktop app — no restart required +- **Plan-Mode toggle:** Claude Code and OpenCode agents now show "Plan-Mode" instead of "Read-Only" for the read-only toggle, matching their native terminology +- **Solarized Dark theme:** New Solarized Dark color theme with tuned contrast for tags, code blocks, and pill labels +- **Files pane icon theme:** Choose between default and rich icon themes in the files pane — rich theme adds colorful, language-specific icons for 70+ file types and folder categories. Toggle under Settings > Display +- **Persistent web link:** The web/mobile interface link now persists across app restarts — no need to re-enable it each session +- **OpenCode v1.2+ session support:** Automatically reads OpenCode's new SQLite session storage format alongside the legacy JSONL format +- **Group chat @mentions:** Use `@agent-name` syntax in the prompt composer to direct messages to specific agents in group chat +- **Group chat over SSH:** Group chat synthesis and moderation now run correctly on SSH remote agents instead of always spawning locally +- **Group chat participant management:** Remove button on participant cards lets you remove stale or unwanted participants from a group chat +- **Batch resume/abort:** New controls in the right panel for resuming or aborting batch operations +- **Default worktree directory:** Worktree configuration now defaults to the parent of the agent's working directory instead of blank - **Drawfinity in Symphony:** Added Drawfinity to the Symphony project registry ### Previous Releases in this Series @@ -56,41 +56,41 @@ Maestro can update itself automatically! This feature was introduced in **v0.8.7 **Latest: v0.14.5** | Released January 24, 2026 -Changes in this point release include: - -- Desktop app performance improvements (more to come on this, we want Maestro blazing fast) 🐌 -- Added local manifest feature for custom playbooks 📖 -- Agents are now inherently aware of your activity history as seen in the history panel 📜 (this is built-in cross context memory!) -- Added markdown rendering support for AI responses in mobile view 📱 -- Bugfix in tracking costs from JSONL files that were aged out 🏦 -- Added BlueSky social media handle for leaderboard 🦋 -- Added options to disable GPU rendering and confetti 🎊 -- Better handling of large files in preview 🗄️ -- Bug fix in Claude context calculation 🧮 -- Addressed bug in OpenSpec version reporting 🐛 - -The major contributions to 0.14.x remain: - -🗄️ Document Graphs. Launch from file preview or from the FIle tree panel. Explore relationships between Markdown documents that contain links between documents and to URLs. - -📶 SSH support for agents. Manage a remote agent with feature parity over SSH. Includes support for Git and File tree panels. Manage agents on remote systems or in containers. This even works for Group Chat, which is rad as hell. - -🧙‍♂️ Added an in-tab wizard for generating Auto Run Playbooks via `/wizard` or a new button in the Auto Run panel. - -# Smaller Changes in 014.x - -- Improved User Dashboard, available from hamburger menu, command palette or hotkey 🎛️ -- Leaderboard tracking now works across multiple systems and syncs level from cloud 🏆 -- Agent duplication. Pro tip: Consider a group of unused "Template" agents ✌️ -- New setting to prevent system from going to sleep while agents are active 🛏️ -- The tab menu has a new "Publish as GitHub Gist" option 📝 -- The tab menu has options to move the tab to the first or last position 🔀 -- [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) can now contain non-markdown assets 📙 -- Improved default shell detection 🐚 -- Added logic to prevent overlapping TTS notifications 💬 -- Added "Toggle Bookmark" shortcut (CTRL/CMD+SHIFT+B) ⌨️ -- Gist publishing now shows previous URLs with copy button 📋 - +Changes in this point release include: + +- Desktop app performance improvements (more to come on this, we want Maestro blazing fast) 🐌 +- Added local manifest feature for custom playbooks 📖 +- Agents are now inherently aware of your activity history as seen in the history panel 📜 (this is built-in cross context memory!) +- Added markdown rendering support for AI responses in mobile view 📱 +- Bugfix in tracking costs from JSONL files that were aged out 🏦 +- Added BlueSky social media handle for leaderboard 🦋 +- Added options to disable GPU rendering and confetti 🎊 +- Better handling of large files in preview 🗄️ +- Bug fix in Claude context calculation 🧮 +- Addressed bug in OpenSpec version reporting 🐛 + +The major contributions to 0.14.x remain: + +🗄️ Document Graphs. Launch from file preview or from the FIle tree panel. Explore relationships between Markdown documents that contain links between documents and to URLs. + +📶 SSH support for agents. Manage a remote agent with feature parity over SSH. Includes support for Git and File tree panels. Manage agents on remote systems or in containers. This even works for Group Chat, which is rad as hell. + +🧙‍♂️ Added an in-tab wizard for generating Auto Run Playbooks via `/wizard` or a new button in the Auto Run panel. + +# Smaller Changes in 014.x + +- Improved User Dashboard, available from hamburger menu, command palette or hotkey 🎛️ +- Leaderboard tracking now works across multiple systems and syncs level from cloud 🏆 +- Agent duplication. Pro tip: Consider a group of unused "Template" agents ✌️ +- New setting to prevent system from going to sleep while agents are active 🛏️ +- The tab menu has a new "Publish as GitHub Gist" option 📝 +- The tab menu has options to move the tab to the first or last position 🔀 +- [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) can now contain non-markdown assets 📙 +- Improved default shell detection 🐚 +- Added logic to prevent overlapping TTS notifications 💬 +- Added "Toggle Bookmark" shortcut (CTRL/CMD+SHIFT+B) ⌨️ +- Gist publishing now shows previous URLs with copy button 📋 + Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @deandebeer @shadown @breki @charles-dyfis-net @ronaldeddings @jlengrand @ksylvan ### Previous Releases in this Series @@ -109,22 +109,20 @@ Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @d ### Changes -- TAKE TWO! Fixed Linux ARM64 build architecture contamination issues 🏗️ - -### v0.13.1 Changes - -- Fixed Linux ARM64 build architecture contamination issues 🏗️ -- Enhanced error handling for Auto Run batch processing 🚨 - -### v0.13.0 Changes - -- Added a global usage dashboard, data collection begins with this install 🎛️ -- Added a Playbook Exchange for downloading pre-defined Auto Run playbooks from [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) 📕 -- Bundled OpenSpec commands for structured change proposals 📝 -- Added pre-release channel support for beta/RC updates 🧪 -- Implemented global hands-on time tracking across sessions ⏱️ -- Added new keyboard shortcut for agent settings (Opt+Cmd+, | Ctrl+Alt+,) ⌨️ -- Added directory size calculation with file/folder counts in file explorer 📊 +- TAKE TWO! Fixed Linux ARM64 build architecture contamination issues 🏗️ + +### v0.13.1 Changes +- Fixed Linux ARM64 build architecture contamination issues 🏗️ +- Enhanced error handling for Auto Run batch processing 🚨 + +### v0.13.0 Changes +- Added a global usage dashboard, data collection begins with this install 🎛️ +- Added a Playbook Exchange for downloading pre-defined Auto Run playbooks from [Maestro-Playbooks](https://github.com/pedramamini/Maestro-Playbooks) 📕 +- Bundled OpenSpec commands for structured change proposals 📝 +- Added pre-release channel support for beta/RC updates 🧪 +- Implemented global hands-on time tracking across sessions ⏱️ +- Added new keyboard shortcut for agent settings (Opt+Cmd+, | Ctrl+Alt+,) ⌨️ +- Added directory size calculation with file/folder counts in file explorer 📊 - Added sleep detection to exclude laptop sleep from time tracking ⏰ ### Previous Releases in this Series @@ -138,26 +136,22 @@ Thanks for the contributions: @t1mmen @aejfager @Crumbgrabber @whglaser @b3nw @d **Latest: v0.12.3** | Released December 28, 2025 -The big changes in the v0.12.x line are the following three: - -## Show Thinking - -🤔 There is now a toggle to show thinking for the agent, the default for new tabs is off, though this can be changed under Settings > General. The toggle shows next to History and Read-Only. Very similar pattern. This has been the #1 most requested feature, though personally, I don't think I'll use it as I prefer to not see the details of the work, but the results of the work. Just as we work with our colleagues. - -## GitHub Spec-Kit Integration - -🎯 Added [GitHub Spec-Kit](https://github.com/github/spec-kit) commands into Maestro with a built in updater to grab the latest prompts from the repository. We do override `/speckit-implement` (the final step) to create Auto Run docs and guide the user through their execution, which thanks to Wortrees from v0.11.x allows us to run in parallel! - -## Context Management Tools - -📖 Added context management options from tab right-click menu. You can now compress, merge, and transfer contexts between agents. You will received (configurable) warnings at 60% and 80% context consumption with a hint to compact. - -## Changes Specific to v0.12.3: - -- We now have hosted documentation through Mintlify 📚 -- Export any tab conversation as self-contained themed HTML file 📄 -- Publish files as private/public Gists 🌐 -- Added tab hover overlay menu with close operations and export 📋 +The big changes in the v0.12.x line are the following three: + +## Show Thinking +🤔 There is now a toggle to show thinking for the agent, the default for new tabs is off, though this can be changed under Settings > General. The toggle shows next to History and Read-Only. Very similar pattern. This has been the #1 most requested feature, though personally, I don't think I'll use it as I prefer to not see the details of the work, but the results of the work. Just as we work with our colleagues. + +## GitHub Spec-Kit Integration +🎯 Added [GitHub Spec-Kit](https://github.com/github/spec-kit) commands into Maestro with a built in updater to grab the latest prompts from the repository. We do override `/speckit-implement` (the final step) to create Auto Run docs and guide the user through their execution, which thanks to Wortrees from v0.11.x allows us to run in parallel! + +## Context Management Tools +📖 Added context management options from tab right-click menu. You can now compress, merge, and transfer contexts between agents. You will received (configurable) warnings at 60% and 80% context consumption with a hint to compact. + +## Changes Specific to v0.12.3: +- We now have hosted documentation through Mintlify 📚 +- Export any tab conversation as self-contained themed HTML file 📄 +- Publish files as private/public Gists 🌐 +- Added tab hover overlay menu with close operations and export 📋 - Added social handles to achievement share images 🏆 ### Previous Releases in this Series @@ -171,12 +165,12 @@ The big changes in the v0.12.x line are the following three: **Latest: v0.11.0** | Released December 22, 2025 -🌳 Github Worktree support was added. Any agent bound to a Git repository has the option to enable worktrees, each of which show up as a sub-agent with their own write-lock and Auto Run capability. Now you can truly develop in parallel on the same project and issue PRs when you're ready, all from within Maestro. Huge improvement, major thanks to @petersilberman. - -# Other Changes - -- @ file mentions now include documents from your Auto Run folder (which may not live in your agent working directory) 🗄️ -- The wizard is now capable of detecting and continuing on past started projects 🧙 +🌳 Github Worktree support was added. Any agent bound to a Git repository has the option to enable worktrees, each of which show up as a sub-agent with their own write-lock and Auto Run capability. Now you can truly develop in parallel on the same project and issue PRs when you're ready, all from within Maestro. Huge improvement, major thanks to @petersilberman. + +# Other Changes + +- @ file mentions now include documents from your Auto Run folder (which may not live in your agent working directory) 🗄️ +- The wizard is now capable of detecting and continuing on past started projects 🧙 - Bug fixes 🐛🐜🐞 --- @@ -187,14 +181,14 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Export group chats as self-contained HTML ⬇️ -- Enhanced system process viewer now has details view with full process args 💻 -- Update button hides until platform binaries are available in releases. ⏳ -- Added Auto Run stall detection at the loop level, if no documents are updated after a loop 🔁 -- Improved Codex session discovery 🔍 -- Windows compatibility fixes 🐛 -- 64-bit Linux ARM build issue fixed (thanks @LilYoopug) 🐜 -- Addressed session enumeration issues with Codex and OpenCode 🐞 +- Export group chats as self-contained HTML ⬇️ +- Enhanced system process viewer now has details view with full process args 💻 +- Update button hides until platform binaries are available in releases. ⏳ +- Added Auto Run stall detection at the loop level, if no documents are updated after a loop 🔁 +- Improved Codex session discovery 🔍 +- Windows compatibility fixes 🐛 +- 64-bit Linux ARM build issue fixed (thanks @LilYoopug) 🐜 +- Addressed session enumeration issues with Codex and OpenCode 🐞 - Addressed pathing issues around gh command (thanks @oliveiraantoniocc) 🐝 ### Previous Releases in this Series @@ -210,13 +204,13 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Add Sentry crashing reporting monitoring with opt-out 🐛 -- Stability fixes on v0.9.0 along with all the changes it brought along, including... - - Major refactor to enable supporting of multiple providers 👨‍👩‍👧‍👦 - - Added OpenAI Codex support 👨‍💻 - - Added OpenCode support 👩‍💻 - - Error handling system detects and recovers from agent failures 🚨 - - Added option to specify CLI arguments to AI providers ✨ +- Add Sentry crashing reporting monitoring with opt-out 🐛 +- Stability fixes on v0.9.0 along with all the changes it brought along, including... + - Major refactor to enable supporting of multiple providers 👨‍👩‍👧‍👦 + - Added OpenAI Codex support 👨‍💻 + - Added OpenCode support 👩‍💻 + - Error handling system detects and recovers from agent failures 🚨 + - Added option to specify CLI arguments to AI providers ✨ - Bunch of other little tweaks and additions 💎 ### Previous Releases in this Series @@ -231,19 +225,19 @@ The big changes in the v0.12.x line are the following three: ### Changes -- Added "Nudge" messages. Short static copy to include with every interactive message sent, perhaps to remind the agent on how to work 📌 -- Addressed various resource consumption issues to reduce battery cost 📉 -- Implemented fuzzy file search in quick actions for instant navigation 🔍 -- Added "clear" command support to clean terminal shell logs 🧹 -- Simplified search highlighting by integrating into markdown pipeline ✨ -- Enhanced update checker to filter prerelease tags like -rc, -beta 🚀 -- Fixed RPM package compatibility for OpenSUSE Tumbleweed 🐧 (H/T @JOduMonT) -- Added libuuid1 support alongside standard libuuid dependency 📦 -- Introduced Cmd+Shift+U shortcut for tab unread toggle ⌨️ -- Enhanced keyboard navigation for marking tabs unread 🎯 -- Expanded Linux distribution support with smart dependencies 🌐 -- Major underlying code re-structuring for maintainability 🧹 -- Improved stall detection to allow for individual docs to stall out while not affecting the entire playbook 📖 (H/T @mattjay) +- Added "Nudge" messages. Short static copy to include with every interactive message sent, perhaps to remind the agent on how to work 📌 +- Addressed various resource consumption issues to reduce battery cost 📉 +- Implemented fuzzy file search in quick actions for instant navigation 🔍 +- Added "clear" command support to clean terminal shell logs 🧹 +- Simplified search highlighting by integrating into markdown pipeline ✨ +- Enhanced update checker to filter prerelease tags like -rc, -beta 🚀 +- Fixed RPM package compatibility for OpenSUSE Tumbleweed 🐧 (H/T @JOduMonT) +- Added libuuid1 support alongside standard libuuid dependency 📦 +- Introduced Cmd+Shift+U shortcut for tab unread toggle ⌨️ +- Enhanced keyboard navigation for marking tabs unread 🎯 +- Expanded Linux distribution support with smart dependencies 🌐 +- Major underlying code re-structuring for maintainability 🧹 +- Improved stall detection to allow for individual docs to stall out while not affecting the entire playbook 📖 (H/T @mattjay) - Added option to select a static listening port for remote control 🎮 (H/T @b3nw) ### Previous Releases in this Series @@ -263,40 +257,35 @@ The big changes in the v0.12.x line are the following three: **Latest: v0.7.4** | Released December 12, 2025 -Minor bugfixes on top of v0.7.3: - -# Onboarding, Wizard, and Tours - -- Implemented comprehensive onboarding wizard with integrated tour system 🚀 -- Added project-understanding confidence display to wizard UI 🎨 -- Enhanced keyboard navigation across all wizard screens ⌨️ -- Added analytics tracking for wizard and tour completion 📈 -- Added First Run Celebration modal with confetti animation 🎉 - -# UI / UX Enhancements - -- Added expand-to-fullscreen button for Auto Run interface 🖥️ -- Created dedicated modal component and improved modal priority constants for expanded Auto Run view 📐 -- Enhanced user experience with fullscreen editing capabilities ✨ -- Fixed tab name display to correctly show full name for active tabs 🏷️ -- Added performance optimizations with throttling and caching for scrolling ⚡ -- Implemented drag-and-drop reordering for execution queue items 🎯 -- Enhanced toast context with agent name for OS notifications 📢 - -# Auto Run Workflow Improvements - -- Created phase document generation for Auto Run workflow 📄 -- Added real-time log streaming to the LogViewer component 📊 - -# Application Behavior / Core Fixes - -- Added validation to prevent nested worktrees inside the main repository 🚫 -- Fixed process manager to properly emit exit events on errors 🔧 -- Fixed process exit handling to ensure proper cleanup 🧹 - -# Update System - -- Implemented automatic update checking on application startup 🚀 +Minor bugfixes on top of v0.7.3: + +# Onboarding, Wizard, and Tours +- Implemented comprehensive onboarding wizard with integrated tour system 🚀 +- Added project-understanding confidence display to wizard UI 🎨 +- Enhanced keyboard navigation across all wizard screens ⌨️ +- Added analytics tracking for wizard and tour completion 📈 +- Added First Run Celebration modal with confetti animation 🎉 + +# UI / UX Enhancements +- Added expand-to-fullscreen button for Auto Run interface 🖥️ +- Created dedicated modal component and improved modal priority constants for expanded Auto Run view 📐 +- Enhanced user experience with fullscreen editing capabilities ✨ +- Fixed tab name display to correctly show full name for active tabs 🏷️ +- Added performance optimizations with throttling and caching for scrolling ⚡ +- Implemented drag-and-drop reordering for execution queue items 🎯 +- Enhanced toast context with agent name for OS notifications 📢 + +# Auto Run Workflow Improvements +- Created phase document generation for Auto Run workflow 📄 +- Added real-time log streaming to the LogViewer component 📊 + +# Application Behavior / Core Fixes +- Added validation to prevent nested worktrees inside the main repository 🚫 +- Fixed process manager to properly emit exit events on errors 🔧 +- Fixed process exit handling to ensure proper cleanup 🧹 + +# Update System +- Implemented automatic update checking on application startup 🚀 - Added settings toggle for enabling/disabling startup update checks ⚙️ ### Previous Releases in this Series @@ -312,40 +301,38 @@ Minor bugfixes on top of v0.7.3: **Latest: v0.6.1** | Released December 4, 2025 -In this release... - -- Added recursive subfolder support for Auto Run markdown files 🗂️ -- Enhanced document tree display with expandable folder navigation 🌳 -- Enabled creating documents in subfolders with path selection 📁 -- Improved batch runner UI with inline progress bars and loop indicators 📊 -- Fixed execution queue display bug for immediate command processing 🐛 -- Added folder icons and better visual hierarchy for document browser 🎨 -- Implemented dynamic task re-counting for batch run loop iterations 🔄 -- Enhanced create document modal with location selector dropdown 📍 -- Improved progress tracking with per-document completion visualization 📈 -- Added support for nested folder structures in document management 🏗️ - -Plus the pre-release ALPHA... - -- Template vars now set context in default autorun prompt 🚀 -- Added Enter key support for queued message confirmation dialog ⌨️ -- Kill process capability added to System Process Monitor 💀 -- Toggle markdown rendering added to Cmd+K Quick Actions 📝 -- Fixed cloudflared detection in packaged app environments 🔧 -- Added debugging logs for process exit diagnostics 🐛 -- Tab switcher shows last activity timestamps and filters by project 🕐 -- Slash commands now fill text on Tab/Enter instead of executing ⚡ -- Added GitHub Actions workflow for auto-assigning issues/PRs 🤖 -- Graceful handling for playbooks with missing documents implemented ✨ -- Added multi-document batch processing for Auto Run 🚀 -- Introduced Git worktree support for parallel execution 🌳 -- Created playbook system for saving run configurations 📚 -- Implemented document reset-on-completion with loop mode 🔄 -- Added drag-and-drop document reordering interface 🎯 -- Built Auto Run folder selector with file management 📁 -- Enhanced progress tracking with per-document metrics 📊 -- Integrated PR creation after worktree completion 🔀 -- Added undo/redo support in document editor ↩️ +In this release... +- Added recursive subfolder support for Auto Run markdown files 🗂️ +- Enhanced document tree display with expandable folder navigation 🌳 +- Enabled creating documents in subfolders with path selection 📁 +- Improved batch runner UI with inline progress bars and loop indicators 📊 +- Fixed execution queue display bug for immediate command processing 🐛 +- Added folder icons and better visual hierarchy for document browser 🎨 +- Implemented dynamic task re-counting for batch run loop iterations 🔄 +- Enhanced create document modal with location selector dropdown 📍 +- Improved progress tracking with per-document completion visualization 📈 +- Added support for nested folder structures in document management 🏗️ + +Plus the pre-release ALPHA... +- Template vars now set context in default autorun prompt 🚀 +- Added Enter key support for queued message confirmation dialog ⌨️ +- Kill process capability added to System Process Monitor 💀 +- Toggle markdown rendering added to Cmd+K Quick Actions 📝 +- Fixed cloudflared detection in packaged app environments 🔧 +- Added debugging logs for process exit diagnostics 🐛 +- Tab switcher shows last activity timestamps and filters by project 🕐 +- Slash commands now fill text on Tab/Enter instead of executing ⚡ +- Added GitHub Actions workflow for auto-assigning issues/PRs 🤖 +- Graceful handling for playbooks with missing documents implemented ✨ +- Added multi-document batch processing for Auto Run 🚀 +- Introduced Git worktree support for parallel execution 🌳 +- Created playbook system for saving run configurations 📚 +- Implemented document reset-on-completion with loop mode 🔄 +- Added drag-and-drop document reordering interface 🎯 +- Built Auto Run folder selector with file management 📁 +- Enhanced progress tracking with per-document metrics 📊 +- Integrated PR creation after worktree completion 🔀 +- Added undo/redo support in document editor ↩️ - Implemented auto-save with 5-second debounce 💾 ### Previous Releases in this Series @@ -360,15 +347,15 @@ Plus the pre-release ALPHA... ### Changes -- Added "Made with Maestro" badge to README header 🎯 -- Redesigned app icon with darker purple color scheme 🎨 -- Created new SVG badge for project attribution 🏷️ -- Added side-by-side image diff viewer for git changes 🖼️ -- Enhanced confetti animation with realistic cannon-style bursts 🎊 -- Fixed z-index layering for standing ovation overlay 📊 -- Improved tab switcher to show all named sessions 🔍 -- Enhanced batch synopsis prompts for cleaner summaries 📝 -- Added binary file detection in git diff parser 🔧 +- Added "Made with Maestro" badge to README header 🎯 +- Redesigned app icon with darker purple color scheme 🎨 +- Created new SVG badge for project attribution 🏷️ +- Added side-by-side image diff viewer for git changes 🖼️ +- Enhanced confetti animation with realistic cannon-style bursts 🎊 +- Fixed z-index layering for standing ovation overlay 📊 +- Improved tab switcher to show all named sessions 🔍 +- Enhanced batch synopsis prompts for cleaner summaries 📝 +- Added binary file detection in git diff parser 🔧 - Implemented git file reading at specific refs 📁 ### Previous Releases in this Series @@ -383,24 +370,24 @@ Plus the pre-release ALPHA... ### Changes -- Added Tab Switcher modal for quick navigation between AI tabs 🚀 -- Implemented @ mention file completion for AI mode references 📁 -- Added navigation history with back/forward through sessions and tabs ⏮️ -- Introduced tab completion filters for branches, tags, and files 🌳 -- Added unread tab indicators and filtering for better organization 📬 -- Implemented token counting display with human-readable formatting 🔢 -- Added markdown rendering toggle for AI responses in terminal 📝 -- Removed built-in slash commands in favor of custom AI commands 🎯 -- Added context menu for sessions with rename, bookmark, move options 🖱️ -- Enhanced file preview with stats showing size, tokens, timestamps 📊 -- Added token counting with js-tiktoken for file preview stats bar 🔢 -- Implemented Tab Switcher modal for fuzzy-search navigation (Opt+Cmd+T) 🔍 -- Added Save to History toggle (Cmd+S) for automatic work synopsis tracking 💾 -- Enhanced tab completion with @ mentions for file references in AI prompts 📎 -- Implemented navigation history with back/forward shortcuts (Cmd+Shift+,/.) 🔙 -- Added git branches and tags to intelligent tab completion system 🌿 -- Enhanced markdown rendering with syntax highlighting and toggle view 📝 -- Added right-click context menus for session management and organization 🖱️ +- Added Tab Switcher modal for quick navigation between AI tabs 🚀 +- Implemented @ mention file completion for AI mode references 📁 +- Added navigation history with back/forward through sessions and tabs ⏮️ +- Introduced tab completion filters for branches, tags, and files 🌳 +- Added unread tab indicators and filtering for better organization 📬 +- Implemented token counting display with human-readable formatting 🔢 +- Added markdown rendering toggle for AI responses in terminal 📝 +- Removed built-in slash commands in favor of custom AI commands 🎯 +- Added context menu for sessions with rename, bookmark, move options 🖱️ +- Enhanced file preview with stats showing size, tokens, timestamps 📊 +- Added token counting with js-tiktoken for file preview stats bar 🔢 +- Implemented Tab Switcher modal for fuzzy-search navigation (Opt+Cmd+T) 🔍 +- Added Save to History toggle (Cmd+S) for automatic work synopsis tracking 💾 +- Enhanced tab completion with @ mentions for file references in AI prompts 📎 +- Implemented navigation history with back/forward shortcuts (Cmd+Shift+,/.) 🔙 +- Added git branches and tags to intelligent tab completion system 🌿 +- Enhanced markdown rendering with syntax highlighting and toggle view 📝 +- Added right-click context menus for session management and organization 🖱️ - Improved mobile app with better WebSocket reconnection and status badges 📱 ### Previous Releases in this Series @@ -415,15 +402,15 @@ Plus the pre-release ALPHA... ### Changes -- Fixed tab handling requiring explicitly selected Claude session 🔧 -- Added auto-scroll navigation for slash command list selection ⚡ -- Implemented TTS audio feedback for toast notifications speak 🔊 -- Fixed shortcut case sensitivity using lowercase key matching 🔤 -- Added Cmd+Shift+J shortcut to jump to bottom instantly ⬇️ -- Sorted shortcuts alphabetically in help modal for discovery 📑 -- Display full commit message body in git log view 📝 -- Added expand/collapse all buttons to process tree header 🌳 -- Support synopsis process type in process tree parsing 🔍 +- Fixed tab handling requiring explicitly selected Claude session 🔧 +- Added auto-scroll navigation for slash command list selection ⚡ +- Implemented TTS audio feedback for toast notifications speak 🔊 +- Fixed shortcut case sensitivity using lowercase key matching 🔤 +- Added Cmd+Shift+J shortcut to jump to bottom instantly ⬇️ +- Sorted shortcuts alphabetically in help modal for discovery 📑 +- Display full commit message body in git log view 📝 +- Added expand/collapse all buttons to process tree header 🌳 +- Support synopsis process type in process tree parsing 🔍 - Renamed "No Group" to "UNGROUPED" for better clarity ✨ ### Previous Releases in this Series @@ -436,15 +423,15 @@ Plus the pre-release ALPHA... **Latest: v0.2.3** | Released November 29, 2025 -• Enhanced mobile web interface with session sync and history panel 📱 -• Added ThinkingStatusPill showing real-time token counts and elapsed time ⏱️ -• Implemented task count badges and session deduplication for batch runner 📊 -• Added TTS stop control and improved voice synthesis compatibility 🔊 -• Created image lightbox with navigation, clipboard, and delete features 🖼️ -• Fixed UI bugs in search, auto-scroll, and sidebar interactions 🐛 -• Added global Claude stats with streaming updates across projects 📈 -• Improved markdown checkbox styling and collapsed palette hover UX ✨ -• Enhanced scratchpad with search, image paste, and attachment support 🔍 +• Enhanced mobile web interface with session sync and history panel 📱 +• Added ThinkingStatusPill showing real-time token counts and elapsed time ⏱️ +• Implemented task count badges and session deduplication for batch runner 📊 +• Added TTS stop control and improved voice synthesis compatibility 🔊 +• Created image lightbox with navigation, clipboard, and delete features 🖼️ +• Fixed UI bugs in search, auto-scroll, and sidebar interactions 🐛 +• Added global Claude stats with streaming updates across projects 📈 +• Improved markdown checkbox styling and collapsed palette hover UX ✨ +• Enhanced scratchpad with search, image paste, and attachment support 🔍 • Added splash screen with logo and progress bar during startup 🎨 ### Previous Releases in this Series @@ -459,15 +446,15 @@ Plus the pre-release ALPHA... **Latest: v0.1.6** | Released November 27, 2025 -• Added template variables for dynamic AI command customization 🎯 -• Implemented session bookmarking with star icons and dedicated section ⭐ -• Enhanced Git Log Viewer with smarter date formatting 📅 -• Improved GitHub release workflow to handle partial failures gracefully 🔧 -• Added collapsible template documentation in AI Commands panel 📚 -• Updated default commit command with session ID traceability 🔍 -• Added tag indicators for custom-named sessions visually 🏷️ -• Improved Git Log search UX with better focus handling 🎨 -• Fixed input placeholder spacing for better readability 📝 +• Added template variables for dynamic AI command customization 🎯 +• Implemented session bookmarking with star icons and dedicated section ⭐ +• Enhanced Git Log Viewer with smarter date formatting 📅 +• Improved GitHub release workflow to handle partial failures gracefully 🔧 +• Added collapsible template documentation in AI Commands panel 📚 +• Updated default commit command with session ID traceability 🔍 +• Added tag indicators for custom-named sessions visually 🏷️ +• Improved Git Log search UX with better focus handling 🎨 +• Fixed input placeholder spacing for better readability 📝 • Updated documentation with new features and template references 📖 ### Previous Releases in this Series @@ -486,7 +473,6 @@ Plus the pre-release ALPHA... All releases are available on the [GitHub Releases page](https://github.com/RunMaestro/Maestro/releases). Maestro is available for: - - **macOS** - Apple Silicon (arm64) and Intel (x64) - **Windows** - x64 - **Linux** - x64 and arm64, AppImage, deb, and rpm packages From 678e251db5bef74452983100baaf073e601f2eee Mon Sep 17 00:00:00 2001 From: ProaFilippi Date: Fri, 17 Apr 2026 07:31:36 -0500 Subject: [PATCH 22/23] perf: exclude venv/node_modules from autorun scan, stabilize SessionList handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - autorun: add SCAN_EXCLUDED_DIRS (venv, node_modules, dist, build, etc.) to scanDirectory/scanDirectoryRemote/checkForMarkdownFiles — prevents scanning thousands of irrelevant .md files on startup - SessionList: derive sessionIdsKey from IDs only so handler Maps don't regenerate on every session state change (name/status/log updates), preventing unnecessary SessionItem re-renders - SettingsSearch: move inline regex literals to module level to avoid recompiling on every search keystroke - AgentErrorModal: guard auto-retry against double-invocation with retryInvoked state; handle expired rateLimitResetAt gracefully - agentStore: support image-only retry, report errors to Sentry on retry failure, re-surface error modal if retry dispatch fails - package.json: bump version to 0.16.9-RC Co-Authored-By: Claude Sonnet 4.6 --- package.json | 2 +- src/main/ipc/handlers/autorun.ts | 31 +++++- src/renderer/components/AgentErrorModal.tsx | 97 ++++++++++++------- .../components/SessionList/SessionList.tsx | 18 ++-- .../components/Settings/SettingsSearch.tsx | 7 +- src/renderer/stores/agentStore.ts | 48 ++++++++- 6 files changed, 150 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index ddcdb24bae..285039ca9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "maestro", - "version": "0.16.8-RC", + "version": "0.16.9-RC", "description": "Maestro hones fractured attention into focused intent.", "main": "dist/main/index.js", "author": { diff --git a/src/main/ipc/handlers/autorun.ts b/src/main/ipc/handlers/autorun.ts index 6fb68c1603..538e5fe1de 100644 --- a/src/main/ipc/handlers/autorun.ts +++ b/src/main/ipc/handlers/autorun.ts @@ -73,6 +73,29 @@ interface TreeNode { children?: TreeNode[]; } +/** + * Directories that are never relevant as Auto Run doc sources. + * Prevents scanning virtualenvs, package trees, and build artifacts. + */ +const SCAN_EXCLUDED_DIRS = new Set([ + 'node_modules', + 'venv', + '.venv', + 'env', + '.env', + '__pycache__', + '.git', + 'dist', + 'build', + '.next', + '.nuxt', + 'coverage', + '.cache', + 'target', + '.tox', + 'site-packages', +]); + /** * Recursively scan directory for markdown files */ @@ -82,7 +105,7 @@ async function scanDirectory(dirPath: string, relativePath: string = ''): Promis // Sort entries: folders first, then files, both alphabetically const sortedEntries = entries - .filter((entry) => !entry.name.startsWith('.')) + .filter((entry) => !entry.name.startsWith('.') && !SCAN_EXCLUDED_DIRS.has(entry.name)) .sort((a, b) => { if (a.isDirectory() && !b.isDirectory()) return -1; if (!a.isDirectory() && b.isDirectory()) return 1; @@ -136,7 +159,7 @@ async function scanDirectoryRemote( // Sort entries: folders first, then files, both alphabetically const sortedEntries = result.data - .filter((entry) => !entry.name.startsWith('.')) + .filter((entry) => !entry.name.startsWith('.') && !SCAN_EXCLUDED_DIRS.has(entry.name)) .sort((a, b) => { if (a.isDirectory && !b.isDirectory) return -1; if (!a.isDirectory && b.isDirectory) return 1; @@ -215,8 +238,8 @@ async function checkForMarkdownFiles(dirPath: string): Promise { const entries = await fs.readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { - // Skip hidden files/folders - if (entry.name.startsWith('.')) { + // Skip hidden files/folders and excluded directories + if (entry.name.startsWith('.') || SCAN_EXCLUDED_DIRS.has(entry.name)) { continue; } diff --git a/src/renderer/components/AgentErrorModal.tsx b/src/renderer/components/AgentErrorModal.tsx index 6471e553cd..3d4479048c 100644 --- a/src/renderer/components/AgentErrorModal.tsx +++ b/src/renderer/components/AgentErrorModal.tsx @@ -223,12 +223,15 @@ export function AgentErrorModal({ [recoveryActions] ); + const [retryInvoked, setRetryInvoked] = useState(false); + // Auto-retry handler: when countdown completes, invoke the "retry" recovery action const handleCountdownComplete = useCallback(() => { - if (retryAction) { + if (retryAction && !retryInvoked) { + setRetryInvoked(true); retryAction.onClick(); } - }, [retryAction]); + }, [retryAction, retryInvoked]); const [autoRetrySettings, setAutoRetrySettings] = useState<{ enabled: boolean; @@ -265,7 +268,10 @@ export function AgentErrorModal({ if (!autoRetrySettings.enabled) return null; // Exact parsed reset time is always preferred - if (error.rateLimitResetAt && error.rateLimitResetAt > Date.now()) { + if (error.rateLimitResetAt) { + if (error.rateLimitResetAt <= Date.now()) { + return null; // Expired, allow immediate retry + } return error.rateLimitResetAt; } @@ -360,39 +366,58 @@ export function AgentErrorModal({ {/* Recovery Actions - only show if there are actions */} {recoveryActions.length > 0 && (
- {recoveryActions.map((action, index) => ( - - ))} + {recoveryActions.map((action, index) => { + const isRetry = action.id === 'retry'; + const isDisabled = isRetry && retryInvoked; + return ( + + ); + })}
)} diff --git a/src/renderer/components/SessionList/SessionList.tsx b/src/renderer/components/SessionList/SessionList.tsx index 5ca2487fe2..ddf46bf8b6 100644 --- a/src/renderer/components/SessionList/SessionList.tsx +++ b/src/renderer/components/SessionList/SessionList.tsx @@ -444,16 +444,18 @@ function SessionListInner(props: SessionListProps) { sortedGroups, } = useSessionCategories(sessionFilter, sortedSessions, showUnreadAgentsOnly, activeSessionId); - // PERF: Cached callback maps to prevent SessionItem re-renders - // These Maps store stable function references keyed by session/editing ID - // The callbacks themselves are memoized, so the Map values remain stable + // PERF: Stable key derived from session IDs only — changes only when sessions are + // added/removed, NOT when a session's name/status/logs change. This prevents the + // Maps below from regenerating (and SessionItem from re-rendering) on every state update. + const sessionIdsKey = useMemo(() => sessions.map((s) => s.id).join(','), [sessions]); + const selectHandlers = useMemo(() => { const map = new Map void>(); sessions.forEach((s) => { map.set(s.id, () => setActiveSessionId(s.id)); }); return map; - }, [sessions, setActiveSessionId]); + }, [sessionIdsKey, setActiveSessionId]); const dragStartHandlers = useMemo(() => { const map = new Map void>(); @@ -461,7 +463,7 @@ function SessionListInner(props: SessionListProps) { map.set(s.id, () => handleDragStart(s.id)); }); return map; - }, [sessions, handleDragStart]); + }, [sessionIdsKey, handleDragStart]); const contextMenuHandlers = useMemo(() => { const map = new Map void>(); @@ -469,7 +471,7 @@ function SessionListInner(props: SessionListProps) { map.set(s.id, (e: React.MouseEvent) => handleContextMenu(e, s.id)); }); return map; - }, [sessions, handleContextMenu]); + }, [sessionIdsKey, handleContextMenu]); const finishRenameHandlers = useMemo(() => { const map = new Map void>(); @@ -477,7 +479,7 @@ function SessionListInner(props: SessionListProps) { map.set(s.id, (newName: string) => finishRenamingSession(s.id, newName)); }); return map; - }, [sessions, finishRenamingSession]); + }, [sessionIdsKey, finishRenamingSession]); const toggleBookmarkHandlers = useMemo(() => { const map = new Map void>(); @@ -485,7 +487,7 @@ function SessionListInner(props: SessionListProps) { map.set(s.id, () => toggleBookmark(s.id)); }); return map; - }, [sessions, toggleBookmark]); + }, [sessionIdsKey, toggleBookmark]); // Helper: compute navIndexMap key for a session based on render context const getNavKey = (variant: string, session: Session, groupId?: string): string => { diff --git a/src/renderer/components/Settings/SettingsSearch.tsx b/src/renderer/components/Settings/SettingsSearch.tsx index b9e38ae9c8..1873844364 100644 --- a/src/renderer/components/Settings/SettingsSearch.tsx +++ b/src/renderer/components/Settings/SettingsSearch.tsx @@ -10,6 +10,9 @@ import React, { type ReactNode } from 'react'; import { useState, useRef, useEffect, useCallback } from 'react'; + +const REGEX_ESCAPE = /[.*+?^${}()|[\]\\]/g; +const WHITESPACE = /\s+/; import { Search, X } from 'lucide-react'; import type { Theme } from '../../types'; import { searchSettings, type SearchableSetting } from './searchableSettings'; @@ -214,9 +217,9 @@ export function SettingsSearchResults({ function highlightMatch(text: string, query: string, theme: Theme): ReactNode { if (!query.trim()) return text; - const terms = query.toLowerCase().trim().split(/\s+/); + const terms = query.toLowerCase().trim().split(WHITESPACE); // Build a regex that matches any of the search terms - const escapedTerms = terms.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); + const escapedTerms = terms.map((t) => t.replace(REGEX_ESCAPE, '\\$&')); const regex = new RegExp(`(${escapedTerms.join('|')})`, 'gi'); const parts = text.split(regex); diff --git a/src/renderer/stores/agentStore.ts b/src/renderer/stores/agentStore.ts index 13546f87cd..56b784c52a 100644 --- a/src/renderer/stores/agentStore.ts +++ b/src/renderer/stores/agentStore.ts @@ -223,11 +223,19 @@ export const useAgentStore = create()((set, get) => ({ const logs = targetTab.logs || []; const lastUserLog = [...logs].reverse().find((l) => l.source === 'user'); - if (!lastUserLog || !lastUserLog.text) { + if (!lastUserLog) { console.warn('[retryAfterError] No user message found to retry.'); return; } + const hasImages = Array.isArray(lastUserLog.images) && lastUserLog.images.length > 0; + const hasText = !!lastUserLog.text?.trim(); + + if (!hasText && !hasImages) { + console.warn('[retryAfterError] Last user message is empty (no text, no images).'); + return; + } + // 4. Re-construct a QueuedItem 'message' to re-dispatch. // By sending it as a 'message' (even if it originally was a command), // we avoid double-substituting template variables, as the text in the log @@ -238,7 +246,7 @@ export const useAgentStore = create()((set, get) => ({ timestamp: Date.now(), tabId: targetTab.id, type: 'message', - text: lastUserLog.text, + text: !hasText && hasImages ? DEFAULT_IMAGE_ONLY_PROMPT : lastUserLog.text!, images: lastUserLog.images, tabName: targetTab.name || @@ -284,6 +292,42 @@ export const useAgentStore = create()((set, get) => ({ .processQueuedItem(sessionId, queuedItem, deps) .catch((err) => { console.error('[retryAfterError] Failed to retry item:', err); + import('../utils/sentry').then((mod) => { + mod.captureException(err, { extra: { operation: 'retryAfterError' } }); + }); + + // Re-surface the error modal + import('./sessionStore').then(({ useSessionStore }) => { + useSessionStore.getState().setSessions((prev) => + prev.map((s) => { + if (s.id !== sessionId) return s; + // Put the error back on the session and target tab + const updatedAiTabs = s.aiTabs?.map((tab) => + tab.id === targetTab.id + ? { + ...tab, + state: 'idle' as const, + } + : tab + ); + return { + ...s, + state: 'error' as SessionState, + busySource: undefined, + aiTabs: updatedAiTabs, + agentError: { + type: 'agent_crashed', + message: err instanceof Error ? err.message : String(err), + recoverable: true, + agentId: s.toolType, + timestamp: Date.now(), + }, + agentErrorTabId: targetTab.id, + agentErrorPaused: true, + }; + }) + ); + }); }); }, 0); }, From 5e2bc39e75e11a7c84eab5f6ab05d6f4a42f2ea1 Mon Sep 17 00:00:00 2001 From: ProaFilippi Date: Fri, 17 Apr 2026 07:33:34 -0500 Subject: [PATCH 23/23] fix(types): add missing createdAt field to remote session creation Co-Authored-By: Claude Sonnet 4.6 --- src/renderer/hooks/remote/useAppRemoteEventListeners.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/hooks/remote/useAppRemoteEventListeners.ts b/src/renderer/hooks/remote/useAppRemoteEventListeners.ts index e32e46a1e4..4b3a994d5c 100644 --- a/src/renderer/hooks/remote/useAppRemoteEventListeners.ts +++ b/src/renderer/hooks/remote/useAppRemoteEventListeners.ts @@ -421,6 +421,7 @@ export function useAppRemoteEventListeners(deps: UseAppRemoteEventListenersDeps) unifiedClosedTabHistory: [], groupId: groupId || undefined, autoRunFolderPath: `${cwd}/${PLAYBOOKS_DIR}`, + createdAt: Date.now(), }; setSessions((prev: Session[]) => [...prev, newSession]);