From 164acc1b4e989ae4c76a2393f74d38fafe0dd16e Mon Sep 17 00:00:00 2001 From: DhanushSantosh Date: Thu, 15 Jan 2026 19:38:18 +0530 Subject: [PATCH 01/93] chore: update package-lock.json --- package-lock.json | 91 ++++++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0d26140a..25445b96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -680,7 +680,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", @@ -1273,7 +1272,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.4.tgz", "integrity": "sha512-xMF6OfEAUVY5Waega4juo1QGACfNkNF+aJLqpd8oUJz96ms2zbfQ9Gh35/tI3y8akEV31FruKfj7hBnIU/nkqA==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", @@ -1316,7 +1314,6 @@ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", "license": "MIT", - "peer": true, "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", @@ -2137,6 +2134,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -2158,6 +2156,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -2174,6 +2173,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -2188,6 +2188,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -2955,6 +2956,7 @@ "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -3079,6 +3081,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -3095,6 +3098,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -3111,6 +3115,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -3219,6 +3224,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3241,6 +3247,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3263,6 +3270,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3348,6 +3356,7 @@ ], "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, + "peer": true, "dependencies": { "@emnapi/runtime": "^1.7.0" }, @@ -3370,6 +3379,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3389,6 +3399,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3788,7 +3799,8 @@ "version": "16.0.10", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz", "integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@next/swc-darwin-arm64": { "version": "16.0.10", @@ -3802,6 +3814,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 10" } @@ -3818,6 +3831,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 10" } @@ -3834,6 +3848,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -3850,6 +3865,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -3866,6 +3882,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -3882,6 +3899,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10" } @@ -3898,6 +3916,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10" } @@ -3914,6 +3933,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10" } @@ -4013,7 +4033,6 @@ "integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "playwright": "1.57.0" }, @@ -5485,6 +5504,7 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.8.0" } @@ -5818,7 +5838,6 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.141.6.tgz", "integrity": "sha512-qWFxi2D6eGc1L03RzUuhyEOplZ7Q6q62YOl7Of9Y0q4YjwQwxRm4zxwDVtvUIoy4RLVCpqp5UoE+Nxv2PY9trg==", "license": "MIT", - "peer": true, "dependencies": { "@tanstack/history": "1.141.0", "@tanstack/react-store": "^0.8.0", @@ -6245,7 +6264,6 @@ "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -6388,7 +6406,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -6399,7 +6416,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -6505,7 +6521,6 @@ "integrity": "sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.50.0", "@typescript-eslint/types": "8.50.0", @@ -6999,8 +7014,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@xyflow/react": { "version": "12.10.0", @@ -7098,7 +7112,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7159,7 +7172,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", @@ -7758,7 +7770,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -8290,7 +8301,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cliui": { "version": "8.0.1", @@ -8595,7 +8607,8 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cross-env": { "version": "10.1.0", @@ -8692,7 +8705,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" } @@ -8994,7 +9006,6 @@ "integrity": "sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "26.0.12", "builder-util": "26.0.11", @@ -9321,6 +9332,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -9341,6 +9353,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -9591,7 +9604,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", @@ -9906,7 +9918,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -11574,6 +11585,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11639,6 +11651,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14080,6 +14093,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -14096,6 +14110,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -14113,6 +14128,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -14301,7 +14317,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -14311,7 +14326,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -14670,6 +14684,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -14858,7 +14873,6 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.0.tgz", "integrity": "sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -14907,6 +14921,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "optional": true, + "peer": true, "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", @@ -14957,6 +14972,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -14979,6 +14995,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15001,6 +15018,7 @@ "os": [ "darwin" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15017,6 +15035,7 @@ "os": [ "darwin" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15033,6 +15052,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15049,6 +15069,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15065,6 +15086,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15081,6 +15103,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15097,6 +15120,7 @@ "os": [ "linux" ], + "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15113,6 +15137,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15135,6 +15160,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15157,6 +15183,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15179,6 +15206,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15201,6 +15229,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15223,6 +15252,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15691,6 +15721,7 @@ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", "license": "MIT", + "peer": true, "dependencies": { "client-only": "0.0.1" }, @@ -15860,6 +15891,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -15923,6 +15955,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -16020,7 +16053,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -16225,7 +16257,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16597,7 +16628,6 @@ "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -16687,8 +16717,7 @@ "resolved": "https://registry.npmjs.org/vite-plugin-electron-renderer/-/vite-plugin-electron-renderer-0.14.6.tgz", "integrity": "sha512-oqkWFa7kQIkvHXG7+Mnl1RTroA4sP0yesKatmAy0gjZC4VwUqlvF9IvOpHd1fpLWsqYX/eZlVxlhULNtaQ78Jw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/vite/node_modules/fdir": { "version": "6.5.0", @@ -16714,7 +16743,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -16757,7 +16785,6 @@ "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.16", "@vitest/mocker": "4.0.16", @@ -17015,7 +17042,6 @@ "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -17084,7 +17110,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz", "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } From c585cee12f3b3e3bd357badc4ca8385857121516 Mon Sep 17 00:00:00 2001 From: DhanushSantosh Date: Thu, 15 Jan 2026 21:05:35 +0530 Subject: [PATCH 02/93] feat: add dynamic usage status icon and tab-aware updates to usage button - Add provider icon (Anthropic/OpenAI) that displays based on active tab - Icon color reflects usage status (green/orange/red) - Progress bar and stale indicator update dynamically when switching tabs - Shows Claude metrics when Claude tab is active, Codex metrics when Codex tab is active Co-Authored-By: Claude Haiku 4.5 --- apps/ui/src/components/usage-popover.tsx | 32 +++++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/ui/src/components/usage-popover.tsx b/apps/ui/src/components/usage-popover.tsx index fa8a6a1b..ac15a519 100644 --- a/apps/ui/src/components/usage-popover.tsx +++ b/apps/ui/src/components/usage-popover.tsx @@ -333,19 +333,43 @@ export function UsagePopover() { return 'bg-green-500'; }; + // Determine which provider icon and percentage to show based on active tab + const getTabInfo = () => { + if (activeTab === 'claude') { + return { + icon: AnthropicIcon, + percentage: claudeMaxPercentage, + isStale: isClaudeStale, + }; + } + return { + icon: OpenAIIcon, + percentage: codexMaxPercentage, + isStale: isCodexStale, + }; + }; + + const tabInfo = getTabInfo(); + const statusColor = getStatusInfo(tabInfo.percentage).color; + const ProviderIcon = tabInfo.icon; + const trigger = ( - + {mode === 'backlog' && ( + <> + - + + + )} + + {mode === 'waiting_approval' && ( + + )} {!allSelected && ( + + + + ); } diff --git a/apps/ui/src/components/views/board-view/hooks/index.ts b/apps/ui/src/components/views/board-view/hooks/index.ts index 72e45677..c4c61a14 100644 --- a/apps/ui/src/components/views/board-view/hooks/index.ts +++ b/apps/ui/src/components/views/board-view/hooks/index.ts @@ -7,5 +7,5 @@ export { useBoardEffects } from './use-board-effects'; export { useBoardBackground } from './use-board-background'; export { useBoardPersistence } from './use-board-persistence'; export { useFollowUpState } from './use-follow-up-state'; -export { useSelectionMode } from './use-selection-mode'; +export { useSelectionMode, type SelectionTarget } from './use-selection-mode'; export { useListViewState } from './use-list-view-state'; diff --git a/apps/ui/src/components/views/board-view/hooks/use-selection-mode.ts b/apps/ui/src/components/views/board-view/hooks/use-selection-mode.ts index 1470f447..e81dca10 100644 --- a/apps/ui/src/components/views/board-view/hooks/use-selection-mode.ts +++ b/apps/ui/src/components/views/board-view/hooks/use-selection-mode.ts @@ -1,10 +1,13 @@ import { useState, useCallback, useEffect } from 'react'; +export type SelectionTarget = 'backlog' | 'waiting_approval' | null; + interface UseSelectionModeReturn { isSelectionMode: boolean; + selectionTarget: SelectionTarget; selectedFeatureIds: Set; selectedCount: number; - toggleSelectionMode: () => void; + toggleSelectionMode: (target?: SelectionTarget) => void; toggleFeatureSelection: (featureId: string) => void; selectAll: (featureIds: string[]) => void; clearSelection: () => void; @@ -13,21 +16,26 @@ interface UseSelectionModeReturn { } export function useSelectionMode(): UseSelectionModeReturn { - const [isSelectionMode, setIsSelectionMode] = useState(false); + const [selectionTarget, setSelectionTarget] = useState(null); const [selectedFeatureIds, setSelectedFeatureIds] = useState>(new Set()); - const toggleSelectionMode = useCallback(() => { - setIsSelectionMode((prev) => { - if (prev) { + const isSelectionMode = selectionTarget !== null; + + const toggleSelectionMode = useCallback((target: SelectionTarget = 'backlog') => { + setSelectionTarget((prev) => { + if (prev === target) { // Exiting selection mode - clear selection setSelectedFeatureIds(new Set()); + return null; } - return !prev; + // Switching to a different target or entering selection mode + setSelectedFeatureIds(new Set()); + return target; }); }, []); const exitSelectionMode = useCallback(() => { - setIsSelectionMode(false); + setSelectionTarget(null); setSelectedFeatureIds(new Set()); }, []); @@ -70,6 +78,7 @@ export function useSelectionMode(): UseSelectionModeReturn { return { isSelectionMode, + selectionTarget, selectedFeatureIds, selectedCount: selectedFeatureIds.size, toggleSelectionMode, diff --git a/apps/ui/src/components/views/board-view/kanban-board.tsx b/apps/ui/src/components/views/board-view/kanban-board.tsx index c670ab70..6ace0e76 100644 --- a/apps/ui/src/components/views/board-view/kanban-board.tsx +++ b/apps/ui/src/components/views/board-view/kanban-board.tsx @@ -50,9 +50,10 @@ interface KanbanBoardProps { onOpenPipelineSettings?: () => void; // Selection mode props isSelectionMode?: boolean; + selectionTarget?: 'backlog' | 'waiting_approval' | null; selectedFeatureIds?: Set; onToggleFeatureSelection?: (featureId: string) => void; - onToggleSelectionMode?: () => void; + onToggleSelectionMode?: (target?: 'backlog' | 'waiting_approval') => void; // Empty state action props onAiSuggest?: () => void; /** Whether currently dragging (hides empty states during drag) */ @@ -95,6 +96,7 @@ export function KanbanBoard({ pipelineConfig, onOpenPipelineSettings, isSelectionMode = false, + selectionTarget = null, selectedFeatureIds = new Set(), onToggleFeatureSelection, onToggleSelectionMode, @@ -189,12 +191,14 @@ export function KanbanBoard({ + ) : column.id === 'waiting_approval' ? ( + ) : column.id === 'in_progress' ? ( + + +
+ + updatePrompt('titleGeneration', 'systemPrompt', value) + } + /> +
+ + + {/* Issue Validation Tab */} + +
+

Issue Validation Prompts

+ +
+ + {/* Critical Warning for Issue Validation */} +
+ +
+

Warning: Critical Prompt

+

+ The issue validation prompt guides the AI through a structured validation process + and expects specific output format. Modifying this prompt incorrectly may affect + validation accuracy. +

+
+
+ +
+ + updatePrompt('issueValidation', 'systemPrompt', value) + } + critical={true} + /> +
+
+ + {/* Ideation Tab */} + +
+

Ideation Prompts

+ +
+ +
+ + updatePrompt('ideation', 'ideationSystemPrompt', value) + } + /> + + + updatePrompt('ideation', 'suggestionsSystemPrompt', value) + } + critical={true} + /> +
+
+ + {/* App Spec Tab */} + +
+

App Specification Prompts

+ +
+ +
+ + updatePrompt('appSpec', 'generateSpecSystemPrompt', value) + } + /> + + + updatePrompt('appSpec', 'structuredSpecInstructions', value) + } + critical={true} + /> + + + updatePrompt('appSpec', 'generateFeaturesFromSpecPrompt', value) + } + critical={true} + /> +
+
+ + {/* Context Description Tab */} + +
+

Context Description Prompts

+ +
+ +
+ + updatePrompt('contextDescription', 'describeFilePrompt', value) + } + /> + + + updatePrompt('contextDescription', 'describeImagePrompt', value) + } + /> +
+
+ + {/* Suggestions Tab */} + +
+

Suggestions Prompts

+ +
+ +
+ + updatePrompt('suggestions', 'featuresPrompt', value) + } + /> + + + updatePrompt('suggestions', 'refactoringPrompt', value) + } + /> + + + updatePrompt('suggestions', 'securityPrompt', value) + } + /> + + + updatePrompt('suggestions', 'performancePrompt', value) + } + /> + + updatePrompt('suggestions', 'baseTemplate', value)} + /> +
+
+ + {/* Task Execution Tab */} + +
+

Task Execution Prompts

+ +
+ + {/* Info Banner for Task Execution */} +
+ +
+

Template Variables

+

+ Task execution prompts use Handlebars syntax for variable substitution. Variables + include{' '} + {'{{taskId}}'},{' '} + + {'{{taskDescription}}'} + + ,{' '} + + {'{{completedTasks}}'} + + , etc. +

+
+
+ +
+ + updatePrompt('taskExecution', 'taskPromptTemplate', value) + } + /> + + + updatePrompt('taskExecution', 'implementationInstructions', value) + } + /> + + + updatePrompt('taskExecution', 'playwrightVerificationInstructions', value) + } + /> + + + updatePrompt('taskExecution', 'learningExtractionSystemPrompt', value) + } + critical={true} + /> + + + updatePrompt('taskExecution', 'learningExtractionUserPromptTemplate', value) + } + critical={true} + /> + + + updatePrompt('taskExecution', 'planRevisionTemplate', value) + } + /> + + + updatePrompt('taskExecution', 'continuationAfterApprovalTemplate', value) + } + /> + + + updatePrompt('taskExecution', 'resumeFeatureTemplate', value) + } + /> + + + updatePrompt('taskExecution', 'projectAnalysisPrompt', value) + } + /> +
+
diff --git a/libs/prompts/src/defaults.ts b/libs/prompts/src/defaults.ts index dfa2ee15..9d6aeaa2 100644 --- a/libs/prompts/src/defaults.ts +++ b/libs/prompts/src/defaults.ts @@ -16,6 +16,9 @@ import type { ResolvedBacklogPlanPrompts, ResolvedEnhancementPrompts, ResolvedCommitMessagePrompts, + ResolvedTitleGenerationPrompts, + ResolvedIssueValidationPrompts, + ResolvedIdeationPrompts, } from '@automaker/types'; import { STATIC_PORT, SERVER_PORT } from '@automaker/types'; @@ -464,6 +467,482 @@ export const DEFAULT_COMMIT_MESSAGE_PROMPTS: ResolvedCommitMessagePrompts = { systemPrompt: DEFAULT_COMMIT_MESSAGE_SYSTEM_PROMPT, }; +/** + * ======================================================================== + * TITLE GENERATION PROMPTS + * ======================================================================== + */ + +export const DEFAULT_TITLE_GENERATION_SYSTEM_PROMPT = `You are a title generator. Your task is to create a concise, descriptive title (5-10 words max) for a software feature based on its description. + +Rules: +- Output ONLY the title, nothing else +- Keep it short and action-oriented (e.g., "Add dark mode toggle", "Fix login validation") +- Start with a verb when possible (Add, Fix, Update, Implement, Create, etc.) +- No quotes, periods, or extra formatting +- Capture the essence of the feature in a scannable way`; + +/** + * Default Title Generation prompts (for AI feature title generation) + */ +export const DEFAULT_TITLE_GENERATION_PROMPTS: ResolvedTitleGenerationPrompts = { + systemPrompt: DEFAULT_TITLE_GENERATION_SYSTEM_PROMPT, +}; + +/** + * ======================================================================== + * ISSUE VALIDATION PROMPTS + * ======================================================================== + */ + +export const DEFAULT_ISSUE_VALIDATION_SYSTEM_PROMPT = `You are an expert code analyst validating GitHub issues against a codebase. + +Your task is to analyze a GitHub issue and determine if it's valid by scanning the codebase. + +## Validation Process + +1. **Read the issue carefully** - Understand what is being reported or requested +2. **Search the codebase** - Use Glob to find relevant files by pattern, Grep to search for keywords +3. **Examine the code** - Use Read to look at the actual implementation in relevant files +4. **Check linked PRs** - If there are linked pull requests, use \`gh pr diff \` to review the changes +5. **Form your verdict** - Based on your analysis, determine if the issue is valid + +## Verdicts + +- **valid**: The issue describes a real problem that exists in the codebase, or a clear feature request that can be implemented. The referenced files/components exist and the issue is actionable. + +- **invalid**: The issue describes behavior that doesn't exist, references non-existent files or components, is based on a misunderstanding of the code, or the described "bug" is actually expected behavior. + +- **needs_clarification**: The issue lacks sufficient detail to verify. Specify what additional information is needed in the missingInfo field. + +## For Bug Reports, Check: +- Do the referenced files/components exist? +- Does the code match what the issue describes? +- Is the described behavior actually a bug or expected? +- Can you locate the code that would cause the reported issue? + +## For Feature Requests, Check: +- Does the feature already exist? +- Is the implementation location clear? +- Is the request technically feasible given the codebase structure? + +## Analyzing Linked Pull Requests + +When an issue has linked PRs (especially open ones), you MUST analyze them: + +1. **Run \`gh pr diff \`** to see what changes the PR makes +2. **Run \`gh pr view \`** to see PR description and status +3. **Evaluate if the PR fixes the issue** - Does the diff address the reported problem? +4. **Provide a recommendation**: + - \`wait_for_merge\`: The PR appears to fix the issue correctly. No additional work needed - just wait for it to be merged. + - \`pr_needs_work\`: The PR attempts to fix the issue but is incomplete or has problems. + - \`no_pr\`: No relevant PR exists for this issue. + +5. **Include prAnalysis in your response** with: + - hasOpenPR: true/false + - prFixesIssue: true/false (based on diff analysis) + - prNumber: the PR number you analyzed + - prSummary: brief description of what the PR changes + - recommendation: one of the above values + +## Response Guidelines + +- **Always include relatedFiles** when you find relevant code +- **Set bugConfirmed to true** only if you can definitively confirm a bug exists in the code +- **Provide a suggestedFix** when you have a clear idea of how to address the issue +- **Use missingInfo** when the verdict is needs_clarification to list what's needed +- **Include prAnalysis** when there are linked PRs - this is critical for avoiding duplicate work +- **Set estimatedComplexity** to help prioritize: + - trivial: Simple text changes, one-line fixes + - simple: Small changes to one file + - moderate: Changes to multiple files or moderate logic changes + - complex: Significant refactoring or new feature implementation + - very_complex: Major architectural changes or cross-cutting concerns + +Be thorough in your analysis but focus on files that are directly relevant to the issue.`; + +/** + * Default Issue Validation prompts (for GitHub issue validation) + */ +export const DEFAULT_ISSUE_VALIDATION_PROMPTS: ResolvedIssueValidationPrompts = { + systemPrompt: DEFAULT_ISSUE_VALIDATION_SYSTEM_PROMPT, +}; + +/** + * ======================================================================== + * IDEATION PROMPTS + * ======================================================================== + */ + +export const DEFAULT_IDEATION_SYSTEM_PROMPT = `You are an AI product strategist and UX expert helping brainstorm ideas for improving a software project. + +Your role is to: +- Analyze the codebase structure and patterns +- Identify opportunities for improvement +- Suggest actionable ideas with clear rationale +- Consider user experience, technical feasibility, and business value +- Be specific and reference actual files/components when possible + +When suggesting ideas: +1. Provide a clear, concise title +2. Explain the problem or opportunity +3. Describe the proposed solution +4. Highlight the expected benefit +5. Note any dependencies or considerations + +IMPORTANT: Do NOT suggest features or ideas that already exist in the project. Check the "Existing Features" and "Existing Ideas" sections below to avoid duplicates. + +Focus on practical, implementable suggestions that would genuinely improve the product.`; + +export const DEFAULT_SUGGESTIONS_SYSTEM_PROMPT = `You are an AI product strategist helping brainstorm feature ideas for a software project. + +IMPORTANT: You do NOT have access to any tools. You CANNOT read files, search code, or run commands. +You must generate suggestions based ONLY on the project context provided below. +Do NOT say "I'll analyze" or "Let me explore" - you cannot do those things. + +Based on the project context and the user's prompt, generate creative and actionable feature suggestions. + +YOUR RESPONSE MUST BE ONLY A JSON ARRAY - nothing else. No explanation, no preamble, no markdown code fences. + +Each suggestion must have this structure: +{ + "title": "Short, actionable title (max 60 chars)", + "description": "Clear description of what to build or improve (2-3 sentences)", + "rationale": "Why this is valuable - the problem it solves or opportunity it creates", + "priority": "high" | "medium" | "low" +} + +Guidelines: +- Be specific and actionable - avoid vague ideas +- Mix different priority levels (some high, some medium, some low) +- Each suggestion should be independently implementable +- Think creatively - include both obvious improvements and innovative ideas +- Consider the project's domain and target users +- IMPORTANT: Do NOT suggest features or ideas that already exist in the "Existing Features" or "Existing Ideas" sections below`; + +/** + * Default Ideation prompts (for AI-powered brainstorming and suggestions) + */ +export const DEFAULT_IDEATION_PROMPTS: ResolvedIdeationPrompts = { + ideationSystemPrompt: DEFAULT_IDEATION_SYSTEM_PROMPT, + suggestionsSystemPrompt: DEFAULT_SUGGESTIONS_SYSTEM_PROMPT, +}; + +/** + * ======================================================================== + * APP SPEC PROMPTS + * ======================================================================== + */ + +export const DEFAULT_APP_SPEC_GENERATE_SYSTEM_PROMPT = `You are helping to define a software project specification. + +IMPORTANT: Never ask for clarification or additional information. Use the information provided and make reasonable assumptions to create the best possible specification. If details are missing, infer them based on common patterns and best practices.`; + +export const DEFAULT_APP_SPEC_STRUCTURED_INSTRUCTIONS = `Analyze the project and provide a comprehensive specification with: + +1. **project_name**: The name of the project +2. **overview**: A comprehensive description of what the project does, its purpose, and key goals +3. **technology_stack**: List all technologies, frameworks, libraries, and tools used +4. **core_capabilities**: List the main features and capabilities the project provides +5. **implemented_features**: For each implemented feature, provide: + - name: Feature name + - description: What it does + - file_locations: Key files where it's implemented (optional) +6. **additional_requirements**: Any system requirements, dependencies, or constraints (optional) +7. **development_guidelines**: Development standards and best practices (optional) +8. **implementation_roadmap**: Project phases with status (completed/in_progress/pending) (optional) + +Be thorough in your analysis. The output will be automatically formatted as structured JSON.`; + +export const DEFAULT_GENERATE_FEATURES_FROM_SPEC_PROMPT = `Generate a prioritized list of implementable features. For each feature provide: + +1. **id**: A unique lowercase-hyphenated identifier +2. **category**: Functional category (e.g., "Core", "UI", "API", "Authentication", "Database") +3. **title**: Short descriptive title +4. **description**: What this feature does (2-3 sentences) +5. **priority**: 1 (high), 2 (medium), or 3 (low) +6. **complexity**: "simple", "moderate", or "complex" +7. **dependencies**: Array of feature IDs this depends on (can be empty) + +Format as JSON: +{ + "features": [ + { + "id": "feature-id", + "category": "Feature Category", + "title": "Feature Title", + "description": "What it does", + "priority": 1, + "complexity": "moderate", + "dependencies": [] + } + ] +} + +Generate features that build on each other logically. + +IMPORTANT: Do not ask for clarification. The specification is provided above. Generate the JSON immediately.`; + +/** + * Default App Spec prompts (for project specification generation) + */ +export const DEFAULT_APP_SPEC_PROMPTS: import('@automaker/types').ResolvedAppSpecPrompts = { + generateSpecSystemPrompt: DEFAULT_APP_SPEC_GENERATE_SYSTEM_PROMPT, + structuredSpecInstructions: DEFAULT_APP_SPEC_STRUCTURED_INSTRUCTIONS, + generateFeaturesFromSpecPrompt: DEFAULT_GENERATE_FEATURES_FROM_SPEC_PROMPT, +}; + +/** + * ======================================================================== + * CONTEXT DESCRIPTION PROMPTS + * ======================================================================== + */ + +export const DEFAULT_DESCRIBE_FILE_PROMPT = `Analyze the following file and provide a 1-2 sentence description suitable for use as context in an AI coding assistant. Focus on what the file contains, its purpose, and why an AI agent might want to use this context in the future (e.g., "API documentation for the authentication endpoints", "Configuration file for database connections", "Coding style guidelines for the project"). + +Respond with ONLY the description text, no additional formatting, preamble, or explanation.`; + +export const DEFAULT_DESCRIBE_IMAGE_PROMPT = `Describe this image in 1-2 sentences suitable for use as context in an AI coding assistant. Focus on what the image shows and its purpose (e.g., "UI mockup showing login form with email/password fields", "Architecture diagram of microservices", "Screenshot of error message in terminal"). + +Respond with ONLY the description text, no additional formatting, preamble, or explanation.`; + +/** + * Default Context Description prompts (for file/image descriptions) + */ +export const DEFAULT_CONTEXT_DESCRIPTION_PROMPTS: import('@automaker/types').ResolvedContextDescriptionPrompts = + { + describeFilePrompt: DEFAULT_DESCRIBE_FILE_PROMPT, + describeImagePrompt: DEFAULT_DESCRIBE_IMAGE_PROMPT, + }; + +/** + * ======================================================================== + * SUGGESTIONS PROMPTS + * ======================================================================== + */ + +export const DEFAULT_SUGGESTIONS_FEATURES_PROMPT = + 'Analyze this project and suggest new features that would add value.'; +export const DEFAULT_SUGGESTIONS_REFACTORING_PROMPT = + 'Analyze this project and identify refactoring opportunities.'; +export const DEFAULT_SUGGESTIONS_SECURITY_PROMPT = + 'Analyze this project for security vulnerabilities and suggest fixes.'; +export const DEFAULT_SUGGESTIONS_PERFORMANCE_PROMPT = + 'Analyze this project for performance issues and suggest optimizations.'; + +export const DEFAULT_SUGGESTIONS_BASE_TEMPLATE = `Look at the codebase and provide 3-5 concrete suggestions. + +For each suggestion, provide: +1. A category (e.g., "User Experience", "Security", "Performance") +2. A clear description of what to implement +3. Priority (1=high, 2=medium, 3=low) +4. Brief reasoning for why this would help + +The response will be automatically formatted as structured JSON.`; + +/** + * Default Suggestions prompts (for features, refactoring, security, performance) + */ +export const DEFAULT_SUGGESTIONS_PROMPTS: import('@automaker/types').ResolvedSuggestionsPrompts = { + featuresPrompt: DEFAULT_SUGGESTIONS_FEATURES_PROMPT, + refactoringPrompt: DEFAULT_SUGGESTIONS_REFACTORING_PROMPT, + securityPrompt: DEFAULT_SUGGESTIONS_SECURITY_PROMPT, + performancePrompt: DEFAULT_SUGGESTIONS_PERFORMANCE_PROMPT, + baseTemplate: DEFAULT_SUGGESTIONS_BASE_TEMPLATE, +}; + +/** + * ======================================================================== + * TASK EXECUTION PROMPTS + * ======================================================================== + */ + +export const DEFAULT_TASK_PROMPT_TEMPLATE = `# Task Execution: {{taskId}} + +You are executing a specific task as part of a larger feature implementation. + +## Your Current Task + +**Task ID:** {{taskId}} +**Description:** {{taskDescription}} +{{#if filePath}}**Primary File:** {{filePath}}{{/if}} +{{#if phase}}**Phase:** {{phase}}{{/if}} + +## Context + +{{#if completedTasks}} +### Already Completed ({{completedTasksCount}} tasks) +{{#each completedTasks}} +- [x] {{id}}: {{description}} +{{/each}} +{{/if}} + +{{#if remainingTasks}} +### Remaining Tasks ({{remainingTasksCount}} tasks) +{{#each remainingTasks}} +- [ ] {{id}}: {{description}} +{{/each}} +{{/if}} + +{{#if userFeedback}} +## User Feedback +{{userFeedback}} +{{/if}} + +## Instructions + +1. Focus ONLY on completing task {{taskId}}: "{{taskDescription}}" +2. Do not work on other tasks +3. Use the existing codebase patterns +4. When done, summarize what you implemented + +Begin implementing task {{taskId}} now.`; + +export const DEFAULT_IMPLEMENTATION_INSTRUCTIONS = `## Instructions + +Implement this feature by: +1. First, explore the codebase to understand the existing structure +2. Plan your implementation approach +3. Write the necessary code changes +4. Ensure the code follows existing patterns and conventions + +When done, wrap your final summary in tags like this: + + +## Summary: [Feature Title] + +### Changes Implemented +- [List of changes made] + +### Files Modified +- [List of files] + +### Notes for Developer +- [Any important notes] + + +This helps parse your summary correctly in the output logs.`; + +export const DEFAULT_PLAYWRIGHT_VERIFICATION_INSTRUCTIONS = `## Verification with Playwright (REQUIRED) + +After implementing the feature, you MUST verify it works correctly using Playwright: + +1. **Create a temporary Playwright test** to verify the feature works as expected +2. **Run the test** to confirm the feature is working +3. **Delete the test file** after verification - this is a temporary verification test, not a permanent test suite addition + +Example verification workflow: +\`\`\`bash +# Create a simple verification test +npx playwright test my-verification-test.spec.ts + +# After successful verification, delete the test +rm my-verification-test.spec.ts +\`\`\` + +The test should verify the core functionality of the feature. If the test fails, fix the implementation and re-test. + +When done, include in your summary: + +### Verification Status +- [Describe how the feature was verified with Playwright]`; + +export const DEFAULT_LEARNING_EXTRACTION_SYSTEM_PROMPT = + 'You are a JSON extraction assistant. You MUST respond with ONLY valid JSON, no explanations, no markdown, no other text. Extract learnings from the provided implementation context and return them as JSON.'; + +export const DEFAULT_LEARNING_EXTRACTION_USER_TEMPLATE = `You are an Architecture Decision Record (ADR) extractor. Analyze this implementation and return ONLY JSON with learnings. No explanations. + +Feature: "{{featureTitle}}" + +Implementation log: +{{implementationLog}} + +Extract MEANINGFUL learnings - not obvious things. For each, capture: +- DECISIONS: Why this approach vs alternatives? What would break if changed? +- GOTCHAS: What was unexpected? What's the root cause? How to avoid? +- PATTERNS: Why this pattern? What problem does it solve? Trade-offs? + +JSON format ONLY (no markdown, no text): +{"learnings": [{ + "category": "architecture|api|ui|database|auth|testing|performance|security|gotchas", + "type": "decision|gotcha|pattern", + "content": "What was done/learned", + "context": "Problem being solved or situation faced", + "why": "Reasoning - why this approach", + "rejected": "Alternative considered and why rejected", + "tradeoffs": "What became easier/harder", + "breaking": "What breaks if this is changed/removed" +}]} + +IMPORTANT: Only include NON-OBVIOUS learnings with real reasoning. Skip trivial patterns. +If nothing notable: {"learnings": []}`; + +export const DEFAULT_PLAN_REVISION_TEMPLATE = `The user has requested revisions to the plan/specification. + +## Previous Plan (v{{planVersion}}) +{{previousPlan}} + +## User Feedback +{{userFeedback}} + +## Instructions +Please regenerate the specification incorporating the user's feedback. +Keep the same format with the \`\`\`tasks block for task definitions. +After generating the revised spec, output: +"[SPEC_GENERATED] Please review the revised specification above."`; + +export const DEFAULT_CONTINUATION_AFTER_APPROVAL_TEMPLATE = `The plan/specification has been approved. Now implement it. +{{#if userFeedback}} + +## User Feedback +{{userFeedback}} +{{/if}} + +## Approved Plan + +{{approvedPlan}} + +## Instructions + +Implement all the changes described in the plan above.`; + +export const DEFAULT_RESUME_FEATURE_TEMPLATE = `## Continuing Feature Implementation + +{{featurePrompt}} + +## Previous Context +The following is the output from a previous implementation attempt. Continue from where you left off: + +{{previousContext}} + +## Instructions +Review the previous work and continue the implementation. If the feature appears complete, verify it works correctly.`; + +export const DEFAULT_PROJECT_ANALYSIS_PROMPT = `Analyze this project and provide a summary of: +1. Project structure and architecture +2. Main technologies and frameworks used +3. Key components and their responsibilities +4. Build and test commands +5. Any existing conventions or patterns + +Format your response as a structured markdown document.`; + +/** + * Default Task Execution prompts (for Auto Mode task execution, learning extraction) + */ +export const DEFAULT_TASK_EXECUTION_PROMPTS: import('@automaker/types').ResolvedTaskExecutionPrompts = + { + taskPromptTemplate: DEFAULT_TASK_PROMPT_TEMPLATE, + implementationInstructions: DEFAULT_IMPLEMENTATION_INSTRUCTIONS, + playwrightVerificationInstructions: DEFAULT_PLAYWRIGHT_VERIFICATION_INSTRUCTIONS, + learningExtractionSystemPrompt: DEFAULT_LEARNING_EXTRACTION_SYSTEM_PROMPT, + learningExtractionUserPromptTemplate: DEFAULT_LEARNING_EXTRACTION_USER_TEMPLATE, + planRevisionTemplate: DEFAULT_PLAN_REVISION_TEMPLATE, + continuationAfterApprovalTemplate: DEFAULT_CONTINUATION_AFTER_APPROVAL_TEMPLATE, + resumeFeatureTemplate: DEFAULT_RESUME_FEATURE_TEMPLATE, + projectAnalysisPrompt: DEFAULT_PROJECT_ANALYSIS_PROMPT, + }; + /** * ======================================================================== * COMBINED DEFAULTS @@ -479,4 +958,11 @@ export const DEFAULT_PROMPTS = { backlogPlan: DEFAULT_BACKLOG_PLAN_PROMPTS, enhancement: DEFAULT_ENHANCEMENT_PROMPTS, commitMessage: DEFAULT_COMMIT_MESSAGE_PROMPTS, + titleGeneration: DEFAULT_TITLE_GENERATION_PROMPTS, + issueValidation: DEFAULT_ISSUE_VALIDATION_PROMPTS, + ideation: DEFAULT_IDEATION_PROMPTS, + appSpec: DEFAULT_APP_SPEC_PROMPTS, + contextDescription: DEFAULT_CONTEXT_DESCRIPTION_PROMPTS, + suggestions: DEFAULT_SUGGESTIONS_PROMPTS, + taskExecution: DEFAULT_TASK_EXECUTION_PROMPTS, } as const; diff --git a/libs/prompts/src/index.ts b/libs/prompts/src/index.ts index 4eae4347..4465599a 100644 --- a/libs/prompts/src/index.ts +++ b/libs/prompts/src/index.ts @@ -43,6 +43,40 @@ export { DEFAULT_ENHANCEMENT_PROMPTS, DEFAULT_COMMIT_MESSAGE_SYSTEM_PROMPT, DEFAULT_COMMIT_MESSAGE_PROMPTS, + DEFAULT_TITLE_GENERATION_SYSTEM_PROMPT, + DEFAULT_TITLE_GENERATION_PROMPTS, + DEFAULT_ISSUE_VALIDATION_SYSTEM_PROMPT, + DEFAULT_ISSUE_VALIDATION_PROMPTS, + DEFAULT_IDEATION_SYSTEM_PROMPT, + DEFAULT_SUGGESTIONS_SYSTEM_PROMPT, + DEFAULT_IDEATION_PROMPTS, + // App Spec prompts + DEFAULT_APP_SPEC_GENERATE_SYSTEM_PROMPT, + DEFAULT_APP_SPEC_STRUCTURED_INSTRUCTIONS, + DEFAULT_GENERATE_FEATURES_FROM_SPEC_PROMPT, + DEFAULT_APP_SPEC_PROMPTS, + // Context Description prompts + DEFAULT_DESCRIBE_FILE_PROMPT, + DEFAULT_DESCRIBE_IMAGE_PROMPT, + DEFAULT_CONTEXT_DESCRIPTION_PROMPTS, + // Suggestions prompts + DEFAULT_SUGGESTIONS_FEATURES_PROMPT, + DEFAULT_SUGGESTIONS_REFACTORING_PROMPT, + DEFAULT_SUGGESTIONS_SECURITY_PROMPT, + DEFAULT_SUGGESTIONS_PERFORMANCE_PROMPT, + DEFAULT_SUGGESTIONS_BASE_TEMPLATE, + DEFAULT_SUGGESTIONS_PROMPTS, + // Task Execution prompts + DEFAULT_TASK_PROMPT_TEMPLATE, + DEFAULT_IMPLEMENTATION_INSTRUCTIONS, + DEFAULT_PLAYWRIGHT_VERIFICATION_INSTRUCTIONS, + DEFAULT_LEARNING_EXTRACTION_SYSTEM_PROMPT, + DEFAULT_LEARNING_EXTRACTION_USER_TEMPLATE, + DEFAULT_PLAN_REVISION_TEMPLATE, + DEFAULT_CONTINUATION_AFTER_APPROVAL_TEMPLATE, + DEFAULT_RESUME_FEATURE_TEMPLATE, + DEFAULT_PROJECT_ANALYSIS_PROMPT, + DEFAULT_TASK_EXECUTION_PROMPTS, DEFAULT_PROMPTS, } from './defaults.js'; @@ -53,6 +87,13 @@ export { mergeBacklogPlanPrompts, mergeEnhancementPrompts, mergeCommitMessagePrompts, + mergeTitleGenerationPrompts, + mergeIssueValidationPrompts, + mergeIdeationPrompts, + mergeAppSpecPrompts, + mergeContextDescriptionPrompts, + mergeSuggestionsPrompts, + mergeTaskExecutionPrompts, mergeAllPrompts, } from './merge.js'; @@ -63,4 +104,11 @@ export type { ResolvedBacklogPlanPrompts, ResolvedEnhancementPrompts, ResolvedCommitMessagePrompts, + ResolvedTitleGenerationPrompts, + ResolvedIssueValidationPrompts, + ResolvedIdeationPrompts, + ResolvedAppSpecPrompts, + ResolvedContextDescriptionPrompts, + ResolvedSuggestionsPrompts, + ResolvedTaskExecutionPrompts, } from '@automaker/types'; diff --git a/libs/prompts/src/merge.ts b/libs/prompts/src/merge.ts index d0d603bd..41cc5db7 100644 --- a/libs/prompts/src/merge.ts +++ b/libs/prompts/src/merge.ts @@ -15,12 +15,26 @@ import type { BacklogPlanPrompts, EnhancementPrompts, CommitMessagePrompts, + TitleGenerationPrompts, + IssueValidationPrompts, + IdeationPrompts, + AppSpecPrompts, + ContextDescriptionPrompts, + SuggestionsPrompts, + TaskExecutionPrompts, CustomPrompt, ResolvedAutoModePrompts, ResolvedAgentPrompts, ResolvedBacklogPlanPrompts, ResolvedEnhancementPrompts, ResolvedCommitMessagePrompts, + ResolvedTitleGenerationPrompts, + ResolvedIssueValidationPrompts, + ResolvedIdeationPrompts, + ResolvedAppSpecPrompts, + ResolvedContextDescriptionPrompts, + ResolvedSuggestionsPrompts, + ResolvedTaskExecutionPrompts, } from '@automaker/types'; import { DEFAULT_AUTO_MODE_PROMPTS, @@ -28,6 +42,13 @@ import { DEFAULT_BACKLOG_PLAN_PROMPTS, DEFAULT_ENHANCEMENT_PROMPTS, DEFAULT_COMMIT_MESSAGE_PROMPTS, + DEFAULT_TITLE_GENERATION_PROMPTS, + DEFAULT_ISSUE_VALIDATION_PROMPTS, + DEFAULT_IDEATION_PROMPTS, + DEFAULT_APP_SPEC_PROMPTS, + DEFAULT_CONTEXT_DESCRIPTION_PROMPTS, + DEFAULT_SUGGESTIONS_PROMPTS, + DEFAULT_TASK_EXECUTION_PROMPTS, } from './defaults.js'; /** @@ -135,6 +156,166 @@ export function mergeCommitMessagePrompts( }; } +/** + * Merge custom Title Generation prompts with defaults + * Custom prompts override defaults only when enabled=true + */ +export function mergeTitleGenerationPrompts( + custom?: TitleGenerationPrompts +): ResolvedTitleGenerationPrompts { + return { + systemPrompt: resolvePrompt( + custom?.systemPrompt, + DEFAULT_TITLE_GENERATION_PROMPTS.systemPrompt + ), + }; +} + +/** + * Merge custom Issue Validation prompts with defaults + * Custom prompts override defaults only when enabled=true + */ +export function mergeIssueValidationPrompts( + custom?: IssueValidationPrompts +): ResolvedIssueValidationPrompts { + return { + systemPrompt: resolvePrompt( + custom?.systemPrompt, + DEFAULT_ISSUE_VALIDATION_PROMPTS.systemPrompt + ), + }; +} + +/** + * Merge custom Ideation prompts with defaults + * Custom prompts override defaults only when enabled=true + */ +export function mergeIdeationPrompts(custom?: IdeationPrompts): ResolvedIdeationPrompts { + return { + ideationSystemPrompt: resolvePrompt( + custom?.ideationSystemPrompt, + DEFAULT_IDEATION_PROMPTS.ideationSystemPrompt + ), + suggestionsSystemPrompt: resolvePrompt( + custom?.suggestionsSystemPrompt, + DEFAULT_IDEATION_PROMPTS.suggestionsSystemPrompt + ), + }; +} + +/** + * Merge custom App Spec prompts with defaults + * Custom prompts override defaults only when enabled=true + */ +export function mergeAppSpecPrompts(custom?: AppSpecPrompts): ResolvedAppSpecPrompts { + return { + generateSpecSystemPrompt: resolvePrompt( + custom?.generateSpecSystemPrompt, + DEFAULT_APP_SPEC_PROMPTS.generateSpecSystemPrompt + ), + structuredSpecInstructions: resolvePrompt( + custom?.structuredSpecInstructions, + DEFAULT_APP_SPEC_PROMPTS.structuredSpecInstructions + ), + generateFeaturesFromSpecPrompt: resolvePrompt( + custom?.generateFeaturesFromSpecPrompt, + DEFAULT_APP_SPEC_PROMPTS.generateFeaturesFromSpecPrompt + ), + }; +} + +/** + * Merge custom Context Description prompts with defaults + * Custom prompts override defaults only when enabled=true + */ +export function mergeContextDescriptionPrompts( + custom?: ContextDescriptionPrompts +): ResolvedContextDescriptionPrompts { + return { + describeFilePrompt: resolvePrompt( + custom?.describeFilePrompt, + DEFAULT_CONTEXT_DESCRIPTION_PROMPTS.describeFilePrompt + ), + describeImagePrompt: resolvePrompt( + custom?.describeImagePrompt, + DEFAULT_CONTEXT_DESCRIPTION_PROMPTS.describeImagePrompt + ), + }; +} + +/** + * Merge custom Suggestions prompts with defaults + * Custom prompts override defaults only when enabled=true + */ +export function mergeSuggestionsPrompts(custom?: SuggestionsPrompts): ResolvedSuggestionsPrompts { + return { + featuresPrompt: resolvePrompt( + custom?.featuresPrompt, + DEFAULT_SUGGESTIONS_PROMPTS.featuresPrompt + ), + refactoringPrompt: resolvePrompt( + custom?.refactoringPrompt, + DEFAULT_SUGGESTIONS_PROMPTS.refactoringPrompt + ), + securityPrompt: resolvePrompt( + custom?.securityPrompt, + DEFAULT_SUGGESTIONS_PROMPTS.securityPrompt + ), + performancePrompt: resolvePrompt( + custom?.performancePrompt, + DEFAULT_SUGGESTIONS_PROMPTS.performancePrompt + ), + baseTemplate: resolvePrompt(custom?.baseTemplate, DEFAULT_SUGGESTIONS_PROMPTS.baseTemplate), + }; +} + +/** + * Merge custom Task Execution prompts with defaults + * Custom prompts override defaults only when enabled=true + */ +export function mergeTaskExecutionPrompts( + custom?: TaskExecutionPrompts +): ResolvedTaskExecutionPrompts { + return { + taskPromptTemplate: resolvePrompt( + custom?.taskPromptTemplate, + DEFAULT_TASK_EXECUTION_PROMPTS.taskPromptTemplate + ), + implementationInstructions: resolvePrompt( + custom?.implementationInstructions, + DEFAULT_TASK_EXECUTION_PROMPTS.implementationInstructions + ), + playwrightVerificationInstructions: resolvePrompt( + custom?.playwrightVerificationInstructions, + DEFAULT_TASK_EXECUTION_PROMPTS.playwrightVerificationInstructions + ), + learningExtractionSystemPrompt: resolvePrompt( + custom?.learningExtractionSystemPrompt, + DEFAULT_TASK_EXECUTION_PROMPTS.learningExtractionSystemPrompt + ), + learningExtractionUserPromptTemplate: resolvePrompt( + custom?.learningExtractionUserPromptTemplate, + DEFAULT_TASK_EXECUTION_PROMPTS.learningExtractionUserPromptTemplate + ), + planRevisionTemplate: resolvePrompt( + custom?.planRevisionTemplate, + DEFAULT_TASK_EXECUTION_PROMPTS.planRevisionTemplate + ), + continuationAfterApprovalTemplate: resolvePrompt( + custom?.continuationAfterApprovalTemplate, + DEFAULT_TASK_EXECUTION_PROMPTS.continuationAfterApprovalTemplate + ), + resumeFeatureTemplate: resolvePrompt( + custom?.resumeFeatureTemplate, + DEFAULT_TASK_EXECUTION_PROMPTS.resumeFeatureTemplate + ), + projectAnalysisPrompt: resolvePrompt( + custom?.projectAnalysisPrompt, + DEFAULT_TASK_EXECUTION_PROMPTS.projectAnalysisPrompt + ), + }; +} + /** * Merge all custom prompts with defaults * Returns a complete PromptCustomization with all fields populated @@ -146,5 +327,12 @@ export function mergeAllPrompts(custom?: PromptCustomization) { backlogPlan: mergeBacklogPlanPrompts(custom?.backlogPlan), enhancement: mergeEnhancementPrompts(custom?.enhancement), commitMessage: mergeCommitMessagePrompts(custom?.commitMessage), + titleGeneration: mergeTitleGenerationPrompts(custom?.titleGeneration), + issueValidation: mergeIssueValidationPrompts(custom?.issueValidation), + ideation: mergeIdeationPrompts(custom?.ideation), + appSpec: mergeAppSpecPrompts(custom?.appSpec), + contextDescription: mergeContextDescriptionPrompts(custom?.contextDescription), + suggestions: mergeSuggestionsPrompts(custom?.suggestions), + taskExecution: mergeTaskExecutionPrompts(custom?.taskExecution), }; } diff --git a/libs/types/src/index.ts b/libs/types/src/index.ts index 497f9ed4..6c654ca8 100644 --- a/libs/types/src/index.ts +++ b/libs/types/src/index.ts @@ -100,12 +100,26 @@ export type { BacklogPlanPrompts, EnhancementPrompts, CommitMessagePrompts, + TitleGenerationPrompts, + IssueValidationPrompts, + IdeationPrompts, + AppSpecPrompts, + ContextDescriptionPrompts, + SuggestionsPrompts, + TaskExecutionPrompts, PromptCustomization, ResolvedAutoModePrompts, ResolvedAgentPrompts, ResolvedBacklogPlanPrompts, ResolvedEnhancementPrompts, ResolvedCommitMessagePrompts, + ResolvedTitleGenerationPrompts, + ResolvedIssueValidationPrompts, + ResolvedIdeationPrompts, + ResolvedAppSpecPrompts, + ResolvedContextDescriptionPrompts, + ResolvedSuggestionsPrompts, + ResolvedTaskExecutionPrompts, } from './prompts.js'; export { DEFAULT_PROMPT_CUSTOMIZATION } from './prompts.js'; diff --git a/libs/types/src/prompts.ts b/libs/types/src/prompts.ts index 2e5282a3..a3c582dc 100644 --- a/libs/types/src/prompts.ts +++ b/libs/types/src/prompts.ts @@ -104,6 +104,125 @@ export interface CommitMessagePrompts { systemPrompt?: CustomPrompt; } +/** + * TitleGenerationPrompts - Customizable prompts for AI feature title generation + * + * Controls how the AI generates short, descriptive titles for features. + */ +export interface TitleGenerationPrompts { + /** System prompt for generating feature titles from descriptions */ + systemPrompt?: CustomPrompt; +} + +/** + * IssueValidationPrompts - Customizable prompts for GitHub issue validation + * + * Controls how the AI validates GitHub issues against the codebase, + * determining if issues are valid, invalid, or need clarification. + */ +export interface IssueValidationPrompts { + /** System prompt for validating GitHub issues against codebase */ + systemPrompt?: CustomPrompt; +} + +/** + * IdeationPrompts - Customizable prompts for AI-powered ideation and brainstorming + * + * Controls how the AI generates feature ideas and suggestions for the project. + */ +export interface IdeationPrompts { + /** System prompt for ideation chat conversations */ + ideationSystemPrompt?: CustomPrompt; + + /** System prompt for generating feature suggestions */ + suggestionsSystemPrompt?: CustomPrompt; +} + +/** + * AppSpecPrompts - Customizable prompts for project specification generation + * + * Controls how the AI generates project specifications and features from specs. + */ +export interface AppSpecPrompts { + /** System prompt for generating project specifications */ + generateSpecSystemPrompt?: CustomPrompt; + + /** Instructions for structured specification output format */ + structuredSpecInstructions?: CustomPrompt; + + /** System prompt for generating features from a specification */ + generateFeaturesFromSpecPrompt?: CustomPrompt; +} + +/** + * ContextDescriptionPrompts - Customizable prompts for context file/image descriptions + * + * Controls how the AI describes context files and images. + */ +export interface ContextDescriptionPrompts { + /** System prompt for describing text files added as context */ + describeFilePrompt?: CustomPrompt; + + /** System prompt for describing images added as context */ + describeImagePrompt?: CustomPrompt; +} + +/** + * SuggestionsPrompts - Customizable prompts for generating various suggestions + * + * Controls how the AI generates feature, refactoring, security, and performance suggestions. + */ +export interface SuggestionsPrompts { + /** Prompt for generating new feature suggestions */ + featuresPrompt?: CustomPrompt; + + /** Prompt for generating refactoring suggestions */ + refactoringPrompt?: CustomPrompt; + + /** Prompt for generating security suggestions */ + securityPrompt?: CustomPrompt; + + /** Prompt for generating performance suggestions */ + performancePrompt?: CustomPrompt; + + /** Base template for all suggestion types */ + baseTemplate?: CustomPrompt; +} + +/** + * TaskExecutionPrompts - Customizable prompts for Auto Mode task execution + * + * Controls how the AI executes tasks, extracts learnings, and handles continuations. + */ +export interface TaskExecutionPrompts { + /** Template for building task execution prompts */ + taskPromptTemplate?: CustomPrompt; + + /** Instructions appended to feature implementation prompts */ + implementationInstructions?: CustomPrompt; + + /** Instructions for Playwright verification (when enabled) */ + playwrightVerificationInstructions?: CustomPrompt; + + /** System prompt for extracting learnings/ADRs from implementation */ + learningExtractionSystemPrompt?: CustomPrompt; + + /** User prompt template for learning extraction */ + learningExtractionUserPromptTemplate?: CustomPrompt; + + /** Template for prompting plan revisions */ + planRevisionTemplate?: CustomPrompt; + + /** Template for continuation after plan approval */ + continuationAfterApprovalTemplate?: CustomPrompt; + + /** Template for resuming interrupted features */ + resumeFeatureTemplate?: CustomPrompt; + + /** Template for project analysis */ + projectAnalysisPrompt?: CustomPrompt; +} + /** * PromptCustomization - Complete set of customizable prompts * @@ -125,6 +244,27 @@ export interface PromptCustomization { /** Commit message prompts (AI-generated commit messages) */ commitMessage?: CommitMessagePrompts; + + /** Title generation prompts (AI-generated feature titles) */ + titleGeneration?: TitleGenerationPrompts; + + /** Issue validation prompts (GitHub issue validation) */ + issueValidation?: IssueValidationPrompts; + + /** Ideation prompts (AI-powered brainstorming and suggestions) */ + ideation?: IdeationPrompts; + + /** App specification prompts (project spec generation) */ + appSpec?: AppSpecPrompts; + + /** Context description prompts (file/image descriptions) */ + contextDescription?: ContextDescriptionPrompts; + + /** Suggestions prompts (features, refactoring, security, performance) */ + suggestions?: SuggestionsPrompts; + + /** Task execution prompts (Auto Mode task execution, learning extraction) */ + taskExecution?: TaskExecutionPrompts; } /** @@ -136,6 +276,13 @@ export const DEFAULT_PROMPT_CUSTOMIZATION: PromptCustomization = { backlogPlan: {}, enhancement: {}, commitMessage: {}, + titleGeneration: {}, + issueValidation: {}, + ideation: {}, + appSpec: {}, + contextDescription: {}, + suggestions: {}, + taskExecution: {}, }; /** @@ -173,3 +320,47 @@ export interface ResolvedEnhancementPrompts { export interface ResolvedCommitMessagePrompts { systemPrompt: string; } + +export interface ResolvedTitleGenerationPrompts { + systemPrompt: string; +} + +export interface ResolvedIssueValidationPrompts { + systemPrompt: string; +} + +export interface ResolvedIdeationPrompts { + ideationSystemPrompt: string; + suggestionsSystemPrompt: string; +} + +export interface ResolvedAppSpecPrompts { + generateSpecSystemPrompt: string; + structuredSpecInstructions: string; + generateFeaturesFromSpecPrompt: string; +} + +export interface ResolvedContextDescriptionPrompts { + describeFilePrompt: string; + describeImagePrompt: string; +} + +export interface ResolvedSuggestionsPrompts { + featuresPrompt: string; + refactoringPrompt: string; + securityPrompt: string; + performancePrompt: string; + baseTemplate: string; +} + +export interface ResolvedTaskExecutionPrompts { + taskPromptTemplate: string; + implementationInstructions: string; + playwrightVerificationInstructions: string; + learningExtractionSystemPrompt: string; + learningExtractionUserPromptTemplate: string; + planRevisionTemplate: string; + continuationAfterApprovalTemplate: string; + resumeFeatureTemplate: string; + projectAnalysisPrompt: string; +} From 8fa8ba0a163ca0e42f987c105792455c1264bdfa Mon Sep 17 00:00:00 2001 From: Shirone Date: Thu, 15 Jan 2026 20:31:19 +0100 Subject: [PATCH 05/93] fix: address PR comments and complete prompt centralization - Fix inline type imports in defaults.ts (move to top-level imports) - Update ideation-service.ts to use centralized prompts from settings - Update generate-title.ts to use centralized prompts - Update validate-issue.ts to use centralized prompts - Clean up validation-schema.ts (prompts already centralized) - Minor server index cleanup Co-Authored-By: Claude Opus 4.5 --- apps/server/src/index.ts | 2 +- apps/server/src/routes/features/index.ts | 8 +- .../routes/features/routes/generate-title.ts | 21 +++-- .../routes/github/routes/validate-issue.ts | 10 ++- .../routes/github/routes/validation-schema.ts | 77 ++----------------- apps/server/src/services/ideation-service.ts | 69 ++++++----------- libs/prompts/src/defaults.ts | 40 +++++----- 7 files changed, 74 insertions(+), 153 deletions(-) diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 609be945..0e52d03b 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -219,7 +219,7 @@ app.get('/api/health/detailed', createDetailedHandler()); app.use('/api/fs', createFsRoutes(events)); app.use('/api/agent', createAgentRoutes(agentService, events)); app.use('/api/sessions', createSessionsRoutes(agentService)); -app.use('/api/features', createFeaturesRoutes(featureLoader)); +app.use('/api/features', createFeaturesRoutes(featureLoader, settingsService)); app.use('/api/auto-mode', createAutoModeRoutes(autoModeService)); app.use('/api/enhance-prompt', createEnhancePromptRoutes(settingsService)); app.use('/api/worktree', createWorktreeRoutes(events, settingsService)); diff --git a/apps/server/src/routes/features/index.ts b/apps/server/src/routes/features/index.ts index e0435f35..dd58e4aa 100644 --- a/apps/server/src/routes/features/index.ts +++ b/apps/server/src/routes/features/index.ts @@ -4,6 +4,7 @@ import { Router } from 'express'; import { FeatureLoader } from '../../services/feature-loader.js'; +import type { SettingsService } from '../../services/settings-service.js'; import { validatePathParams } from '../../middleware/validate-paths.js'; import { createListHandler } from './routes/list.js'; import { createGetHandler } from './routes/get.js'; @@ -15,7 +16,10 @@ import { createDeleteHandler } from './routes/delete.js'; import { createAgentOutputHandler, createRawOutputHandler } from './routes/agent-output.js'; import { createGenerateTitleHandler } from './routes/generate-title.js'; -export function createFeaturesRoutes(featureLoader: FeatureLoader): Router { +export function createFeaturesRoutes( + featureLoader: FeatureLoader, + settingsService?: SettingsService +): Router { const router = Router(); router.post('/list', validatePathParams('projectPath'), createListHandler(featureLoader)); @@ -35,7 +39,7 @@ export function createFeaturesRoutes(featureLoader: FeatureLoader): Router { router.post('/delete', validatePathParams('projectPath'), createDeleteHandler(featureLoader)); router.post('/agent-output', createAgentOutputHandler(featureLoader)); router.post('/raw-output', createRawOutputHandler(featureLoader)); - router.post('/generate-title', createGenerateTitleHandler()); + router.post('/generate-title', createGenerateTitleHandler(settingsService)); return router; } diff --git a/apps/server/src/routes/features/routes/generate-title.ts b/apps/server/src/routes/features/routes/generate-title.ts index a838e5aa..e7603eb8 100644 --- a/apps/server/src/routes/features/routes/generate-title.ts +++ b/apps/server/src/routes/features/routes/generate-title.ts @@ -9,6 +9,8 @@ import type { Request, Response } from 'express'; import { createLogger } from '@automaker/utils'; import { CLAUDE_MODEL_MAP } from '@automaker/model-resolver'; import { simpleQuery } from '../../../providers/simple-query-service.js'; +import type { SettingsService } from '../../../services/settings-service.js'; +import { getPromptCustomization } from '../../../lib/settings-helpers.js'; const logger = createLogger('GenerateTitle'); @@ -26,16 +28,9 @@ interface GenerateTitleErrorResponse { error: string; } -const SYSTEM_PROMPT = `You are a title generator. Your task is to create a concise, descriptive title (5-10 words max) for a software feature based on its description. - -Rules: -- Output ONLY the title, nothing else -- Keep it short and action-oriented (e.g., "Add dark mode toggle", "Fix login validation") -- Start with a verb when possible (Add, Fix, Update, Implement, Create, etc.) -- No quotes, periods, or extra formatting -- Capture the essence of the feature in a scannable way`; - -export function createGenerateTitleHandler(): (req: Request, res: Response) => Promise { +export function createGenerateTitleHandler( + settingsService?: SettingsService +): (req: Request, res: Response) => Promise { return async (req: Request, res: Response): Promise => { try { const { description } = req.body as GenerateTitleRequestBody; @@ -61,11 +56,15 @@ export function createGenerateTitleHandler(): (req: Request, res: Response) => P logger.info(`Generating title for description: ${trimmedDescription.substring(0, 50)}...`); + // Get customized prompts from settings + const prompts = await getPromptCustomization(settingsService, '[GenerateTitle]'); + const systemPrompt = prompts.titleGeneration.systemPrompt; + const userPrompt = `Generate a concise title for this feature:\n\n${trimmedDescription}`; // Use simpleQuery - provider abstraction handles all the streaming/extraction const result = await simpleQuery({ - prompt: `${SYSTEM_PROMPT}\n\n${userPrompt}`, + prompt: `${systemPrompt}\n\n${userPrompt}`, model: CLAUDE_MODEL_MAP.haiku, cwd: process.cwd(), maxTurns: 1, diff --git a/apps/server/src/routes/github/routes/validate-issue.ts b/apps/server/src/routes/github/routes/validate-issue.ts index 14de437b..e7d83d99 100644 --- a/apps/server/src/routes/github/routes/validate-issue.ts +++ b/apps/server/src/routes/github/routes/validate-issue.ts @@ -30,11 +30,11 @@ import { writeValidation } from '../../../lib/validation-storage.js'; import { streamingQuery } from '../../../providers/simple-query-service.js'; import { issueValidationSchema, - ISSUE_VALIDATION_SYSTEM_PROMPT, buildValidationPrompt, ValidationComment, ValidationLinkedPR, } from './validation-schema.js'; +import { getPromptCustomization } from '../../../lib/settings-helpers.js'; import { trySetValidationRunning, clearValidationStatus, @@ -117,13 +117,17 @@ async function runValidation( let responseText = ''; + // Get customized prompts from settings + const prompts = await getPromptCustomization(settingsService, '[ValidateIssue]'); + const issueValidationSystemPrompt = prompts.issueValidation.systemPrompt; + // Determine if we should use structured output (Claude/Codex support it, Cursor/OpenCode don't) const useStructuredOutput = isClaudeModel(model) || isCodexModel(model); // Build the final prompt - for Cursor, include system prompt and JSON schema instructions let finalPrompt = basePrompt; if (!useStructuredOutput) { - finalPrompt = `${ISSUE_VALIDATION_SYSTEM_PROMPT} + finalPrompt = `${issueValidationSystemPrompt} CRITICAL INSTRUCTIONS: 1. DO NOT write any files. Return the JSON in your response only. @@ -167,7 +171,7 @@ ${basePrompt}`; prompt: finalPrompt, model: model as string, cwd: projectPath, - systemPrompt: useStructuredOutput ? ISSUE_VALIDATION_SYSTEM_PROMPT : undefined, + systemPrompt: useStructuredOutput ? issueValidationSystemPrompt : undefined, abortController, thinkingLevel: effectiveThinkingLevel, reasoningEffort: effectiveReasoningEffort, diff --git a/apps/server/src/routes/github/routes/validation-schema.ts b/apps/server/src/routes/github/routes/validation-schema.ts index 010fcd7f..9ba48a2b 100644 --- a/apps/server/src/routes/github/routes/validation-schema.ts +++ b/apps/server/src/routes/github/routes/validation-schema.ts @@ -1,8 +1,11 @@ /** - * Issue Validation Schema and System Prompt + * Issue Validation Schema and Prompt Building * * Defines the JSON schema for Claude's structured output and - * the system prompt that guides the validation process. + * helper functions for building validation prompts. + * + * Note: The system prompt is now centralized in @automaker/prompts + * and accessed via getPromptCustomization() in validate-issue.ts */ /** @@ -82,76 +85,6 @@ export const issueValidationSchema = { additionalProperties: false, } as const; -/** - * System prompt that guides Claude in validating GitHub issues. - * Instructs the model to use read-only tools to analyze the codebase. - */ -export const ISSUE_VALIDATION_SYSTEM_PROMPT = `You are an expert code analyst validating GitHub issues against a codebase. - -Your task is to analyze a GitHub issue and determine if it's valid by scanning the codebase. - -## Validation Process - -1. **Read the issue carefully** - Understand what is being reported or requested -2. **Search the codebase** - Use Glob to find relevant files by pattern, Grep to search for keywords -3. **Examine the code** - Use Read to look at the actual implementation in relevant files -4. **Check linked PRs** - If there are linked pull requests, use \`gh pr diff \` to review the changes -5. **Form your verdict** - Based on your analysis, determine if the issue is valid - -## Verdicts - -- **valid**: The issue describes a real problem that exists in the codebase, or a clear feature request that can be implemented. The referenced files/components exist and the issue is actionable. - -- **invalid**: The issue describes behavior that doesn't exist, references non-existent files or components, is based on a misunderstanding of the code, or the described "bug" is actually expected behavior. - -- **needs_clarification**: The issue lacks sufficient detail to verify. Specify what additional information is needed in the missingInfo field. - -## For Bug Reports, Check: -- Do the referenced files/components exist? -- Does the code match what the issue describes? -- Is the described behavior actually a bug or expected? -- Can you locate the code that would cause the reported issue? - -## For Feature Requests, Check: -- Does the feature already exist? -- Is the implementation location clear? -- Is the request technically feasible given the codebase structure? - -## Analyzing Linked Pull Requests - -When an issue has linked PRs (especially open ones), you MUST analyze them: - -1. **Run \`gh pr diff \`** to see what changes the PR makes -2. **Run \`gh pr view \`** to see PR description and status -3. **Evaluate if the PR fixes the issue** - Does the diff address the reported problem? -4. **Provide a recommendation**: - - \`wait_for_merge\`: The PR appears to fix the issue correctly. No additional work needed - just wait for it to be merged. - - \`pr_needs_work\`: The PR attempts to fix the issue but is incomplete or has problems. - - \`no_pr\`: No relevant PR exists for this issue. - -5. **Include prAnalysis in your response** with: - - hasOpenPR: true/false - - prFixesIssue: true/false (based on diff analysis) - - prNumber: the PR number you analyzed - - prSummary: brief description of what the PR changes - - recommendation: one of the above values - -## Response Guidelines - -- **Always include relatedFiles** when you find relevant code -- **Set bugConfirmed to true** only if you can definitively confirm a bug exists in the code -- **Provide a suggestedFix** when you have a clear idea of how to address the issue -- **Use missingInfo** when the verdict is needs_clarification to list what's needed -- **Include prAnalysis** when there are linked PRs - this is critical for avoiding duplicate work -- **Set estimatedComplexity** to help prioritize: - - trivial: Simple text changes, one-line fixes - - simple: Small changes to one file - - moderate: Changes to multiple files or moderate logic changes - - complex: Significant refactoring or new feature implementation - - very_complex: Major architectural changes or cross-cutting concerns - -Be thorough in your analysis but focus on files that are directly relevant to the issue.`; - /** * Comment data structure for validation prompt */ diff --git a/apps/server/src/services/ideation-service.ts b/apps/server/src/services/ideation-service.ts index 81fc3de6..4ef3d8a8 100644 --- a/apps/server/src/services/ideation-service.ts +++ b/apps/server/src/services/ideation-service.ts @@ -41,6 +41,7 @@ import type { FeatureLoader } from './feature-loader.js'; import { createChatOptions, validateWorkingDirectory } from '../lib/sdk-options.js'; import { resolveModelString } from '@automaker/model-resolver'; import { stripProviderPrefix } from '@automaker/types'; +import { getPromptCustomization } from '../lib/settings-helpers.js'; const logger = createLogger('IdeationService'); @@ -195,8 +196,12 @@ export class IdeationService { // Gather existing features and ideas to prevent duplicate suggestions const existingWorkContext = await this.gatherExistingWorkContext(projectPath); + // Get customized prompts from settings + const prompts = await getPromptCustomization(this.settingsService, '[IdeationService]'); + // Build system prompt for ideation const systemPrompt = this.buildIdeationSystemPrompt( + prompts.ideation.ideationSystemPrompt, contextResult.formattedPrompt, activeSession.session.promptCategory, existingWorkContext @@ -645,8 +650,12 @@ export class IdeationService { // Gather existing features and ideas to prevent duplicates const existingWorkContext = await this.gatherExistingWorkContext(projectPath); + // Get customized prompts from settings + const prompts = await getPromptCustomization(this.settingsService, '[IdeationService]'); + // Build system prompt for structured suggestions const systemPrompt = this.buildSuggestionsSystemPrompt( + prompts.ideation.suggestionsSystemPrompt, contextPrompt, category, count, @@ -721,8 +730,14 @@ export class IdeationService { /** * Build system prompt for structured suggestion generation + * @param basePrompt - The base system prompt from settings + * @param contextFilesPrompt - Project context from loaded files + * @param category - The idea category to focus on + * @param count - Number of suggestions to generate + * @param existingWorkContext - Context about existing features/ideas */ private buildSuggestionsSystemPrompt( + basePrompt: string, contextFilesPrompt: string | undefined, category: IdeaCategory, count: number = 10, @@ -734,35 +749,18 @@ export class IdeationService { const existingWorkSection = existingWorkContext ? `\n\n${existingWorkContext}` : ''; - return `You are an AI product strategist helping brainstorm feature ideas for a software project. + // Replace placeholder {{count}} if present, otherwise append count instruction + let prompt = basePrompt; + if (prompt.includes('{{count}}')) { + prompt = prompt.replace(/\{\{count\}\}/g, String(count)); + } else { + prompt += `\n\nGenerate exactly ${count} suggestions.`; + } -IMPORTANT: You do NOT have access to any tools. You CANNOT read files, search code, or run commands. -You must generate suggestions based ONLY on the project context provided below. -Do NOT say "I'll analyze" or "Let me explore" - you cannot do those things. - -Based on the project context and the user's prompt, generate exactly ${count} creative and actionable feature suggestions. - -YOUR RESPONSE MUST BE ONLY A JSON ARRAY - nothing else. No explanation, no preamble, no markdown code fences. - -Each suggestion must have this structure: -{ - "title": "Short, actionable title (max 60 chars)", - "description": "Clear description of what to build or improve (2-3 sentences)", - "rationale": "Why this is valuable - the problem it solves or opportunity it creates", - "priority": "high" | "medium" | "low" -} + return `${prompt} Focus area: ${this.getCategoryDescription(category)} -Guidelines: -- Generate exactly ${count} suggestions -- Be specific and actionable - avoid vague ideas -- Mix different priority levels (some high, some medium, some low) -- Each suggestion should be independently implementable -- Think creatively - include both obvious improvements and innovative ideas -- Consider the project's domain and target users -- IMPORTANT: Do NOT suggest features or ideas that already exist in the "Existing Features" or "Existing Ideas" sections below - ${contextSection}${existingWorkSection}`; } @@ -1269,30 +1267,11 @@ ${contextSection}${existingWorkSection}`; // ============================================================================ private buildIdeationSystemPrompt( + basePrompt: string, contextFilesPrompt: string | undefined, category?: IdeaCategory, existingWorkContext?: string ): string { - const basePrompt = `You are an AI product strategist and UX expert helping brainstorm ideas for improving a software project. - -Your role is to: -- Analyze the codebase structure and patterns -- Identify opportunities for improvement -- Suggest actionable ideas with clear rationale -- Consider user experience, technical feasibility, and business value -- Be specific and reference actual files/components when possible - -When suggesting ideas: -1. Provide a clear, concise title -2. Explain the problem or opportunity -3. Describe the proposed solution -4. Highlight the expected benefit -5. Note any dependencies or considerations - -IMPORTANT: Do NOT suggest features or ideas that already exist in the project. Check the "Existing Features" and "Existing Ideas" sections below to avoid duplicates. - -Focus on practical, implementable suggestions that would genuinely improve the product.`; - const categoryContext = category ? `\n\nFocus area: ${this.getCategoryDescription(category)}` : ''; diff --git a/libs/prompts/src/defaults.ts b/libs/prompts/src/defaults.ts index 9d6aeaa2..27aa332e 100644 --- a/libs/prompts/src/defaults.ts +++ b/libs/prompts/src/defaults.ts @@ -19,6 +19,10 @@ import type { ResolvedTitleGenerationPrompts, ResolvedIssueValidationPrompts, ResolvedIdeationPrompts, + ResolvedAppSpecPrompts, + ResolvedContextDescriptionPrompts, + ResolvedSuggestionsPrompts, + ResolvedTaskExecutionPrompts, } from '@automaker/types'; import { STATIC_PORT, SERVER_PORT } from '@automaker/types'; @@ -686,7 +690,7 @@ IMPORTANT: Do not ask for clarification. The specification is provided above. Ge /** * Default App Spec prompts (for project specification generation) */ -export const DEFAULT_APP_SPEC_PROMPTS: import('@automaker/types').ResolvedAppSpecPrompts = { +export const DEFAULT_APP_SPEC_PROMPTS: ResolvedAppSpecPrompts = { generateSpecSystemPrompt: DEFAULT_APP_SPEC_GENERATE_SYSTEM_PROMPT, structuredSpecInstructions: DEFAULT_APP_SPEC_STRUCTURED_INSTRUCTIONS, generateFeaturesFromSpecPrompt: DEFAULT_GENERATE_FEATURES_FROM_SPEC_PROMPT, @@ -709,11 +713,10 @@ Respond with ONLY the description text, no additional formatting, preamble, or e /** * Default Context Description prompts (for file/image descriptions) */ -export const DEFAULT_CONTEXT_DESCRIPTION_PROMPTS: import('@automaker/types').ResolvedContextDescriptionPrompts = - { - describeFilePrompt: DEFAULT_DESCRIBE_FILE_PROMPT, - describeImagePrompt: DEFAULT_DESCRIBE_IMAGE_PROMPT, - }; +export const DEFAULT_CONTEXT_DESCRIPTION_PROMPTS: ResolvedContextDescriptionPrompts = { + describeFilePrompt: DEFAULT_DESCRIBE_FILE_PROMPT, + describeImagePrompt: DEFAULT_DESCRIBE_IMAGE_PROMPT, +}; /** * ======================================================================== @@ -743,7 +746,7 @@ The response will be automatically formatted as structured JSON.`; /** * Default Suggestions prompts (for features, refactoring, security, performance) */ -export const DEFAULT_SUGGESTIONS_PROMPTS: import('@automaker/types').ResolvedSuggestionsPrompts = { +export const DEFAULT_SUGGESTIONS_PROMPTS: ResolvedSuggestionsPrompts = { featuresPrompt: DEFAULT_SUGGESTIONS_FEATURES_PROMPT, refactoringPrompt: DEFAULT_SUGGESTIONS_REFACTORING_PROMPT, securityPrompt: DEFAULT_SUGGESTIONS_SECURITY_PROMPT, @@ -930,18 +933,17 @@ Format your response as a structured markdown document.`; /** * Default Task Execution prompts (for Auto Mode task execution, learning extraction) */ -export const DEFAULT_TASK_EXECUTION_PROMPTS: import('@automaker/types').ResolvedTaskExecutionPrompts = - { - taskPromptTemplate: DEFAULT_TASK_PROMPT_TEMPLATE, - implementationInstructions: DEFAULT_IMPLEMENTATION_INSTRUCTIONS, - playwrightVerificationInstructions: DEFAULT_PLAYWRIGHT_VERIFICATION_INSTRUCTIONS, - learningExtractionSystemPrompt: DEFAULT_LEARNING_EXTRACTION_SYSTEM_PROMPT, - learningExtractionUserPromptTemplate: DEFAULT_LEARNING_EXTRACTION_USER_TEMPLATE, - planRevisionTemplate: DEFAULT_PLAN_REVISION_TEMPLATE, - continuationAfterApprovalTemplate: DEFAULT_CONTINUATION_AFTER_APPROVAL_TEMPLATE, - resumeFeatureTemplate: DEFAULT_RESUME_FEATURE_TEMPLATE, - projectAnalysisPrompt: DEFAULT_PROJECT_ANALYSIS_PROMPT, - }; +export const DEFAULT_TASK_EXECUTION_PROMPTS: ResolvedTaskExecutionPrompts = { + taskPromptTemplate: DEFAULT_TASK_PROMPT_TEMPLATE, + implementationInstructions: DEFAULT_IMPLEMENTATION_INSTRUCTIONS, + playwrightVerificationInstructions: DEFAULT_PLAYWRIGHT_VERIFICATION_INSTRUCTIONS, + learningExtractionSystemPrompt: DEFAULT_LEARNING_EXTRACTION_SYSTEM_PROMPT, + learningExtractionUserPromptTemplate: DEFAULT_LEARNING_EXTRACTION_USER_TEMPLATE, + planRevisionTemplate: DEFAULT_PLAN_REVISION_TEMPLATE, + continuationAfterApprovalTemplate: DEFAULT_CONTINUATION_AFTER_APPROVAL_TEMPLATE, + resumeFeatureTemplate: DEFAULT_RESUME_FEATURE_TEMPLATE, + projectAnalysisPrompt: DEFAULT_PROJECT_ANALYSIS_PROMPT, +}; /** * ======================================================================== From 3a2ba6dbfea4bbd19ee092467895ec914e614149 Mon Sep 17 00:00:00 2001 From: Shirone Date: Thu, 15 Jan 2026 20:54:26 +0100 Subject: [PATCH 06/93] feat: connect Task Execution prompts to auto-mode-service Update auto-mode-service.ts to use centralized Task Execution prompts from settings, making all 9 task execution prompts customizable via UI: - buildFeaturePrompt: uses implementationInstructions and playwrightVerificationInstructions from settings - buildTaskPrompt: uses taskPromptTemplate with variable substitution - buildPipelineStepPrompt: updated to pass prompts through - executeFeatureWithContext: uses resumeFeatureTemplate - resolvePlanApproval recovery: uses continuationAfterApprovalTemplate - Multi-agent continuation: uses continuationAfterApprovalTemplate - recordLearningsFromFeature: uses learningExtractionSystemPrompt and learningExtractionUserPromptTemplate All 12 prompt categories are now fully customizable from the UI. Co-Authored-By: Claude Opus 4.5 --- apps/server/src/services/auto-mode-service.ts | 290 +++++++----------- 1 file changed, 107 insertions(+), 183 deletions(-) diff --git a/apps/server/src/services/auto-mode-service.ts b/apps/server/src/services/auto-mode-service.ts index 29caa4e1..05722181 100644 --- a/apps/server/src/services/auto-mode-service.ts +++ b/apps/server/src/services/auto-mode-service.ts @@ -579,6 +579,9 @@ export class AutoModeService { '[AutoMode]' ); + // Get customized prompts from settings + const prompts = await getPromptCustomization(this.settingsService, '[AutoMode]'); + // Build the prompt - use continuation prompt if provided (for recovery after plan approval) let prompt: string; // Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.) and memory files @@ -604,7 +607,7 @@ export class AutoModeService { logger.info(`Using continuation prompt for feature ${featureId}`); } else { // Normal flow: build prompt with planning phase - const featurePrompt = this.buildFeaturePrompt(feature); + const featurePrompt = this.buildFeaturePrompt(feature, prompts.taskExecution); const planningPrefix = await this.getPlanningPromptPrefix(feature); prompt = planningPrefix + featurePrompt; @@ -783,6 +786,9 @@ export class AutoModeService { ): Promise { logger.info(`Executing ${steps.length} pipeline step(s) for feature ${featureId}`); + // Get customized prompts from settings + const prompts = await getPromptCustomization(this.settingsService, '[AutoMode]'); + // Load context files once with feature context for smart memory selection const contextResult = await loadContextFiles({ projectPath, @@ -827,7 +833,12 @@ export class AutoModeService { }); // Build prompt for this pipeline step - const prompt = this.buildPipelineStepPrompt(step, feature, previousContext); + const prompt = this.buildPipelineStepPrompt( + step, + feature, + previousContext, + prompts.taskExecution + ); // Get model from feature const model = resolveModelString(feature.model, DEFAULT_MODELS.claude); @@ -882,14 +893,18 @@ export class AutoModeService { private buildPipelineStepPrompt( step: PipelineStep, feature: Feature, - previousContext: string + previousContext: string, + taskExecutionPrompts: { + implementationInstructions: string; + playwrightVerificationInstructions: string; + } ): string { let prompt = `## Pipeline Step: ${step.name} This is an automated pipeline step following the initial feature implementation. ### Feature Context -${this.buildFeaturePrompt(feature)} +${this.buildFeaturePrompt(feature, taskExecutionPrompts)} `; @@ -1279,6 +1294,9 @@ Complete the pipeline step instructions above. Review the previous work and appl '[AutoMode]' ); + // Get customized prompts from settings + const prompts = await getPromptCustomization(this.settingsService, '[AutoMode]'); + // Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.) - passed as system prompt const contextResult = await loadContextFiles({ projectPath, @@ -1296,7 +1314,7 @@ Complete the pipeline step instructions above. Review the previous work and appl // Build complete prompt with feature info, previous context, and follow-up instructions let fullPrompt = `## Follow-up on Feature Implementation -${feature ? this.buildFeaturePrompt(feature) : `**Feature ID:** ${featureId}`} +${feature ? this.buildFeaturePrompt(feature, prompts.taskExecution) : `**Feature ID:** ${featureId}`} `; if (previousContext) { @@ -1888,13 +1906,17 @@ Format your response as a structured markdown document.`; content: editedPlan || feature.planSpec.content, }); - // Build continuation prompt and re-run the feature + // Get customized prompts from settings + const prompts = await getPromptCustomization(this.settingsService, '[AutoMode]'); + + // Build continuation prompt using centralized template const planContent = editedPlan || feature.planSpec.content || ''; - let continuationPrompt = `The plan/specification has been approved. `; - if (feedback) { - continuationPrompt += `\n\nUser feedback: ${feedback}\n\n`; - } - continuationPrompt += `Now proceed with the implementation as specified in the plan:\n\n${planContent}\n\nImplement the feature now.`; + let continuationPrompt = prompts.taskExecution.continuationAfterApprovalTemplate; + continuationPrompt = continuationPrompt.replace( + /\{\{userFeedback\}\}/g, + feedback || '' + ); + continuationPrompt = continuationPrompt.replace(/\{\{approvedPlan\}\}/g, planContent); logger.info(`Starting recovery execution for feature ${featureId}`); @@ -2225,7 +2247,13 @@ Format your response as a structured markdown document.`; return planningPrompt + '\n\n---\n\n## Feature Request\n\n'; } - private buildFeaturePrompt(feature: Feature): string { + private buildFeaturePrompt( + feature: Feature, + taskExecutionPrompts: { + implementationInstructions: string; + playwrightVerificationInstructions: string; + } + ): string { const title = this.extractTitleFromDescription(feature.description); let prompt = `## Feature Implementation Task @@ -2267,80 +2295,10 @@ You can use the Read tool to view these images at any time during implementation // Add verification instructions based on testing mode if (feature.skipTests) { // Manual verification - just implement the feature - prompt += ` -## Instructions - -Implement this feature by: -1. First, explore the codebase to understand the existing structure -2. Plan your implementation approach -3. Write the necessary code changes -4. Ensure the code follows existing patterns and conventions - -When done, wrap your final summary in tags like this: - - -## Summary: [Feature Title] - -### Changes Implemented -- [List of changes made] - -### Files Modified -- [List of files] - -### Notes for Developer -- [Any important notes] - - -This helps parse your summary correctly in the output logs.`; + prompt += `\n${taskExecutionPrompts.implementationInstructions}`; } else { // Automated testing - implement and verify with Playwright - prompt += ` -## Instructions - -Implement this feature by: -1. First, explore the codebase to understand the existing structure -2. Plan your implementation approach -3. Write the necessary code changes -4. Ensure the code follows existing patterns and conventions - -## Verification with Playwright (REQUIRED) - -After implementing the feature, you MUST verify it works correctly using Playwright: - -1. **Create a temporary Playwright test** to verify the feature works as expected -2. **Run the test** to confirm the feature is working -3. **Delete the test file** after verification - this is a temporary verification test, not a permanent test suite addition - -Example verification workflow: -\`\`\`bash -# Create a simple verification test -npx playwright test my-verification-test.spec.ts - -# After successful verification, delete the test -rm my-verification-test.spec.ts -\`\`\` - -The test should verify the core functionality of the feature. If the test fails, fix the implementation and re-test. - -When done, wrap your final summary in tags like this: - - -## Summary: [Feature Title] - -### Changes Implemented -- [List of changes made] - -### Files Modified -- [List of files] - -### Verification Status -- [Describe how the feature was verified with Playwright] - -### Notes for Developer -- [Any important notes] - - -This helps parse your summary correctly in the output logs.`; + prompt += `\n${taskExecutionPrompts.implementationInstructions}\n\n${taskExecutionPrompts.playwrightVerificationInstructions}`; } return prompt; @@ -2910,6 +2868,12 @@ After generating the revised spec, output: `Starting multi-agent execution: ${parsedTasks.length} tasks for feature ${featureId}` ); + // Get customized prompts for task execution + const taskPrompts = await getPromptCustomization( + this.settingsService, + '[AutoMode]' + ); + // Execute each task with a separate agent for (let taskIndex = 0; taskIndex < parsedTasks.length; taskIndex++) { const task = parsedTasks[taskIndex]; @@ -2941,6 +2905,7 @@ After generating the revised spec, output: parsedTasks, taskIndex, approvedPlanContent, + taskPrompts.taskExecution.taskPromptTemplate, userFeedback ); @@ -3023,15 +2988,21 @@ After generating the revised spec, output: `No parsed tasks, using single-agent execution for feature ${featureId}` ); - const continuationPrompt = `The plan/specification has been approved. Now implement it. -${userFeedback ? `\n## User Feedback\n${userFeedback}\n` : ''} -## Approved Plan - -${approvedPlanContent} - -## Instructions - -Implement all the changes described in the plan above.`; + // Get customized prompts for continuation + const taskPrompts = await getPromptCustomization( + this.settingsService, + '[AutoMode]' + ); + let continuationPrompt = + taskPrompts.taskExecution.continuationAfterApprovalTemplate; + continuationPrompt = continuationPrompt.replace( + /\{\{userFeedback\}\}/g, + userFeedback || '' + ); + continuationPrompt = continuationPrompt.replace( + /\{\{approvedPlan\}\}/g, + approvedPlanContent + ); const continuationStream = provider.executeQuery({ prompt: continuationPrompt, @@ -3151,17 +3122,16 @@ Implement all the changes described in the plan above.`; throw new Error(`Feature ${featureId} not found`); } - const prompt = `## Continuing Feature Implementation + // Get customized prompts from settings + const prompts = await getPromptCustomization(this.settingsService, '[AutoMode]'); -${this.buildFeaturePrompt(feature)} + // Build the feature prompt + const featurePrompt = this.buildFeaturePrompt(feature, prompts.taskExecution); -## Previous Context -The following is the output from a previous implementation attempt. Continue from where you left off: - -${context} - -## Instructions -Review the previous work and continue the implementation. If the feature appears complete, verify it works correctly.`; + // Use the resume feature template with variable substitution + let prompt = prompts.taskExecution.resumeFeatureTemplate; + prompt = prompt.replace(/\{\{featurePrompt\}\}/g, featurePrompt); + prompt = prompt.replace(/\{\{previousContext\}\}/g, context); return this.executeFeature(projectPath, featureId, useWorktrees, false, undefined, { continuationPrompt: prompt, @@ -3282,68 +3252,42 @@ Review the previous work and continue the implementation. If the feature appears allTasks: ParsedTask[], taskIndex: number, planContent: string, + taskPromptTemplate: string, userFeedback?: string ): string { const completedTasks = allTasks.slice(0, taskIndex); const remainingTasks = allTasks.slice(taskIndex + 1); - let prompt = `# Task Execution: ${task.id} + // Build completed tasks string + const completedTasksStr = + completedTasks.length > 0 + ? `### Already Completed (${completedTasks.length} tasks)\n${completedTasks.map((t) => `- [x] ${t.id}: ${t.description}`).join('\n')}\n` + : ''; -You are executing a specific task as part of a larger feature implementation. + // Build remaining tasks string + const remainingTasksStr = + remainingTasks.length > 0 + ? `### Coming Up Next (${remainingTasks.length} tasks remaining)\n${remainingTasks + .slice(0, 3) + .map((t) => `- [ ] ${t.id}: ${t.description}`) + .join( + '\n' + )}${remainingTasks.length > 3 ? `\n... and ${remainingTasks.length - 3} more tasks` : ''}\n` + : ''; -## Your Current Task + // Build user feedback string + const userFeedbackStr = userFeedback ? `### User Feedback\n${userFeedback}\n` : ''; -**Task ID:** ${task.id} -**Description:** ${task.description} -${task.filePath ? `**Primary File:** ${task.filePath}` : ''} -${task.phase ? `**Phase:** ${task.phase}` : ''} - -## Context - -`; - - // Show what's already done - if (completedTasks.length > 0) { - prompt += `### Already Completed (${completedTasks.length} tasks) -${completedTasks.map((t) => `- [x] ${t.id}: ${t.description}`).join('\n')} - -`; - } - - // Show remaining tasks - if (remainingTasks.length > 0) { - prompt += `### Coming Up Next (${remainingTasks.length} tasks remaining) -${remainingTasks - .slice(0, 3) - .map((t) => `- [ ] ${t.id}: ${t.description}`) - .join('\n')} -${remainingTasks.length > 3 ? `... and ${remainingTasks.length - 3} more tasks` : ''} - -`; - } - - // Add user feedback if any - if (userFeedback) { - prompt += `### User Feedback -${userFeedback} - -`; - } - - // Add relevant excerpt from plan (just the task-related part to save context) - prompt += `### Reference: Full Plan -
-${planContent} -
- -## Instructions - -1. Focus ONLY on completing task ${task.id}: "${task.description}" -2. Do not work on other tasks -3. Use the existing codebase patterns -4. When done, summarize what you implemented - -Begin implementing task ${task.id} now.`; + // Use centralized template with variable substitution + let prompt = taskPromptTemplate; + prompt = prompt.replace(/\{\{taskId\}\}/g, task.id); + prompt = prompt.replace(/\{\{taskDescription\}\}/g, task.description); + prompt = prompt.replace(/\{\{taskFilePath\}\}/g, task.filePath || ''); + prompt = prompt.replace(/\{\{taskPhase\}\}/g, task.phase || ''); + prompt = prompt.replace(/\{\{completedTasks\}\}/g, completedTasksStr); + prompt = prompt.replace(/\{\{remainingTasks\}\}/g, remainingTasksStr); + prompt = prompt.replace(/\{\{userFeedback\}\}/g, userFeedbackStr); + prompt = prompt.replace(/\{\{planContent\}\}/g, planContent); return prompt; } @@ -3553,32 +3497,13 @@ Begin implementing task ${task.id} now.`; // Limit output to avoid token limits const truncatedOutput = agentOutput.length > 10000 ? agentOutput.slice(-10000) : agentOutput; - const userPrompt = `You are an Architecture Decision Record (ADR) extractor. Analyze this implementation and return ONLY JSON with learnings. No explanations. + // Get customized prompts from settings + const prompts = await getPromptCustomization(this.settingsService, '[AutoMode]'); -Feature: "${feature.title}" - -Implementation log: -${truncatedOutput} - -Extract MEANINGFUL learnings - not obvious things. For each, capture: -- DECISIONS: Why this approach vs alternatives? What would break if changed? -- GOTCHAS: What was unexpected? What's the root cause? How to avoid? -- PATTERNS: Why this pattern? What problem does it solve? Trade-offs? - -JSON format ONLY (no markdown, no text): -{"learnings": [{ - "category": "architecture|api|ui|database|auth|testing|performance|security|gotchas", - "type": "decision|gotcha|pattern", - "content": "What was done/learned", - "context": "Problem being solved or situation faced", - "why": "Reasoning - why this approach", - "rejected": "Alternative considered and why rejected", - "tradeoffs": "What became easier/harder", - "breaking": "What breaks if this is changed/removed" -}]} - -IMPORTANT: Only include NON-OBVIOUS learnings with real reasoning. Skip trivial patterns. -If nothing notable: {"learnings": []}`; + // Build user prompt using centralized template with variable substitution + let userPrompt = prompts.taskExecution.learningExtractionUserPromptTemplate; + userPrompt = userPrompt.replace(/\{\{featureTitle\}\}/g, feature.title || ''); + userPrompt = userPrompt.replace(/\{\{implementationLog\}\}/g, truncatedOutput); try { // Get model from phase settings @@ -3612,8 +3537,7 @@ If nothing notable: {"learnings": []}`; cwd: projectPath, maxTurns: 1, allowedTools: [], - systemPrompt: - 'You are a JSON extraction assistant. You MUST respond with ONLY valid JSON, no explanations, no markdown, no other text. Extract learnings from the provided implementation context and return them as JSON.', + systemPrompt: prompts.taskExecution.learningExtractionSystemPrompt, }); const responseText = result.text; From 1abf21923051342377a2292c6356b4fd43c9b579 Mon Sep 17 00:00:00 2001 From: Shirone Date: Thu, 15 Jan 2026 21:00:32 +0100 Subject: [PATCH 07/93] refactor: create reusable PromptTabContent component and add {{count}} placeholder - Create PromptTabContent reusable component in prompt-customization-section.tsx - Update all tabs (Agent, Commit Message, Title Generation, Ideation, App Spec, Context Description, Suggestions, Task Execution) to use the new component - Add {{count}} placeholder to DEFAULT_SUGGESTIONS_SYSTEM_PROMPT for dynamic suggestion count Addresses PR review comments from Gemini. Co-Authored-By: Claude Opus 4.5 --- .../prompts/prompt-customization-section.tsx | 700 ++++++++---------- libs/prompts/src/defaults.ts | 2 +- 2 files changed, 326 insertions(+), 376 deletions(-) diff --git a/apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx b/apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx index a6b9bf44..c0a7308e 100644 --- a/apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx +++ b/apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx @@ -65,6 +65,44 @@ function calculateMinHeight(text: string): string { return `${minHeight}px`; } +/** + * PromptTabContent Component + * + * Reusable container for prompt customization tabs. + * Provides consistent header with title and reset button. + */ +interface PromptTabContentProps { + value: string; + title: string; + category: keyof PromptCustomization; + onReset: (category: keyof PromptCustomization) => void; + children: React.ReactNode; + infoBanner?: React.ReactNode; +} + +function PromptTabContent({ + value, + title, + category, + onReset, + children, + infoBanner, +}: PromptTabContentProps) { + return ( + +
+

{title}

+ +
+ {infoBanner} +
{children}
+
+ ); +} + /** * PromptField Component * @@ -423,30 +461,20 @@ export function PromptCustomizationSection({ {/* Agent Tab */} - -
-

Agent Runner Prompts

- -
- -
- updatePrompt('agent', 'systemPrompt', value)} - /> -
-
+ + updatePrompt('agent', 'systemPrompt', value)} + /> + {/* Backlog Plan Tab */} @@ -569,60 +597,38 @@ export function PromptCustomizationSection({ {/* Commit Message Tab */} - -
-

Commit Message Prompts

- -
- -
- - updatePrompt('commitMessage', 'systemPrompt', value) - } - /> -
-
+ + updatePrompt('commitMessage', 'systemPrompt', value)} + /> + {/* Title Generation Tab */} - -
-

Title Generation Prompts

- -
- -
- - updatePrompt('titleGeneration', 'systemPrompt', value) - } - /> -
-
+ + + updatePrompt('titleGeneration', 'systemPrompt', value) + } + /> + {/* Issue Validation Tab */} @@ -667,330 +673,274 @@ export function PromptCustomizationSection({ {/* Ideation Tab */} - -
-

Ideation Prompts

- -
+ + + updatePrompt('ideation', 'ideationSystemPrompt', value) + } + /> -
- - updatePrompt('ideation', 'ideationSystemPrompt', value) - } - /> - - - updatePrompt('ideation', 'suggestionsSystemPrompt', value) - } - critical={true} - /> -
-
+ + updatePrompt('ideation', 'suggestionsSystemPrompt', value) + } + critical={true} + /> + {/* App Spec Tab */} - -
-

App Specification Prompts

- -
+ + + updatePrompt('appSpec', 'generateSpecSystemPrompt', value) + } + /> -
- - updatePrompt('appSpec', 'generateSpecSystemPrompt', value) - } - /> + + updatePrompt('appSpec', 'structuredSpecInstructions', value) + } + critical={true} + /> - - updatePrompt('appSpec', 'structuredSpecInstructions', value) - } - critical={true} - /> - - - updatePrompt('appSpec', 'generateFeaturesFromSpecPrompt', value) - } - critical={true} - /> -
-
+ + updatePrompt('appSpec', 'generateFeaturesFromSpecPrompt', value) + } + critical={true} + /> + {/* Context Description Tab */} - -
-

Context Description Prompts

- -
+ + + updatePrompt('contextDescription', 'describeFilePrompt', value) + } + /> -
- - updatePrompt('contextDescription', 'describeFilePrompt', value) - } - /> - - - updatePrompt('contextDescription', 'describeImagePrompt', value) - } - /> -
-
+ + updatePrompt('contextDescription', 'describeImagePrompt', value) + } + /> + {/* Suggestions Tab */} - -
-

Suggestions Prompts

- -
+ + updatePrompt('suggestions', 'featuresPrompt', value)} + /> -
- - updatePrompt('suggestions', 'featuresPrompt', value) - } - /> + + updatePrompt('suggestions', 'refactoringPrompt', value) + } + /> - - updatePrompt('suggestions', 'refactoringPrompt', value) - } - /> + updatePrompt('suggestions', 'securityPrompt', value)} + /> - - updatePrompt('suggestions', 'securityPrompt', value) - } - /> + + updatePrompt('suggestions', 'performancePrompt', value) + } + /> - - updatePrompt('suggestions', 'performancePrompt', value) - } - /> - - updatePrompt('suggestions', 'baseTemplate', value)} - /> -
-
+ updatePrompt('suggestions', 'baseTemplate', value)} + /> + {/* Task Execution Tab */} - -
-

Task Execution Prompts

- -
- - {/* Info Banner for Task Execution */} -
- -
-

Template Variables

-

- Task execution prompts use Handlebars syntax for variable substitution. Variables - include{' '} - {'{{taskId}}'},{' '} - - {'{{taskDescription}}'} - - ,{' '} - - {'{{completedTasks}}'} - - , etc. -

+ + +
+

Template Variables

+

+ Task execution prompts use Handlebars syntax for variable substitution. + Variables include{' '} + {'{{taskId}}'},{' '} + + {'{{taskDescription}}'} + + ,{' '} + + {'{{completedTasks}}'} + + , etc. +

+
-
+ } + > + + updatePrompt('taskExecution', 'taskPromptTemplate', value) + } + /> -
- - updatePrompt('taskExecution', 'taskPromptTemplate', value) - } - /> + + updatePrompt('taskExecution', 'implementationInstructions', value) + } + /> - - updatePrompt('taskExecution', 'implementationInstructions', value) - } - /> + + updatePrompt('taskExecution', 'playwrightVerificationInstructions', value) + } + /> - - updatePrompt('taskExecution', 'playwrightVerificationInstructions', value) - } - /> + + updatePrompt('taskExecution', 'learningExtractionSystemPrompt', value) + } + critical={true} + /> - - updatePrompt('taskExecution', 'learningExtractionSystemPrompt', value) - } - critical={true} - /> + + updatePrompt('taskExecution', 'learningExtractionUserPromptTemplate', value) + } + critical={true} + /> - - updatePrompt('taskExecution', 'learningExtractionUserPromptTemplate', value) - } - critical={true} - /> + + updatePrompt('taskExecution', 'planRevisionTemplate', value) + } + /> - - updatePrompt('taskExecution', 'planRevisionTemplate', value) - } - /> + + updatePrompt('taskExecution', 'continuationAfterApprovalTemplate', value) + } + /> - - updatePrompt('taskExecution', 'continuationAfterApprovalTemplate', value) - } - /> + + updatePrompt('taskExecution', 'resumeFeatureTemplate', value) + } + /> - - updatePrompt('taskExecution', 'resumeFeatureTemplate', value) - } - /> - - - updatePrompt('taskExecution', 'projectAnalysisPrompt', value) - } - /> -
-
+ + updatePrompt('taskExecution', 'projectAnalysisPrompt', value) + } + /> + diff --git a/libs/prompts/src/defaults.ts b/libs/prompts/src/defaults.ts index 27aa332e..a582313d 100644 --- a/libs/prompts/src/defaults.ts +++ b/libs/prompts/src/defaults.ts @@ -604,7 +604,7 @@ IMPORTANT: You do NOT have access to any tools. You CANNOT read files, search co You must generate suggestions based ONLY on the project context provided below. Do NOT say "I'll analyze" or "Let me explore" - you cannot do those things. -Based on the project context and the user's prompt, generate creative and actionable feature suggestions. +Based on the project context and the user's prompt, generate exactly {{count}} creative and actionable feature suggestions. YOUR RESPONSE MUST BE ONLY A JSON ARRAY - nothing else. No explanation, no preamble, no markdown code fences. From d6c5c93fe5c86dbf6c624f5f84557c4cf38bd5f2 Mon Sep 17 00:00:00 2001 From: Shirone Date: Thu, 15 Jan 2026 21:03:51 +0100 Subject: [PATCH 08/93] refactor: use data-driven configuration for prompt customization UI - Replace repetitive JSX with TAB_CONFIGS array defining all tabs and fields - Create reusable Banner component for info/warning banners - Create PromptFieldList component for rendering fields from config - Support nested sections (like Auto Mode's Template Prompts section) - Reduce file from ~950 lines to ~810 lines (-15% code) Benefits: - Adding new prompt tabs/fields is now declarative (just add to config) - Consistent structure enforced by TypeScript interfaces - Much easier to maintain and extend Co-Authored-By: Claude Opus 4.5 --- .../prompts/prompt-customization-section.tsx | 1302 ++++++++--------- 1 file changed, 586 insertions(+), 716 deletions(-) diff --git a/apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx b/apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx index c0a7308e..40ecf569 100644 --- a/apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx +++ b/apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx @@ -1,4 +1,5 @@ import { useState } from 'react'; +import type { LucideIcon } from 'lucide-react'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Button } from '@/components/ui/button'; @@ -38,6 +39,10 @@ import { DEFAULT_TASK_EXECUTION_PROMPTS, } from '@automaker/prompts'; +// ============================================================================= +// Types +// ============================================================================= + interface PromptCustomizationSectionProps { promptCustomization?: PromptCustomization; onPromptCustomizationChange: (customization: PromptCustomization) => void; @@ -49,69 +54,506 @@ interface PromptFieldProps { defaultValue: string; customValue?: CustomPrompt; onCustomValueChange: (value: CustomPrompt | undefined) => void; - critical?: boolean; // Whether this prompt requires strict output format + critical?: boolean; } +/** Configuration for a single prompt field */ +interface PromptFieldConfig { + key: string; + label: string; + description: string; + defaultValue: string; + critical?: boolean; +} + +/** Banner type for tabs */ +type BannerType = 'info' | 'warning'; + +interface BannerConfig { + type: BannerType; + title: string; + description: string; +} + +/** Configuration for a tab with prompt fields */ +interface TabConfig { + id: string; + label: string; + icon: LucideIcon; + title: string; + category: keyof PromptCustomization; + banner?: BannerConfig; + fields: PromptFieldConfig[]; + /** For tabs with grouped sections (like Auto Mode) */ + sections?: { + title?: string; + banner?: BannerConfig; + fields: PromptFieldConfig[]; + }[]; +} + +// ============================================================================= +// Tab Configuration +// ============================================================================= + +const TAB_CONFIGS: TabConfig[] = [ + { + id: 'auto-mode', + label: 'Auto Mode', + icon: Bot, + title: 'Auto Mode Prompts', + category: 'autoMode', + banner: { + type: 'info', + title: 'Planning Mode Markers', + description: + 'Planning prompts use special markers like [PLAN_GENERATED] and [SPEC_GENERATED] to control the Auto Mode workflow. These markers must be preserved for proper functionality.', + }, + fields: [ + { + key: 'planningLite', + label: 'Planning: Lite Mode', + description: 'Quick planning outline without approval requirement', + defaultValue: DEFAULT_AUTO_MODE_PROMPTS.planningLite, + critical: true, + }, + { + key: 'planningLiteWithApproval', + label: 'Planning: Lite with Approval', + description: 'Planning outline that waits for user approval', + defaultValue: DEFAULT_AUTO_MODE_PROMPTS.planningLiteWithApproval, + critical: true, + }, + { + key: 'planningSpec', + label: 'Planning: Spec Mode', + description: 'Detailed specification with task breakdown', + defaultValue: DEFAULT_AUTO_MODE_PROMPTS.planningSpec, + critical: true, + }, + { + key: 'planningFull', + label: 'Planning: Full SDD Mode', + description: 'Comprehensive Software Design Document with phased implementation', + defaultValue: DEFAULT_AUTO_MODE_PROMPTS.planningFull, + critical: true, + }, + ], + sections: [ + { + title: 'Template Prompts', + banner: { + type: 'info', + title: 'Template Variables', + description: + 'Template prompts use Handlebars syntax for variable substitution. Available variables include {{featureId}}, {{title}}, {{description}}, etc.', + }, + fields: [ + { + key: 'featurePromptTemplate', + label: 'Feature Prompt Template', + description: + 'Template for building feature implementation prompts. Variables: featureId, title, description, spec, imagePaths, dependencies, verificationInstructions', + defaultValue: DEFAULT_AUTO_MODE_PROMPTS.featurePromptTemplate, + }, + { + key: 'followUpPromptTemplate', + label: 'Follow-up Prompt Template', + description: + 'Template for follow-up prompts when resuming work. Variables: featurePrompt, previousContext, followUpInstructions', + defaultValue: DEFAULT_AUTO_MODE_PROMPTS.followUpPromptTemplate, + }, + { + key: 'continuationPromptTemplate', + label: 'Continuation Prompt Template', + description: + 'Template for continuation prompts. Variables: featurePrompt, previousContext', + defaultValue: DEFAULT_AUTO_MODE_PROMPTS.continuationPromptTemplate, + }, + { + key: 'pipelineStepPromptTemplate', + label: 'Pipeline Step Prompt Template', + description: + 'Template for pipeline step execution prompts. Variables: stepName, featurePrompt, previousContext, stepInstructions', + defaultValue: DEFAULT_AUTO_MODE_PROMPTS.pipelineStepPromptTemplate, + }, + ], + }, + ], + }, + { + id: 'agent', + label: 'Agent', + icon: MessageSquareText, + title: 'Agent Runner Prompts', + category: 'agent', + fields: [ + { + key: 'systemPrompt', + label: 'System Prompt', + description: "Defines the AI's role and behavior in interactive chat sessions", + defaultValue: DEFAULT_AGENT_PROMPTS.systemPrompt, + }, + ], + }, + { + id: 'backlog-plan', + label: 'Backlog', + icon: KanbanSquare, + title: 'Backlog Planning Prompts', + category: 'backlogPlan', + banner: { + type: 'warning', + title: 'Warning: Critical Prompts', + description: + 'Backlog plan prompts require a strict JSON output format. Modifying these prompts incorrectly can break the backlog planning feature and potentially corrupt your feature data. Only customize if you fully understand the expected output structure.', + }, + fields: [ + { + key: 'systemPrompt', + label: 'System Prompt', + description: + 'Defines how the AI modifies the feature backlog (Plan button on Kanban board)', + defaultValue: DEFAULT_BACKLOG_PLAN_PROMPTS.systemPrompt, + critical: true, + }, + { + key: 'userPromptTemplate', + label: 'User Prompt Template', + description: + 'Template for the user prompt sent to the AI. Variables: currentFeatures, userRequest', + defaultValue: DEFAULT_BACKLOG_PLAN_PROMPTS.userPromptTemplate, + critical: true, + }, + ], + }, + { + id: 'enhancement', + label: 'Enhancement', + icon: Sparkles, + title: 'Enhancement Prompts', + category: 'enhancement', + fields: [ + { + key: 'improveSystemPrompt', + label: 'Improve Mode', + description: 'Transform vague requests into clear, actionable tasks', + defaultValue: DEFAULT_ENHANCEMENT_PROMPTS.improveSystemPrompt, + }, + { + key: 'technicalSystemPrompt', + label: 'Technical Mode', + description: 'Add implementation details and technical specifications', + defaultValue: DEFAULT_ENHANCEMENT_PROMPTS.technicalSystemPrompt, + }, + { + key: 'simplifySystemPrompt', + label: 'Simplify Mode', + description: 'Make verbose descriptions concise and focused', + defaultValue: DEFAULT_ENHANCEMENT_PROMPTS.simplifySystemPrompt, + }, + { + key: 'acceptanceSystemPrompt', + label: 'Acceptance Criteria Mode', + description: 'Add testable acceptance criteria to descriptions', + defaultValue: DEFAULT_ENHANCEMENT_PROMPTS.acceptanceSystemPrompt, + }, + { + key: 'uxReviewerSystemPrompt', + label: 'User Experience Mode', + description: 'Review and enhance from a user experience and design perspective', + defaultValue: DEFAULT_ENHANCEMENT_PROMPTS.uxReviewerSystemPrompt, + }, + ], + }, + { + id: 'commit-message', + label: 'Commit', + icon: GitCommitHorizontal, + title: 'Commit Message Prompts', + category: 'commitMessage', + fields: [ + { + key: 'systemPrompt', + label: 'System Prompt', + description: + 'Instructions for generating git commit messages from diffs. The AI will receive the git diff and generate a conventional commit message.', + defaultValue: DEFAULT_COMMIT_MESSAGE_PROMPTS.systemPrompt, + }, + ], + }, + { + id: 'title-generation', + label: 'Title', + icon: Type, + title: 'Title Generation Prompts', + category: 'titleGeneration', + fields: [ + { + key: 'systemPrompt', + label: 'System Prompt', + description: + 'Instructions for generating concise, descriptive feature titles from descriptions. Used when auto-generating titles for new features.', + defaultValue: DEFAULT_TITLE_GENERATION_PROMPTS.systemPrompt, + }, + ], + }, + { + id: 'issue-validation', + label: 'Issues', + icon: CheckCircle, + title: 'Issue Validation Prompts', + category: 'issueValidation', + banner: { + type: 'warning', + title: 'Warning: Critical Prompt', + description: + 'The issue validation prompt guides the AI through a structured validation process and expects specific output format. Modifying this prompt incorrectly may affect validation accuracy.', + }, + fields: [ + { + key: 'systemPrompt', + label: 'System Prompt', + description: + 'Instructions for validating GitHub issues against the codebase. Guides the AI to determine if issues are valid, invalid, or need clarification.', + defaultValue: DEFAULT_ISSUE_VALIDATION_PROMPTS.systemPrompt, + critical: true, + }, + ], + }, + { + id: 'ideation', + label: 'Ideation', + icon: Lightbulb, + title: 'Ideation Prompts', + category: 'ideation', + fields: [ + { + key: 'ideationSystemPrompt', + label: 'Ideation Chat System Prompt', + description: + 'System prompt for AI-powered ideation chat conversations. Guides the AI to brainstorm and suggest feature ideas.', + defaultValue: DEFAULT_IDEATION_PROMPTS.ideationSystemPrompt, + }, + { + key: 'suggestionsSystemPrompt', + label: 'Suggestions System Prompt', + description: + 'System prompt for generating structured feature suggestions. Used when generating batch suggestions from prompts.', + defaultValue: DEFAULT_IDEATION_PROMPTS.suggestionsSystemPrompt, + critical: true, + }, + ], + }, + { + id: 'app-spec', + label: 'App Spec', + icon: FileCode, + title: 'App Specification Prompts', + category: 'appSpec', + fields: [ + { + key: 'generateSpecSystemPrompt', + label: 'Generate Spec System Prompt', + description: 'System prompt for generating project specifications from overview', + defaultValue: DEFAULT_APP_SPEC_PROMPTS.generateSpecSystemPrompt, + }, + { + key: 'structuredSpecInstructions', + label: 'Structured Spec Instructions', + description: 'Instructions for structured specification output format', + defaultValue: DEFAULT_APP_SPEC_PROMPTS.structuredSpecInstructions, + critical: true, + }, + { + key: 'generateFeaturesFromSpecPrompt', + label: 'Generate Features from Spec', + description: 'Prompt for generating features from a project specification', + defaultValue: DEFAULT_APP_SPEC_PROMPTS.generateFeaturesFromSpecPrompt, + critical: true, + }, + ], + }, + { + id: 'context-description', + label: 'Context', + icon: FileText, + title: 'Context Description Prompts', + category: 'contextDescription', + fields: [ + { + key: 'describeFilePrompt', + label: 'Describe File Prompt', + description: 'Prompt for generating descriptions of text files added as context', + defaultValue: DEFAULT_CONTEXT_DESCRIPTION_PROMPTS.describeFilePrompt, + }, + { + key: 'describeImagePrompt', + label: 'Describe Image Prompt', + description: 'Prompt for generating descriptions of images added as context', + defaultValue: DEFAULT_CONTEXT_DESCRIPTION_PROMPTS.describeImagePrompt, + }, + ], + }, + { + id: 'suggestions', + label: 'Suggestions', + icon: Wand2, + title: 'Suggestions Prompts', + category: 'suggestions', + fields: [ + { + key: 'featuresPrompt', + label: 'Features Suggestion Prompt', + description: 'Prompt for analyzing the project and suggesting new features', + defaultValue: DEFAULT_SUGGESTIONS_PROMPTS.featuresPrompt, + }, + { + key: 'refactoringPrompt', + label: 'Refactoring Suggestion Prompt', + description: 'Prompt for identifying refactoring opportunities', + defaultValue: DEFAULT_SUGGESTIONS_PROMPTS.refactoringPrompt, + }, + { + key: 'securityPrompt', + label: 'Security Suggestion Prompt', + description: 'Prompt for analyzing security vulnerabilities', + defaultValue: DEFAULT_SUGGESTIONS_PROMPTS.securityPrompt, + }, + { + key: 'performancePrompt', + label: 'Performance Suggestion Prompt', + description: 'Prompt for identifying performance issues', + defaultValue: DEFAULT_SUGGESTIONS_PROMPTS.performancePrompt, + }, + { + key: 'baseTemplate', + label: 'Base Template', + description: 'Base template applied to all suggestion types', + defaultValue: DEFAULT_SUGGESTIONS_PROMPTS.baseTemplate, + }, + ], + }, + { + id: 'task-execution', + label: 'Tasks', + icon: Cog, + title: 'Task Execution Prompts', + category: 'taskExecution', + banner: { + type: 'info', + title: 'Template Variables', + description: + 'Task execution prompts use Handlebars syntax for variable substitution. Variables include {{taskId}}, {{taskDescription}}, {{completedTasks}}, etc.', + }, + fields: [ + { + key: 'taskPromptTemplate', + label: 'Task Prompt Template', + description: 'Template for building individual task execution prompts', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.taskPromptTemplate, + }, + { + key: 'implementationInstructions', + label: 'Implementation Instructions', + description: 'Instructions appended to feature implementation prompts', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.implementationInstructions, + }, + { + key: 'playwrightVerificationInstructions', + label: 'Playwright Verification Instructions', + description: 'Instructions for automated Playwright verification (when enabled)', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.playwrightVerificationInstructions, + }, + { + key: 'learningExtractionSystemPrompt', + label: 'Learning Extraction System Prompt', + description: 'System prompt for extracting learnings/ADRs from implementation output', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.learningExtractionSystemPrompt, + critical: true, + }, + { + key: 'learningExtractionUserPromptTemplate', + label: 'Learning Extraction User Template', + description: + 'User prompt template for learning extraction. Variables: featureTitle, implementationLog', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.learningExtractionUserPromptTemplate, + critical: true, + }, + { + key: 'planRevisionTemplate', + label: 'Plan Revision Template', + description: + 'Template for prompting plan revisions. Variables: planVersion, previousPlan, userFeedback', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.planRevisionTemplate, + }, + { + key: 'continuationAfterApprovalTemplate', + label: 'Continuation After Approval Template', + description: + 'Template for continuation after plan approval. Variables: userFeedback, approvedPlan', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.continuationAfterApprovalTemplate, + }, + { + key: 'resumeFeatureTemplate', + label: 'Resume Feature Template', + description: + 'Template for resuming interrupted features. Variables: featurePrompt, previousContext', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.resumeFeatureTemplate, + }, + { + key: 'projectAnalysisPrompt', + label: 'Project Analysis Prompt', + description: 'Prompt for AI-powered project analysis', + defaultValue: DEFAULT_TASK_EXECUTION_PROMPTS.projectAnalysisPrompt, + }, + ], + }, +]; + +// ============================================================================= +// Helper Components +// ============================================================================= + /** * Calculate dynamic minimum height based on content length - * Ensures long prompts have adequate space */ function calculateMinHeight(text: string): string { const lines = text.split('\n').length; const estimatedLines = Math.max(lines, Math.ceil(text.length / 80)); - - // Min 120px, scales up for longer content, max 600px const minHeight = Math.min(Math.max(120, estimatedLines * 20), 600); return `${minHeight}px`; } /** - * PromptTabContent Component - * - * Reusable container for prompt customization tabs. - * Provides consistent header with title and reset button. + * Renders an info or warning banner */ -interface PromptTabContentProps { - value: string; - title: string; - category: keyof PromptCustomization; - onReset: (category: keyof PromptCustomization) => void; - children: React.ReactNode; - infoBanner?: React.ReactNode; -} +function Banner({ config }: { config: BannerConfig }) { + const isWarning = config.type === 'warning'; + const Icon = isWarning ? AlertTriangle : Info; -function PromptTabContent({ - value, - title, - category, - onReset, - children, - infoBanner, -}: PromptTabContentProps) { return ( - -
-

{title}

- +
+ +
+

{config.title}

+

{config.description}

- {infoBanner} -
{children}
- +
); } /** - * PromptField Component - * - * Shows a prompt with a toggle to switch between default and custom mode. - * - Toggle OFF: Shows default prompt in read-only mode, custom value is preserved but not used - * - Toggle ON: Allows editing, custom value is used instead of default - * - * IMPORTANT: Custom value is ALWAYS preserved, even when toggle is OFF. - * This prevents users from losing their work when temporarily switching to default. + * PromptField Component - Shows a prompt with toggle for custom/default mode */ function PromptField({ label, @@ -126,14 +568,11 @@ function PromptField({ const minHeight = calculateMinHeight(displayValue); const handleToggle = (enabled: boolean) => { - // When toggling, preserve the existing custom value if it exists, - // otherwise initialize with the default value. const value = customValue?.value ?? defaultValue; onCustomValueChange({ value, enabled }); }; const handleTextChange = (newValue: string) => { - // Only allow editing when enabled if (isEnabled) { onCustomValueChange({ value: newValue, enabled: true }); } @@ -143,7 +582,7 @@ function PromptField({
{critical && isEnabled && (
- +

Critical Prompt

@@ -183,23 +622,57 @@ function PromptField({ } /** - * PromptCustomizationSection Component - * - * Allows users to customize AI prompts for different parts of the application: - * - Auto Mode (feature implementation) - * - Agent Runner (interactive chat) - * - Backlog Plan (Kanban planning) - * - Enhancement (feature description improvement) + * Renders a list of prompt fields from configuration */ +function PromptFieldList({ + fields, + category, + promptCustomization, + updatePrompt, +}: { + fields: PromptFieldConfig[]; + category: keyof PromptCustomization; + promptCustomization?: PromptCustomization; + updatePrompt: ( + category: keyof PromptCustomization, + field: string, + value: CustomPrompt | undefined + ) => void; +}) { + return ( + <> + {fields.map((field) => ( + | undefined)?.[ + field.key + ] + } + onCustomValueChange={(value) => updatePrompt(category, field.key, value)} + critical={field.critical} + /> + ))} + + ); +} + +// ============================================================================= +// Main Component +// ============================================================================= + export function PromptCustomizationSection({ promptCustomization = {}, onPromptCustomizationChange, }: PromptCustomizationSectionProps) { const [activeTab, setActiveTab] = useState('auto-mode'); - const updatePrompt = ( - category: T, - field: keyof NonNullable, + const updatePrompt = ( + category: keyof PromptCustomization, + field: string, value: CustomPrompt | undefined ) => { const updated = { @@ -258,7 +731,7 @@ export function PromptCustomizationSection({ {/* Info Banner */}

- +

How to Customize Prompts

@@ -274,673 +747,70 @@ export function PromptCustomizationSection({

- - - Auto Mode - - - - Agent - - - - Backlog - - - - Enhancement - - - - Commit - - - - Title - - - - Issues - - - - Ideation - - - - App Spec - - - - Context - - - - Suggestions - - - - Tasks - + {TAB_CONFIGS.map((tab) => ( + + + {tab.label} + + ))} - {/* Auto Mode Tab */} - -
-

Auto Mode Prompts

- -
- - {/* Info Banner for Auto Mode */} -
- -
-

Planning Mode Markers

-

- Planning prompts use special markers like{' '} - [PLAN_GENERATED] and{' '} - [SPEC_GENERATED] to - control the Auto Mode workflow. These markers must be preserved for proper - functionality. -

+ {TAB_CONFIGS.map((tab) => ( + + {/* Tab Header */} +
+

{tab.title}

+
-
-
- updatePrompt('autoMode', 'planningLite', value)} - critical={true} - /> + {/* Tab Banner */} + {tab.banner && } - - updatePrompt('autoMode', 'planningLiteWithApproval', value) - } - critical={true} - /> - - updatePrompt('autoMode', 'planningSpec', value)} - critical={true} - /> - - updatePrompt('autoMode', 'planningFull', value)} - critical={true} - /> -
- - {/* Template Prompts Section */} -
-

Template Prompts

- - {/* Info Banner for Templates */} -
- -
-

Template Variables

-

- Template prompts use Handlebars syntax for variable substitution. Available - variables include{' '} - {'{{featureId}}'},{' '} - {'{{title}}'},{' '} - - {'{{description}}'} - - , etc. -

+ {/* Main Fields */} + {tab.fields.length > 0 && ( +
+
-
+ )} -
- - updatePrompt('autoMode', 'featurePromptTemplate', value) - } - /> - - - updatePrompt('autoMode', 'followUpPromptTemplate', value) - } - /> - - - updatePrompt('autoMode', 'continuationPromptTemplate', value) - } - /> - - - updatePrompt('autoMode', 'pipelineStepPromptTemplate', value) - } - /> -
-
- - - {/* Agent Tab */} - - updatePrompt('agent', 'systemPrompt', value)} - /> - - - {/* Backlog Plan Tab */} - -
-

Backlog Planning Prompts

- -
- - {/* Critical Warning for Backlog Plan */} -
- -
-

Warning: Critical Prompts

-

- Backlog plan prompts require a strict JSON output format. Modifying these prompts - incorrectly can break the backlog planning feature and potentially corrupt your - feature data. Only customize if you fully understand the expected output - structure. -

-
-
- -
- updatePrompt('backlogPlan', 'systemPrompt', value)} - critical={true} - /> - - - updatePrompt('backlogPlan', 'userPromptTemplate', value) - } - critical={true} - /> -
-
- - {/* Enhancement Tab */} - -
-

Enhancement Prompts

- -
- -
- - updatePrompt('enhancement', 'improveSystemPrompt', value) - } - /> - - - updatePrompt('enhancement', 'technicalSystemPrompt', value) - } - /> - - - updatePrompt('enhancement', 'simplifySystemPrompt', value) - } - /> - - - updatePrompt('enhancement', 'acceptanceSystemPrompt', value) - } - /> - - - updatePrompt('enhancement', 'uxReviewerSystemPrompt', value) - } - /> -
-
- - {/* Commit Message Tab */} - - updatePrompt('commitMessage', 'systemPrompt', value)} - /> - - - {/* Title Generation Tab */} - - - updatePrompt('titleGeneration', 'systemPrompt', value) - } - /> - - - {/* Issue Validation Tab */} - -
-

Issue Validation Prompts

- -
- - {/* Critical Warning for Issue Validation */} -
- -
-

Warning: Critical Prompt

-

- The issue validation prompt guides the AI through a structured validation process - and expects specific output format. Modifying this prompt incorrectly may affect - validation accuracy. -

-
-
- -
- - updatePrompt('issueValidation', 'systemPrompt', value) - } - critical={true} - /> -
-
- - {/* Ideation Tab */} - - - updatePrompt('ideation', 'ideationSystemPrompt', value) - } - /> - - - updatePrompt('ideation', 'suggestionsSystemPrompt', value) - } - critical={true} - /> - - - {/* App Spec Tab */} - - - updatePrompt('appSpec', 'generateSpecSystemPrompt', value) - } - /> - - - updatePrompt('appSpec', 'structuredSpecInstructions', value) - } - critical={true} - /> - - - updatePrompt('appSpec', 'generateFeaturesFromSpecPrompt', value) - } - critical={true} - /> - - - {/* Context Description Tab */} - - - updatePrompt('contextDescription', 'describeFilePrompt', value) - } - /> - - - updatePrompt('contextDescription', 'describeImagePrompt', value) - } - /> - - - {/* Suggestions Tab */} - - updatePrompt('suggestions', 'featuresPrompt', value)} - /> - - - updatePrompt('suggestions', 'refactoringPrompt', value) - } - /> - - updatePrompt('suggestions', 'securityPrompt', value)} - /> - - - updatePrompt('suggestions', 'performancePrompt', value) - } - /> - - updatePrompt('suggestions', 'baseTemplate', value)} - /> - - - {/* Task Execution Tab */} - - -
-

Template Variables

-

- Task execution prompts use Handlebars syntax for variable substitution. - Variables include{' '} - {'{{taskId}}'},{' '} - - {'{{taskDescription}}'} - - ,{' '} - - {'{{completedTasks}}'} - - , etc. -

+ {/* Sections (for tabs like Auto Mode with grouped fields) */} + {tab.sections?.map((section, idx) => ( +
+ {section.title && ( +

+ {section.title} +

+ )} + {section.banner && ( +
+ +
+ )} +
+ +
-
- } - > - - updatePrompt('taskExecution', 'taskPromptTemplate', value) - } - /> - - - updatePrompt('taskExecution', 'implementationInstructions', value) - } - /> - - - updatePrompt('taskExecution', 'playwrightVerificationInstructions', value) - } - /> - - - updatePrompt('taskExecution', 'learningExtractionSystemPrompt', value) - } - critical={true} - /> - - - updatePrompt('taskExecution', 'learningExtractionUserPromptTemplate', value) - } - critical={true} - /> - - - updatePrompt('taskExecution', 'planRevisionTemplate', value) - } - /> - - - updatePrompt('taskExecution', 'continuationAfterApprovalTemplate', value) - } - /> - - - updatePrompt('taskExecution', 'resumeFeatureTemplate', value) - } - /> - - - updatePrompt('taskExecution', 'projectAnalysisPrompt', value) - } - /> -
+ ))} + + ))}
From fd03cb4afad100b670efdbac3cdff9ca3f58ed48 Mon Sep 17 00:00:00 2001 From: Shirone Date: Thu, 15 Jan 2026 21:07:38 +0100 Subject: [PATCH 09/93] refactor: split prompt customization into multiple files Split prompt-customization-section.tsx into focused modules: - types.ts (51 lines) - Type definitions - tab-configs.ts (448 lines) - Configuration data for all tabs - components.tsx (159 lines) - Reusable Banner, PromptField, PromptFieldList - prompt-customization-section.tsx (176 lines) - Main component Benefits: - Main component reduced from ~810 to 176 lines - Clear separation of concerns - Easier to find and modify specific parts - Configuration data isolated for easy updates Co-Authored-By: Claude Opus 4.5 --- .../settings-view/prompts/components.tsx | 159 +++++ .../prompts/prompt-customization-section.tsx | 664 +----------------- .../settings-view/prompts/tab-configs.ts | 448 ++++++++++++ .../views/settings-view/prompts/types.ts | 51 ++ 4 files changed, 669 insertions(+), 653 deletions(-) create mode 100644 apps/ui/src/components/views/settings-view/prompts/components.tsx create mode 100644 apps/ui/src/components/views/settings-view/prompts/tab-configs.ts create mode 100644 apps/ui/src/components/views/settings-view/prompts/types.ts diff --git a/apps/ui/src/components/views/settings-view/prompts/components.tsx b/apps/ui/src/components/views/settings-view/prompts/components.tsx new file mode 100644 index 00000000..81eaeb05 --- /dev/null +++ b/apps/ui/src/components/views/settings-view/prompts/components.tsx @@ -0,0 +1,159 @@ +import { Label } from '@/components/ui/label'; +import { Textarea } from '@/components/ui/textarea'; +import { Switch } from '@/components/ui/switch'; +import { Info, AlertTriangle } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import type { PromptCustomization, CustomPrompt } from '@automaker/types'; +import type { BannerConfig, PromptFieldConfig, PromptFieldProps } from './types'; + +/** + * Calculate dynamic minimum height based on content length. + * Ensures long prompts have adequate space. + */ +export function calculateMinHeight(text: string): string { + const lines = text.split('\n').length; + const estimatedLines = Math.max(lines, Math.ceil(text.length / 80)); + const minHeight = Math.min(Math.max(120, estimatedLines * 20), 600); + return `${minHeight}px`; +} + +/** + * Renders an info or warning banner. + */ +export function Banner({ config }: { config: BannerConfig }) { + const isWarning = config.type === 'warning'; + const Icon = isWarning ? AlertTriangle : Info; + + return ( +
+ +
+

{config.title}

+

{config.description}

+
+
+ ); +} + +/** + * PromptField Component + * + * Shows a prompt with a toggle to switch between default and custom mode. + * - Toggle OFF: Shows default prompt in read-only mode + * - Toggle ON: Allows editing, custom value is used instead of default + * + * Custom value is always preserved, even when toggle is OFF. + */ +export function PromptField({ + label, + description, + defaultValue, + customValue, + onCustomValueChange, + critical = false, +}: PromptFieldProps) { + const isEnabled = customValue?.enabled ?? false; + const displayValue = isEnabled ? (customValue?.value ?? defaultValue) : defaultValue; + const minHeight = calculateMinHeight(displayValue); + + const handleToggle = (enabled: boolean) => { + const value = customValue?.value ?? defaultValue; + onCustomValueChange({ value, enabled }); + }; + + const handleTextChange = (newValue: string) => { + if (isEnabled) { + onCustomValueChange({ value: newValue, enabled: true }); + } + }; + + return ( +
+ {critical && isEnabled && ( +
+ +
+

Critical Prompt

+

+ This prompt requires a specific output format. Changing it incorrectly may break + functionality. Only modify if you understand the expected structure. +

+
+
+ )} +
+ +
+ {isEnabled ? 'Custom' : 'Default'} + +
+
+