diff --git a/package-lock.json b/package-lock.json index 02397c75..95c1bdec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -91,7 +91,9 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.0.1", "globals": "^16.5.0", + "husky": "^9.1.7", "jsdom": "^27.2.0", + "lint-staged": "^16.2.7", "lucide-react": "^0.303.0", "playwright": "^1.57.0", "postcss": "^8.4.33", @@ -261,7 +263,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", @@ -665,7 +666,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -709,7 +709,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -2283,7 +2282,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" } @@ -2305,7 +2303,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" }, @@ -2318,7 +2315,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" }, @@ -2334,7 +2330,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", @@ -2722,7 +2717,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" @@ -2739,7 +2733,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", @@ -2757,7 +2750,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" } @@ -3648,7 +3640,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", @@ -4186,7 +4179,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" @@ -4198,7 +4190,6 @@ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -4324,7 +4315,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", @@ -4755,7 +4745,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" }, @@ -4837,7 +4826,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", @@ -4914,6 +4902,22 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -5841,7 +5845,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -6324,7 +6327,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", @@ -6562,6 +6564,13 @@ "color-support": "bin.js" } }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -7050,7 +7059,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" } @@ -7460,7 +7468,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" } @@ -7958,7 +7965,6 @@ "integrity": "sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "24.13.3", "builder-util": "24.13.1", @@ -8054,7 +8060,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", @@ -8198,6 +8205,7 @@ "integrity": "sha512-oHkV0iogWfyK+ah9ZIvMDpei1m9ZRpdXcvde1wTpra2U8AFDNNpqJdnin5z+PM1GbQ5BoaKCWas2HSjtR0HwMg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "24.13.3", "archiver": "^5.3.1", @@ -8211,6 +8219,7 @@ "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.4", @@ -8230,6 +8239,7 @@ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", @@ -8252,6 +8262,7 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -8268,6 +8279,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", @@ -8284,6 +8296,7 @@ "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" @@ -8298,6 +8311,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", @@ -8313,6 +8327,7 @@ "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -8325,7 +8340,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", @@ -8333,6 +8349,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -8343,6 +8360,7 @@ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -8353,6 +8371,7 @@ "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "archiver-utils": "^3.0.4", "compress-commons": "^4.1.2", @@ -8368,6 +8387,7 @@ "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", @@ -8764,6 +8784,19 @@ "node": ">=6" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -9049,7 +9082,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", @@ -10151,6 +10183,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -10881,6 +10926,22 @@ "ms": "^2.0.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -10953,7 +11014,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" @@ -11774,7 +11834,6 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -12197,6 +12256,201 @@ "dev": true, "license": "MIT" }, + "node_modules/lint-staged": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.2", + "listr2": "^9.0.5", + "micromatch": "^4.0.8", + "nano-spawn": "^2.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/cli-truncate": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/local-pkg": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", @@ -12244,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", @@ -12264,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", @@ -12278,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", @@ -12292,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", @@ -12311,6 +12570,193 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -12383,6 +12829,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -13588,6 +14035,19 @@ "node": ">=8" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -13923,6 +14383,19 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nano-spawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", + "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -14667,6 +15140,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -14880,7 +15366,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -15121,6 +15606,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -15136,6 +15622,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -15480,7 +15967,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" }, @@ -15510,7 +15996,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" @@ -15558,7 +16043,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" @@ -15745,8 +16229,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", @@ -16939,6 +17422,16 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -17503,7 +17996,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -17814,7 +18306,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18188,7 +18679,6 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -18694,7 +19184,6 @@ "integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.15", "@vitest/mocker": "4.0.15", @@ -19285,7 +19774,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -19299,7 +19787,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", @@ -19784,6 +20271,22 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -19897,7 +20400,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/index.test.ts b/src/__tests__/main/parsers/index.test.ts index 54b4f3af..1a982fbf 100644 --- a/src/__tests__/main/parsers/index.test.ts +++ b/src/__tests__/main/parsers/index.test.ts @@ -41,21 +41,29 @@ describe('parsers/index', () => { expect(hasOutputParser('codex')).toBe(true); }); - it('should register exactly 3 parsers', () => { + it('should register Factory Droid parser', () => { + expect(hasOutputParser('factory-droid')).toBe(false); + + initializeOutputParsers(); + + expect(hasOutputParser('factory-droid')).toBe(true); + }); + + it('should register exactly 4 parsers', () => { initializeOutputParsers(); const parsers = getAllOutputParsers(); - expect(parsers.length).toBe(3); + expect(parsers.length).toBe(4); // Claude, OpenCode, Codex, Factory Droid }); it('should clear existing parsers before registering', () => { // First initialization initializeOutputParsers(); - expect(getAllOutputParsers().length).toBe(3); + expect(getAllOutputParsers().length).toBe(4); - // Second initialization should still have exactly 3 + // Second initialization should still have exactly 4 initializeOutputParsers(); - expect(getAllOutputParsers().length).toBe(3); + expect(getAllOutputParsers().length).toBe(4); }); }); @@ -65,7 +73,7 @@ describe('parsers/index', () => { ensureParsersInitialized(); - expect(getAllOutputParsers().length).toBe(3); + expect(getAllOutputParsers().length).toBe(4); }); it('should be idempotent after first call', () => { diff --git a/src/__tests__/renderer/services/contextGroomer.test.ts b/src/__tests__/renderer/services/contextGroomer.test.ts index 94cfc804..273ee856 100644 --- a/src/__tests__/renderer/services/contextGroomer.test.ts +++ b/src/__tests__/renderer/services/contextGroomer.test.ts @@ -469,6 +469,7 @@ describe('AGENT_ARTIFACTS', () => { 'aider', 'opencode', 'codex', + 'factory-droid', 'claude', 'terminal', ]; @@ -622,7 +623,7 @@ describe('buildContextTransferPrompt', () => { }); it('should work for all agent type combinations', () => { - const agents: ToolType[] = ['claude-code', 'aider', 'opencode', 'codex', 'claude', 'terminal']; + const agents: ToolType[] = ['claude-code', 'aider', 'opencode', 'codex', 'factory-droid', 'claude', 'terminal']; for (const source of agents) { for (const target of agents) { diff --git a/src/main/agent-capabilities.ts b/src/main/agent-capabilities.ts index 73f8b15e..aaa99d8b 100644 --- a/src/main/agent-capabilities.ts +++ b/src/main/agent-capabilities.ts @@ -303,6 +303,34 @@ export const AGENT_CAPABILITIES: Record = { supportsContextMerge: true, // Can receive merged context via prompts supportsContextExport: true, // Session storage supports context export }, + + /** + * Factory Droid - Enterprise AI coding assistant from Factory + * https://docs.factory.ai/cli + * + * Verified capabilities based on CLI testing (droid exec --help) and session file analysis. + */ + 'factory-droid': { + supportsResume: true, // -s, --session-id (requires a prompt) - Verified + supportsReadOnlyMode: true, // Default mode (no --auto flags) - Verified + supportsJsonOutput: true, // -o stream-json - Verified + supportsSessionId: true, // UUID in session filenames - Verified + supportsImageInput: true, // -f, --file flag - Verified + supportsImageInputOnResume: true, // -f works with -s flag - Verified + supportsSlashCommands: false, // Factory uses different command system + supportsSessionStorage: true, // ~/.factory/sessions/ (JSONL files) - Verified + supportsCostTracking: false, // Token counts only in settings.json, no USD cost + supportsUsageStats: true, // tokenUsage in settings.json - Verified + supportsBatchMode: true, // droid exec subcommand - Verified + requiresPromptToStart: true, // Requires prompt argument for exec + supportsStreaming: true, // stream-json format - Verified + supportsResultMessages: true, // Can detect end of conversation + supportsModelSelection: true, // -m, --model flag - Verified + supportsStreamJsonInput: true, // --input-format stream-json - Verified + supportsThinkingDisplay: true, // Emits thinking content in messages - Verified + supportsContextMerge: true, // Can receive merged context via prompts + supportsContextExport: true, // Session files are exportable + }, }; /** diff --git a/src/main/agent-detector.ts b/src/main/agent-detector.ts index 890f99fb..fe5ec087 100644 --- a/src/main/agent-detector.ts +++ b/src/main/agent-detector.ts @@ -179,6 +179,93 @@ export const AGENT_DEFINITIONS: Omit (requires a prompt) + resumeArgs: (sessionId: string) => ['-s', sessionId], + + // Read-only mode is DEFAULT in droid exec (no flag needed) + readOnlyArgs: [], + + // YOLO mode (same as batchModeArgs, kept for explicit yoloMode requests) + yoloModeArgs: ['--skip-permissions-unsafe'], + + // Model selection is handled by configOptions.model.argBuilder below + // Don't define modelArgs here to avoid duplicate -m flags + + // Working directory + workingDirArgs: (dir: string) => ['--cwd', dir], + + // File/image input + imageArgs: (imagePath: string) => ['-f', imagePath], + + // Prompt is positional argument (no separator needed) + noPromptSeparator: true, + + // Default env vars - don't set NO_COLOR as it conflicts with FORCE_COLOR + defaultEnvVars: {}, + + // UI config options + // Model IDs from droid CLI (exact IDs required) + // NOTE: autonomyLevel is NOT configurable - Maestro always uses --skip-permissions-unsafe + // which conflicts with --auto. This matches Claude Code's behavior. + configOptions: [ + { + key: 'model', + type: 'select', + label: 'Model', + description: 'Model to use for Factory Droid', + // Model IDs from `droid exec --help` (2026-01-22) + options: [ + '', // Empty = use droid's default (claude-opus-4-5-20251101) + // OpenAI models + 'gpt-5.1', + 'gpt-5.1-codex', + 'gpt-5.1-codex-max', + 'gpt-5.2', + // Claude models + 'claude-sonnet-4-5-20250929', + 'claude-opus-4-5-20251101', + 'claude-haiku-4-5-20251001', + // Google models + 'gemini-3-pro-preview', + ], + default: '', // Empty = use droid's default (claude-opus-4-5-20251101) + argBuilder: (value: string) => (value && value.trim() ? ['-m', value.trim()] : []), + }, + { + key: 'reasoningEffort', + type: 'select', + label: 'Reasoning Effort', + description: 'How much the model should reason before responding', + options: ['', 'low', 'medium', 'high'], + default: '', // Empty = use droid's default reasoning + argBuilder: (value: string) => (value && value.trim() ? ['-r', value.trim()] : []), + }, + { + key: 'contextWindow', + type: 'number', + label: 'Context Window Size', + description: 'Maximum context window in tokens (for UI display)', + default: 200000, + }, + ], + }, ]; export class AgentDetector { @@ -544,6 +631,16 @@ export class AgentDetector { path.join(localAppData, 'Programs', 'Python', 'Python311', 'Scripts', 'aider.exe'), path.join(localAppData, 'Programs', 'Python', 'Python310', 'Scripts', 'aider.exe'), ], + droid: [ + // Factory Droid installation paths + path.join(home, '.factory', 'bin', 'droid.exe'), + path.join(localAppData, 'Factory', 'droid.exe'), + path.join(appData, 'Factory', 'droid.exe'), + path.join(home, '.local', 'bin', 'droid.exe'), + // npm global installation + path.join(appData, 'npm', 'droid.cmd'), + path.join(localAppData, 'npm', 'droid.cmd'), + ], }; const pathsToCheck = knownPaths[binaryName] || []; @@ -632,6 +729,15 @@ export class AgentDetector { // Add paths from Node version managers (in case installed via npm) ...versionManagerPaths.map((p) => path.join(p, 'aider')), ], + droid: [ + // Factory Droid installation paths + path.join(home, '.factory', 'bin', 'droid'), + path.join(home, '.local', 'bin', 'droid'), + '/opt/homebrew/bin/droid', + '/usr/local/bin/droid', + // Add paths from Node version managers (in case installed via npm) + ...versionManagerPaths.map((p) => path.join(p, 'droid')), + ], }; const pathsToCheck = knownPaths[binaryName] || []; diff --git a/src/main/agent-session-storage.ts b/src/main/agent-session-storage.ts index ca2b979f..8ffc7fee 100644 --- a/src/main/agent-session-storage.ts +++ b/src/main/agent-session-storage.ts @@ -22,7 +22,7 @@ const LOG_CONTEXT = '[AgentSessionStorage]'; /** * Known agent IDs that have session storage support */ -const KNOWN_AGENT_IDS: ToolType[] = ['claude-code', 'codex', 'opencode']; +const KNOWN_AGENT_IDS: ToolType[] = ['claude-code', 'codex', 'opencode', 'factory-droid']; /** * Session origin types - indicates how the session was created diff --git a/src/main/group-chat/group-chat-storage.ts b/src/main/group-chat/group-chat-storage.ts index 07d0207a..7e4858d3 100644 --- a/src/main/group-chat/group-chat-storage.ts +++ b/src/main/group-chat/group-chat-storage.ts @@ -21,7 +21,7 @@ import type { ModeratorConfig, GroupChatHistoryEntry } from '../../shared/group- * Valid agent IDs that can be used as moderators. * Must match available agents from agent-detector. */ -const VALID_MODERATOR_AGENT_IDS: ToolType[] = ['claude-code', 'codex', 'opencode']; +const VALID_MODERATOR_AGENT_IDS: ToolType[] = ['claude-code', 'codex', 'opencode', 'factory-droid']; /** * Bootstrap settings store for custom storage location. diff --git a/src/main/ipc/handlers/agents.ts b/src/main/ipc/handlers/agents.ts index 90270abb..8fcd35d5 100644 --- a/src/main/ipc/handlers/agents.ts +++ b/src/main/ipc/handlers/agents.ts @@ -327,11 +327,26 @@ export function registerAgentsHandlers(deps: AgentsHandlerDependencies): void { ); // Get all configuration for an agent + // Merges stored config with defaults from agent's configOptions ipcMain.handle( 'agents:getConfig', withIpcErrorLogging(handlerOpts('getConfig', CONFIG_LOG_CONTEXT), async (agentId: string) => { const allConfigs = agentConfigsStore.get('configs', {}); - return allConfigs[agentId] || {}; + const storedConfig = allConfigs[agentId] || {}; + + // Get defaults from agent definition's configOptions + const agentDef = AGENT_DEFINITIONS.find((a) => a.id === agentId); + const defaults: Record = {}; + if (agentDef?.configOptions) { + for (const option of agentDef.configOptions) { + if (option.default !== undefined) { + defaults[option.key] = option.default; + } + } + } + + // Merge: stored config takes precedence over defaults + return { ...defaults, ...storedConfig }; }) ); @@ -351,6 +366,7 @@ export function registerAgentsHandlers(deps: AgentsHandlerDependencies): void { ); // Get a specific configuration value for an agent + // Falls back to default from agent's configOptions if not stored ipcMain.handle( 'agents:getConfigValue', withIpcErrorLogging( @@ -358,7 +374,16 @@ export function registerAgentsHandlers(deps: AgentsHandlerDependencies): void { async (agentId: string, key: string) => { const allConfigs = agentConfigsStore.get('configs', {}); const agentConfig = allConfigs[agentId] || {}; - return agentConfig[key]; + + // Return stored value if present + if (agentConfig[key] !== undefined) { + return agentConfig[key]; + } + + // Fall back to default from agent definition + const agentDef = AGENT_DEFINITIONS.find((a) => a.id === agentId); + const option = agentDef?.configOptions?.find((o) => o.key === key); + return option?.default; } ) ); diff --git a/src/main/parsers/agent-output-parser.ts b/src/main/parsers/agent-output-parser.ts index 51088288..3144003d 100644 --- a/src/main/parsers/agent-output-parser.ts +++ b/src/main/parsers/agent-output-parser.ts @@ -42,6 +42,7 @@ const VALID_TOOL_TYPES: ToolType[] = [ 'terminal', 'claude', 'aider', + 'factory-droid', ]; /** diff --git a/src/main/parsers/error-patterns.ts b/src/main/parsers/error-patterns.ts index 239379e3..c0ca3ce2 100644 --- a/src/main/parsers/error-patterns.ts +++ b/src/main/parsers/error-patterns.ts @@ -30,6 +30,7 @@ const VALID_TOOL_TYPES = new Set([ 'opencode', 'codex', 'terminal', + 'factory-droid', ]); /** @@ -543,6 +544,148 @@ export const CODEX_ERROR_PATTERNS: AgentErrorPatterns = { ], }; +// ============================================================================ +// Factory Droid Error Patterns +// ============================================================================ + +export const FACTORY_DROID_ERROR_PATTERNS: AgentErrorPatterns = { + auth_expired: [ + { + pattern: /invalid.*api.*key/i, + message: 'Invalid API key. Please check your Factory credentials.', + recoverable: true, + }, + { + pattern: /authentication.*failed/i, + message: 'Authentication failed. Please verify your Factory API key.', + recoverable: true, + }, + { + pattern: /unauthorized/i, + message: 'Unauthorized access. Please check your Factory API key.', + recoverable: true, + }, + { + pattern: /FACTORY_API_KEY/i, + message: 'Factory API key not set. Please set FACTORY_API_KEY environment variable.', + recoverable: true, + }, + { + pattern: /api.*key.*expired/i, + message: 'Your API key has expired. Please renew your Factory credentials.', + recoverable: true, + }, + ], + + token_exhaustion: [ + { + pattern: /context.*exceeded/i, + message: 'Context limit exceeded. Start a new session.', + recoverable: true, + }, + { + pattern: /maximum.*tokens/i, + message: 'Maximum token limit reached. Start a new session.', + recoverable: true, + }, + { + pattern: /token.*limit/i, + message: 'Token limit reached. Consider starting a fresh conversation.', + recoverable: true, + }, + { + pattern: /prompt.*too\s+long/i, + message: 'Prompt is too long. Try a shorter message or start a new session.', + recoverable: true, + }, + ], + + rate_limited: [ + { + pattern: /rate.*limit/i, + message: 'Rate limit exceeded. Please wait before trying again.', + recoverable: true, + }, + { + pattern: /too many requests/i, + message: 'Too many requests. Please wait before sending more messages.', + recoverable: true, + }, + { + pattern: /quota.*exceeded/i, + message: 'Your API quota has been exceeded.', + recoverable: false, + }, + { + pattern: /\b429\b/, + message: 'Rate limited. Please wait and try again.', + recoverable: true, + }, + ], + + network_error: [ + { + pattern: /connection\s*(failed|refused|error|reset|closed)/i, + message: 'Connection failed. Check your internet connection.', + recoverable: true, + }, + { + pattern: /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND/i, + message: 'Network error. Check your internet connection.', + recoverable: true, + }, + { + pattern: /request\s+timed?\s*out|timed?\s*out\s+waiting/i, + message: 'Request timed out. Please try again.', + recoverable: true, + }, + { + pattern: /network\s+(error|failure|unavailable)/i, + message: 'Network error occurred. Please check your connection.', + recoverable: true, + }, + ], + + permission_denied: [ + { + pattern: /permission denied/i, + message: 'Permission denied. The agent cannot access the requested resource.', + recoverable: false, + }, + { + pattern: /access denied/i, + message: 'Access denied to the requested resource.', + recoverable: false, + }, + { + pattern: /autonomy.*level/i, + message: 'Operation requires higher autonomy level. Use --auto flag.', + recoverable: true, + }, + ], + + agent_crashed: [ + { + pattern: /\b(fatal|unexpected|internal|unhandled)\s+error\b/i, + message: 'An unexpected error occurred in the agent.', + recoverable: true, + }, + ], + + session_not_found: [ + { + pattern: /session.*not found/i, + message: 'Session not found. Starting fresh conversation.', + recoverable: true, + }, + { + pattern: /invalid.*session/i, + message: 'Invalid session. Starting fresh conversation.', + recoverable: true, + }, + ], +}; + // ============================================================================ // SSH Error Patterns // ============================================================================ @@ -724,6 +867,7 @@ const patternRegistry = new Map([ ['claude-code', CLAUDE_ERROR_PATTERNS], ['opencode', OPENCODE_ERROR_PATTERNS], ['codex', CODEX_ERROR_PATTERNS], + ['factory-droid', FACTORY_DROID_ERROR_PATTERNS], ]); /** diff --git a/src/main/parsers/index.ts b/src/main/parsers/index.ts index bb433ab1..06e44e21 100644 --- a/src/main/parsers/index.ts +++ b/src/main/parsers/index.ts @@ -53,6 +53,7 @@ export { import { ClaudeOutputParser } from './claude-output-parser'; import { OpenCodeOutputParser } from './opencode-output-parser'; import { CodexOutputParser } from './codex-output-parser'; +import { FactoryDroidOutputParser } from './factory-droid-output-parser'; import { registerOutputParser, clearParserRegistry, @@ -64,6 +65,7 @@ import { logger } from '../utils/logger'; export { ClaudeOutputParser } from './claude-output-parser'; export { OpenCodeOutputParser } from './opencode-output-parser'; export { CodexOutputParser } from './codex-output-parser'; +export { FactoryDroidOutputParser } from './factory-droid-output-parser'; const LOG_CONTEXT = '[OutputParsers]'; @@ -79,6 +81,7 @@ export function initializeOutputParsers(): void { registerOutputParser(new ClaudeOutputParser()); registerOutputParser(new OpenCodeOutputParser()); registerOutputParser(new CodexOutputParser()); + registerOutputParser(new FactoryDroidOutputParser()); // Log registered parsers for debugging const registeredParsers = getAllOutputParsers().map((p) => p.agentId); diff --git a/src/main/parsers/usage-aggregator.ts b/src/main/parsers/usage-aggregator.ts index a1017f8c..9fcf6daf 100644 --- a/src/main/parsers/usage-aggregator.ts +++ b/src/main/parsers/usage-aggregator.ts @@ -48,6 +48,7 @@ export const DEFAULT_CONTEXT_WINDOWS: Record = { opencode: 128000, // OpenCode (depends on model, 128k is conservative default) aider: 128000, // Aider (varies by model, 128k is conservative default) terminal: 0, // Terminal has no context window + 'factory-droid': 200000, // Factory Droid (Claude Opus 4.5 default context) }; /** diff --git a/src/main/process-manager/handlers/ExitHandler.ts b/src/main/process-manager/handlers/ExitHandler.ts index 942480c3..2228354f 100644 --- a/src/main/process-manager/handlers/ExitHandler.ts +++ b/src/main/process-manager/handlers/ExitHandler.ts @@ -95,6 +95,17 @@ export class ExitHandler { this.handleBatchModeExit(sessionId, managedProcess); } + // Handle stream-json mode: emit accumulated streamed text if no result was emitted + // Some agents (like Factory Droid) don't send explicit "done" events, they just exit + if (isStreamJsonMode && !managedProcess.resultEmitted && managedProcess.streamedText) { + managedProcess.resultEmitted = true; + logger.debug('[ProcessManager] Emitting streamed text at exit (no result event)', 'ProcessManager', { + sessionId, + streamedTextLength: managedProcess.streamedText.length, + }); + this.bufferManager.emitDataBuffered(sessionId, managedProcess.streamedText); + } + // Check for errors using the parser (if not already emitted) if (outputParser && !managedProcess.errorEmitted) { const agentError = outputParser.detectErrorFromExit( diff --git a/src/main/storage/index.ts b/src/main/storage/index.ts index ae555c8f..e905bc1d 100644 --- a/src/main/storage/index.ts +++ b/src/main/storage/index.ts @@ -8,12 +8,14 @@ export { ClaudeSessionStorage, ClaudeSessionOriginsData } from './claude-session-storage'; export { OpenCodeSessionStorage } from './opencode-session-storage'; export { CodexSessionStorage } from './codex-session-storage'; +export { FactoryDroidSessionStorage } from './factory-droid-session-storage'; import Store from 'electron-store'; import { registerSessionStorage } from '../agent-session-storage'; import { ClaudeSessionStorage, ClaudeSessionOriginsData } from './claude-session-storage'; import { OpenCodeSessionStorage } from './opencode-session-storage'; import { CodexSessionStorage } from './codex-session-storage'; +import { FactoryDroidSessionStorage } from './factory-droid-session-storage'; /** * Options for initializing session storages @@ -33,4 +35,5 @@ export function initializeSessionStorages(options?: InitializeSessionStoragesOpt registerSessionStorage(new ClaudeSessionStorage(options?.claudeSessionOriginsStore)); registerSessionStorage(new OpenCodeSessionStorage()); registerSessionStorage(new CodexSessionStorage()); + registerSessionStorage(new FactoryDroidSessionStorage()); } diff --git a/src/renderer/components/NewInstanceModal.tsx b/src/renderer/components/NewInstanceModal.tsx index 54de2211..4cb711be 100644 --- a/src/renderer/components/NewInstanceModal.tsx +++ b/src/renderer/components/NewInstanceModal.tsx @@ -73,7 +73,7 @@ interface EditAgentModalProps { } // Supported agents that are fully implemented -const SUPPORTED_AGENTS = ['claude-code', 'opencode', 'codex']; +const SUPPORTED_AGENTS = ['claude-code', 'opencode', 'codex', 'factory-droid']; export function NewInstanceModal({ isOpen, diff --git a/src/renderer/components/Wizard/screens/AgentSelectionScreen.tsx b/src/renderer/components/Wizard/screens/AgentSelectionScreen.tsx index 682c1106..b7ccb3e2 100644 --- a/src/renderer/components/Wizard/screens/AgentSelectionScreen.tsx +++ b/src/renderer/components/Wizard/screens/AgentSelectionScreen.tsx @@ -63,6 +63,13 @@ export const AGENT_TILES: AgentTile[] = [ description: 'Open-source AI coding assistant', brandColor: '#F97316', // Orange }, + { + id: 'factory-droid', + name: 'Factory Droid', + supported: true, + description: "Factory's AI coding assistant", + brandColor: '#8B5CF6', // Purple/violet + }, // Coming soon agents at the bottom { id: 'aider', @@ -87,9 +94,9 @@ export const AGENT_TILES: AgentTile[] = [ }, ]; -// Grid dimensions for keyboard navigation (3 cols for 5 items) +// Grid dimensions for keyboard navigation (3 cols for 7 items) const GRID_COLS = 3; -const GRID_ROWS = 2; +const GRID_ROWS = 3; /** * Get SVG logo for an agent with brand colors diff --git a/src/renderer/components/shared/AgentConfigPanel.tsx b/src/renderer/components/shared/AgentConfigPanel.tsx index 00147681..26129ec6 100644 --- a/src/renderer/components/shared/AgentConfigPanel.tsx +++ b/src/renderer/components/shared/AgentConfigPanel.tsx @@ -626,6 +626,28 @@ export function AgentConfigPanel({ )} + {option.type === 'select' && option.options && ( + + )}

{option.description}

))} diff --git a/src/renderer/constants/agentIcons.ts b/src/renderer/constants/agentIcons.ts index 8c43fb90..2e976f85 100644 --- a/src/renderer/constants/agentIcons.ts +++ b/src/renderer/constants/agentIcons.ts @@ -43,6 +43,9 @@ export const AGENT_ICONS: Record = { opencode: '📟', aider: '🛠️', + // Enterprise + 'factory-droid': '🏭', + // Terminal/shell (internal) terminal: '💻', }; diff --git a/src/renderer/hooks/input/useInputProcessing.ts b/src/renderer/hooks/input/useInputProcessing.ts index 4d608b50..3ab9be11 100644 --- a/src/renderer/hooks/input/useInputProcessing.ts +++ b/src/renderer/hooks/input/useInputProcessing.ts @@ -666,14 +666,15 @@ export function useInputProcessing(deps: UseInputProcessingDeps): UseInputProces ? `${activeSession.id}-ai-${activeTabForSpawn?.id || 'default'}` : `${activeSession.id}-terminal`; - // Check if this is an AI agent in batch mode (e.g., Claude Code, OpenCode, Codex) + // Check if this is an AI agent in batch mode (e.g., Claude Code, OpenCode, Codex, Factory Droid) // Batch mode agents spawn a new process per message rather than writing to stdin const isBatchModeAgent = currentMode === 'ai' && (activeSession.toolType === 'claude' || activeSession.toolType === 'claude-code' || activeSession.toolType === 'opencode' || - activeSession.toolType === 'codex'); + activeSession.toolType === 'codex' || + activeSession.toolType === 'factory-droid'); if (isBatchModeAgent) { // Batch mode: Spawn new agent process with prompt diff --git a/src/renderer/services/contextGroomer.ts b/src/renderer/services/contextGroomer.ts index 04897e02..eb7a080a 100644 --- a/src/renderer/services/contextGroomer.ts +++ b/src/renderer/services/contextGroomer.ts @@ -110,6 +110,18 @@ export const AGENT_ARTIFACTS: Record = { 'openai codex', 'OpenAI Codex', ], + 'factory-droid': [ + // Brand references + 'Factory', + 'Droid', + 'Factory Droid', + // Model references (can use multiple providers) + 'Claude', + 'GPT', + 'Gemini', + 'Opus', + 'Sonnet', + ], claude: [ // This is the base Claude (not Claude Code) 'Claude', @@ -150,6 +162,12 @@ export const AGENT_TARGET_NOTES: Record = { It uses reasoning models like o1, o3, and o4-mini. It can read files, edit code, and run terminal commands. It excels at complex reasoning and problem-solving. + `, + 'factory-droid': ` + Factory Droid is an enterprise AI coding assistant by Factory. + It supports multiple model providers (Claude, GPT, Gemini). + It can read and edit files, run commands, search code, and interact with git. + It has tiered autonomy levels for controlling operation permissions. `, claude: ` Claude is a general-purpose AI assistant by Anthropic. @@ -171,6 +189,7 @@ export function getAgentDisplayName(agentType: ToolType): string { aider: 'Aider', opencode: 'OpenCode', codex: 'OpenAI Codex', + 'factory-droid': 'Factory Droid', claude: 'Claude', terminal: 'Terminal', }; diff --git a/src/renderer/utils/contextUsage.ts b/src/renderer/utils/contextUsage.ts index 1b150ddb..193f7d16 100644 --- a/src/renderer/utils/contextUsage.ts +++ b/src/renderer/utils/contextUsage.ts @@ -18,6 +18,7 @@ export const DEFAULT_CONTEXT_WINDOWS: Record = { codex: 200000, // OpenAI o3/o4-mini context window opencode: 128000, // OpenCode (depends on model, 128k is conservative default) aider: 128000, // Aider (varies by model, 128k is conservative default) + 'factory-droid': 200000, // Factory Droid (varies by model, defaults to Claude Opus) terminal: 0, // Terminal has no context window }; diff --git a/src/renderer/utils/sessionValidation.ts b/src/renderer/utils/sessionValidation.ts index d08133e4..978f73f6 100644 --- a/src/renderer/utils/sessionValidation.ts +++ b/src/renderer/utils/sessionValidation.ts @@ -114,6 +114,7 @@ export function getProviderDisplayName(toolType: ToolType): string { aider: 'Aider', opencode: 'OpenCode', codex: 'Codex', + 'factory-droid': 'Factory Droid', terminal: 'Terminal', }; return displayNames[toolType] || toolType; diff --git a/src/shared/types.ts b/src/shared/types.ts index 1048f1a0..5854d0f5 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -1,7 +1,7 @@ // Shared type definitions for Maestro CLI and Electron app // These types are used by both the CLI tool and the renderer process -export type ToolType = 'claude' | 'claude-code' | 'aider' | 'opencode' | 'codex' | 'terminal'; +export type ToolType = 'claude' | 'claude-code' | 'aider' | 'opencode' | 'codex' | 'terminal' | 'factory-droid'; // Session group export interface Group {