diff --git a/.vscode/settings.json b/.vscode/settings.json index 67c2afe60..a03577882 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,5 +14,5 @@ "dist": true, "**/node_modules": true, ".vscode-test": true - }, + } } diff --git a/package-lock.json b/package-lock.json index 57a83c671..2327da06f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,14 +15,16 @@ "@microsoft/vscode-azext-azureutils": "^4.1.0", "@microsoft/vscode-azext-utils": "^4.1.0", "@microsoft/vscode-azext-webview": "^1.0.2", - "form-data": "^4.0.4", + "@microsoft/vscode-inproc-mcp": "^0.3.0", + "form-data": "^4.0.6", "fs-extra": "^11.3.0", "jsonc-parser": "^2.2.1", "semver": "^7.7.3", "uuid": "^14.0.0", "vscode-nls": "^5.0.1", "vscode-uri": "^3.0.7", - "ws": "^8.20.1" + "ws": "^8.21.0", + "zod": "^4.4.3" }, "devDependencies": { "@azure/arm-msi": "^2.1.0", @@ -2783,6 +2785,18 @@ "csstype": "^3.1.3" } }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -3324,6 +3338,22 @@ "@azure/ms-rest-azure-env": "^2.0.0" } }, + "node_modules/@microsoft/vscode-inproc-mcp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@microsoft/vscode-inproc-mcp/-/vscode-inproc-mcp-0.3.0.tgz", + "integrity": "sha512-OBzIyyknfjf/bUSw2f9Q6CGdsI5pEr7G5jT954TZVcw5XBRjAYaJtfnnLdCnRf1ddUO/iaxxT88qGi9/omHsJg==", + "license": "See LICENSE in the project root for license information.", + "dependencies": { + "@microsoft/vscode-azext-utils": "^4.0.0", + "@microsoft/vscode-processutils": "^0.2.1", + "@modelcontextprotocol/sdk": "^1.26.0", + "express": "~5", + "zod": "~4" + }, + "engines": { + "vscode": "^1.105.0" + } + }, "node_modules/@microsoft/vscode-processutils": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@microsoft/vscode-processutils/-/vscode-processutils-0.2.1.tgz", @@ -3361,6 +3391,46 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, "node_modules/@nevware21/ts-async": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.5.5.tgz", @@ -5321,6 +5391,44 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -5357,7 +5465,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -5389,7 +5496,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -5605,6 +5711,59 @@ "node": ">= 6" } }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -5706,6 +5865,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/c8": { "version": "10.1.3", "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", @@ -5756,7 +5924,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -6098,6 +6265,28 @@ "dev": true, "license": "MIT" }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -6105,6 +6294,24 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -6112,6 +6319,23 @@ "dev": true, "license": "MIT" }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cose-base": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", @@ -6126,7 +6350,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6862,6 +7085,15 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -7004,6 +7236,12 @@ "url": "https://bevry.me/fund" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, "node_modules/embla-carousel": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", @@ -7035,6 +7273,15 @@ "dev": true, "license": "MIT" }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/encoding-sniffer": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", @@ -7257,6 +7504,12 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -7498,6 +7751,36 @@ "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -7509,11 +7792,96 @@ "node": ">=6" } }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { "version": "3.3.3", @@ -7550,7 +7918,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", - "dev": true, "funding": [ { "type": "github", @@ -7609,6 +7976,27 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -7675,20 +8063,39 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -7945,9 +8352,10 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -7965,6 +8373,15 @@ "he": "bin/he" } }, + "node_modules/hono": { + "version": "4.12.28", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.28.tgz", + "integrity": "sha512-YwUvVpSF7m1yOblFPrU3Hbo8XhPheBoiyfGuII6z19LnOr6JpDnyyp7LFNrfV56wS8tpvtBFGRISHN02pDdLOA==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -8020,6 +8437,26 @@ "entities": "^4.4.0" } }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -8152,7 +8589,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, "license": "ISC" }, "node_modules/ini": { @@ -8173,6 +8609,24 @@ "node": ">=12" } }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -8309,6 +8763,12 @@ "node": ">=8" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -8348,7 +8808,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -8444,6 +8903,15 @@ "dev": true, "license": "MIT" }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -8481,9 +8949,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, "license": "MIT" }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -8876,6 +9349,27 @@ "dev": true, "license": "MIT" }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -9151,6 +9645,15 @@ "dev": true, "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -9251,11 +9754,19 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9264,13 +9775,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", - "optional": true, "dependencies": { "wrappy": "1" } @@ -9602,6 +10123,15 @@ "url": "https://ko-fi.com/killymxi" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-data-parser": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", @@ -9623,7 +10153,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9660,6 +10189,16 @@ "dev": true, "license": "ISC" }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -9706,6 +10245,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -9779,6 +10327,19 @@ "dev": true, "license": "MIT" }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/pump": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", @@ -9815,7 +10376,6 @@ "version": "6.15.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -9858,6 +10418,50 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -10009,7 +10613,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10094,6 +10697,22 @@ "points-on-path": "^0.2.1" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/rtl-css-js": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", @@ -10155,7 +10774,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, "license": "MIT" }, "node_modules/sass": { @@ -10377,6 +10995,57 @@ "node": ">=10" } }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -10387,6 +11056,25 @@ "randombytes": "^2.1.0" } }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -10394,11 +11082,16 @@ "dev": true, "license": "MIT" }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -10411,7 +11104,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10421,7 +11113,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -10441,7 +11132,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -10458,7 +11148,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -10477,7 +11166,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -10644,6 +11332,15 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/stdin-discarder": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", @@ -11132,6 +11829,15 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -11240,6 +11946,62 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/typed-rest-client": { "version": "1.8.11", "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", @@ -11334,6 +12096,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -11406,6 +12177,15 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/version-range": { "version": "4.15.0", "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", @@ -11470,7 +12250,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -11601,14 +12380,12 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/ws": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", - "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -11759,6 +12536,24 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } } } } diff --git a/package.json b/package.json index 6ddf69484..8ddad4186 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,11 @@ ], "preview": true, "activationEvents": [ - "onFileSystem:azureResourceGroups" + "onFileSystem:azureResourceGroups", + "onStartupFinished", + "workspaceContains:**/.azure/project-plan.md", + "workspaceContains:**/.azure/requirements.json", + "workspaceContains:**/.azure/vscode-debug-plan.md" ], "main": "./main.js", "contributes": { @@ -99,30 +103,25 @@ } ], "chatAgents": [ + { + "path": "resources/agents/azure-project-plan.agent.md" + }, { "path": "resources/agents/azure-project-scaffold.agent.md" }, { - "path": "resources/agents/azure-local-debug.agent.md" + "path": "resources/agents/azure-project-integrate.agent.md" + }, + { + "path": "resources/agents/azure-debug-plan.agent.md" + }, + { + "path": "resources/agents/azure-debug-generate.agent.md" }, { "path": "resources/agents/azure-deploy.agent.md" } ], - "languageModelTools": [ - { - "displayName": "Azure Resources: Get Azure Activity Log", - "icon": "$(azure)", - "inputSchema": {}, - "modelDescription": "Gets the Azure activity log", - "name": "azureResources_getAzureActivityLog", - "canBeReferencedInPrompt": true, - "toolReferenceName": "azureActivityLog", - "tags": [ - "azure" - ] - } - ], "terminal": { "profiles": [ { @@ -148,6 +147,22 @@ ] }, "commands": [ + { + "command": "copilotOnRails.inspectDiagnostics", + "title": "%copilotOnRails.inspectDiagnostics%", + "category": "Azure" + }, + { + "command": "copilotOnRails.reportIssue", + "title": "%copilotOnRails.reportIssue%", + "category": "Azure", + "icon": "$(feedback)" + }, + { + "command": "copilotOnRails.downloadAgentInstructions", + "title": "%copilotOnRails.downloadAgentInstructions%", + "category": "Azure" + }, { "command": "azureResourceGroups.uploadFileCloudConsole", "title": "%azureResourceGroups.uploadToCloudShell%", @@ -248,6 +263,12 @@ "category": "Azure", "icon": "$(refresh)" }, + { + "command": "azureProject.refresh", + "title": "%azureProject.refresh%", + "category": "Azure", + "icon": "$(refresh)" + }, { "command": "azureResourceGroups.refresh", "title": "%azureResourceGroups.refresh%", @@ -264,11 +285,6 @@ "title": "%azureResourceGroups.viewProperties%", "category": "Azure" }, - { - "command": "azureResourceGroups.reportIssue", - "title": "%azureResourceGroups.reportIssue%", - "category": "Azure" - }, { "command": "ms-azuretools.getStarted", "title": "%ms-azuretools.getStarted%", @@ -377,23 +393,38 @@ "title": "%azureResourceGroups.askAzure%" }, { - "command": "azureResourceGroups.createProjectWithCopilot", - "title": "%azureResourceGroups.createProjectWithCopilot%", + "command": "copilotOnRails.openScaffoldPlanView", + "title": "%copilotOnRails.openScaffoldPlanView%", + "category": "Azure" + }, + { + "command": "copilotOnRails.openDebugPlanView", + "title": "%copilotOnRails.openDebugPlanView%", + "category": "Azure" + }, + { + "command": "copilotOnRails.openDeploymentPlanView", + "title": "%copilotOnRails.openDeploymentPlanView%", + "category": "Azure" + }, + { + "command": "copilotOnRails.openRequirementsView", + "title": "%copilotOnRails.openRequirementsView%", "category": "Azure" }, { - "command": "azureResourceGroups.openPlanView", - "title": "%azureResourceGroups.openPlanView%", + "command": "copilotOnRails.openFrontendPreviewView", + "title": "%copilotOnRails.openFrontendPreviewView%", "category": "Azure" }, { - "command": "azureResourceGroups.openLocalPlanView", - "title": "%azureResourceGroups.openLocalPlanView%", + "command": "copilotOnRails.openDebugNextStepsView", + "title": "%copilotOnRails.openDebugNextStepsView%", "category": "Azure" }, { - "command": "azureResourceGroups.openDeployPlanView", - "title": "%azureResourceGroups.openDeployPlanView%", + "command": "copilotOnRails.openScaffoldNextStepsView", + "title": "%copilotOnRails.openScaffoldNextStepsView%", "category": "Azure" } ], @@ -431,11 +462,6 @@ "name": "Workspace", "visibility": "visible" }, - { - "id": "azureProject", - "name": "%azureProject.viewName%", - "visibility": "visible" - }, { "id": "azureTenantsView", "name": "Accounts & Tenants", @@ -455,6 +481,14 @@ "icon": "$(azure)", "type": "tree" } + ], + "explorer": [ + { + "id": "azureProject", + "name": "%azureProject.viewName%", + "visibility": "visible", + "when": "ms-azuretools.vscode-azureresourcegroups.hasProjectPlanFiles == true || ms-azuretools.vscode-azureresourcegroups.hasPendingProjectSubmission == true || ms-azuretools.vscode-azureresourcegroups.isEmptyWorkspace == true" + } ] }, "viewsWelcome": [ @@ -480,6 +514,10 @@ "view": "azureResourceGroups", "contents": "Please sign in to a specific tenant (directory) to continue. \n [Sign in to Tenant (Directory)...](command:azureResourceGroups.signInToTenant)\n[View Accounts & Tenants](command:azureTenantsView.focus)", "when": "azureResourceGroups.needsTenantAuth == true" + }, + { + "view": "workbench.explorer.emptyView", + "contents": "%azureProject.emptyExplorerWelcomeContent%" } ], "menus": { @@ -523,6 +561,16 @@ "when": "view == azureResourceGroups", "group": "navigation@3" }, + { + "command": "azureProject.refresh", + "when": "view == azureProject", + "group": "navigation@1" + }, + { + "command": "copilotOnRails.reportIssue", + "when": "view == azureProject", + "group": "navigation@2" + }, { "command": "azureResourceGroups.askAgentAboutActivityLog", "when": "view == azureActivityLog", @@ -671,6 +719,18 @@ "command": "azureResourceGroups.uploadFileCloudConsole", "when": "isWorkspaceTrusted" }, + { + "command": "copilotOnRails.reportIssue", + "when": "never" + }, + { + "command": "copilotOnRails.openScaffoldNextStepsView", + "when": "never" + }, + { + "command": "copilotOnRails.openDebugNextStepsView", + "when": "never" + }, { "command": "azureResourceGroups.showGroupOptions", "when": "never" @@ -718,6 +778,10 @@ { "command": "azureResourceGroups.askAgentAboutActivityLogItem", "when": "never" + }, + { + "command": "copilotOnRails.openFrontendPreviewView", + "when": "never" } ], "azureResourceGroups.groupBy": [ @@ -934,6 +998,12 @@ } ] } + ], + "mcpServerDefinitionProviders": [ + { + "id": "vscode-azureresourcegroups.mcp", + "label": "%azureResourceGroups.copilot.mcp.label%" + } ] }, "scripts": { @@ -974,13 +1044,15 @@ "@microsoft/vscode-azext-azureutils": "^4.1.0", "@microsoft/vscode-azext-utils": "^4.1.0", "@microsoft/vscode-azext-webview": "^1.0.2", - "form-data": "^4.0.4", + "@microsoft/vscode-inproc-mcp": "^0.3.0", + "form-data": "^4.0.6", "fs-extra": "^11.3.0", "jsonc-parser": "^2.2.1", "semver": "^7.7.3", "uuid": "^14.0.0", "vscode-nls": "^5.0.1", "vscode-uri": "^3.0.7", - "ws": "^8.20.1" + "ws": "^8.21.0", + "zod": "^4.4.3" } } diff --git a/package.nls.json b/package.nls.json index e6d7b382c..6c8886077 100644 --- a/package.nls.json +++ b/package.nls.json @@ -27,6 +27,7 @@ "azureResourceGroups.deleteConfirmation.EnterName": "Prompts with an input box where you enter the resource group name to delete.", "azureResourceGroups.deleteConfirmation.ClickButton": "Prompts with a warning dialog where you click a button to delete.", "azureResourceGroups.reportIssue": "Report Issue...", + "copilotOnRails.reportIssue": "Report Issue", "azureResourceGroups.showHiddenTypes": "Show some ancillary resources that are created/managed by Azure infrastructure. Displaying them is typically useful when you want to clean up your resource groups or subscriptions.", "ms-azuretools.getStarted": "Get Started...", "ms-azuretools.helpAndFeedback": "Help and Feedback", @@ -64,10 +65,18 @@ "Do not translate any of the words in the command URL." ] }, - "azureResourceGroups.createProjectWithCopilot": "Create Project with Copilot", - "azureResourceGroups.openPlanView": "Open Scaffold Plan View", - "azureResourceGroups.openLocalPlanView": "Open Local Plan View", - "azureResourceGroups.openDeployPlanView": "Open Deploy Plan View", + "copilotOnRails.downloadAgentInstructions": "Download Azure Agent Instructions", + "copilotOnRails.openRequirementsView": "Open Project Requirements View", + "copilotOnRails.openScaffoldPlanView": "Open Scaffold Plan View", + "copilotOnRails.openFrontendPreviewView": "Open Frontend Preview View", + "copilotOnRails.openScaffoldNextStepsView": "Open Scaffold Next Steps View", + "copilotOnRails.openDebugPlanView": "Open Debug Plan View", + "copilotOnRails.openDebugNextStepsView": "Open Debug Next Steps View", + "copilotOnRails.openDeploymentPlanView": "Open Deploy Plan View", + "copilotOnRails.inspectDiagnostics": "Inspect Copilot on Rails Diagnostics", + "azureProject.refresh": "Refresh", "azureProject.viewName": "Azure Project", - "azureProject.welcomeContent": "Use Copilot to plan and create a complete application that's configured for Azure services and setup for local development.\n[Create New Project With Copilot](command:azureResourceGroups.createProjectWithCopilot)" + "azureProject.welcomeContent": "Use Copilot to plan and create a complete application that's configured for Azure services and setup for local development.\n[Create New Project With Copilot](command:copilotOnRails.createProjectWithCopilot)", + "azureProject.emptyExplorerWelcomeContent": "Use Copilot to plan and create a complete application that's configured for Azure services and setup for local development.\n[Create New Project With Copilot](command:copilotOnRails.createProjectWithCopilot)", + "azureResourceGroups.copilot.mcp.label": "Copilot Azure Resources Extension Tools" } diff --git a/resources/agents/azure-debug-generate.agent.md b/resources/agents/azure-debug-generate.agent.md new file mode 100644 index 000000000..dc369da89 --- /dev/null +++ b/resources/agents/azure-debug-generate.agent.md @@ -0,0 +1,168 @@ +--- +name: azure-debug-generate +description: Generate artifacts for an approved VS Code debugging plan. Responsible for generating docker-compose, VS Code launch/tasks, and emulator orchestration for streamlined project debugging. +tools: [vscode, copilot-azure-resources-extension-tools/*, tool_search, execute, read, agent, browser, edit, search, web, azure-mcp/search, todo] +model: [Claude Opus 4.6 (copilot), Claude Opus 4.7 (copilot), Claude Sonnet 4.6 (copilot)] +target: vscode +--- + +# Azure Debug Generate + +You are an expert at generating VS Code debug configurations, Docker Compose files, and local development infrastructure from an approved debug plan. You produce production-quality launch configs, task definitions, and emulator orchestration that enable fully automated F5 debugging. + +You are the debug setup generation agent in a guided VS Code project setup workflow: + +**Plan → Scaffold → Verify → Debug (Plan → Generate) → Deploy** + +## Azure Resources MCP Tools + +Every `copilot-azure-resources-extension-tools/*` tool this agent uses is provided by an MCP server declared in this agent's `tools:` frontmatter, so **these tools ARE available in this session.** VS Code does not always surface them directly in your active tool list; that absence does **not** mean the tool is missing or that "the extension does not expose this MCP endpoint." + +When a step tells you to call one of these tools and you do not see it directly available, do **not** give up — load it and call it: + +1. Call `tool_search` with the **exact tool name only** as the query (e.g. `start_deployment`) — a single tool name, never a phrase like "azure mcp deploy". +2. If the tool is not already active, enable it with `activate_tools`, then invoke the tool (e.g. `start_deployment`). +3. If the search misses or a call errors, **retry** the search → activate → invoke loop with the exact tool name. Persist until the call succeeds. + +Never claim one of these tools is "not available" or "not exposed", never fall back to a manual work-around (invoking another agent by hand, or doing its file edits yourself), and never stop, summarize, or announce completion until the required tool call has actually **succeeded**. Treating a required view/hand-off tool as unavailable is a **failure of this agent**, not an acceptable outcome. + +## Prerequisites + +The workspace must contain `.azure/vscode-debug-plan.md` with status `Approved`. This plan is produced by the `azure-debug-plan` agent. If the plan does not exist or is not approved, stop and redirect the user to run the `azure-debug-plan` agent first. + +## Workflow + +The steps below are **strictly ordered**. You **must not** start a later step until the earlier one is completed: + +- Step 1: Execute the generation instructions. +- Step 2: Verify generation completed and guide the user through next steps. + +### Step 1: Execute the generation instructions + +Read through and strictly follow the generation instructions found in the user's workspace project: `.github/agents/azure-debug-generate/instructions.md`. + +These instructions cover generation and validation of the debug configuration artifacts. + +After running through all phases in the instructions, the plan status in `.azure/vscode-debug-plan.md` should be set to `Implemented`. + +## Interruption recovery + +If the flow is interrupted for any reason — a terminal command requests a password and the user declines, a tool call fails, a network request times out, or any other error breaks the current step — **do not stop working**. Instead: + +1. **Acknowledge** the interruption briefly (one sentence). +2. **Identify** which step you were on and what remains to be done. +3. **Continue** from where you left off. Re-read the relevant `.azure/*` artifacts to re-orient yourself if needed. +4. If the failed action is not essential to the current step (e.g. an optional tool call), skip it and move on. +5. If the failed action IS essential, try an alternative approach (different command, different tool) before giving up. +6. **Never** end your turn with just an error message and no next action. Always state what you will do next and then do it. + +### Step 2: Verify and present next steps + +**Gate:** Before proceeding, confirm that `.azure/vscode-debug-plan.md` has status `Implemented`. If the status is not `Implemented`, do not proceed — go back and complete the remaining validation steps from the instructions. + +Once verified, **first** open the visual "What's next?" view, **then** present the chat guidance and interactive options below. + +#### Open the Next Steps view + +Determine whether API test collections were generated by inspecting `.azure/vscode-debug-plan.md` (the plan's Services table includes API test entries marked for generation). Then call the `open_local_next_steps_view` tool to surface the post-local-development webview: + +```json +{ "hasApiTests": true } +``` + +Pass `"hasApiTests": true` when API tests were generated and `false` when they were not. This is the only argument the tool accepts and it controls whether the "Run API tests" card appears in the view. + +After opening the view, continue with the chat guidance below so the user has both a visual surface and a textual one. + +#### Opening — How to Start Debugging + +Present the following guidance: + +> ## 🚀 Ready to Debug +> +> Your local development environment is fully configured. Here's how to start debugging: +> +> 1. **Open the Run & Debug panel** — Click the "Run and Debug" play icon in the Activity Bar (left sidebar) or press `Ctrl+Shift+D` (`Cmd+Shift+D` on macOS). +> 2. **Select the compound launch configuration** — In the dropdown at the top of the Run & Debug panel, choose the service configuration you would like to start. If you have multiple services, choose the compound launch configuration. This launches all your services together — backend, frontend, and any emulators — in a single coordinated debug session. If you only need to debug one service, you can select its individual configuration instead. +> 3. **Press F5** (or click the green play button) to start debugging. VS Code will build your project, start all services, and attach debuggers automatically. +> 4. **Set breakpoints** by clicking in the gutter (left margin) of any source file. When execution hits a breakpoint, VS Code will pause and let you inspect variables, step through code, and evaluate expressions. +> +> 💡 **Tip:** The Debug Console (bottom panel) shows output from all running services. Use the dropdown in the Debug Console to switch between service outputs. + +#### Next Steps — Ask the User + +Preface the options with the following statement: + +> You can pick any of the options below to continue, but these aren't one-time choices — you can come back at any time and ask for any of the others. For example, you might iterate on your code for a while, then come back to [run API tests or] deploy when you're ready. + +Adjust the prefacing statement to omit the "run API tests or" portion if API tests were not generated. + +Then ask the user what they would like to do next. Ask this as a plain open chat question (regular chat text) — do **NOT** call `vscode_askQuestions` or any other interactive question API for it. Keep calling the Next Steps view as described above; only the follow-up question itself must stay in chat. Check `.azure/vscode-debug-plan.md` to determine whether API test collections were generated (i.e., the plan's Services table includes API test entries marked for generation). Present options conditionally: + +- **Always offer:** "Keep iterating" and "Deploy to Azure" +- **Only offer "Run API tests"** if the plan included API test collection generation. + +The options are: + +1. **"Keep iterating — start debugging and improve my code"** +2. **"Run API tests to verify my endpoints"** *(only if API tests were generated)* +3. **"Deploy to Azure"** + +Handle each response as follows: + +--- + +**Answer: "Keep iterating"** → + +Tell the user: + +> ### Iterate with Copilot +> +> 1. **Press F5** to start your application with your preferred launch configuration. +> 2. **Open your app** in the browser or client and interact with it — observe the behavior, test different flows, and note anything you'd like to change. +> 3. **Come back to this chat** and describe what you want to improve. For example: +> - Share a **screenshot** of your frontend and describe the changes you'd like (layout, styling, new components). +> - Paste an **error message** or stack trace and ask me to help fix it. +> - Describe a **new feature** you'd like to add or an existing one you'd like to refactor. +> +> I can edit your code, add new files, and help you debug — all while your app is running. When you're done iterating, come back and ask me to run API tests or deploy to Azure. + +--- + +**Answer: "Run API tests"** → + +Tell the user: + +> ### Run API Tests +> +> The generated API test scripts are in the `api-test-collections/` directory. These scripts call your app's endpoints and verify the responses. +> +> ⚠️ **Your app must be running first.** Press **F5** to start your application, then once your services are ready, come back and ask me to execute the API test collection scripts. + +Then **STOP and wait** for the user to confirm their app is running. Once the user confirms, read and execute the test scripts from `api-test-collections/` using the `execute` tool. Report results including status codes, response summaries, and any failures. + +**Iterate on failures:** If any API tests fail, do not just report the failures and stop. Diagnose the root cause, fix the underlying code, and re-run the failing tests. Keep iterating — fix, re-run, fix, re-run — until all tests pass. This is the whole point of running the API tests: to surface issues and resolve them, not just to report them. + +**After all tests pass (or there are no more actionable failures):** Call the `open_local_next_steps_view` tool to reopen the Next Steps view so the user can choose their next action: + +```json +{ "hasApiTests": true } +``` + +--- + +**Answer: "Deploy to Azure"** → + +Call the `start_deployment` tool to hand off to the deployment agent: + +```json +{ "prompt": "The local development environment is set up and verified. Now prepare the project for deployment to Azure." } +``` + +Then **STOP** — do not do anything else after this call. + +--- + +#### Handling Follow-Up Requests + +If the user returns later in the conversation and asks to do something that matches one of the three options above (e.g., "now I want to run API tests" or "let's deploy"), recognize the request and execute the corresponding option handler directly. Do **not** re-present the opening guidance or the option menu — just proceed with the requested path. diff --git a/resources/agents/azure-debug-generate/.metadata.json b/resources/agents/azure-debug-generate/.metadata.json new file mode 100644 index 000000000..abd818a3e --- /dev/null +++ b/resources/agents/azure-debug-generate/.metadata.json @@ -0,0 +1,4 @@ +{ + "name": "azure-debug-generate", + "version": "0.0.1" +} diff --git a/resources/agents/azure-debug-generate/instructions.md b/resources/agents/azure-debug-generate/instructions.md new file mode 100644 index 000000000..5dfce6502 --- /dev/null +++ b/resources/agents/azure-debug-generate/instructions.md @@ -0,0 +1,83 @@ +# Azure Debug Generate + +> **AUTHORITATIVE GUIDANCE — MANDATORY COMPLIANCE** +> +> This document is the **official, canonical source** for generating VS Code debug +> configuration from an approved plan. You **MUST** follow these instructions +> exactly as written. When in doubt, defer to this document. Do not improvise, +> infer, or substitute steps. + +--- + +## Global Rules (NO EXCEPTIONS) + +1. **Plan is the source of truth** — Read `.azure/vscode-debug-plan.md` and generate exactly what it specifies. Only generate artifacts for rows where `Generate` is checked (`[x]`). +2. **Update plan progressively** — Mark steps complete as you go; update **Last Updated** timestamp on every status change +3. ❌ **Destructive actions require `ask_user`** — Always confirm before overwriting, deleting, or modifying existing files +4. **Preserve existing config** — Never silently overwrite project configuration files or `docker-compose.yml`. Merge or ask first. +5. **Scope — VS Code debug setup only** — These instructions are for generating local debug configurations in VS Code. Cloud deployment is handled by **azure-prepare** → **azure-validate** → **azure-deploy**. +6. **Warn on limited support** — When a project type, runtime, or emulator declared in the plan has no matching reference file, emit a `⚠️ LIMITED SUPPORT:` warning — [limited-support.md](references/limited-support.md). + +--- + +## Autopilot mode + +**Active when** the invoking chat query begins with `[AUTOPILOT MODE]`, **or** `.azure/vscode-debug-plan.md` contains `executionMode: auto` or equivalent. When active, run fully unattended: +- **Do NOT call `ask_user`.** This is the tail of an autopilot chain over a freshly generated project, so overwriting/merging the scaffolded config files is expected and safe — proceed without prompting (still preserve and merge existing configs rather than blindly overwriting). +- Validation (Phase 3) still runs in full — autopilot never skips validation or the `Implemented` status write. Setting status to `Implemented` is what signals the workflow is complete (the extension restores its auto-approve setting at that point). + +--- + +## Phase 1: Pre-Flight + +Verify the plan and environment before generating any files. + +| # | Action | Reference | +|---|--------|-----------| +| 1 | **Verify plan** — Confirm `.azure/vscode-debug-plan.md` exists with status `Approved`. Set status to `Executing` and update **Last Updated**. | `.azure/vscode-debug-plan.md` | +| 2 | **Load references** — For each service in the plan's Services table (where Generate is checked), load the corresponding project-type and runtime reference files. If no reference file exists, emit a limited-support warning. | [limited-support.md](references/limited-support.md) | +| 3 | **Run pre-flight checks** — Stale data directories and port conflicts. | [preflight.md](references/preflight.md) | + +--- + +## Phase 2: Generate + +The plan drives implementation. Read each section of `.azure/vscode-debug-plan.md` and generate the corresponding artifacts. Use the reference files for implementation details — the plan specifies WHAT to generate, the references specify HOW. + +Follow the generation steps in [generate.md](references/generate.md) in order. + +--- + +## Phase 3: Validate + +> ⚠️ **CRITICAL:** You MUST complete every validation step before proceeding. Do NOT mark the task as complete, do NOT set status to `Implemented`, and do NOT deliver a closing message until validation is finished and the checklist is updated with real results. + +| # | Action | Reference | +|---|--------|-----------| +| 1 | **Validate each launch configuration** — Follow every step in validation.md for each non-compound config. | [validation.md](references/validation.md) | +| 2 | **Update Debug Configuration Checklist** — Create or update the `## Debug Configuration Checklist` section in `.azure/vscode-debug-plan.md` with real ✅ or ❌ results for each configuration. | [validation.md](references/validation.md) § Plan Integration | +| 3 | **Set status** — Only after every checklist stub has been replaced with a real result, set plan status to `Implemented` and update **Last Updated**. | `.azure/vscode-debug-plan.md` | + +> ⛔ **VALIDATION IS NOT OPTIONAL.** Do NOT set status to `Implemented` until every stub in the Debug Configuration Checklist has been replaced with a real ✅ or ❌ result. A checklist with any remaining stubs or missing entries means validation is incomplete — go back and finish it. This is the single most common failure mode. + +--- + +## Outputs + +| Artifact | Location | +|----------|----------| +| **Plan** (updated) | `.azure/vscode-debug-plan.md` | +| Docker Compose | `docker-compose.yml` | +| VS Code Debug Config | `.vscode/launch.json` — see [project-types/](references/project-types/) and [runtimes/](references/runtimes/) | +| VS Code Build Config | `.vscode/tasks.json` — see [project-types/](references/project-types/) and [runtimes/](references/runtimes/) | +| VS Code Extensions | `.vscode/extensions.json` — see [generate.md](references/generate.md) § assembly protocol | +| VS Code Settings | `.vscode/settings.json` — see [generate.md](references/generate.md) § assembly protocol | +| Connection Strings | `local.settings.json` or `.env` | +| Convenience Scripts | Runtime-specific script runner (see [runtimes/](references/runtimes/)) | +| API Test Collections | `api-test-collections/{service-id}//invoke.{sh,ps1}` | + +--- + +## Post-Generation + +After validation completes with status `Implemented`, **stop**. Do not present next steps or a closing message — the `azure-debug-generate` agent handles post-generation guidance and interactive next steps. diff --git a/resources/agents/azure-debug-generate/references/api-test-collections.md b/resources/agents/azure-debug-generate/references/api-test-collections.md new file mode 100644 index 000000000..117dede45 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/api-test-collections.md @@ -0,0 +1,220 @@ +# API Test Collection Patterns + +> Reference for generating `api-test-collections/{service-id}/` scripts, where `{service-id}` is the canonical service ID derived from the plan's **Service Label** column (see [generate.md](generate.md) § Service ID Derivation). Only generate test collections for services whose **Generate** column is checked in the plan. Scripts should be language-agnostic commands that exercise the running app and test its integration with any live emulators. + +--- + +## HTTP + + **HTTP patterns** use `{baseUrl}` — the project type supplies the base URL (e.g., `http://localhost:7071/api` for Functions). All other patterns target the emulator directly and are reusable across project types. + +### GET request + +```sh +curl -i "{baseUrl}/{FunctionName}" +``` + +### POST with JSON body + +```sh +curl -i -X POST "{baseUrl}/{FunctionName}" \ + -H "Content-Type: application/json" \ + -d @sample-data.json +``` + +> **`{baseUrl}` by project type:** +> +> | Project Type | Base URL | +> |-------------|---------| +> | Azure Functions | `http://localhost:7071/api` | +> | Container App | `http://localhost:{port}` (from Dockerfile `EXPOSE`) | +> | App Service | `http://localhost:{port}` (from framework dev server) | + +--- + +## Storage (Azurite — Blob / Queue / Table) + +> Requires Azurite running. Uses `--connection-string "UseDevelopmentStorage=true"` for all commands. + +### Blob trigger — upload a file + +```sh +az storage blob upload \ + --connection-string "UseDevelopmentStorage=true" \ + --container-name {container-name} \ + --name "sample-file.json" \ + --file sample-file.json \ + --overwrite +``` + +### Queue trigger — send a message + +```sh +az storage message put \ + --connection-string "UseDevelopmentStorage=true" \ + --queue-name {queue-name} \ + --content '{"id": "test-001", "data": "sample"}' +``` + +### Table trigger — insert an entity + +```sh +az storage entity insert \ + --connection-string "UseDevelopmentStorage=true" \ + --table-name {table-name} \ + --entity PartitionKey=pk RowKey=rk001 Value=test +``` + +--- + +## Cosmos DB + +> Requires Cosmos DB Emulator running on `https://localhost:8081`. TLS verification must be disabled for local calls. + +### Insert a document + +```sh +curl -k -X POST "https://localhost:8081/dbs/{database}/colls/{collection}/docs" \ + -H "Authorization: type=master&ver=1.0&sig=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==" \ + -H "Content-Type: application/json" \ + -H "x-ms-documentdb-partitionkey: [\"test\"]" \ + -H "x-ms-version: 2018-12-31" \ + -d '{"id": "test-001", "partitionKey": "test", "data": "sample"}' +``` + +> `-k` disables TLS verification for the emulator's self-signed cert. Never use in production. + +--- + +## Service Bus + +> Requires Service Bus Emulator running. Uses curl against the Service Bus Emulator's HTTP endpoint. + +### Send a message to a queue + +```sh +curl -i -X POST "http://localhost:5672/messages" \ + -H "Content-Type: application/json" \ + -H "BrokerProperties: {\"Label\": \"test\"}" \ + -d '{"id": "test-001", "data": "sample"}' +``` + +> The Service Bus Emulator's HTTP endpoint and port may vary. Check the emulator documentation and docker-compose configuration for the correct URL. For SDK-based testing, use the Azure Service Bus SDK with the emulator connection string from `emulators/` config. + +### Send a message to a topic + +```sh +curl -i -X POST "http://localhost:5672/messages" \ + -H "Content-Type: application/json" \ + -H "BrokerProperties: {\"Label\": \"test\"}" \ + -d '{"id": "test-001", "data": "sample"}' +``` + +> Adjust the URL path for topic-specific endpoints per the emulator's API surface. + +--- + +## Event Hubs + +> Requires Event Hubs Emulator running. + +### Send an event + +```sh +curl -i -X POST "http://localhost:5672/messages" \ + -H "Content-Type: application/json" \ + -d '{"id": "test-001", "data": "sample"}' +``` + +> The Event Hubs Emulator's HTTP endpoint and port may vary. Check the emulator documentation and docker-compose configuration for the correct URL. For SDK-based testing, use the Azure Event Hubs SDK with the emulator connection string from `emulators/` config. + +--- + +## Timer (Azure Functions only) + +Timer triggers cannot be fired by an external event — the Functions host fires them on schedule. Use the Functions admin API to trigger them on demand: + +```sh +curl -i -X POST "http://localhost:7071/admin/functions/{FunctionName}" \ + -H "Content-Type: application/json" \ + -d '{}' +``` + +> This calls the Functions admin endpoint which is only available locally. The `{}` body is required; the timer trigger ignores it. + +--- + +## Generation Rules + +When generating API test collections during Phase 2: + +1. Create one top-level subdirectory per service: `api-test-collections/{service-id}/`, where `{service-id}` is derived from the plan's **Service Label** column (see [generate.md](generate.md) § Service ID Derivation). Only generate for services whose **Generate** column is checked in the plan. +2. Within each service directory, generate one subdirectory per trigger/endpoint found during inventory +3. Name the trigger directory after the trigger: `{trigger-type}-{function-or-endpoint-name}` (e.g., `http-GetOrder`, `blob-ProcessUpload`) +4. Create an `invoke` script (`.sh` on macOS/Linux, `.ps1` on Windows) with the appropriate pattern from this file, substituting discovered values (function name, container name, queue name, etc.) +5. Create a `sample-data.json` or `sample-message.json` next to the invoke script when the test requires a body +6. On macOS/Linux, make the script executable (`chmod +x`) + +> **Do not generate timer test scripts** unless the user explicitly requests it — they're rarely needed for local debugging. + +--- + +## Plan Section Formatting Rules + +When writing the **API Test Collections** section of the plan, the heading format may vary by trigger type. In all cases, the subfolder names under `api-test-collections/{service-id}/` (e.g., `http-register`, `http-createOrder`) should also be referenced in each section's markdown heading when they differ so users can easily see which routes map to each invokable script. + +--- + +### HTTP triggers / web API endpoints + +``` +### {METHOD} {route} [{🔒}] `{folder-name}` +``` + +- **`{METHOD} {route}`** — HTTP verb and full route path (e.g., `GET /api/health`) +- **`🔒`** — Include this emoji when the endpoint requires authentication (any auth scheme: Bearer JWT, API key, etc.). Omit entirely for anonymous/public endpoints. +- **`` `{folder-name}` ``** — The exact folder name under `api-test-collections/{service-id}/` (e.g., `` `http-health` ``) + +**Examples:** + +```markdown +### GET /api/health `http-health` + +### POST /api/auth/register `http-register` + +### GET /api/auth/me 🔒 `http-getMe` + +### POST /api/orders 🔒 `http-createOrder` +``` + +**Auth key** — add this once at the top of the API Test Collections section, just after the folder tree, when any 🔒 routes are present: + +```markdown +> 🔒 = requires authentication (replace `` with a JWT from the login endpoint before running) +``` + +--- + +### Non-HTTP triggers (blob, queue, Service Bus, Event Hubs, etc.) + +``` +### {TriggerType}: {function-or-resource-name} `{folder-name}` +``` + +- **`{TriggerType}`** — Human-readable trigger category: `Blob`, `Queue`, `Service Bus`, `Event Hubs`, `Table`, `Cosmos DB`, etc. +- **`{function-or-resource-name}`** — The function name or the specific resource being targeted (container name, queue name, topic name, etc.) +- **`` `{folder-name}` ``** — The exact folder name under `api-test-collections/{service-id}/` (e.g., `` `blob-ProcessUpload` ``) + +**Examples:** + +```markdown +### Blob: uploads container `blob-processUpload` + +### Queue: order-requests `queue-sendOrder` + +### Service Bus: invoices topic `servicebus-sendInvoice` + +### Event Hubs: telemetry `eventhubs-sendTelemetry` +``` + +> The 🔒 indicator does not apply to non-HTTP triggers — they are invoked by pushing data into the resource directly, not via an authenticated HTTP call. diff --git a/resources/agents/azure-debug-generate/references/emulators/_template.md b/resources/agents/azure-debug-generate/references/emulators/_template.md new file mode 100644 index 000000000..05abae0db --- /dev/null +++ b/resources/agents/azure-debug-generate/references/emulators/_template.md @@ -0,0 +1,54 @@ +# {Emulator Name} + +> **Template** — Copy this file to `emulators/{name}.md` when adding a new emulator. + +--- + +## Docker Image + + + +``` +{org}/{image}:{tag} +``` + +## docker-compose Service Block + + + +```yaml +services: + {service-name}: + image: {org}/{image}:{tag} + ports: + - "{host-port}:{container-port}" + volumes: + - ./.{service-name}:/data + restart: unless-stopped +``` + +## Connection String + + + +``` +{connection-string} +``` + +## Required App Environment Variables + + + +| Variable | Value | +|----------|-------| +| `{VAR_NAME}` | `{value}` | + +## Healthcheck (Database Emulators Only) + + + + + +## Notes + + diff --git a/resources/agents/azure-debug-generate/references/emulators/azurite.md b/resources/agents/azure-debug-generate/references/emulators/azurite.md new file mode 100644 index 000000000..d211a5439 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/emulators/azurite.md @@ -0,0 +1,46 @@ +# Azurite (Azure Blob / Queue / Table Storage) + +## Docker Image + +``` +mcr.microsoft.com/azure-storage/azurite +``` + +## docker-compose Service Block + +```yaml +services: + azurite: + image: mcr.microsoft.com/azure-storage/azurite + # Overriding the default command requires re-specifying --blobHost/--queueHost/--tableHost 0.0.0.0 + # so Azurite listens on all interfaces (the image's default). Without them, Azurite falls back to + # 127.0.0.1 inside the container and becomes unreachable from the host via port mapping. + # --skipApiVersionCheck allows newer Azure SDK API versions to work with older Azurite releases. + command: azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --skipApiVersionCheck + ports: + - "10000:10000" + - "10001:10001" + - "10002:10002" + volumes: + - ./.azurite:/data + restart: unless-stopped +``` + +## Connection String + +``` +UseDevelopmentStorage=true +``` + +## Required App Environment Variables + +| Variable | Value | +|----------|-------| +| `AzureWebJobsStorage` (Functions) | `UseDevelopmentStorage=true` | +| `AZURE_STORAGE_CONNECTION_STRING` (SDK) | `UseDevelopmentStorage=true` | + +## Notes + +- Ports: 10000 (Blob), 10001 (Queue), 10002 (Table) +- **Consolidation:** If multiple storage bindings are detected (blob + queue + table), use a **single** Azurite service — not one per binding type. +- The Event Hubs Emulator requires Azurite for checkpointing. If both are needed, the `azurite` service is shared. diff --git a/resources/agents/azure-debug-generate/references/emulators/postgres.md b/resources/agents/azure-debug-generate/references/emulators/postgres.md new file mode 100644 index 000000000..df5354785 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/emulators/postgres.md @@ -0,0 +1,66 @@ +# PostgreSQL + +> PostgreSQL has no Azure-provided emulator. Use the standard `postgres` Docker image for local development. If the project targets **Azure Cosmos DB for PostgreSQL**, note in the plan that no local emulator is available. + +## Docker Image + +``` +postgres:16 +``` + +## docker-compose Service Block + +```yaml +services: + postgres: + image: postgres:16 + ports: + - "5432:5432" + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: localdev + volumes: + - ./.postgres:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + start_period: 30s + restart: unless-stopped +``` + +## Connection String + +``` +postgresql://postgres:postgres@localhost:5432/localdev +``` + +## Required App Environment Variables + +| Variable | Value | +|----------|-------| +| `DATABASE_URL` | `postgresql://postgres:postgres@localhost:5432/localdev` | +| `POSTGRES_CONNECTION_STRING` | `postgresql://postgres:postgres@localhost:5432/localdev` | + +> Use whichever variable name the project's ORM or SDK expects. Both forms above are shown as reference. + +## Healthcheck + +The healthcheck is included in the docker-compose service block above. It uses `pg_isready` to verify PostgreSQL is accepting connections. The migration service (see [migrations.md](../migrations.md)) depends on `condition: service_healthy` to wait for readiness before running migrations. + +```yaml +healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + start_period: 30s +``` + +## Notes + +- Port 5432 is the standard PostgreSQL port. +- Default credentials (`postgres`/`postgres`) are intentionally simple for local dev. Never use in production. +- Data is persisted to `./.postgres/`. diff --git a/resources/agents/azure-debug-generate/references/generate.md b/resources/agents/azure-debug-generate/references/generate.md new file mode 100644 index 000000000..28b2e7a70 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/generate.md @@ -0,0 +1,240 @@ +# Artifact Generation + +Cross-cutting rules, step sequence, and assembly protocols for generating local development configuration files from an approved plan. + +--- + +## Reading the Plan + +The plan's tables drive all generation: + +| Plan Section | What It Drives | +|-------------|----------------| +| **Services** table | Which services get launch.json/tasks.json entries. | +| **Emulators** table | Which emulator docker-compose services to generate. | +| **Orchestrator** table | Which orchestrator to use (e.g., Docker Compose) | +| **Migrations** table | Which migration docker-compose services to generate. | +| **API Test Collections** table | Which API test scripts to generate. | +| **Convenience Scripts** table | Which convenience scripts to generate. | + +### Targeted Resolution + +The plan provides high-level intent. For implementation details, perform **targeted resolution scans** of the workspace: + +- **Migration details** — Scan for migration directory path, existing migration scripts, connection env var names. See [migrations.md](migrations.md). +- **API endpoints** — Parse function definitions or route handlers to get specific endpoint names, methods, routes, auth levels. +- **Connection string keys** — Check `local.settings.json`, `.env`, or app config for existing key names. +- **Existing config** — Check for existing `.vscode/launch.json`, `.vscode/tasks.json`, `docker-compose.yml` to determine merge vs create. +- **Framework details** — For frontend SPAs, detect the specific framework (Vite, Next.js, Angular, CRA) and dev server port from config files. +- **TypeScript source maps** — For TypeScript services, verify `tsconfig.json` has `"sourceMap": true` in `compilerOptions`. Without it, breakpoints in `.ts` files appear as unverified. See `runtimes/node.md` § Debugger Properties. + +--- + +## Generation Steps + +For each service in the plan's Services table (where Generate is checked), generate the following artifacts in order. The plan specifies WHAT to generate; the reference files linked below specify HOW. + +| # | Action | Reference | +|---|--------|-----------| +| 1 | **Generate docker-compose** — For each emulator in the plan's Emulators table, load the emulator reference and assemble the docker-compose service block. If migrations are checked, add healthcheck and migration service. | [emulators/](emulators/), [migrations.md](migrations.md) | +| 2 | **Generate VS Code debug config** — Assemble `launch.json` and `tasks.json` entries from the project-type and runtime references. For multi-service workspaces, generate compound configuration. | generate.md § Source Ownership, [project-types/](project-types/), [runtimes/](runtimes/), [multi-service.md](multi-service.md) | +| 3 | **Generate VS Code workspace config** — Assemble `.vscode/extensions.json` and `.vscode/settings.json` from project-type and runtime references. Add emulator data directory exclusions. | generate.md § VS Code Extension Recommendations, generate.md § VS Code Workspace Settings | +| 4 | **Configure connection strings** — Update `local.settings.json`, `.env`, or app config with emulator connection strings. Never overwrite existing values. | `project-types/{type}.md` § Connection Strings, `emulators/{name}.md` § Required App Environment Variables | +| 5 | **Generate convenience scripts** — For each checked script in the plan's Convenience Scripts table, add to the project's native script runner. | `runtimes/{rt}.md` § Convenience Scripts | +| 6 | **Generate migrations** — If the plan's Migrations table has checked rows, do targeted resolution for migration details, then generate the docker-compose migration service. | [migrations.md](migrations.md) | +| 7 | **Generate API test collections** — If the plan's API Test Collections table has checked rows, do targeted resolution for endpoints/triggers, then generate test scripts. | [api-test-collections.md](api-test-collections.md) | + +--- + +## Dependency Availability + +> ⚠️ **Do not assume CLI tools or packages are installed in the target project.** + +Before writing any script or task command that invokes a CLI tool (e.g., `rimraf`, `concurrently`, `cross-env`): + +1. **Check** — Verify the tool is already a project dependency. +2. **Add dependency** — Add it as a project dev dependency. This ensures it is version-locked and works consistently across all machines. +3. **Ask if uncertain** — Use `ask_user` if the tool is expensive, opinionated, or has multiple alternatives. + +--- + +## VS Code Debug & Task Configuration + +Assemble `.vscode/launch.json` and `.vscode/tasks.json` by combining properties from the detected **project type** and **runtime** references. Use the source ownership table below to determine which file provides each property. + +### Source Ownership + +| Concern | Server-side project source | Browser SPA source | +|---------|---------------------------|-------------------| +| Debugger type (`node`, `coreclr`) | `runtimes/{rt}.md` § Debugger Properties | `project-types/frontend-spa/debug-adapters/{adapter}.md` | +| Debug port | `runtimes/{rt}.md` § Debugger Properties | N/A (uses dev server URL) | +| Request mode (`attach` / `launch`) | `project-types/{type}.md` § Runtime Wiring | `project-types/frontend-spa/frontend-spa.md` § Runtime Wiring | +| Top-level startup task (type, command, problem matcher) | `project-types/{type}.md` § VS Code Task Configuration | `project-types/frontend-spa/frontend-spa.md` § VS Code Task Configuration | +| Build chain tasks (install, clean, watch) | `runtimes/{rt}.md` § Build Chain | N/A (dev server handles compilation) | +| Runtime-specific launch properties (`outFiles`, `processName`) | `runtimes/{rt}.md` § Debugger Properties | N/A | +| Compound configuration | [multi-service.md](multi-service.md) § Compound Debug Configuration | [multi-service.md](multi-service.md) § Compound Debug Configuration | +| Working directory (`cwd`) rules | generate.md § Working Directory (`cwd`) Rules | generate.md § Working Directory (`cwd`) Rules | +| Task `runOptions` rules | generate.md § Task `runOptions` Rules | generate.md § Task `runOptions` Rules | +| Emulator startup task (`Start Emulators`) | `runtimes/{rt}.md` § Build Chain | N/A (backend service owns emulators) | + +> `project-types/{type}.md` § VS Code Task Configuration provides **concrete task JSON per runtime** — use those blocks directly. `runtimes/{rt}.md` § Build Chain provides the dependency tasks that the startup task's `dependsOn` references. + +### Service ID Derivation + +Derive a canonical service ID from the plan's **Service Label** column: lowercase, kebab-case (e.g., "Functions API" → `functions-api`, "Web App" → `web-app`). This ID is used for: + +- Task labels (e.g., `functions-api: func host start`) +- Launch config naming (use the plan's **Launch Config Name** column directly) +- Compound config member references + +If two services resolve to the same ID, append the project type: `payments-api-functions`. + +> ⛔ Every generated task label should conform to `{service-id}: {task name}` (e.g., `functions-api: func host start`, `functions-api: dotnet build`). Wherever a task label is referenced — generation blocks, `dependsOn` chains, `preLaunchTask` values, validation Ready-Signal tables, and validation checklists — it **MUST** use this `{service-id}:` form. Instruction files and any examples that show a label without the `{service-id}:` prefix added are illustrating the latter part of the label; resolve it to the full form before writing or matching. + +### Task Chain Shape (Server-side only) + +> Browser-based projects (e.g., Frontend SPA) skip the build chain — the dev server task is the only task. See `project-types/{type}.md` § VS Code Task Configuration. + +``` +"{service-id}: {top-level-task}" ← project-type-specific (see project-types/{type}.md) + ├── dependsOn: "{service-id}: {watch-task}" ← from runtimes/{rt}.md + │ └── dependsOn: "{service-id}: {clean-task}" + │ └── dependsOn: "{service-id}: {install-task}" + └── dependsOn: "Start Emulators" ← only when emulators are required +``` + +> Adjust task labels and commands for alternative package managers (`yarn`, `pnpm`, `gradle`). The key invariant is the chain shape: **install → clean → build/watch → top-level task** (with `Start Emulators` as a sibling dependency of the top-level task, NOT nested under install). Some runtimes skip steps — use only what applies. + +### Project Type Path Resolution + +Most project types have a single reference file at `project-types/{type}.md`. Some use a subdirectory: + +| Project Type | Reference Path | +|--------------|---------------| +| `functions` | `project-types/functions.md` | +| `frontend-spa` | `project-types/frontend-spa/frontend-spa.md` | + +When instructions reference `project-types/{type}.md`, resolve via this table. If the type is not listed, look for `project-types/{type}.md` first, then `project-types/{type}/{type}.md`. + +### Working Directory (`cwd`) Rules + +> ⚠️ **CRITICAL for multi-service repos.** Without correct `cwd`, commands like `npm install` or `func host start` will run from the workspace root and fail. + +Use the **Service Root** column from the plan's Services table to determine the `cwd` for each task. + +| Task Scope | `cwd` Setting | Example | +|------------|--------------|---------| +| **Per-service tasks** (install, clean, watch, build, top-level) | `"options": { "cwd": "${workspaceFolder}/{service-root}" }` | `"cwd": "${workspaceFolder}/api"` | +| **Shared tasks** (Start Emulators) | Workspace root (omit `cwd` — it defaults to workspace root) | — | +| **Single-service repos** | Omit `cwd` — workspace root is the service root | — | + +### Task `runOptions` Rules + +Every task generated for the debug chain (install, clean, watch, build, top-level, and emulator tasks) **must** include `runOptions` with `instanceLimit: 1` and `instancePolicy: "silent"`. This prevents duplicate task instances and silently skips re-invocations when a task is already running (e.g., from compound + individual `preLaunchTask` chains). + +### Start Emulators Task + +When the plan includes emulators, generate a shared `Start Emulators` task. This task is a **sibling dependency** of each service's top-level startup task (e.g., `func host start`). Do NOT place `Start Emulators` as a dependency of build chain tasks like `npm install` or `npm watch` — it belongs in the startup task's `dependsOn` array alongside the build chain prerequisite. + +```json +{ + "type": "shell", + "label": "Start Emulators", + "command": "docker compose up -d", + "problemMatcher": [], + "runOptions": { "instanceLimit": 1, "instancePolicy": "silent" } +} +``` + +### instanceLimit and instancePolicy + +Set **`instanceLimit: 1`** and **`instancePolicy: "silent"`** on every task. You never want parallel instances of the same build or startup task, and `"silent"` ensures that duplicate invocations are skipped without prompting the user. + +### Problem Matchers + +**Background tasks (`isBackground: true`) MUST have a real `problemMatcher`.** An empty matcher (`"problemMatcher": []`) on a background task causes a blocking VS Code dialog ("This task is tracked by a problem matcher"). Look up the correct matcher from the relevant reference file: + +- **Runtime tasks** (build, watch) → `runtimes/{rt}.md` § VS Code Problem Matchers +- **Project-type tasks** (top-level startup) → `project-types/{type}.md` § VS Code Task Configuration +- **Frontend dev servers** → `project-types/frontend-spa/frontend-spa.md` § Framework Lookup Table + +For non-background tasks: + +| Task Type | Matcher | +|-----------|---------| +| Short-lived commands (`npm install`, `npm clean`, `docker compose up -d`) | `"problemMatcher": []` | +| Dependency-only tasks (only `dependsOn`, no `command`) | Omit `problemMatcher` entirely | + +Short-lived commands use an empty matcher to suppress matching on tasks that don't produce compiler-style output. + +### Example + +```json +{ + "type": "shell", + "label": "npm install", + "command": "npm install", + "runOptions": { "instanceLimit": 1, "instancePolicy": "silent" }, + "problemMatcher": [] +} +``` + +--- + +## VS Code Extension Recommendations (`.vscode/extensions.json`) + +Aggregate extension recommendations from the detected **runtime** and **project type** into `.vscode/extensions.json`. Each source lists its required extensions in a `## VS Code Extension Recommendations` section with an `Extension ID | Why Required` table. + +### Assembly Protocol + +| Step | Action | Details | +|------|--------|---------| +| 1. Collect | Gather from runtime | Read extension IDs from `runtimes/{rt}.md § VS Code Extension Recommendations` | +| 2. Collect | Gather from project type | Read extension IDs from `project-types/{type}.md § VS Code Extension Recommendations` | +| 3. Deduplicate | Remove duplicates | Each extension ID appears once in the final list | +| 4. Write | Output `.vscode/extensions.json` | Contribute to the file — do not replace existing entries | + +### Output Format + +```json +{ + "recommendations": [ + "{runtime-extension-1}", + "{project-type-extension-1}" + ] +} +``` + +--- + +## VS Code Workspace Settings (`.vscode/settings.json`) + +Aggregate workspace settings from the detected **runtime**, **project type**, and **emulator configuration** into `.vscode/settings.json`. Each source lists its contributed settings in a `## VS Code Workspace Settings` section with a `Setting | Value | Why` table. + +### Assembly Protocol + +| Step | Action | Details | +|------|--------|---------| +| 1. Collect | Gather from runtime | Read settings from `runtimes/{rt}.md § VS Code Workspace Settings` | +| 2. Collect | Gather from project type | Read settings from `project-types/{type}.md § VS Code Workspace Settings` | +| 3. Collect | Gather emulator exclusions | Derive data directory exclusions from `docker-compose.yml` `volumes:` mounts | +| 4. Write | Output `.vscode/settings.json` | Contribute to the file — do not replace existing entries or user customizations | + +### Emulator Data Directory Exclusions + +When emulators are configured via docker-compose, add their data directories to both `files.exclude` and `search.exclude` in **`.vscode/settings.json`** to reduce workspace noise: + +```json +{ + "files.exclude": { + "**/.azurite": true, + "**/.postgres": true + }, + "search.exclude": { + "**/.azurite": true, + "**/.postgres": true + } +} +``` + +> Derive directory names from the actual `volumes:` mounts in `docker-compose.yml` — do not hardcode. Each emulator's data directory pattern is defined in `emulators/{name}.md`. diff --git a/resources/agents/azure-debug-generate/references/limited-support.md b/resources/agents/azure-debug-generate/references/limited-support.md new file mode 100644 index 000000000..0023b26e1 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/limited-support.md @@ -0,0 +1,71 @@ +# Limited Support Warnings + +> Emit a standardized warning when the skill detects a feature that is not yet fully supported. The warning format is consistent across all feature categories so the user always knows what to expect. + +--- + +## ⛔ Detection Algorithm — MANDATORY + +For every project type, runtime, and emulator declared in the plan's tables, follow this procedure **exactly**: + +1. **Check for a matching reference file** — List the files and subdirectories in the category folder (ignoring `_template.md`). If any filename or subdirectory name loosely matches the declared value (ignoring case, spaces, dashes, and underscores), the feature has a reference file. +2. **Check the status inside the reference file** — Open the matched reference file and look for a status indicator. If the file is marked `🔲 Planned` (in a frontmatter note, status field, or top-level callout), the feature has **limited support** despite having a reference file. You **MUST** emit a warning. +3. **If a match exists AND the file is not marked Planned** → the feature is fully supported. Proceed normally. +4. **If no match exists** → the feature has limited support. You **MUST** emit a warning. Do NOT substitute a different, supported feature. + +| Category | Category Folder | Path Notes | +|----------|-----------------|------------| +| Project type | `references/project-types/` | Some types use subdirectories (e.g., `frontend-spa/frontend-spa.md`). Match against both filenames and subdirectory names. | +| Runtime | `references/runtimes/` | | +| Emulator | `references/emulators/` | | + +> ⚠️ **Do NOT skip this check.** Every declared feature MUST be verified against the category folder before generating artifacts. + +--- + +## Warning Format + +``` +⚠️ LIMITED SUPPORT: {Category} "{value}" is not yet fully supported. +``` + +Where: +- `{Category}` — a short label for the feature area (e.g., `Project type`, `Runtime`, `Emulator`) +- `{value}` — the specific feature declared in the plan (e.g., `python`, `Container App`, `Cosmos DB`) + +--- + +## ⛔ Emission Protocol — MANDATORY + +When a limited-support feature is detected, you **MUST** follow this exact sequence: + +### Step 1: Emit in assistant message + +Write the canonical warning in your **regular assistant message text**. This is mandatory — the warning must be visible in the chat output, not hidden inside a tool call. + +``` +⚠️ LIMITED SUPPORT: Emulator "Durable Task Scheduler" is not yet fully supported. +``` + +### Step 2: Confirm with user + +For the **first** limited-support feature encountered in the session, call `ask_user` to confirm whether to proceed: + +``` +ask_user( + question: "⚠️ LIMITED SUPPORT: {Category} \"{value}\" is not yet fully supported. Would you still like me to put forth a best-effort attempt?", + choices: [ + "Yes, proceed with best effort", + "No, stop here" + ] +) +``` + +If the user agrees, treat that as blanket consent for the rest of the session. Any additional limited-support features discovered later should still be emitted as a warning — but do **not** call `ask_user` again. + +> Emit each `⚠️ LIMITED SUPPORT:` warning exactly once per `(Category, value)` pair in assistant messages. +--- + +## No Silent Substitution + +**Do NOT silently substitute a supported alternative** when a feature has limited support (e.g. switching a Container App to Azure Functions, or Python to Node.js). Always generate for the project type, runtime, and emulators declared in the plan, even when support is limited. diff --git a/resources/agents/azure-debug-generate/references/migrations.md b/resources/agents/azure-debug-generate/references/migrations.md new file mode 100644 index 000000000..efca4e1fe --- /dev/null +++ b/resources/agents/azure-debug-generate/references/migrations.md @@ -0,0 +1,82 @@ +# Database Migrations — Generation + +Generate docker-compose migration services from the plan's Migrations table. The plan records WHAT migration tool is in use and which service needs it. This reference covers HOW to generate the docker-compose configuration. + +--- + +## Targeted Resolution + +The plan's Migrations table provides: `Generate | Service | Migration Tool`. Before generating the docker-compose migration service, perform targeted resolution to fill in the details: + +| Detail | How to Resolve | +|--------|---------------| +| **Migration directory** | Scan for tool-specific directories: `prisma/migrations/`, `migrations/`, `Migrations/`, `alembic/` | +| **Migration command** | Check the project's script runner (e.g., `package.json` scripts) for an existing migration command. If found, use it. If not, construct from the tool name. | +| **Target database service** | Match against the plan's Emulators table — the database emulator's compose service name | +| **Connection env var** | Check `local.settings.json`, `.env`, or the migration tool's config file for the variable name | +| **Compose-network connection string** | Same shape as the local connection string but with the compose service name as host instead of `localhost` | +| **Existing script** | Check whether a migration script already exists in the project's script runner | + +### Migration Script Lookup + +| Detection Evidence | Instruction | +|--------------------|-------------| +| Existing migration script in project (e.g., `npm run db:migrate`) | Use it as-is in the docker-compose service | +| Migration tool detected but no script | Create a script in the project's native script runner that wraps the tool's CLI command (e.g., `"db:migrate": "npx prisma migrate deploy"` in `package.json`) | +| Raw SQL files only, no migration tool | Recommend and install a lightweight migration tool as a dev dependency (e.g., `node-pg-migrate` for Node.js). Ask the user before installing. | + +--- + +## Docker Compose Patterns + +Two patterns are needed: a **healthcheck** on the database service and a one-shot **migration service**. + +### Healthcheck Pattern + +When migrations are present, the target database service **must** have a healthcheck so the migration service can use `depends_on` with `condition: service_healthy`. The healthcheck definition belongs in the emulator's docker-compose config — see the emulator reference files in [emulators/](emulators/). + +### Migration Service Pattern + +```yaml +services: + db-migrate: + image: ${RUNTIME_IMAGE} + working_dir: /app + depends_on: + ${DATABASE_SERVICE}: + condition: service_healthy + volumes: + - ./:/app:ro + ${EXTRA_VOLUME_MOUNTS} + environment: + ${CONNECTION_ENV_VAR}: ${CONNECTION_STRING_FOR_COMPOSE_NETWORK} + entrypoint: ${MIGRATION_SCRIPT} + restart: "no" +``` + +**Filling in the template — use resolved details:** + +| Placeholder | How to determine | +|-------------|-----------------| +| `RUNTIME_IMAGE` | A Docker image that provides the language runtime. See the table below. | +| `DATABASE_SERVICE` | The compose service name for the target database (from Emulators table) | +| `CONNECTION_ENV_VAR` | The environment variable the migration tool expects (from targeted resolution) | +| `CONNECTION_STRING_FOR_COMPOSE_NETWORK` | Same shape as local connection string but with compose service name as host | +| `EXTRA_VOLUME_MOUNTS` | Additional mounts needed for the ecosystem. See the table below. | +| `MIGRATION_SCRIPT` | The project's migration script command (from targeted resolution) | + +**Runtime images and extra volume mounts:** + +| Ecosystem | Image | Extra Volume Mounts | Notes | +|-----------|-------|-------------------|-------| +| Node.js / TypeScript | `node:{major}-slim` | `./node_modules:/app/node_modules:ro` | Mount node_modules separately for native modules | +| .NET | `mcr.microsoft.com/dotnet/sdk:{version}` | — | Best-effort — emit limited support warning | +| Python | `python:{version}-slim` | `./.venv:/app/.venv:ro` (if applicable) | Best-effort — emit limited support warning | +| Java | `eclipse-temurin:{version}` | — | Best-effort — emit limited support warning | +| Go | `golang:{version}` | — | Best-effort — emit limited support warning | + +> **Key properties:** +> - `depends_on` with `condition: service_healthy` — waits for the database to accept connections +> - `volumes` with `:ro` — mounts project files read-only for safety +> - `restart: "no"` — runs once per `docker compose up`, does not restart after exit +> - Mount ecosystem-specific dependency directories when the migration tool is installed as a project dependency diff --git a/resources/agents/azure-debug-generate/references/multi-service.md b/resources/agents/azure-debug-generate/references/multi-service.md new file mode 100644 index 000000000..db8d855c6 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/multi-service.md @@ -0,0 +1,101 @@ +# Multi-Service Orchestration — Generation + +> Applies when the plan's Services table has **2+ rows** (excluding the compound config row). Governs compound debug configuration, working directory rules, startup ordering, and partial configuration handling. + +--- + +## Port Assignment + +When two or more services share the same runtime, each needs a unique debug port. Look up the `Base debug port` from `runtimes/{rt}.md` and assign ports sequentially: first service gets the base port, second gets base + 1, third gets base + 2, etc. + +> Browser-based project types (e.g., Frontend SPA) do not use debug ports — they connect via the dev server URL instead. + +--- + +## Partial Configuration Handling + +Check each service root for existing VS Code debug config before generating anything. A service is considered already configured if it has an existing debug configuration entry in `.vscode/launch.json` matching its service ID or Launch Config Name. + +| State | Action | +|-------|--------| +| **Fully configured service** | Skip all artifact generation for that service; carry its existing config into the compound configuration unchanged | +| **Partially configured service** | Generate only what is missing (e.g. tasks but no debug config → generate debug config only) | +| **Unconfigured service** | Generate all artifacts as normal | + +Adding a second service to an existing single-service repo is safe — the original service's config is preserved and the new service is added alongside it. + +--- + +## Compound Debug Configuration + +> ⛔ **MANDATORY:** When 2+ service roots are detected (including Frontend SPA projects), a compound debug configuration **must** be generated. A frontend SPA counts as a service root — it does not need emulators, but it does need a debug config entry and inclusion in the compound. + +> ⚠️ **Working directory:** Multi-service task chains require correct `cwd` on every per-service task. See [generate.md § Working Directory (`cwd`) Rules](generate.md) — without it, commands like `npm install` or `func host start` run from the workspace root and fail. + +Use the plan's Services table to assemble the compound config. The compound config row in the plan specifies the Launch Config Name (e.g., "Debug All Services"). + +### Startup Ordering + +VS Code compound launch configurations always start their listed configurations **in parallel**. There is no `dependsOrder` property for compounds — only individual tasks support sequenced dependencies. This means you cannot directly tell a compound to "start the backend before the frontend." + +When a frontend service proxies to a local backend (e.g., a dev server proxy for API calls), the backend must be ready before the frontend starts. Otherwise the frontend proxy may produce `ECONNREFUSED` errors on startup. Since compounds cannot enforce this ordering, the workaround is to push the sequencing into a **compound task** that uses `dependsOrder: "sequence"`, and set that task as the compound's `preLaunchTask`. + +> The plan may include a note like "ℹ️ **Proxy detected:**" indicating this dependency. Check the frontend's config files (e.g., `vite.config.ts` `server.proxy`) to confirm. + +#### Pattern + +**1. Generate a sequenced compound task** that starts services in order: + +```json +{ + "label": "Start All Services", + "dependsOn": [ + "{backend-service-id}: {backend-top-level-task}", + "{frontend-service-id}: {frontend-top-level-task}" + ], + "dependsOrder": "sequence" +} +``` + +The backend is listed first. Its `problemMatcher` (from `project-types/{type}.md`) signals "ready" before the frontend task starts. + +**2. Set the compound config's `preLaunchTask`** to the sequenced task: + +```json +{ + "name": "{Launch Config Name from plan's compound row}", + "configurations": ["{Backend Launch Config Name}", "{Frontend Launch Config Name}"], + "preLaunchTask": "Start All Services", + "stopAll": true +} +``` + +**3. Individual configs keep their own `preLaunchTask`** so they work standalone: + +```json +{ + "name": "{Backend Launch Config Name}", + "preLaunchTask": "{backend-service-id}: {backend-top-level-task}" +} +``` + +```json +{ + "name": "{Frontend Launch Config Name}", + "preLaunchTask": "{frontend-service-id}: {frontend-top-level-task}" +} +``` + +**4. Set `instanceLimit: 1` and `instancePolicy: "silent"` on background tasks** to prevent duplicate instances. + +When the compound runs, "Start All Services" starts both services via `dependsOrder: "sequence"`. Then each individual configuration's `preLaunchTask` fires again — but those services are already running. With `instanceLimit: 1` and `instancePolicy: "silent"`, the duplicate invocation is silently skipped and the existing instance keeps running. + +#### Why This Pattern Is Necessary + +| Concern | How it's solved | +|---------|----------------| +| Compounds can't sequence configurations | The sequenced compound **task** (`dependsOrder: "sequence"`) handles ordering instead | +| Backend must be ready before frontend starts | Backend is listed first in `dependsOn`; its problem matcher signals readiness | +| Debuggers must not attach before services are running | The compound's `preLaunchTask` ensures all services are started before any debugger attaches | +| Individual configs must still work standalone | Each config has its own `preLaunchTask` pointing to its service's top-level task | +| Duplicate task invocations from compound + individual preLaunchTasks | `instanceLimit: 1` + `instancePolicy: "silent"` silently skips the duplicate — the first instance keeps running | diff --git a/resources/agents/azure-debug-generate/references/preflight.md b/resources/agents/azure-debug-generate/references/preflight.md new file mode 100644 index 000000000..2a9fae7e5 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/preflight.md @@ -0,0 +1,51 @@ +# Pre-Flight Checks + +Verify the plan exists and environment is ready before proceeding onwards to generating files. + +## Stale Data Directory Check + +Before generating any files, check for leftover emulator data directories from a previous run (e.g. `.postgres/`, `.azurite/`, `.cosmos/`, `.servicebus/`). These directories can cause container startup failures — for example, PostgreSQL's `initdb` will refuse to initialize if `/var/lib/postgresql/data` (mounted from `.postgres/`) already contains files from an incompatible or partially-initialized cluster. + +If any stale directories are found: + +1. **List all found directories** with their sizes. +2. **Ask the user how to proceed** using `ask_user`: + +``` +ask_user( + question: "The following emulator data directories were found from a previous run:\n\n- .postgres/ (45 MB)\n- .azurite/ (12 MB)\n\nThese can cause container startup failures. How would you like to handle this?", + choices: [ + "Delete them and start fresh (recommended)", + "Keep them — I want to preserve the existing data" + ] +) +``` + +3. **If the user chooses to delete** — Remove the directories before proceeding with generation. Use platform-appropriate removal (e.g., `rm -rf` on macOS/Linux, `Remove-Item -Recurse -Force` on Windows). +4. **If the user wants to keep them** — Proceed, but warn that containers may fail to start. If they do fail, offer to clean up at that point. +5. **Never delete data directories silently** — Always confirm with the user first. + +--- + +## Port Conflict Check + +Before generating any files, scan all ports required by the planned emulators (e.g. `lsof -i -P -n`). For each occupied port, identify the process name and PID. + +If any conflicts are found: + +1. **List all conflicts clearly** — port number, process name, PID. +2. **Ask the user how to proceed** using `ask_user`: + +``` +ask_user( + question: "The following ports are already in use on your machine:\n\n- Port 5432 → postgres (PID 1234)\n\nThese ports are needed by the planned emulators. How would you like to handle this?", + choices: [ + "Help me remap the conflicting ports to alternatives", + "I'll handle it myself — proceed with the plan as-is" + ] +) +``` + +3. **If the user wants help remapping** — Propose alternative port numbers, update all references in the plan and project files (docker-compose service ports, connection strings, convenience scripts, VS Code debug config), then resume generation. +4. **If the user will handle it themselves** — Proceed with generation using the original ports. +5. **Never remap ports or modify config silently** — Always confirm with the user before making changes. diff --git a/resources/agents/azure-debug-generate/references/project-types/_template.md b/resources/agents/azure-debug-generate/references/project-types/_template.md new file mode 100644 index 000000000..96ba035e4 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/project-types/_template.md @@ -0,0 +1,166 @@ +# {Type} — Project Type + +> **Template** — Copy this file to `project-types/{type}.md` when adding a new server-side project type. For browser-based project types, use `project-types/frontend-spa/` as a reference — the structure differs (Framework Lookup Table replaces Startup Command, debug adapters replace Debugger Properties). + +--- + +## Detection Signals + + + +| Signal | Notes | +|--------|-------| +| `{file}` | {description} | + +--- + +## Prerequisites + + + +| Tool | Detection Command | Required For | Install Link | +|------|-------------------|-------------|-------------| +| `{tool}` | `{command}` | {purpose} | `{install-url}` | + +--- + +## Runtime Support Matrix + + + +| Runtime | Status | Reference | +|---------|--------|-----------| +| node-ts | | | +| node-js | | | +| dotnet | | | +| python | | | +| java | | | +| go | | | + +--- + +## Dependency Discovery + + + + +| Dependency Signal | Azure Service | Emulator | +|------------------|---------------|---------| +| `{signal}` | {service} | [{name}](../emulators/{name}.md) | + +--- + +## Startup Command + + + +``` +{command} +``` + +--- + +## Runtime Wiring + + + +> See **§ VS Code Task Configuration** below for the concrete task JSON for each runtime. + +| Runtime | Startup task label | Task type | Problem matcher | Request Mode | Status | Reference | +|---------|--------------------|-----------|-----------------|--------------|--------|-----------| +| node-ts | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | | +| node-js | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | | +| dotnet | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | | +| python | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | | +| java | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | | +| go | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | | + +### VS Code Debug Configuration + + + +### VS Code Task Configuration + + + +### Connection Strings + + + +| Emulator | Key | Value | File | +|----------|-----|-------|------| +| {emulator} | `{VAR_NAME}` | `{value}` | `{file}` | + +--- + +## API Test Collections + + + +See [api-test-collections.md](../api-test-collections.md) for all test script patterns. + +--- + +## VS Code Extension Recommendations (`.vscode/extensions.json`) + + + +| Extension ID | Why Required | +|--------------|-------------| +| `{extension-id}` | {reason} | + +--- + +## VS Code Workspace Settings (`.vscode/settings.json`) + + + +| Setting | Value | Why | +|---------|-------|-----| +| `{setting.key}` | `{value}` | {reason} | + +--- + +## Validation Signals + + + +### Ready Signal + +| Top-Level Task | Ready Signal (stdout) | +|----------------|----------------------| +| {task label} | `"{pattern}"` | + +### HTTP Verification + +| Curl Target | Expected Status | Notes | +|-------------|-----------------|-------| +| `http://localhost:{port}/{path}` | `{status}` | {notes} | + +--- + +## Checklist — {Type} Project Validation + + + +After generating `launch.json`, `tasks.json`, and `extensions.json`, verify the following were produced correctly: + +1. ✅ Startup task exists in `tasks.json` with the correct type and problem matcher +2. ✅ `launch.json` `preLaunchTask` points to the startup task +3. ✅ `.vscode/extensions.json` includes project-type extensions listed above +4. ✅ `dependsOn` chain includes runtime build/watch task and `Start Emulators` (when emulators are required) + +> Runtime-specific checks (e.g., build task, debugger type) are defined in `runtimes/{rt}.md`. diff --git a/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/_template.md b/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/_template.md new file mode 100644 index 000000000..fb35f266a --- /dev/null +++ b/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/_template.md @@ -0,0 +1,37 @@ +# {Adapter} — Browser Debug Adapter + +> **Template** — Copy this file to `{adapter}.md` when adding a new browser debug adapter. + +## VS Code Debugger Type + +| Browser | VS Code Debugger Type | Required Extension | +|---------|----------------------|-------------------| +| {browser} | `{type}` | {extension or "None — built-in"} | + +--- + +## Launch Configuration + +```json +{ + "name": "{id} (debug)", + "type": "{type}", + "request": "launch", + "url": "http://localhost:{port from Framework Lookup Table}", + "preLaunchTask": "{id} dev" +} +``` + +| Field | Source | +|-------|--------| +| `type` | VS Code Debugger Type from table above | +| `url` | Default Port from [frontend-spa.md § Framework Lookup Table](../frontend-spa.md) | +| `preLaunchTask` | `{id} dev` — the dev server task from [frontend-spa.md § VS Code Task Configuration](../frontend-spa.md) | + + + +--- + +## Notes + + diff --git a/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/blazorwasm.md b/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/blazorwasm.md new file mode 100644 index 000000000..b00c7e8cb --- /dev/null +++ b/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/blazorwasm.md @@ -0,0 +1,40 @@ +# Blazor WASM — Browser Debug Adapter + +> 🔲 **Planned** — This adapter is not yet implemented. Emit a `⚠️ LIMITED SUPPORT:` warning per [limited-support.md](../../../limited-support.md). + +## VS Code Debugger Type + +| Browser / Runtime | VS Code Debugger Type | Required Extension | +|-------------------|----------------------|-------------------| +| Blazor WASM (.NET) | `blazorwasm` | `ms-dotnettools.csharp` | + +--- + +## Launch Configuration + +```json +{ + "name": "{id} (debug)", + "type": "blazorwasm", + "request": "launch", + "url": "http://localhost:{port from Framework Lookup Table}", + "browser": "chrome", + "cwd": "${workspaceFolder}/{service-root}", + "preLaunchTask": "{id} dev" +} +``` + +| Field | Source | +|-------|--------| +| `type` | Always `blazorwasm` | +| `url` | Default Port from [frontend-spa.md § Framework Lookup Table](../frontend-spa.md) | +| `browser` | Which browser to launch — defaults to `chrome` | +| `cwd` | .NET project root | +| `preLaunchTask` | `{id} dev` — the dev server task from [frontend-spa.md § VS Code Task Configuration](../frontend-spa.md) | + +--- + +## Notes + +- The `blazorwasm` adapter is provided by the C# extension, not built into VS Code. +- The launch config shape differs from the CDP-based `chrome`/`msedge` adapter — it requires `browser` and `cwd` fields, and does not use `webRoot`. diff --git a/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/chromium.md b/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/chromium.md new file mode 100644 index 000000000..a614e2fe3 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/project-types/frontend-spa/debug-adapters/chromium.md @@ -0,0 +1,60 @@ +# Chromium — Browser Debug Adapter + +> Covers all **Chromium-based browsers** (Chrome, Edge, etc.). The launch configuration is identical — only the `type` field differs. + +## VS Code Debugger Type + +| Browser | VS Code Debugger Type | Required Extension | +|---------|----------------------|-------------------| +| Chrome | `chrome` | None — built-in | +| Edge | `msedge` | None — built-in | + +Use the browser recorded in the plan's Prerequisites section (see [prerequisites.md](../../../../../shared-references/prerequisites.md) § Browser detection) to pick the `type`. + +--- + +## Launch Configuration + +```json +{ + "name": "{id} (debug)", + "type": "{chrome or msedge}", + "request": "launch", + "url": "http://localhost:{port from Framework Lookup Table}", + "webRoot": "${workspaceFolder}/{service-root}", + "preLaunchTask": "{id} dev" +} +``` + +| Field | Source | +|-------|--------| +| `type` | Browser Debugger Type from table above — matches the browser recorded in the plan's Prerequisites (`chrome` for Chrome, `msedge` for Edge) | +| `url` | Default Port from [frontend-spa.md § Framework Lookup Table](../frontend-spa.md) | +| `webRoot` | **Framework root** — see `webRoot` Resolution below | +| `preLaunchTask` | `{id} dev` — the dev server task from [frontend-spa.md § VS Code Task Configuration](../frontend-spa.md) | + +--- + +## `webRoot` Resolution + +> **Universal rule:** `webRoot` must ALWAYS be the **framework root directory** (where the framework's config file lives), NEVER a subdirectory within it. The dev server determines its URL path structure relative to this root. Setting `webRoot` to a subdirectory like `src/` causes path doubling and breaks breakpoint resolution. + +This applies to **all frameworks** — any framework where the config file lives in a parent directory of `src/` will exhibit the same bug. + +| Framework | Config file that defines the root | `webRoot` value | +|-----------|----------------------------------|-----------------| +| Vite | `vite.config.*` | Directory containing `vite.config.*` | +| CRA | `package.json` (with `react-scripts`) | Directory containing `package.json` | +| Angular | `angular.json` | Workspace root (or project root in monorepo) | +| Next.js | `next.config.*` | Directory containing `next.config.*` | +| Blazor WASM | `*.csproj` | Directory containing `*.csproj` | + +> ⛔ **Before writing `webRoot`**, verify: does `{service-root}` contain the framework config file (e.g., `vite.config.ts`, `angular.json`)? If the plan's Service Root points to a `src/` subdirectory that does NOT contain the config file, walk up to the parent that does. + +--- + +## Notes + +- The `"request": "launch"` mode opens a new browser window with CDP debugging enabled — breakpoints work immediately. +- `webRoot` maps the browser's served files back to workspace source files for correct breakpoint resolution. +- Chrome and Edge share the same CDP protocol, so all behavior is identical between them. diff --git a/resources/agents/azure-debug-generate/references/project-types/frontend-spa/frontend-spa.md b/resources/agents/azure-debug-generate/references/project-types/frontend-spa/frontend-spa.md new file mode 100644 index 000000000..f9dbc0202 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/project-types/frontend-spa/frontend-spa.md @@ -0,0 +1,178 @@ +# Project Type: Frontend SPA + +Reference guide for local development setup of frontend single-page application projects. + +> All SPA frameworks share the same VS Code debug configuration shape: browser debugger type (e.g., `chrome`, `msedge`), `launch` request mode, dev server as a prerequisite task. The per-framework differences — runtime, startup command, default port, and background problem matcher — are resolved from the Framework Lookup Table below. + +--- + +## Detection Signals + +Match against these signals to classify a workspace root as a frontend SPA. If the workspace clearly is an SPA but doesn't match a specific signal below, still classify it as Frontend SPA — use the Framework Lookup Table's fallback row for configuration. + +| Signal | Notes | +|--------|-------| +| `vite.config.*` or `vite` in devDependencies | Vite-based SPA | +| `next.config.*` or `next` in dependencies | Next.js app | +| `angular.json` | Angular app | +| `react-scripts` in dependencies | Create React App | +| `*.razor` files + `Microsoft.AspNetCore.Components.WebAssembly` in `*.csproj` | Blazor WASM | + +--- + +## Prerequisites + +No VS Code extension is required — browser debugging uses VS Code's built-in adapter. A Chromium-based browser (Chrome or Edge) must be installed, though; that is captured as a Debug prerequisite via [prerequisites.md](../../../../shared-references/prerequisites.md) § Browser detection. Runtime prerequisites (e.g., Node.js) are listed in `runtimes/{rt}.md § Prerequisites`. + +--- + +## Runtime Support Matrix + +Runtime support for Frontend SPAs is tracked per-framework in the **Framework Lookup Table** below. Each row's `Status` column indicates implementation readiness. + +--- + +## Dependency Discovery + +Frontend SPAs communicate with backend services via HTTP during local development — they do not connect to Azure emulators directly. In monorepo setups, Azure service dependencies (storage, databases, etc.) are handled by the backend project type. In standalone SPA projects, the backend may already be running as a deployed service or a separate local process — no emulator setup is needed for the SPA itself. + +--- + +## Backend Proxy Dependencies + +Frontend dev servers often proxy API requests to a local backend during development. In multi-service setups, if a proxy config is detected pointing to another local service, that backend service's startup task should be a dependency of the frontend's dev server task to prevent `ECONNREFUSED` errors during initial page load. + +| Framework | Proxy Config Location | +|-----------|----------------------| +| Vite | `server.proxy` in `vite.config.*` | +| Create React App | `"proxy"` field in `package.json` | +| Angular | `proxy.conf.json` | +| Next.js | `rewrites()` in `next.config.*` | + +--- + +## Startup Command + +The startup command varies per framework. See the **Framework Lookup Table** below for the specific command for each detected framework (e.g., `npm run dev` for Vite, `npm start` for Angular). + +--- + +## Framework Lookup Table + +Use this table to resolve per-framework values when generating the VS Code configuration. The `Status` column is the source of truth for implementation readiness — if a framework is not ✅ Implemented, emit a `⚠️ LIMITED SUPPORT:` warning per [limited-support.md](../../limited-support.md). + +> **To add a new framework:** add a row with its runtime, detection signal, startup command, default port, problem matcher patterns, and status. + +| Framework | Runtime | Detection | Startup Command | Default Port | Ready Pattern (begins) | Ready Pattern (ends) | Status | +|-----------|---------|----------|-----------------|--------------|----------------------|---------------------|--------| +| Vite | node | `vite.config.*` or `vite` in devDependencies | `npm run dev` | 5173 | `VITE` | `Local:` | ✅ Implemented | +| Next.js | node | `next.config.*` or `next` in dependencies | `npm run dev` | 3000 | `\s*ready` | `started server on` | ✅ Implemented | +| Angular | node | `angular.json` | `npm start` | 4200 | `Compiling` | `Compiled successfully` | ✅ Implemented | +| Create React App | node | `react-scripts` in dependencies | `npm start` | 3000 | `Starting the development server` | `Compiled` | ✅ Implemented | +| Blazor WASM | dotnet | `*.razor` + `WebAssembly` SDK in `*.csproj` | `dotnet watch run` | 5000 | `Now listening on` | `Application started` | 🔲 Planned | +| other | — | No match | — | — | — | — | [limited-support.md](../../limited-support.md) | + +> ⚠️ **ANSI escape codes:** Dev servers often wrap output in color codes (e.g., `\x1b[32m...\x1b[0m`). Prefer plain-text anchors that appear outside styled regions (e.g., `Local:` instead of `ready in \d+`) to avoid regex mismatches. + +--- + +## Runtime Wiring + + + +| Startup command | Startup task label | Task type | Problem matcher | Request Mode | +|----------------|-------------------|-----------|-----------------|--------------| +| From Framework Lookup Table | `{id} dev` | `shell` | From Framework Lookup Table | `launch` | + +### VS Code Debug Configuration + +The request mode is always `launch` (VS Code opens the browser). The browser (Chrome or Edge) is the one recorded in the plan's Prerequisites section during the browser detection pass (see [prerequisites.md](../../../../shared-references/prerequisites.md) § Browser detection) — use its debug adapter `type` (`chrome` for Chrome, `msedge` for Edge). The user can change the browser in the plan before approval. + +Look up the launch configuration template from the corresponding adapter file in [`debug-adapters/`](debug-adapters/): + +| Browser / Adapter | Adapter File | Status | +|-------------------|-------------|--------| +| Chromium (Chrome, Edge, etc.) | [debug-adapters/chromium.md](debug-adapters/chromium.md) | ✅ Implemented | +| Blazor WASM (.NET) | [debug-adapters/blazorwasm.md](debug-adapters/blazorwasm.md) | 🔲 Planned | +| ∞ | [debug-adapters/_template.md](debug-adapters/_template.md) | — | + +> **To add a new debug adapter:** copy `debug-adapters/_template.md` to `debug-adapters/{adapter}.md` and add a row to this table. + +### VS Code Task Configuration + +The top-level task is the framework's dev server. No runtime build chain — the dev server handles compilation internally. The task label follows the pattern `"{id} dev"`. + +```json +{ + "type": "shell", + "label": "{id} dev", + "command": "{command from Framework Lookup Table}", + "options": { "cwd": "${workspaceFolder}/{service-root}" }, + "isBackground": true, + "runOptions": { "instanceLimit": 1, "instancePolicy": "silent" }, + "problemMatcher": { + "owner": "{framework name, lowercased}", + "pattern": { "regexp": "^$" }, + "background": { + "activeOnStart": true, + "beginsPattern": "{Ready Pattern (begins) from Framework Lookup Table}", + "endsPattern": "{Ready Pattern (ends) from Framework Lookup Table}" + } + } +} +``` + +### Connection Strings + +Not applicable — Frontend SPAs do not connect to Azure emulators directly. In monorepo setups, connection strings are owned by the backend project type. + +--- + +## API Test Collections + +Not applicable — Frontend SPAs do not expose API endpoints. In monorepo setups, API test collections are owned by the backend project type. See [api-test-collections.md](../../api-test-collections.md) for backend patterns. + +--- + +## VS Code Extension Recommendations (`.vscode/extensions.json`) + +No project-type-specific extensions. Browser debugging uses VS Code's built-in capabilities. + +> Framework-specific extensions (if any) would be listed here. Runtime extensions are listed in `runtimes/{rt}.md`. + +--- + +## VS Code Workspace Settings (`.vscode/settings.json`) + +No project-type-specific workspace settings. + +--- + +## Validation Signals + +Used by [validation.md](../../validation.md) during Phase 3 to verify the generated debug configuration works. + +### Ready Signal + +Use the `Ready Pattern (begins)` and `Ready Pattern (ends)` columns from the **Framework Lookup Table** above for the detected framework. The ready signal is observed on stdout of the dev server task. + +### HTTP Verification + +| Curl Target | Expected Status | Notes | +|-------------|-----------------|-------| +| `http://localhost:{dev-server-port}` | `200` or `301` | Use the resolved dev server port from the Framework Lookup Table. Validates the dev server started — do NOT launch a browser. Framework-specific redirects (e.g., `301` for Next.js) are acceptable. | + +--- + +## Checklist — Frontend SPA Project Validation + +After generating `launch.json` and `tasks.json`, verify the following were produced correctly: + +1. ✅ Dev server task exists in `tasks.json` with a custom `background` problem matcher using the correct begin/end patterns from the Framework Lookup Table +2. ✅ `launch.json` uses the browser debug adapter matching the browser recorded in the plan's Prerequisites (`chrome` or `msedge`) with `"request": "launch"` +3. ✅ `launch.json` `url` matches the framework's default port from the Framework Lookup Table +4. ✅ `launch.json` `preLaunchTask` points to the dev server task + +> Runtime-specific checks (e.g., build task, debugger type) are defined in `runtimes/{rt}.md`. diff --git a/resources/agents/azure-debug-generate/references/project-types/functions.md b/resources/agents/azure-debug-generate/references/project-types/functions.md new file mode 100644 index 000000000..b69223fc8 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/project-types/functions.md @@ -0,0 +1,278 @@ +# Project Type: Azure Functions + +Reference guide for local development setup of Azure Functions projects. + +--- + +## Detection Signals + +| Signal | Notes | +|--------|-------| +| `host.json` present | Primary signal — required | +| Azure Functions SDK in dependencies | Confirms it's a Functions project — identified during the plan phase | + +--- + +## Prerequisites + +| Tool | Detection Command | Required For | Install Link | +|------|-------------------|-------------|-------------| +| Azure Functions Core Tools | `func --version` | Run Functions host locally | [aka.ms/azure-functions-core-tools](https://aka.ms/azure-functions-core-tools) | + +--- + +## Runtime Support Matrix + +| Runtime | Status | Reference | +|---------|--------|-----------| +| node-ts | ✅ Implemented | [runtimes/node.md](../runtimes/node.md) | +| node-js | ✅ Implemented | [runtimes/node.md](../runtimes/node.md) | +| dotnet (Functions isolated) | ✅ Implemented | [runtimes/dotnet.md](../runtimes/dotnet.md) | +| python | 🔲 Planned | [limited-support.md](../limited-support.md) | +| java | 🔲 Planned | [limited-support.md](../limited-support.md) | + +> **Limited-support runtimes:** When a runtime with limited support is detected, emit a `⚠️ LIMITED SUPPORT:` warning per [limited-support.md](../limited-support.md) and ask the user whether to proceed. If the user agrees, proceed with best-effort generation for all artifacts (emulators, debug config, tasks). Do not silently skip debug/launch configuration — let the user decide. + +--- + +## Dependency Discovery + +Scan every `function.json` for its `"type"` binding field, **or** scan Python/Java source files for trigger decorator/attribute names. Each binding maps to an emulator. + +### Binding → Emulator Mapping + +| Binding Type(s) | Azure Service | Default Ports | Connection String | Status | Reference | +|----------------|---------------|---------------|-------------------|--------|-----------| +| `blobTrigger`, `blob` | Blob Storage | 10000 | `UseDevelopmentStorage=true` | ✅ Implemented | [emulators/azurite.md](../emulators/azurite.md) | +| `queueTrigger`, `queue` | Queue Storage | 10001 | `UseDevelopmentStorage=true` | ✅ Implemented | [emulators/azurite.md](../emulators/azurite.md) | +| `table` | Table Storage | 10002 | `UseDevelopmentStorage=true` | ✅ Implemented | [emulators/azurite.md](../emulators/azurite.md) | +| `cosmosDBTrigger`, `cosmosDB` | Cosmos DB | 8081, 10250–10254 | — | 🔲 Planned | [limited-support.md](../limited-support.md) | +| `serviceBusTrigger`, `serviceBus` | Service Bus | 5672 | — | 🔲 Planned | [limited-support.md](../limited-support.md) | +| `eventHubTrigger`, `eventHub` | Event Hubs | 9093 | — | 🔲 Planned | [limited-support.md](../limited-support.md) | +| `sql`, `sqlTrigger` | Azure SQL | 1433 | — | 🔲 Planned | [limited-support.md](../limited-support.md) | +| `httpTrigger` | (built-in) | — | — | ✅ Implemented | — | +| `timerTrigger` | (built-in) | — | — | ✅ Implemented | — | + +> **Azurite consolidation:** If multiple storage bindings (blob + queue + table) are detected, create a **single** Azurite service — not one per binding type. + +### Services Without Azure Emulators + +| Binding Type | Azure Service | Recommendation | +|-------------|---------------|----------------| +| `signalR` | Azure SignalR | Use a dev-tier Azure SignalR instance | +| PostgreSQL (SDK, not a binding) | Azure Database for PostgreSQL | [emulators/postgres.md](../emulators/postgres.md) | + +--- + +## Startup Command + +> For VS Code `"type": "func"` tasks, omit the `func` executable prefix — the Azure Functions extension supplies it. The equivalent CLI commands are shown below for reference. + +**Node.js (TypeScript & JavaScript):** + +``` +languageWorkers__node__arguments="--inspect=9229" func host start +``` + +> ⚠️ The Azure Functions Core Tools do **not** automatically enable the Node.js debugger. You **must** supply `--inspect=9229` to the Node worker so it opens a debug port for VS Code to attach to. Without it, the `attach` configuration connects to nothing. In the VS Code `func` task, set this via `options.env` (`languageWorkers__node__arguments`) rather than a command-line flag — the env-var form avoids shell/JSON quoting issues and uses the same `languageWorkers____arguments` convention across runtimes. + +**dotnet:** + +``` +func host start +``` + +> For .NET, the Functions host spawns a worker process that VS Code attaches to via `coreclr` — no additional debug flags are needed on the command line. + +--- + +## Runtime Wiring + + + +> See **§ VS Code Task Configuration** below for the concrete task JSON for each runtime. + +| Runtime | Startup task label | Task type | Problem matcher | Request mode | Status | Reference | +|---------|--------------------|-----------|-----------------|--------------|--------|-----------| +| node-ts | `{service-id}: func host start` | `func` | `$func-node-watch` | `attach` | ✅ Implemented | [runtimes/node.md](../runtimes/node.md) | +| node-js | `{service-id}: func host start` | `func` | `$func-node-watch` | `attach` | ✅ Implemented | [runtimes/node.md](../runtimes/node.md) | +| dotnet | `{service-id}: func host start` | `func` | `$func-dotnet-watch` | `attach` | ✅ Implemented | [runtimes/dotnet.md](../runtimes/dotnet.md) | +| python | `{service-id}: func host start` | `func` | `$func-python-watch` | `attach` | 🔲 Planned | [limited-support.md](../limited-support.md) | +| java | `{service-id}: func host start` | `func` | `$func-java-watch` | `attach` | 🔲 Planned | [limited-support.md](../limited-support.md) | + +> `{service-id}` is the kebab-case ID derived from the plan's Service Label column — see [generate.md § Service ID Derivation](../generate.md). + +> **dotnet `processName` warning.** The .NET `coreclr` (request: `attach`) configuration requires the literal `processName` in `launch.json` — `.exe` suffix on Windows, no extension on macOS/Linux. Without it, F5 fails with `"No process with the specified name is currently running"`. Do NOT use `${command:pickProcess}`. See [runtimes/dotnet.md § processName Determination](../runtimes/dotnet.md). + +The startup step `dependsOn`: +1. The runtime-specific build/watch task label from `runtimes/{rt}.md` § Build Chain (e.g., `{service-id}: npm watch` for node-ts, `{service-id}: dotnet build` for dotnet) +2. `"Start Emulators"` (only when emulators are required — omit when the plan has no checked emulators) + +### VS Code Task Configuration + +The top-level task uses the VS Code `func` task type provided by the Azure Functions extension (`ms-azuretools.vscode-azurefunctions`). The launch configuration's `preLaunchTask` points to this task. + +> **Task label scoping:** All task labels MUST be prefixed with the service ID (e.g., `functions-api: func host start`). This prevents label collisions in multi-service workspaces. See [generate.md § Service ID Derivation](../generate.md). + +#### Debug Argument Injection + +The Functions host runs your code in a separate **language-worker** process, so the worker must start with the runtime's debug flag. Inject it through the task's `options.env` using the `languageWorkers____arguments` convention, then point a matching `attach` config at the resulting port. Only the env key, the flag value, and the attach `type`/`port` change per runtime — the rest of the `func host start` task stays identical, so new runtimes slot straight into this table. + +| Runtime | `options.env` setting | Value to inject | Debug port | `attach` type | Status | +|---------|-----------------------|-----------------|------------|---------------|--------| +| node-ts | `languageWorkers__node__arguments` | `--inspect=9229` | 9229 | `node` | ✅ Implemented | +| node-js | `languageWorkers__node__arguments` | `--inspect=9229` | 9229 | `node` | ✅ Implemented | + + +**node-ts** (has watch task): + +```json +{ + "type": "func", + "label": "{service-id}: func host start", + "command": "host start", + "options": { + "cwd": "${workspaceFolder}/{path-to-functions-project}", + "env": { "languageWorkers__node__arguments": "--inspect=9229" } + }, + "problemMatcher": "$func-node-watch", + "isBackground": true, + "runOptions": { "instanceLimit": 1, "instancePolicy": "silent" }, + "dependsOn": ["{service-id}: npm watch", "Start Emulators"] +} +``` + +> Remove `"Start Emulators"` from `dependsOn` when the plan has no checked emulators. + +**node-js** (no compile/watch step): + +```json +{ + "type": "func", + "label": "{service-id}: func host start", + "command": "host start", + "options": { + "cwd": "${workspaceFolder}/{path-to-functions-project}", + "env": { "languageWorkers__node__arguments": "--inspect=9229" } + }, + "problemMatcher": "$func-node-watch", + "isBackground": true, + "runOptions": { "instanceLimit": 1, "instancePolicy": "silent" }, + "dependsOn": ["{service-id}: npm install", "Start Emulators"] +} +``` + +> Remove `"Start Emulators"` from `dependsOn` when the plan has no checked emulators. + +> `dependsOn`: first entry is the runtime-specific prerequisite — watch task for TypeScript, install task for JavaScript. The exact task labels come from `runtimes/{rt}.md` § Build Chain, prefixed with the service ID. + +**dotnet** (compiled — requires build before host start): + +```json +{ + "type": "func", + "label": "{service-id}: func host start", + "command": "host start", + "options": { "cwd": "${workspaceFolder}/{path-to-functions-project}" }, + "problemMatcher": "$func-dotnet-watch", + "isBackground": true, + "runOptions": { "instanceLimit": 1, "instancePolicy": "silent" }, + "dependsOn": ["{service-id}: dotnet build", "Start Emulators"] +} +``` + +> Remove `"Start Emulators"` from `dependsOn` when the plan has no checked emulators. + +> **dotnet `processName`:** The `coreclr` attach configuration requires a literal `processName` in `launch.json`. See [runtimes/dotnet.md § processName Determination](../runtimes/dotnet.md) for how to derive it from the `.csproj`, including cross-platform rules (`.exe` suffix on Windows only). + +#### .NET Isolated Worker Version Constraints + +Functions Worker **2.x** is required for .NET 10: +- `Microsoft.Azure.Functions.Worker >= 2.50.0` +- `Microsoft.Azure.Functions.Worker.Sdk >= 2.0.5` + +When detecting a .NET Functions project, verify these minimum versions. Worker 2.x uses the canonical `func host start` + `coreclr` (request: `attach`) flow where the Functions host spawns the worker process. + +### Connection Strings + +| Emulator | Key | Value | Status | Reference | +|----------|-----|-------|--------|-----------| +| Azurite (storage) | `AzureWebJobsStorage` | `UseDevelopmentStorage=true` | ✅ Implemented | [emulators/azurite.md](../emulators/azurite.md) | +| Cosmos DB | {detected from bindings} | — | 🔲 Planned | [limited-support.md](../limited-support.md) | +| Service Bus | {detected from bindings} | — | 🔲 Planned | [limited-support.md](../limited-support.md) | +| Event Hubs | {detected from bindings} | — | 🔲 Planned | [limited-support.md](../limited-support.md) | +| SQL Edge | {detected from bindings} | — | 🔲 Planned | [limited-support.md](../limited-support.md) | +| PostgreSQL | {detected from code} | See [emulators/postgres.md](../emulators/postgres.md) | ✅ Implemented | [emulators/postgres.md](../emulators/postgres.md) | + +> **Key discovery:** Except for `AzureWebJobsStorage` (a well-known Azure Functions convention), connection string key names are not fixed. Perform targeted resolution — check `local.settings.json`, `.env`, binding configurations, and SDK usage to detect the actual key names. Use the detected names — do not invent defaults. + +> **Never overwrite** existing values in `local.settings.json` — only add missing keys. + +--- + +## API Test Collections + +See [api-test-collections.md](../api-test-collections.md) for all test script patterns. For this project type, generate tests for: + +- HTTP triggers → HTTP patterns with `baseUrl: http://localhost:7071/api` +- Blob triggers → Storage § Blob trigger pattern +- Queue triggers → Storage § Queue trigger pattern +- Timer triggers → Timer § admin API pattern (only if explicitly requested) +- Cosmos DB triggers → Cosmos DB pattern +- Service Bus triggers → Service Bus pattern +- Event Hub triggers → Event Hubs pattern + +--- + +## VS Code Extension Recommendations (`.vscode/extensions.json`) + +Contribute the following to `.vscode/extensions.json`. + +| Extension ID | Why Required | +|--------------|-------------| +| `ms-azuretools.vscode-azurefunctions` | Contributes the `"type": "func"` task type | + +--- + +## VS Code Workspace Settings (`.vscode/settings.json`) + +Contribute the following to `.vscode/settings.json`. + +| Setting | Value | Why | +|---------|-------|-----| +| `azureFunctions.showProjectWarning` | `false` | Suppresses the "failed to detect project" prompt that fires when the extension scans the workspace — our generated config already handles project setup | +| `azureFunctions.validateEmulators` | `false` | Suppresses emulator validation warnings from the extension — emulators are managed via user's orchestrator configuration | + +--- + +## Validation Signals + +Used by [validation.md](../validation.md) during Phase 3 to verify the generated debug configuration works. + +### Ready Signal + +| Top-Level Task | Ready Signal (stdout) | +|----------------|----------------------| +| `{service-id}: func host start` | `"Host lock lease acquired"` or `"Functions host started"` | + +> The `Top-Level Task` column uses the canonical `{service-id}:`-prefixed label — see [generate.md § Service ID Derivation](../generate.md). Resolve `{service-id}` to the same value used during generation before matching against `tasks.json`. + +### HTTP Verification + +| Curl Target | Expected Status | Notes | +|-------------|-----------------|-------| +| First discovered anonymous `httpTrigger` route (e.g., `http://localhost:7071/api/{function-name}`) | `200` | Port `7071` is the Functions host HTTP port; debug port `9229` is for the debugger only. Use the first anonymous HTTP trigger found during targeted resolution. If only function-key/admin routes exist, skip HTTP verification with a warning rather than assuming a route. | + +--- + +## Checklist — Functions Project Validation + +After generating `launch.json`, `tasks.json`, and `extensions.json`, verify the following were produced correctly: + +1. ✅ `{service-id}: func host start` task exists in `tasks.json` with `"type": "func"` +2. ✅ `launch.json` `preLaunchTask` points to `{service-id}: func host start` +3. ✅ `.vscode/extensions.json` includes `ms-azuretools.vscode-azurefunctions` +4. ✅ `local.settings.json` contains all required connection string keys (e.g., `AzureWebJobsStorage`) +5. ✅ `dependsOn` chain includes the runtime build/watch task and `Start Emulators` (when emulators are required) + +> Runtime-specific checks (e.g., `dotnet build` task, `processName` derivation) are defined in `runtimes/{rt}.md`. diff --git a/resources/agents/azure-debug-generate/references/runtimes/_template.md b/resources/agents/azure-debug-generate/references/runtimes/_template.md new file mode 100644 index 000000000..ab39b0048 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/runtimes/_template.md @@ -0,0 +1,135 @@ +# {Runtime} — Debug & Build Configuration + +> **Template** — Copy this file to `runtimes/{rt}.md` when adding a new runtime. + +--- + +## Prerequisites + + + + +| Tool | Detection Command | Required For | Install Link | +|------|-------------------|-------------|-------------| +| `{tool}` | `{tool} --version` | {purpose} | `{install-url}` | + +--- + +## Debugger Properties + + + +| Property | Value | Notes | +|----------|-------|-------| +| Debug protocol | `{protocol}` | The wire protocol the runtime exposes (e.g., `Node Inspector`, `CoreCLR DAP`, `debugpy DAP`, `JDWP`, `Delve DAP`). | +| VS Code debugger type | `{type}` | The VS Code debugger adapter identifier (e.g., `node`, `coreclr`, `debugpy`, `java`, `go`). | +| Base debug port | `{port}` | Default debug port for this runtime; overridden per-service in monorepos | + +### VS Code Problem Matchers + + + +| Task | Watch Problem Matcher | Build Problem Matcher | +|------|----------------------|----------------------| +| {task} | `{matcher}` | `{matcher}` | + +--- + +## Build Chain + + + +Chain shape (startup task comes from the project type): + +``` +"{service-id}: {startup task}" ← from project-types/{type}.md Runtime Wiring + ├── dependsOn: "{service-id}: {build/watch step}" ← this file + └── dependsOn: "Start Emulators" ← only when emulators are required +``` + +> **Task label scoping:** All task labels MUST be prefixed with the service ID derived from the plan's Service Label column. See [generate.md § Service ID Derivation](../generate.md). + +### Build Commands + +| Step | Command | Purpose | Background? | +|------|---------|---------|------------| +| Start Emulators | `docker compose up -d` | Start all emulator services (idempotent — no-op if already running) | No | + +See [generate.md](../generate.md) § Task `runOptions` Rules for how these build steps are rendered into VS Code task configuration. + +--- + +## Convenience Scripts + + + +The plan's Convenience Scripts table specifies WHICH scripts to generate. This section covers HOW to register them for this runtime. + +**Script runner:** `{file}` (e.g., `package.json` scripts, `scripts/` directory, `Makefile`, `pyproject.toml`) +**Run command pattern:** `{command}` (e.g., `npm run {script}`, `./scripts/{script}.sh`) + +> When the runtime's script runner is not inherently cross-platform (e.g., standalone scripts vs `package.json`), generate platform-appropriate scripts or document cross-platform alternatives. + +### Script Format + + + +### Common Script Implementations + +Use these implementations when building scripts from the plan: + +| Script Purpose | Typical Command | Notes | +|---------------|-----------------|-------| +| Start emulators | `docker compose up -d` | Idempotent — safe to re-run | +| Stop emulators | `docker compose down` | Stops and removes containers | +| Clean emulator data | Stop containers and remove data directories | `{data-dirs}` = `./.{name}` directories derived from `docker-compose.yml` `volumes:` mounts. Use platform-appropriate removal. | +| Run migrations | `{migration tool CLI command}` | See [migrations.md](../migrations.md) for how to determine the command | + +--- + +## VS Code Extension Recommendations (`.vscode/extensions.json`) + + + +| Extension ID | Why Required | +|--------------|-------------| +| `{extension-id}` | {reason} | + +--- + +## VS Code Workspace Settings (`.vscode/settings.json`) + + + +| Setting | Value | Why | +|---------|-------|-----| +| `{setting.key}` | `{value}` | {reason} | + +--- + +## Checklist — {Runtime} Validation + +> ⛔ **MANDATORY — runs during Phase 3 validation after all artifacts are generated.** You MUST verify every item below. Do NOT skip, assume, or approximate results. + + + +After generating VS Code configuration, verify the following were produced correctly: + +### Post-Generation Checks + +1. ✅ Build task exists in `tasks.json` with the correct problem matcher +2. ✅ `launch.json` uses the correct debugger type and request mode +3. ✅ `.vscode/extensions.json` includes runtime extensions listed above + +### Live Validation Checks + + + +> Project-type-specific checks (e.g., startup task, connection strings) are defined in `project-types/{type}.md`. diff --git a/resources/agents/azure-debug-generate/references/runtimes/dotnet.md b/resources/agents/azure-debug-generate/references/runtimes/dotnet.md new file mode 100644 index 000000000..06478f632 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/runtimes/dotnet.md @@ -0,0 +1,191 @@ +# .NET / C# — Debug & Build Configuration + +> Covers **.NET** projects. Project-type-specific hosting (Functions, App Service, etc.) is defined in `project-types/{type}.md` — this file covers the .NET runtime layer only. + +## Prerequisites + +| Tool | Detection Command | Required For | Install Link | +|------|-------------------|-------------|-------------| +| .NET SDK | `dotnet --version` | Build and run .NET projects | [dotnet.microsoft.com](https://dotnet.microsoft.com/download) | +| C# extension | VS Code extension `ms-dotnettools.csharp` installed | Contributes the `coreclr` debugger type required for F5 debugging | [Marketplace](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) | + +--- + +## Debugger Properties + + + +| Property | Value | Notes | +|----------|-------|-------| +| Debug protocol | `CoreCLR DAP` | .NET Core / .NET 5+ debug adapter protocol | +| VS Code debugger type | `coreclr` | Contributed by the C# extension (`ms-dotnettools.csharp`) | +| Request mode | `attach` | VS Code attaches to a running .NET process by `processName` | +| Base debug port | — | CoreCLR attach uses `processName`, not a port | + +### VS Code Problem Matchers + +| Task | Watch Problem Matcher | Build Problem Matcher | +|------|----------------------|----------------------| +| `dotnet build` | — | `$msCompile` | + +--- + +## processName Determination + +The `coreclr` debugger (request: `attach`) matches `processName` **literally** against the OS process list. Getting this wrong means F5 silently fails. + +### Cross-Platform Rules + +| Platform | Process name | Example | +|----------|-------------|---------| +| Windows | `{AssemblyName}.exe` | `Scrapbook.Api.exe` | +| macOS / Linux | `{AssemblyName}` (no extension) | `Scrapbook.Api` | + +> ⛔ **Windows requires the `.exe` suffix.** Writing `"Scrapbook.Api"` instead of `"Scrapbook.Api.exe"` produces: +> +> ``` +> No process with the specified name is currently running. +> ``` + +### Deriving `AssemblyName` + +The process name is derived from the project's `.csproj`: + +1. If `` is defined, use that value +2. Otherwise, the `.csproj` filename without extension (e.g., `Functions.csproj` → `Functions`) +3. The `.csproj` **MUST** have `Exe` — otherwise no executable is produced and there's no target to debug + +**Verify before writing `launch.json`:** after `dotnet build`, confirm the executable exists at `{projectDir}/bin/Debug/{tfm}/{AssemblyName}[.exe]`. + +> ❌ **Do NOT use `${command:pickProcess}` or `${command:azureFunctions.pickProcess}`** — both pop a blocking dialog every F5. Use literal `processName`. + +--- + +## Build Chain + +Tasks owned by this runtime: build. The startup task and its dependency wiring are provided by the project type's Runtime Wiring table — not this file. + +> **Task label scoping:** All task labels MUST be prefixed with the service ID (e.g., `functions-api: dotnet build`). See [generate.md § Service ID Derivation](../generate.md). + +Chain shape (startup task comes from the project type): + +``` +"{service-id}: {startup task}" ← from project-types/{type}.md Runtime Wiring + ├── dependsOn: "{service-id}: dotnet build" ← this file + └── dependsOn: "Start Emulators" ← only when emulators are required +``` + +### Build Commands + +| Step | Task Label | Command | Purpose | Background? | +|------|-----------|---------|---------|------------| +| build | `{service-id}: dotnet build` | `dotnet build {path-to-csproj} --configuration Debug` | Restore + compile | No | + +```json +{ + "label": "{service-id}: dotnet build", + "type": "process", + "command": "dotnet", + "args": [ + "build", + "${workspaceFolder}/{path-to-csproj}", + "--configuration", + "Debug" + ], + "problemMatcher": "$msCompile", + "group": "build", + "runOptions": { "instanceLimit": 1, "instancePolicy": "silent" } +} +``` + +> .NET does not have a watch-based incremental compile step in the debug chain (unlike TypeScript's `tsc --watch`). Each F5 re-runs `dotnet build`. + +See [generate.md](../generate.md) § Task `runOptions` Rules for how these build steps are rendered into VS Code task configuration. + +--- + +## Convenience Scripts + +The plan's Convenience Scripts table specifies WHICH scripts to generate. This section covers HOW to register them for .NET projects. + +Because .NET projects do not have a built-in script runner equivalent to `npm run`, convenience scripts live as standalone scripts under `scripts/`. + +**Script runner:** Scripts in `scripts/` directory +**Run command pattern:** Platform-dependent (see below) + +### Script Format + +Generate scripts appropriate for the user's platform: + +| Platform | File extension | Shebang / header | Make executable | +|----------|---------------|-------------------|-----------------| +| macOS / Linux | `.sh` | `#!/bin/bash` | `chmod +x` | +| Windows | `.ps1` | — | — (PowerShell scripts run directly) | + +> When the platform is ambiguous, generate `.sh` scripts — they also work on Windows via Git Bash or WSL. + +### Common Script Implementations + +Use these implementations when building scripts from the plan: + +| Script Purpose | Typical Command | Notes | +|---------------|-----------------|-------| +| Start emulators | `docker compose up -d` | Idempotent — safe to re-run | +| Stop emulators | `docker compose down` | Stops and removes containers | +| Clean emulator data | Stop containers and remove data directories | `{data-dirs}` = `./.{name}` directories derived from `docker-compose.yml` `volumes:` mounts. Use platform-appropriate removal (e.g., `rm -rf` on macOS/Linux, `Remove-Item -Recurse` on Windows) | +| Run migrations | `{migration tool CLI command}` | See [migrations.md](../migrations.md) for how to determine the command | + +--- + +## VS Code Extension Recommendations (`.vscode/extensions.json`) + + + +| Extension ID | Why Required | +|--------------|-------------| +| `ms-dotnettools.csharp` | Contributes the `"type": "coreclr"` debugger for .NET attach/launch | +| `ms-dotnettools.csdevkit` | C# Dev Kit — adds Solution Explorer, test discovery, and enhanced debugging experience | + +> Project-type-specific extensions (e.g., `ms-azuretools.vscode-azurefunctions` for Functions) are listed in `project-types/{type}.md`. + +--- + +## VS Code Workspace Settings (`.vscode/settings.json`) + + + +| Setting | Value | Why | +|---------|-------|-----| +| `files.exclude: **/bin` | `true` | Hide .NET build output from explorer | +| `files.exclude: **/obj` | `true` | Hide .NET intermediate build files from explorer | + +> These exclusions reduce workspace noise. They are deep-merged with any existing `files.exclude` entries — see [generate.md § VS Code Workspace Settings](../generate.md). + +--- + +## Checklist — .NET Runtime Validation + +> ⛔ **MANDATORY — runs during Phase 3 validation after all artifacts are generated.** You MUST verify every item below. Do NOT skip, assume, or approximate results. + +After generating VS Code configuration, verify the following were produced correctly: + +### Post-Generation Checks + +1. ✅ `dotnet build` task exists in `tasks.json` with `$msCompile` problem matcher +2. ✅ `processName` in `launch.json` matches the `AssemblyName` derived from `.csproj` (platform-appropriate — see § processName Determination) +3. ✅ `launch.json` uses `"type": "coreclr"` with `"request": "attach"` +4. ✅ `.vscode/extensions.json` includes `ms-dotnettools.csharp` and `ms-dotnettools.csdevkit` + +### Live Validation Checks + +These checks run during Phase 3 validation ([validation.md](../validation.md) Step 7), after the ready signal is observed: + +1. ✅ Verify the target process exists for attachment — the `processName` in `launch.json` must match a running OS process: + - **Windows PowerShell:** `Get-Process -Name "" -ErrorAction SilentlyContinue` → must return a process + - **macOS/Linux:** `pgrep -x ""` → must return a PID +2. ✅ On Windows, confirm `processName` includes the `.exe` suffix (e.g., `"Scrapbook.Api.exe"`, NOT `"Scrapbook.Api"`) +3. ✅ If process check fails, fix `launch.json` before marking the config ✅ + +> If the process is not found, the F5 attach WILL fail with: `"No process with the specified name is currently running"` diff --git a/resources/agents/azure-debug-generate/references/runtimes/node.md b/resources/agents/azure-debug-generate/references/runtimes/node.md new file mode 100644 index 000000000..370ead946 --- /dev/null +++ b/resources/agents/azure-debug-generate/references/runtimes/node.md @@ -0,0 +1,187 @@ +# Node.js — Debug & Build Configuration + +> Covers both **JavaScript** and **TypeScript** projects. The debugger properties are identical; only the build chain differs. + +## Prerequisites + +| Tool | Detection Command | Required For | Install Link | +|------|-------------------|-------------|-------------| +| Node.js | `node --version` | All Node projects | [nodejs.org](https://nodejs.org/) | +| npm | `npm --version` | Dependency management | (bundled with Node) | + +--- + +## Debugger Properties + +| Property | Value | Notes | +|----------|-------|-------| +| Debug protocol | `Node Inspector` | V8 inspector protocol over WebSocket | +| VS Code debugger type | `node` | Maps Node Inspector to VS Code's built-in Node debugger | +| Base debug port | `9229` | Default Node.js inspector port | +| Auto-restart | `true` | Re-attach after the host restarts on file changes | + +### `outFiles` (node-ts only — REQUIRED) + +For any TypeScript Node.js project, the `launch.json` attach configuration **must** include `outFiles` pointing to the compiled JavaScript output. Without it, VS Code cannot locate `.js.map` files and breakpoints set in `.ts` source files will not trigger. + +**Derivation:** Read the project's `tsconfig.json` to determine the output directory: +1. Check `compilerOptions.outDir` — this is the compiled output root (e.g., `"outDir": "./dist"`) +2. Construct the glob: `${workspaceFolder}/{service-root}/{outDir}/**/*.js` +3. If `outDir` is not set, fall back to the project root: `${workspaceFolder}/{service-root}/**/*.js` + +> `{service-root}` is the path from the workspace root to the project directory. In a single-project workspace this is empty (just `${workspaceFolder}/dist/**/*.js`). In a monorepo it includes the nested path (e.g., `${workspaceFolder}/services/functions/dist/**/*.js`). + +**Example:** +```json +{ + "name": "My API (debug)", + "type": "node", + "request": "attach", + "port": 9229, + "restart": true, + "outFiles": ["${workspaceFolder}/services/functions/dist/**/*.js"], + "preLaunchTask": "{service-id}: func host start" +} +``` + +> `preLaunchTask` uses the canonical `{service-id}:`-prefixed task label — see [generate.md § Service ID Derivation](../generate.md). The example above corresponds to a `functions-api` service, so the resolved value is `functions-api: func host start`. + +> **Verify:** `tsconfig.json` must have `"sourceMap": true` in `compilerOptions` for any TypeScript project that will be debugged. Without source maps, VS Code breakpoints in `.ts` files cannot bind to the compiled `.js` output and will appear as gray (unverified) dots — even when the debugger is successfully attached. The build/watch task must run **before** the startup task so compiled output exists when the debugger attaches. + +### VS Code Problem Matchers + +| Variant | Watch Problem Matcher | Build Problem Matcher | +|---------|----------------------|----------------------| +| node-ts | `$tsc-watch` | `$tsc` | +| node-js | — | — | + +> **Monorepo / multi-service:** When multiple Node services are present, each is assigned a sequential debug port starting from the base port defined in the project type's Runtime Wiring table. See [multi-service.md](../multi-service.md) for port assignment rules. + +--- + +## Variant Detection + +| Signal | Variant | Notes | +|--------|---------|-------| +| `tsconfig.json` present | **node-ts** | TypeScript — requires compile step | +| `package.json` without `tsconfig.json` | **node-js** | Plain JavaScript — no compile step | + +--- + +## Build Chain + +Tasks owned by this runtime: install, clean, build, watch. The startup task and its dependency wiring are provided by the project type's Runtime Wiring table — not this file. + +> **Task label scoping:** All task labels MUST be prefixed with the service ID (e.g., `functions-api: npm watch`). See [generate.md § Service ID Derivation](../generate.md). + +### Build Commands + +#### node-ts (TypeScript) + +``` +"{service-id}: {startup task}" ← from project-types/{type}.md Runtime Wiring + ├── dependsOn: "{service-id}: npm watch" + │ └── dependsOn: "{service-id}: npm clean" + │ └── dependsOn: "{service-id}: npm install" + └── dependsOn: "Start Emulators" ← only when emulators are required +``` + +| Step | Task Label | Command | Purpose | Background? | +|------|-----------|---------|---------|------------| +| install | `{service-id}: npm install` | `npm install` | Installs dependencies | No | +| clean | `{service-id}: npm clean` | `npm run clean` | Cleans build output | No | +| watch | `{service-id}: npm watch` | `npm run watch` | Runs `tsc --watch` for incremental builds | ✅ Yes | +| build | `{service-id}: npm build` | `npm run build` | One-shot build (used outside debug flow) | No | + +#### node-js (JavaScript) + +``` +"{service-id}: {startup task}" ← from project-types/{type}.md Runtime Wiring + ├── dependsOn: "{service-id}: npm install" + └── dependsOn: "Start Emulators" ← only when emulators are required +``` + +| Step | Task Label | Command | Purpose | Background? | +|------|-----------|---------|---------|------------| +| install | `{service-id}: npm install` | `npm install` | Installs dependencies | No | + +> No compile, clean, or watch step — JavaScript runs directly. + +> **Monorepo / alternative package managers:** Adjust commands if the project uses `yarn`, `pnpm`, or a monorepo layout. The key invariant is the chain shape: **install → [clean → build/watch →] startup task** (compile steps only for TypeScript). + +See [generate.md](../generate.md) § Task `runOptions` Rules for how these build steps are rendered into VS Code task configuration. + + +--- + +## Convenience Scripts + +The plan's Convenience Scripts table specifies WHICH scripts to generate. This section covers HOW to register them for Node.js projects. + +**Script runner:** `package.json` `"scripts"` block +**Run command pattern:** `npm run {script-name}` + +### Script Format + +Each script is a shell command added to `package.json` `"scripts"`. Example entry: + +```json +{ + "{script-name}": "{shell command}" +} +``` + +### Common Script Implementations + +Use these implementations when building scripts from the plan: + +| Script Purpose | Typical Command | Notes | +|---------------|-----------------|-------| +| Start emulators | `docker compose up -d` | Idempotent — safe to re-run | +| Stop emulators | `docker compose down` | Stops and removes containers | +| Clean emulator data | `docker compose down && rimraf {data-dirs}` | `{data-dirs}` = space-separated `./.{name}` directories derived from `docker-compose.yml` `volumes:` mounts (e.g., `.azurite .postgres`). Use `rimraf` for cross-platform compatibility. Requires `rimraf` in `devDependencies` — see [generate.md § Dependency Availability](../generate.md). | +| Run migrations | `{migration tool CLI command}` | See [migrations.md](../migrations.md) for how to determine the command | + +--- + +## VS Code Extension Recommendations (`.vscode/extensions.json`) + +No recommended extensions. + +--- + +## VS Code Workspace Settings (`.vscode/settings.json`) + + + +| Setting | Value | Why | +|---------|-------|-----| +| `files.exclude: **/node_modules` | `true` | Hide dependency tree from explorer — large and noisy | + +> This exclusion reduces workspace noise. It is deep-merged with any existing `files.exclude` entries — see [generate.md § VS Code Workspace Settings](../generate.md). + +--- + +## Checklist — Node.js Runtime Validation + +> ⛔ **MANDATORY — runs during Phase 3 validation after all artifacts are generated.** You MUST verify every item below. Do NOT skip, assume, or approximate results. + +After generating VS Code configuration, verify the following were produced correctly: + +### Post-Generation Checks + +1. ✅ `launch.json` uses `"type": "node"` with the correct debug port +2. ✅ For TypeScript: `launch.json` includes `"outFiles"` derived from `tsconfig.json` `outDir` (e.g., `["${workspaceFolder}/{service-root}/{outDir}/**/*.js"]`) +3. ✅ For TypeScript: `tsconfig.json` has `"sourceMap": true` — without it, breakpoints in `.ts` files appear as gray (unverified) dots +4. ✅ For TypeScript: watch task exists in `tasks.json` with `$tsc-watch` problem matcher +5. ✅ For TypeScript: build chain follows install → clean → watch dependency order + +### Live Validation Checks + +These checks run during Phase 3 validation ([validation.md](../validation.md) Step 7), after the ready signal is observed: + +1. ✅ For TypeScript: verify `tsconfig.json` has `"sourceMap": true` in `compilerOptions`. If missing, add `"sourceMap": true` and re-run the build task before marking the config ✅ + +> The Node Inspector debug port (`9229`) is handled automatically by the Functions host or `--inspect` flag. + +> Project-type-specific checks (e.g., `{service-id}: func host start` task, connection strings) are defined in `project-types/{type}.md`. diff --git a/resources/agents/azure-debug-generate/references/validation.md b/resources/agents/azure-debug-generate/references/validation.md new file mode 100644 index 000000000..6e8f0426d --- /dev/null +++ b/resources/agents/azure-debug-generate/references/validation.md @@ -0,0 +1,103 @@ +# Validation + +Verify that the generated VS Code debug configuration actually works. This phase runs after all artifacts are generated (Phase 2) and before the closing message. + +> ⛔ **MANDATORY.** You MUST execute every step in this file for each launch configuration. Do NOT skip, assume, or approximate results. Do NOT proceed to the closing message until every checklist entry has a real ✅ or ❌ result. + +--- + +## Validation Algorithm + +For each **non-compound** launch configuration in `.vscode/launch.json`: + +### Step 1: Resolve the Task Chain + +1. Read the config's `preLaunchTask` value +2. Trace the full `dependsOn` chain in `.vscode/tasks.json` to resolve the dependency order + +### Step 2: Verify Script Dependencies + +3. For each task in the resolved chain, verify that its command can actually execute: + - **Package scripts** (e.g., `npm run clean`, `dotnet build`) — Confirm a matching script entry or build target exists in the project + - **CLI tool invocations** (e.g., `rimraf`, `concurrently`) — Confirm the tool is installed as a project dependency + - If a dependency is missing, add it as a project dev dependency before proceeding (see [generate.md § Dependency Availability](generate.md)) + +### Step 3: Start Services + +4. Run prerequisite tasks first (install, clean, emulators), then start the `preLaunchTask` itself as a background process + +### Step 4: Verify Emulators + +5. If a `docker-compose.yml` was generated, verify all services started correctly after `docker compose up -d`: + - **Long-running services** (database emulators, Azurite) → should be running and healthy + - **One-shot services** (e.g., `db-migrate`) → should have exited with code 0 + - Use `docker compose ps` and `docker compose logs ` to check + - If any service failed, diagnose the issue, fix the configuration, and re-run until all services are healthy or exited cleanly + - Only mark the config ❌ after exhausting reasonable fix attempts + +### Step 5: Confirm Ready Signal + +6. Watch stdout from the **top-level task** for the ready signal. Look up the expected pattern from `project-types/{type}.md` § Validation Signals § Ready Signal. + +### Step 6: Confirm HTTP Reachability + +7. After the ready signal, confirm with `curl` using the **application HTTP port** (not the debug port). Look up the expected URL and status from `project-types/{type}.md` § Validation Signals § HTTP Verification. + +> Use the curl template: `curl -s -o /dev/null -w "%{http_code}" ` + +> **HTTP verification not applicable:** If the project type's HTTP Verification table says "N/A" or no anonymous/public endpoint is available (e.g., all routes require auth keys), skip HTTP verification. The config can still pass (✅) based on the ready signal alone — note "HTTP verification skipped: {reason}" in the checklist entry. + +### Step 7: Per-Debugger-Type Checks + +8. Run additional checks based on the `type` field in the launch configuration. See the Per-Debugger-Type Validation section below. If no additional checks are listed for the debugger type, skip this step. + +### Step 8: Cleanup + +9. Kill background processes, then move to the next config + +### Step 9: Compound Configs + +10. For compound configs: skip running them; mark ✅ if all named member configs passed, ❌ if any failed + +--- + +## Validation Signal Lookup + +Ready signals and HTTP verification targets are defined in each project-type reference file under `§ Validation Signals`. Load the project-type file for the service being validated and read its signal tables. + +| Information | Where to find it | +|-------------|-----------------| +| Ready signal (stdout pattern) | `project-types/{type}.md` § Validation Signals § Ready Signal | +| HTTP verification (curl target, expected status) | `project-types/{type}.md` § Validation Signals § HTTP Verification | +| Debugger-specific checks (processName, etc.) | `runtimes/{rt}.md` § Checklist — Live Validation Checks | +| Runtime-specific details (debug port, outFiles) | `runtimes/{rt}.md` § Debugger Properties | + +> **Path resolution:** Some project types use subdirectories — see [generate.md § Project Type Path Resolution](generate.md) for the lookup table. + +--- + +## Per-Runtime Validation Checks + +Additional runtime-specific checks beyond the generic algorithm. These run after the ready signal and HTTP verification. + +> ⛔ You **MUST** load and execute the runtime's live validation checks. Do NOT skip this step or assume the checks pass. + +8. Load `runtimes/{rt}.md` § Checklist and execute every item under **Live Validation Checks**. Each runtime's checklist contains debugger-specific verifications (e.g., source map verification for Node.js, process attachment verification for .NET). + +--- + +## Plan Integration + +After validating all configurations, **create or update** the `## Debug Configuration Checklist` section in `.azure/vscode-debug-plan.md`. If the section does not exist, add it at the end of the plan before closing. + +``` +## Debug Configuration Checklist + +Debug Configuration Checklist: +✅ +✅ +``` + +One line per config (non-compound and compound). ✅ requires the ready signal observed AND curl confirmed (or curl skipped with a valid reason). + +> ⛔ Do NOT set status to `Implemented` until every stub in the Debug Configuration Checklist has been replaced with a real ✅ or ❌ result. A checklist with any remaining stubs is incomplete — go back and validate. diff --git a/resources/agents/azure-debug-plan.agent.md b/resources/agents/azure-debug-plan.agent.md new file mode 100644 index 000000000..58f1d86d9 --- /dev/null +++ b/resources/agents/azure-debug-plan.agent.md @@ -0,0 +1,100 @@ +--- +name: azure-debug-plan +description: Scan an Azure-centric workspace project. Classify its services and dependencies, and produce a local debugging plan covering automated emulator startup, VS Code launch/task configs, and API tests. +tools: [vscode, copilot-azure-resources-extension-tools/*, tool_search, execute, read, browser, edit, search, web, todo] +model: [Claude Opus 4.6 (copilot), Claude Opus 4.7 (copilot), Claude Sonnet 4.6 (copilot)] +target: vscode +--- + +# Azure Debug Plan + +You are an expert with deep knowledge of Azure service dependencies, local emulators, and VS Code debugging infrastructure. You know how to scan workspaces; inventory services, runtime, and Azure dependencies; and produce a comprehensive debug plan for generating configuration files. The plan you generate later drives the `azure-debug-generate` agent. + +You are the debug setup planning agent in a guided VS Code project setup workflow: + +**Plan → Scaffold → Verify → Debug (Plan → Generate) → Deploy** + +## Azure Resources MCP Tools + +Every `copilot-azure-resources-extension-tools/*` tool this agent uses is provided by an MCP server declared in this agent's `tools:` frontmatter, so **these tools ARE available in this session.** VS Code does not always surface them directly in your active tool list; that absence does **not** mean the tool is missing or that "the extension does not expose this MCP endpoint." + +When a step tells you to call one of these tools and you do not see it directly available, do **not** give up — load it and call it: + +1. Call `tool_search` with the **exact tool name only** as the query (e.g. `start_azure_debug_generate`) — a single tool name, never a phrase like "azure mcp debug generate". +2. If the tool is not already active, enable it with `activate_tools`, then invoke the tool (e.g. `start_azure_debug_generate`). +3. If the search misses or a call errors, **retry** the search → activate → invoke loop with the exact tool name. Persist until the call succeeds. + +Never claim one of these tools is "not available" or "not exposed", never fall back to a manual work-around (invoking another agent by hand, or doing its file edits yourself), and never stop, summarize, or announce completion until the required tool call has actually **succeeded**. Treating a required view/hand-off tool as unavailable is a **failure of this agent**, not an acceptable outcome. + +## Prerequisites + +The workspace is expected to contain a substantive and buildable project (source files, dependency manifests, and the typical structure expected for its language/framework). This agent assumes the project is functional or nearly functional; debugging setup is not useful for an empty directory or a half-started skeleton. + +If the project appears incomplete (missing entry points, no dependency file, half-started features), stop and redirect the user to run the `azure-project-scaffold` agent first before proceeding with debugging setup. + +## Workflow + +The steps below are **strictly ordered**. You **must not** start a later step until the earlier one is completed: + +- Step 1: Scan the project and generate a plan. +- Step 2: Preview the generated plan. +- Step 3: Iterate and wait for approval. +- Step 4: Invoke the generation tool `start_azure_debug_generate`. + +### Step 1: Scan the project and generate a plan + +Read through and strictly follow the planning instructions found in the user's workspace project: `.github/agents/azure-debug-plan/instructions.md`. + +After you've completed all phases of this instruction set, you should be left with a plan file `.azure/vscode-debug-plan.md` with status set to `Planning`. + +### Step 2: Preview the generated plan + +**Action:** Call the `open_local_plan_view` tool immediately, before any other output. It takes no arguments. + +This must happen the instant you finish writing `.azure/vscode-debug-plan.md` to disk — **before** you summarize the plan or ask the user for approval. + +If you skip this call, the user will not see the plan preview. + +This is a hard requirement of this agent. The user cannot review the plan without it. If you skip this step, the workflow is broken. Do not ask the user whether to do it — just do it as the very next tool call after the file write completes. + +### Step 3: Iterate and wait for approval + +After step 2, **STOP AND WAIT** for explicit user approval of the plan. Do **not** hand off to `azure-debug-generate`, and do **not** attempt to generate any configuration artifacts yourself. + +If the user requests changes to the plan, revise `.azure/vscode-debug-plan.md` and re-run step 2 so the preview reloads with updates. Only once the user explicitly approves the entire plan should you proceed to step 4. + +### Step 4: Invoke the generation command + +Once the user has explicitly approved the plan, mark the plan status as **Approved**. + +Then you MUST call the `start_azure_debug_generate` tool with the following input and then **STOP**. If the tool is not directly listed, load it first per "Azure Resources MCP Tools" above — do **not** conclude it is unavailable and do **not** offer to run `azure-debug-generate` manually. Once the call has **succeeded**, do nothing else after it — no summaries, no file reads, no further tool calls. + +```json +{ "prompt": "The local debugging plan has been approved. Now generate the artifacts as specified by `.azure/vscode-debug-plan.md`." } +``` + +## Autopilot mode (overrides Steps 2–4 gating) + +**Autopilot is active when** the invoking chat query begins with the marker `[AUTOPILOT MODE]`, **or** `.azure/project-plan.md` / `.azure/vscode-debug-plan.md` contains `executionMode: auto`. When autopilot is active, run fully unattended — **no chat questions, no manual approval**: + +1. **Step 1 still runs in full** — scan the project and write `.azure/vscode-debug-plan.md`. Additionally record `executionMode: auto` in the plan's front-matter (or as an `**Execution Mode**: auto` row) so `azure-debug-generate` inherits autopilot. +2. **Skip Step 2** — do **not** open the local plan preview (`open_local_plan_view`). +3. **Skip Step 3** — do not stop for approval. +4. **Step 4** — set the plan status to **Approved**, then call the `start_azure_debug_generate` tool exactly as below, with the `[AUTOPILOT MODE] ` prefix on the prompt, and then **STOP**. This hand-off is mandatory — if the tool is not directly listed, load it first per "Azure Resources MCP Tools" above; do **not** stop or claim it is unavailable until the call has succeeded: + +```json +{ "prompt": "[AUTOPILOT MODE] The local debugging plan has been approved. Now generate the artifacts as specified by `.azure/vscode-debug-plan.md`." } +``` + +The plan-scanning quality and completeness still apply in full — autopilot suppresses **the preview and approval gates only**. + +## Interruption recovery + +If the flow is interrupted for any reason — a terminal command requests a password and the user declines, a tool call fails, a network request times out, or any other error breaks the current step — **do not stop working**. Instead: + +1. **Acknowledge** the interruption briefly (one sentence). +2. **Identify** which step you were on and what remains to be done. +3. **Continue** from where you left off. Re-read the relevant `.azure/*` artifacts to re-orient yourself if needed. +4. If the failed action is not essential to the current step (e.g. an optional tool call), skip it and move on. +5. If the failed action IS essential, try an alternative approach (different command, different tool) before giving up. +6. **Never** end your turn with just an error message and no next action. Always state what you will do next and then do it. diff --git a/resources/agents/azure-debug-plan/.metadata.json b/resources/agents/azure-debug-plan/.metadata.json new file mode 100644 index 000000000..ee89de609 --- /dev/null +++ b/resources/agents/azure-debug-plan/.metadata.json @@ -0,0 +1,4 @@ +{ + "name": "azure-debug-plan", + "version": "0.0.1" +} diff --git a/resources/agents/azure-debug-plan/instructions.md b/resources/agents/azure-debug-plan/instructions.md new file mode 100644 index 000000000..e8cdcabbc --- /dev/null +++ b/resources/agents/azure-debug-plan/instructions.md @@ -0,0 +1,64 @@ +# Azure Debug Plan + +> **AUTHORITATIVE GUIDANCE — MANDATORY COMPLIANCE** +> +> This document is the **official, canonical source** for classifying a workspace +> and generating a VS Code debug setup plan. You **MUST** follow these instructions +> exactly as written. When in doubt, defer to this document. Do not improvise, +> infer, or substitute steps. + +--- + +## Global Rules (NO EXCEPTIONS) + +1. **Update plan progressively** — Mark steps complete as you go; update **Last Updated** timestamp on every status change +2. ❌ **Destructive actions require `ask_user`** — Always confirm before overwriting, deleting, or modifying existing files +3. **Preserve existing config** — Never silently overwrite project configuration files or `docker-compose.yml`. Merge or ask first. +4. **Scope — VS Code debug setup only** — This instruction set classifies the workspace and generates a plan. Cloud deployment is handled by **azure-prepare** → **azure-validate** → **azure-deploy**. +--- + +## Autopilot mode (overrides the approval STOP) +**Active when** the invoking chat query begins with `[AUTOPILOT MODE]`, **or** `.azure/project-plan.md` records `executionMode: auto` or equivalent. When active, run fully unattended: +- **Phase 0–1 still run in full**. When generating the plan `.azure/vscode-debug-plan.md`, also record `executionMode: auto` or similar. Follow any specific instructions per the template. +- Skip the step that instructs to run `openLocalPlanView` and do NOT wait for approval. Set status straight to `Approved`, then invoke `azure-debug-generate` as you normally would, but with the chat arg prefixed with `[AUTOPILOT MODE] `. +- Never call `ask_user` for non-destructive steps. Scan completeness is unchanged — autopilot suppresses **the preview and approval gates only**. + +## Workflow + +> **Two phases — Classify → Plan — then STOP.** +> +> Do NOT generate any configuration files (docker-compose, launch.json, tasks.json, etc.). +> All `.azure/` artifacts must be created inside the **workspace root**, not a session-state folder. + +--- + +## Phase 0: Classify + +Scan the workspace for service roots. Produce a `services[]` list. + +| Action | Reference | +|--------|-----------| +| Check for `.azure/project-plan.md` — if found, read for advisory context. **Optional.** | — | +| Scan all subdirectories; detect project type + runtime per service root | [classify.md](references/classify.md) | +| If 2+ service roots: assign service IDs, deduplicate emulators, plan compound debug config | [multi-service.md](references/multi-service.md) | + +--- + +## Phase 1: Plan + +Scan dependencies, detect configuration, and generate the plan directly. The user reviews and edits the plan markdown before approving. + +| # | Action | Reference | +|---|--------|-----------| +| 1 | **Detect prerequisites** — Check required tools and VS Code extensions | [inventory.md](references/inventory.md) § Step 1 | +| 2 | **Scan Azure dependencies** — For each service, scan bindings (Functions) or SDK packages (other types) to identify Azure service dependencies | [inventory.md](references/inventory.md) § Step 2 | +| 3 | **Map dependencies to emulators** — Map each detected Azure dependency to its local emulator. Deduplicate across services. | [inventory.md](references/inventory.md) § Step 2 | +| 4 | **Detect orchestrator** — Scan for existing `docker-compose.yml` or compose files. If none found, default to Docker Compose. | — | +| 5 | **Detect migrations** — Scan for migration files, dependencies, and scripts | [migrations.md](references/migrations.md) | +| 6 | **Inventory API test opportunities** — List HTTP endpoints and triggers per service | [inventory.md](references/inventory.md) § Step 3 | +| 7 | **Write plan** — Generate `.azure/vscode-debug-plan.md` from scan results. Fill all sections completely. | [plan-template.md](references/plan-template.md) | +| 8 | **Present plan** — Show plan to user and ask for approval. Highlight any ❓ prerequisites to double-check. The user can edit the plan directly before approving. On approval, update status to `Approved`. | `.azure/vscode-debug-plan.md` | + +--- + +> **❌ STOP HERE** — Do NOT proceed to artifact generation. Do NOT generate docker-compose.yml, launch.json, tasks.json, or any other configuration files. Present the plan to the user and wait for approval. After approval, the custom agent wrapper will invoke `azure-debug-generate` to handle generation. diff --git a/resources/agents/azure-debug-plan/references/classify.md b/resources/agents/azure-debug-plan/references/classify.md new file mode 100644 index 000000000..bc39c3975 --- /dev/null +++ b/resources/agents/azure-debug-plan/references/classify.md @@ -0,0 +1,30 @@ +# Classify Workspace + +Determine the project type(s) and runtime(s) for each service root in the workspace. Classification produces an array of service contexts — even single-service workspaces produce a one-item list so the rest of the flow is uniform. + +> **Always scan the full directory tree** — not just the workspace root. Service roots nested in subdirectories (e.g. `./api/`, `./web/`) must be found regardless of project layout. +> Ignore: `node_modules/`, `.git/`, `dist/`, `build/`, `bin/`, `obj/`. + +### ⚠️ Exclude Non-Service Directories + +Only include directories that represent **runnable services** (APIs, web apps, functions, workers, etc.). Exclude directories that are **shared libraries, utility packages, or common modules** — these are consumed by services but are not independently launchable and should never appear as a service. + +Common exclusion signals: +- Directory name or `package.json` name contains `shared`, `common`, `utils`, `lib`, or `helpers` +- No entry point (no `main`, `start` script, `host.json`, `server.*`, or framework config) +- Used as a dependency by other service roots (e.g. via workspace references or `file:` dependencies) +- Project type is `library` — a package that exports modules but is not runnable on its own + +--- + +## Step 1: Detect Project Types + +Scan every subdirectory and classify each service root by project type. See [project-types.md](project-types.md) for the detection table and per-type nuances. + +## Step 2: Detect Runtimes + +For each service root, determine the language/runtime and version. See [runtimes.md](runtimes.md) for the detection table and per-runtime nuances. + +## Output + +Classification produces a `services[]` list of `{ root, projectType, runtime, ... }` entries. Even single-service workspaces produce a one-item list. This information will be used in follow-up sections. diff --git a/resources/agents/azure-debug-plan/references/inventory.md b/resources/agents/azure-debug-plan/references/inventory.md new file mode 100644 index 000000000..392666c66 --- /dev/null +++ b/resources/agents/azure-debug-plan/references/inventory.md @@ -0,0 +1,42 @@ +# Inventory + +Scan the workspace to populate the plan. For multi-service workspaces, loop over each service in `services[]` from classify.md; deduplicate emulators across services per [multi-service.md](multi-service.md). + +--- + +## Step 1: Prerequisites + +Identify required tools and then inventory them by following [prerequisites.md](../../shared-references/prerequisites.md). + +The required tools are derived from a scan of the currently opened workspace project — check only the tools and extensions relevant to the detected project types, runtimes, and Azure bindings. Both tool sets defined in prerequisites.md apply here — the **Run** tools (Node.js, .NET SDK, Python, Functions Core Tools, ...) and the **Debug** tools (Docker, Docker Compose, VS Code extensions, ...) — since debugging exercises the full local stack. + +For every detected project type, include its VS Code debug-integration extension from the Debug Tools table as its own Debug row (e.g. an Azure Functions project always includes `ms-azuretools.vscode-azurefunctions`) — these extensions are required for the debug experience and are separate from the Run-group CLI/runtime tools, so never omit them. + +--- + +## Step 2: Azure Dependencies + +For each service, identify Azure service dependencies by scanning bindings or SDK packages. + +- **Functions projects:** Scan bindings per [project-types.md](project-types.md) § functions +- **Other project types:** Scan dependency files (e.g. `package.json`, `requirements.txt`, `*.csproj`) for packages that indicate an Azure service dependency + +The table below shows common SDK-to-service mappings — this is **not exhaustive**. Any package that implies connectivity to an Azure service should be mapped accordingly. + +| Example Packages | Azure Service | Emulator | +|-----------------|--------------|----------| +| `@azure/storage-blob`, `@azure/storage-queue`, `@azure/data-tables` | Azure Storage | azurite | +| `pg`, `postgres`, `@prisma/client`, `typeorm`, `sequelize`, `Npgsql`, `psycopg2` | PostgreSQL | postgresql | +| `@azure/cosmos` | Cosmos DB | cosmosdb-emulator | +| `@azure/service-bus` | Service Bus | servicebus-emulator | +| `@azure/event-hubs` | Event Hubs | eventhubs-emulator | +| `mssql`, `Microsoft.Data.SqlClient` | Azure SQL | azure-sql-edge | + +> Multiple storage bindings (blob + queue + table) consolidate to a **single** azurite entry. +> Cross-check `local.settings.json`, `.env`, and app config for existing connection references to confirm findings. + +--- + +## Step 3: API Test Collection Inventory + +For each service, identify whether it exposes testable HTTP endpoints or triggers and provide a brief summary for the plan. Detailed endpoint parsing happens during the generation phase. diff --git a/resources/agents/azure-debug-plan/references/migrations.md b/resources/agents/azure-debug-plan/references/migrations.md new file mode 100644 index 000000000..e5547b433 --- /dev/null +++ b/resources/agents/azure-debug-plan/references/migrations.md @@ -0,0 +1,44 @@ +# Database Migrations — Detection + +When a database dependency is found, detect the migration tool so the plan can record it. The generation phase uses this to configure migration automation within the orchestrator. + +--- + +## Detection + +Scan three layers, then synthesize. + +### Layer 1: Migration Files + +Non-exhaustive detection pattern examples: + +| Pattern | Tool | +|---------|------| +| `prisma/migrations/` | Prisma | +| `alembic/`, `alembic.ini` | Alembic | +| `**/migrations/*.py` | Django | +| `Migrations/*.cs` | EF Core | +| `flyway.conf` | Flyway | +| `migrations/*.sql` | Raw SQL | + +### Layer 2: Dependencies + +Check dependency manifests for migration tools, ORMs with built-in migration support, and database driver packages. + +### Layer 3: Scripts + +Check script runners (`package.json`, `Makefile`, etc.) for existing migration commands (grep for common migration key words like: `migrate`, `schema`, `seed`). + +### Synthesis + +1. Cross-reference all three layers — they should agree +2. If an existing migration command exists, use it (don't invent a new one) +3. If layers conflict, ask the user which tool is active + +### Insufficient Evidence + +If a database dependency exists but no migration strategy is found across all three layers: + +1. Do not guess +2. Ask the user via `ask_user` how they manage schema changes +3. Record the gap in the plan's Migrations section with `⚠️ Not detected` diff --git a/resources/agents/azure-debug-plan/references/multi-service.md b/resources/agents/azure-debug-plan/references/multi-service.md new file mode 100644 index 000000000..f6a7d6342 --- /dev/null +++ b/resources/agents/azure-debug-plan/references/multi-service.md @@ -0,0 +1,45 @@ +# Multi-Service Orchestration + +> Runs when `classify.md` finds **2+ service roots**, before inventory scanning begins. + +--- + +## Service ID Assignment + +Derive a short kebab-case ID per service root. Use project manifest name if available, otherwise fall back to directory name. + +| Runtime | Manifest Source | Field | +|---------|----------------|-------| +| `node-ts`, `node-js` | `package.json` | `"name"` | +| `dotnet` | `*.csproj` | `` or filename | +| *Other* | Service directory name | Fallback when no manifest name exists | + +If two IDs collide, append the project type (e.g. `payments-api` becomes `payments-api-functions`). + +--- + +## Emulator Deduplication + +Collect emulator lists from all services. Each emulator appears **once** in the plan's Emulators table — multiple services may depend on the same emulator. + +--- + +## Partial Configuration + +Check each service root for existing debug config before planning. + +| State | Plan Action | +|-------|------------| +| Fully configured | Skip | +| Partially configured | Generate only missing artifacts | +| Unconfigured | Full generation | + +--- + +## Compound Debug Configuration + +Required when 2+ service roots are detected (including Frontend SPAs). + +### Startup Dependencies + +If a frontend SPA has a proxy pointing to a local backend (detected via [project-types.md](project-types.md) § Backend Proxy Dependencies), record the `proxyTarget` service ID on that service entry. The compound config uses this to order startup (backends before frontends) that depend on them. diff --git a/resources/agents/azure-debug-plan/references/plan-template.md b/resources/agents/azure-debug-plan/references/plan-template.md new file mode 100644 index 000000000..ddb9ff786 --- /dev/null +++ b/resources/agents/azure-debug-plan/references/plan-template.md @@ -0,0 +1,187 @@ +# Plan Template + +> Generate `.azure/vscode-debug-plan.md` using this template. This file is the +> **single source of truth** for the generation phase. The generation phase reads this plan and +> generates all artifacts from it — no re-scanning of the workspace is needed. +> +> The plan is generated directly from the workspace scan. The user reviews the plan, +> edits it as needed, then approves it before generation proceeds. + +## ⛔ BLOCKING REQUIREMENT + +You **MUST** create this plan file and get user approval BEFORE generating any configuration files. + +--- + +## Markdown Table Integrity + +When editing markdown tables with `replace_string_in_file` or `multi_replace_string_in_file`, always **read the file back** after the edit and verify that each table row is on its own line. Markdown tables require exactly one row per line — a missing newline between `|---|` and `| data |` breaks parsing completely. + +**Post-edit verification rule:** After any edit to `.azure/vscode-debug-plan.md` that modifies a table, immediately read the affected lines back to confirm the table renders correctly (header, separator, and each data row on separate lines). If rows are concatenated, fix before proceeding. + +--- + +## Template + +````markdown +# Azure Debug Plan + +> This plan is the source of truth for generating the +> VS Code debug setup in this workspace. +> +> **Status:** {Planning | Approved | Executing | Implemented} +> **Execution Mode:** {Auto | Guided} +> **Created:** {ISO-8601 datetime} +> **Last Updated:** {ISO-8601 datetime} +> +> +> + +--- + +## Prerequisites + + + + + + +| Tool / Extension | Category | Service(s) | Installed | Version | Install | +|------------------|----------|------------|-----------|---------|---------| +| {name} | {Runtime / Package manager / …} | {service(s) or *} | {✅/❓} | {version or —} | {reference URL} | + +> ⚠️ **Action required:** Confirm any tool or extension marked ❓ is installed and ready before approving this plan — rerun the recheck to confirm CLI tools provided by a version manager. + +--- + +## Debug Configurations + + + + + + + + + +Each checked row below produces a VS Code debug configuration in the `.vscode/launch.json`. + +| Generate | Debug Config Name | Service Label | Service Root | Project Type | Runtime | Version | Azure Dependencies | +|----------|--------------------|---------------|--------------|--------------|---------|---------|-----| +| {[x] / [ ]} | {e.g. Payments API (debug)} | {label} | {path} | {type} | {runtime} | {version} | {comma-separated azure service labels} | + + + + + + + + + +
+ℹ️ Project Type Descriptions + +| Project Type | Description | +|-------------|-------------| +| {type} | {brief description of what this project type means} | + + + + + + + +
+ + + + +--- + +## Orchestrator + + + + +| Orchestrator | Description | +|-------------|-------------| +| {display name, e.g. Docker Compose} | {description, e.g. Uses Docker Compose to orchestrate emulators and dependent services during local development} | + + + + +--- + +## Emulators + + + +| Dependent Service | Emulator | Purpose | +|-------------------|----------|---------| +| {azure service label} | {emulator name} | {description of what this emulator provides} | + + + + + +--- + +## Architecture Diagram + +{One sentence describing how the app connects to its dependencies during debugging.} + +```mermaid +graph LR + %% Generated from Debug Configurations + Emulators tables above. + %% Show each service as a node, each emulator as a node, + %% and edges for the Azure Dependencies that connect them. +``` + +--- + +## Migrations + + + + +When selected, the generation phase creates automated VS Code tasks that run migration scripts on launch — so emulator databases are automatically provisioned with the correct schema and seed data before the app starts debugging. No manual migration steps needed. + +| Generate | Service | Migration Tool | +|----------|---------|---------------| +| {[x] / [ ]} | {service label} | {tool name, e.g. Prisma / Knex / Drizzle / EF Core} | + +--- + +## API Test Collections + + + + +When selected, the generation phase produces lightweight, runnable API test scripts in the project so you can quickly smoke-test endpoints and triggers once everything is launched and connected locally. + +| Generate | Service | Description | +|----------|---------|-------------| +| {[x] / [ ]} | {service label} | {collapsible lists of HTTP endpoints and/or triggers — see format below} | + + + + + + + +--- + +## Convenience Scripts + + + + +| Generate | Script | Registered In | Description | +|----------|--------|---------------|-------------| +| {[x] / [ ]} | {script name} | {path to file where script is registered, e.g. ./package.json} | {what the script does} | + + + + + + diff --git a/resources/agents/azure-debug-plan/references/project-types.md b/resources/agents/azure-debug-plan/references/project-types.md new file mode 100644 index 000000000..590d9f2bc --- /dev/null +++ b/resources/agents/azure-debug-plan/references/project-types.md @@ -0,0 +1,68 @@ +# Project Types + +> These are **common examples, not an exhaustive list**. If a service root does not match +> any of these, classify it by whatever best describes its purpose (e.g. `background-worker`, `console`, etc.). + +## Detection Table + +| Detection Signals | Project Type | Include in Plan? | +|-------------------|-------------|------------------| +| `host.json` + Azure Functions SDK | **functions** | ✅ Yes | +| SPA framework in `package.json`, or `vite.config.*` / `next.config.*` / `angular.json` (no `host.json`) | **frontend-spa** | ✅ Yes | +| HTTP framework (Express, Fastify, Flask, FastAPI, ASP.NET, Spring Boot, etc.) | **app-service** | ✅ Yes | +| `Dockerfile` with a containerized application | **container-app** | ✅ Yes | +| No entry point, no framework, exports modules only (shared/common/util packages) | **library** | ❌ Exclude | + +--- + +## functions + +For Azure Functions projects, scan bindings to identify Azure service dependencies. Parse `function.json` files or decorator/attribute bindings in source code. + +> **Implicit dependency:** All Azure Functions projects require Azure Storage for the host runtime (trigger management, lease coordination, internal state). Always emit an Azurite emulator entry in the plan regardless of whether application-level storage SDK packages are detected. + +| Binding | Azure Service | Emulator | +|---------|--------------|----------| +| `blobTrigger`, `blob` | Blob Storage | azurite | +| `queueTrigger`, `queue` | Queue Storage | azurite | +| `table` | Table Storage | azurite | +| `httpTrigger` | (built-in) | — | +| `timerTrigger` | (built-in) | — | +| `warmupTrigger` | (built-in) | — | +| `durableClient`, `orchestrationTrigger`, `activityTrigger` | Durable Functions | durable-task-scheduler | +| `cosmosDBTrigger`, `cosmosDB` | Cosmos DB | cosmosdb-emulator | +| `serviceBusTrigger`, `serviceBus` | Service Bus | servicebus-emulator | +| `eventHubTrigger`, `eventHub` | Event Hubs | eventhubs-emulator | +| `eventGridTrigger`, `eventGrid` | Event Grid | — | +| `signalRTrigger`, `signalR` | SignalR Service | — | +| `sql`, `sqlTrigger` | Azure SQL | azure-sql-edge | + +> Multiple storage bindings (blob + queue + table) consolidate to a **single** azurite entry. +> This table is **not exhaustive** — map any other bindings to their Azure service accordingly. + +--- + +## frontend-spa + +Frontend SPA projects do not require emulators or Azure bindings, but they **are** service roots. When a frontend is detected alongside a backend, the workspace is multi-service and **must** produce a compound debug configuration. + +### Framework Detection + +| Framework | Detection Signals | +|-----------|-------------------| +| Vite | `vite.config.*` or `vite` in devDependencies | +| Next.js | `next.config.*` or `next` in dependencies | +| Angular | `angular.json` | +| Create React App | `react-scripts` in dependencies | +| Blazor WASM | `*.razor` + `WebAssembly` SDK in `*.csproj` | + +### Backend Proxy Dependencies + +If a proxy config points to a local backend, record the dependency so the compound debug configuration can order startup (backends before frontends). + +| Framework | Proxy Config Location | +|-----------|----------------------| +| Vite | `server.proxy` in `vite.config.*` | +| Create React App | `"proxy"` in `package.json` | +| Angular | `proxy.conf.json` | +| Next.js | `rewrites()` in `next.config.*` | diff --git a/resources/agents/azure-debug-plan/references/runtimes.md b/resources/agents/azure-debug-plan/references/runtimes.md new file mode 100644 index 000000000..76d66383c --- /dev/null +++ b/resources/agents/azure-debug-plan/references/runtimes.md @@ -0,0 +1,30 @@ +# Runtimes + +> These are **common examples, not an exhaustive list**. If a service root uses a runtime +> not listed here, identify it by the language and toolchain present (e.g. `rust`, `ruby`, etc.). + +## Detection Table + +| Detection Signals | Runtime | Version Source | +|-------------------|---------|---------------| +| `package.json` + `tsconfig.json` | **node-ts** | `engines.node` / `.nvmrc` / `.node-version` | +| `package.json` (no `tsconfig.json`) | **node-js** | Same | +| `*.csproj` | **dotnet** | `` element (e.g. `net8.0` → `8.0`) | +| `requirements.txt`, `pyproject.toml`, or `Pipfile` | **python** | `.python-version` / `pyproject.toml` `requires-python` | +| `pom.xml` or `build.gradle` | **java** | `` / `sourceCompatibility` | +| `go.mod` | **go** | `go` directive in `go.mod` | + +--- + +## dotnet + +### Version Detection + +Read `` from the `.csproj` to determine the runtime version (e.g. `net8.0` → `8.0`). + +### Assembly Name + +Derive the assembly name for the plan's Service Label: + +1. If `` is set → use that value +2. Otherwise → `.csproj` filename without extension (e.g. `Functions.csproj` → `Functions`) diff --git a/resources/agents/azure-deploy.agent.md b/resources/agents/azure-deploy.agent.md index 69194ff52..db14aa8f5 100644 --- a/resources/agents/azure-deploy.agent.md +++ b/resources/agents/azure-deploy.agent.md @@ -1,37 +1,101 @@ --- name: azure-deploy description: Prepare an Azure-centric project for deployment — generate Bicep/Terraform infrastructure, `azure.yaml`, Dockerfiles, and any other artifacts required by `azd up` / `terraform apply`. Run after the local development environment is set up. WHEN: "deploy to Azure", "prepare for deployment", "generate infra", "generate Bicep", "generate Terraform", "create azure.yaml", "ship to Azure", "host on Azure", "create and deploy". -tools: [vscode, run_vscode_command, tool_search, execute, read, agent, browser, edit, search, web, azure-mcp/search, todo] +tools: [vscode, copilot-azure-resources-extension-tools/*, tool_search, execute, read, agent, browser, edit, search, web, azure-mcp/search, todo] +model: ['Claude Opus 4.6 (copilot)', 'Claude Opus 4.7 (copilot)', 'Claude Sonnet 4.6 (copilot)'] --- # Azure Deploy Agent +## Azure Resources MCP Tools + +Every `copilot-azure-resources-extension-tools/*` tool this agent uses is provided by an MCP server declared in this agent's `tools:` frontmatter, so **these tools ARE available in this session.** VS Code does not always surface them directly in your active tool list; that absence does **not** mean the tool is missing or that "the extension does not expose this MCP endpoint." + +When a step tells you to call one of these tools and you do not see it directly available, do **not** give up — load it and call it: + +1. Call `tool_search` with the **exact tool name only** as the query (e.g. `open_deploy_plan_view`) — a single tool name, never a phrase like "azure mcp deploy plan". +2. If the tool is not already active, enable it with `activate_tools`, then invoke the tool (e.g. `open_deploy_plan_view`). +3. If the search misses or a call errors, **retry** the search → activate → invoke loop with the exact tool name. Persist until the call succeeds. + +Never claim one of these tools is "not available" or "not exposed", never fall back to a manual work-around (invoking another agent by hand, or doing its file edits yourself), and never stop, summarize, or announce completion until the required tool call has actually **succeeded**. Treating a required view/hand-off tool as unavailable is a **failure of this agent**, not an acceptable outcome. + ## Critical workflow rules (read first, do not skip) The phases below are **strictly ordered**. You **must not** start a later phase until the earlier one has completed: -1. Write `.azure/deployment-plan.md` (the `azure-prepare` skill calls this the deployment plan). -2. **Step A** — open the deployment plan preview (see below). Mandatory. -3. **Step B** — wait for the user's explicit approval of the deployment plan. Mandatory. -4. Generate the deployment artifacts (infra, `azure.yaml`, Dockerfiles, etc.) as directed by the `azure-prepare` skill. +1. Write the `.azure/deployment-plan.md` skeleton (the `azure-prepare` skill calls this the deployment plan). +2. **Step A** — confirm subscription and location, then validate quotas (see below). Mandatory before presenting the plan. +3. Finalize `.azure/deployment-plan.md` with all fields populated — no `_TBD_`, `⚠️ MUST confirm`, or blank cells. +4. **Step B** — open the deployment plan preview (see below). Mandatory. +5. **Step C** — wait for the user's explicit approval of the deployment plan. Mandatory. +6. Generate the deployment artifacts (infra, `azure.yaml`, Dockerfiles, etc.) as directed by the `azure-prepare` skill, following the **azure.yaml hook rules** below. +7. **Step D** — validate the artifacts with `azd package` before declaring the deployment ready. Mandatory. -### Step A — open the deployment plan preview (MANDATORY, do not skip) +### Step A — confirm subscription, location, and quotas BEFORE presenting the plan (MANDATORY) -**Trigger:** the instant the `azure-prepare` skill finishes writing `.azure/deployment-plan.md` to disk. This must happen **before** the skill's approval gate (before you summarize the plan or ask for approval). +The `azure-prepare` skill's plan template marks Subscription and Location as `⚠️ MUST confirm with user`, and its Provisioning Limit Checklist (Section 6) requires completed quota data with no `_TBD_` entries. Both of these **must be resolved before** you open the plan preview or present the plan. -**Action — call `run_vscode_command` immediately, before any other output:** +Follow `azure-prepare/references/azure-context.md` for the exact flow: -```json -{ "commandId": "azureResourceGroups.openDeployPlanView", "name": "Open Deploy Plan View" } -``` +1. Check for an existing AZD environment (`azd env list` / `azd env get-values`). +2. If no environment exists or the user wants different settings, detect defaults (`azd config get defaults`, fall back to `az account show`). +3. **Ask the user** to confirm the subscription (showing the actual name and ID). +4. **Ask the user** to confirm the location (showing only regions that support all planned services). +5. **Validate quotas** — invoke the `azure-quotas` skill to populate the Provisioning Limit Checklist. Every row must have actual numbers; no `_TBD_` or placeholder values. +6. Record the confirmed subscription, location, and quota results in `.azure/deployment-plan.md`. + +Only after all six sub-steps succeed should you finalize the plan and proceed to Step B. + +### Plan completeness gate (MANDATORY) + +Before opening the plan preview (Step B), verify that `.azure/deployment-plan.md` satisfies **all** of these: + +- **Section 2 (Requirements):** Subscription and Location rows contain actual values (not `⚠️ MUST confirm with user`). +- **Section 6 (Provisioning Limit Checklist):** Every row in Phase 2 has numeric values for Total After Deployment, Limit/Quota, and Notes. No cells contain `_TBD_` or `_To be filled in Phase 2_`. +- **All template sections** from `azure-prepare/references/plan-template.md` are present. Do not omit, rename, or reorder sections. + +If any check fails, go back and resolve it before continuing. Do **not** present an incomplete plan. + +### Step B — open the deployment plan preview (MANDATORY, do not skip) + +**Trigger:** the instant the plan is finalized and passes the completeness gate above. This must happen **before** you summarize the plan or ask for approval. -`run_vscode_command` is a deferred tool. If it isn't already loaded, call `tool_search` first with the query `run_vscode_command` (or "run vscode command") to load it, **then** invoke it. Both `tool_search` and `run_vscode_command` are listed in this agent's `tools:` frontmatter — they are available in this session. Do **not** claim the tool is unavailable or that `tool_search` is disabled; load it and call it. There is no file-watcher fallback — if you skip this call, the user will not see the plan preview. +**Action — call the `open_deploy_plan_view` tool immediately, before any other output.** It takes no arguments. -This is not optional and not conditional. Do not summarize the plan, do not ask the user a question, do not begin generating infrastructure, and do not move on until this command has been called. If `run_vscode_command` returns an error, report it verbatim — but still attempt the call first. +There is no file-watcher fallback — if you skip this call, the user will not see the plan preview. -### Step B — require explicit user approval before generating artifacts +This is not optional and not conditional. Do not summarize the plan, do not ask the user a question, do not begin generating infrastructure, and do not move on until this tool has been called. If the tool returns an error, report it verbatim — but still attempt the call first. -After Step A, **stop and wait** for explicit user approval of the deployment plan. Do **not** begin generating Bicep/Terraform/`azure.yaml`/Dockerfiles until the user confirms. Treat anything other than a clear approval (e.g. questions, edits, "looks good but…") as not-yet-approved. +### Step C — require explicit user approval before generating artifacts + +After Step B, **stop and wait** for explicit user approval of the deployment plan. Do **not** begin generating Bicep/Terraform/`azure.yaml`/Dockerfiles until the user confirms. Treat anything other than a clear approval (e.g. questions, edits, "looks good but…") as not-yet-approved. + +### azure.yaml hook rules (avoid the deploy retry loop) + +`azd` validates `azure.yaml` hooks strictly. A malformed hook makes **every** `azd package` / `azd deploy` fail with a schema error, and retrying without fixing the hook produces an infinite failure loop (the artifacts never build, so a Functions app reports "no functions"). When you write or edit hooks in `azure.yaml`, obey these rules — do **not** improvise: + +1. **`shell` must be exactly `sh` or `pwsh`.** Never `powershell`, `bash`, `cmd`, `python`, or anything else. `shell: powershell` fails with `The 'powershell' kind is not supported for hook ''.` — use `pwsh`. +2. **Inline `run:` scripts are allowed only for shell hooks (`sh`/`pwsh`).** Any other kind fails with `Inline scripts are only supported for shell hooks.` If you need a non-shell/language hook, write the script to a file and set `run:` to that file path (e.g. `run: ./hooks/prepackage.js`). +3. **Prefer azd's built-in build over hooks.** For a service whose `language:` azd already builds (`js`, `ts`, `python`, `dotnet`, etc.), do **not** add a `prepackage` hook to run `npm run build` — azd runs the build for you. Only add a build hook when the build genuinely is not covered by `language:`. +4. **Make hooks cross-platform.** When a hook must differ per OS, use `windows:` / `posix:` sub-keys, each with a valid `shell` (`pwsh` for `windows:`, `sh` for `posix:`), rather than a single OS-specific shell. + +```yaml +# ✅ correct — cross-platform, valid shells, file-based for non-shell logic +hooks: + postprovision: + posix: + shell: sh + run: ./scripts/seed-data.sh + windows: + shell: pwsh + run: ./scripts/seed-data.ps1 +``` + +### Step D — validate the generated artifacts before declaring success (MANDATORY) + +After generating `azure.yaml` and the infra, **run `azd package`** (from the workspace root) to validate the manifest and confirm the app's build output is produced (for a Functions app, that the host actually discovers functions). Do **not** report the deployment as ready — and do **not** enter a retry-`azd deploy` loop — until `azd package` succeeds. + +If `azd package` (or a later `azd` step) fails with a hook error such as `The '' kind is not supported for hook` or `Inline scripts are only supported for shell hooks`, the fix is the `azure.yaml` hook itself (see the rules above), **not** re-running the same command. Correct the hook, then re-validate. Never retry the identical failing command more than once without changing the underlying artifact. --- @@ -45,7 +109,7 @@ Follow the authoritative guidance in the `azure-prepare` skill: 📖 **Read and follow:** `.agents/skills/azure-prepare/SKILL.md` -That skill is the canonical, mandatory source for this phase. Treat it as your operating manual — do not improvise or substitute steps. **Exception:** the "Critical workflow rules" above govern preview-opening and approval gating — always route through the matching `run_vscode_command` call, never bypass it. +That skill is the canonical, mandatory source for this phase. Treat it as your operating manual — do not improvise or substitute steps. **Exception:** the "Critical workflow rules" above govern preview-opening and approval gating — always route through the matching MCP tool call, never bypass it. ## Your deliverable @@ -57,6 +121,17 @@ A workspace ready to deploy to Azure: - Dockerfiles where required - Any environment files / parameter files referenced by the plan +## Interruption recovery + +If the flow is interrupted for any reason — a terminal command requests a password and the user declines, a tool call fails, a network request times out, or any other error breaks the current step — **do not stop working**. Instead: + +1. **Acknowledge** the interruption briefly (one sentence). +2. **Identify** which step you were on and what remains to be done. +3. **Continue** from where you left off. Re-read the relevant `.azure/*` artifacts to re-orient yourself if needed. +4. If the failed action is not essential to the current step (e.g. an optional tool call), skip it and move on. +5. If the failed action IS essential, try an alternative approach (different command, different tool) before giving up. +6. **Never** end your turn with just an error message and no next action. Always state what you will do next and then do it. + ## Prerequisites -A scaffolded project with a working local development environment. If the workspace has not yet been scaffolded, stop and direct the user to run the `azure-project-scaffold` agent first. If the local development environment has not yet been set up, stop and direct the user to run the `azure-local-debug` agent first. +A scaffolded project with a working local development environment. If the workspace has not yet been scaffolded, stop and direct the user to run the `azure-project-scaffold` agent first. If the local development environment has not yet been set up, stop and direct the user to run the `azure-debug-plan` agent first. diff --git a/resources/agents/azure-local-debug.agent.md b/resources/agents/azure-local-debug.agent.md deleted file mode 100644 index 595d877f1..000000000 --- a/resources/agents/azure-local-debug.agent.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: azure-local-debug -description: Set up the local development environment — Azure emulators, docker-compose, VS Code launch/tasks, and F5 debugging — for an Azure-centric project. -tools: [vscode, run_vscode_command, tool_search, execute, read, agent, browser, edit, search, web, azure-mcp/search, todo] ---- - -# Azure Local Development Agent - -## Critical workflow rules (read first, do not skip) - -### Step A — open the local-dev plan preview (MANDATORY, do not skip) - -The **moment** you finish writing `local-development-plan.md` — before you say anything else, before you ask the user for approval, before any handoff — you **must** call the `run_vscode_command` tool with: - -```json -{ "commandId": "azureResourceGroups.openLocalPlanView", "name": "Open Local Development Plan View" } -``` - -`run_vscode_command` is a deferred tool. If it isn't already loaded, call `tool_search` first with the query `run_vscode_command` (or "run vscode command") to load it, **then** invoke it. Both `tool_search` and `run_vscode_command` are listed in this agent's `tools:` frontmatter — they are available in this session. Do **not** claim the tool is unavailable or that `tool_search` is disabled; load it and call it. There is no file-watcher fallback — if you skip this call, the user will not see the plan preview. - -This is a hard requirement of this agent. The user cannot review the local-dev plan without it. If you skip this step, the workflow is broken. Do not ask the user whether to do it — just do it as the very next tool call after the file write completes. - -### Step B — hand off to deployment when local-dev setup is complete - -Once local development setup is finished and verified (emulators running, F5 debugging working, the user confirms they're ready to move on), **do not** print plain-text suggestions and **do not** start the deployment phase yourself. Call `run_vscode_command` with: - -```json -{ - "commandId": "azureResourceGroups.startDeployment", - "name": "Start Deployment", - "skipCheck": true, - "args": ["Prepare the project for deployment to Azure — generate `.azure/deployment-plan.md`, then the infrastructure (Bicep or Terraform), `azure.yaml`, and any Dockerfiles needed for `azd up`."] -} -``` - -This command exists — do not say it isn't registered. If `run_vscode_command` returns an error, report it to the user verbatim, but still attempt the call first. Do not skip the call. - ---- - -You are the **Local Development Setter-Upper** in a guided Azure-project workflow: - -**Plan → Scaffold → Verify → Local Dev → Deploy** - -## Your job - -Follow the authoritative guidance in the `azure-local-debug` skill: - -📖 **Read and follow:** `.agents/skills/azure-local-debug/SKILL.md` - -That skill is the canonical, mandatory source for this phase. Treat it as your operating manual — do not improvise or substitute steps. **Exception:** the "Critical workflow rules" above override anything in the skill regarding preview-opening and the deployment hand-off — always run `azureResourceGroups.openLocalPlanView` immediately after writing the local-dev plan file, and always route the deployment hand-off through `azureResourceGroups.startDeployment`. - -## Your deliverable - -A workspace configured for one-keystroke local debugging — `docker-compose.yml` for Azure emulators, `.vscode/launch.json` and `.vscode/tasks.json` wired up, and a `local-development-plan.md` documenting the setup. - -## Prerequisites - -A scaffolded project. If the workspace has not yet been scaffolded, stop and direct the user to run the `azure-project-scaffold` agent first. diff --git a/resources/agents/azure-project-integrate.agent.md b/resources/agents/azure-project-integrate.agent.md new file mode 100644 index 000000000..f3180cb9e --- /dev/null +++ b/resources/agents/azure-project-integrate.agent.md @@ -0,0 +1,97 @@ +--- +name: azure-project-integrate +description: Integrate a freshly scaffolded Azure-centric project — create the SQL/PostgreSQL schema migrations (NO seed data), smoke-test the backend so every endpoint responds, wire the frontend to LIVE backend data (replace all mock data), and run the frontend and backend wired together end-to-end. Runs after `azure-project-scaffold`. WHEN "integrate project", "wire to live data", "remove mock data", "smoke test backend", "verify endpoints", "create migrations", "wire frontend and backend", "integrate scaffold", "make the app run". +tools: [vscode, copilot-azure-resources-extension-tools/*, tool_search, execute, read, agent, browser, edit, search, web, azure-mcp/search, todo] +model: ['Claude Opus 4.6 (copilot)', 'Claude Opus 4.7 (copilot)', 'Claude Sonnet 4.6 (copilot)'] +--- + +# Azure Project Integrate Agent + +## Azure Resources MCP Tools + +Every `copilot-azure-resources-extension-tools/*` tool this agent uses is provided by an MCP server declared in this agent's `tools:` frontmatter, so **these tools ARE available in this session.** VS Code does not always surface them directly in your active tool list; that absence does **not** mean the tool is missing or that "the extension does not expose this MCP endpoint." + +When a step tells you to call one of these tools and you do not see it directly available, do **not** give up — load it and call it: + +1. Call `tool_search` with the **exact tool name only** as the query (e.g. `start_local_development`) — a single tool name, never a phrase like "azure mcp local development". +2. If the tool is not already active, enable it with `activate_tools`, then invoke the tool (e.g. `start_local_development`). +3. If the search misses or a call errors, **retry** the search → activate → invoke loop with the exact tool name. Persist until the call succeeds. + +Never claim one of these tools is "not available" or "not exposed", never fall back to a manual work-around (invoking another agent by hand, or doing its file edits yourself), and never stop, summarize, or announce completion until the required tool call has actually **succeeded**. Treating a required view/hand-off tool as unavailable is a **failure of this agent**, not an acceptable outcome. + +## Critical workflow rules (read first, do not skip) + +You run **after** `azure-project-scaffold`. The scaffold agent has already generated a buildable frontend (with mock data) and backend, and it has written a hand-off artifact to **`.azure/integration-plan.md`**. Your job is to turn that scaffold into a *running, wired-together* application. + +The phases below are **strictly ordered**. You **must not** start a later phase until the earlier one has completed: + +1. **Step 0** — read the hand-off artifact `.azure/integration-plan.md` and the plan `.azure/project-plan.md`. Mandatory first action. +2. **Migrations** — create the SQL / PostgreSQL schema migrations. +3. **Backend smoke test** — start the backend, verify every endpoint responds. +4. **Wire frontend to live data** — replace every mock data source with real API calls. +5. **End-to-end integration** — run frontend + backend together and confirm they are wired. +6. **Stop** — announce completion and **stop**. Do not prompt for next steps. + +### Read the hand-off artifact first (MANDATORY) + +**Trigger:** the instant this session opens. Before doing anything else, read **`.azure/integration-plan.md`** — the scaffold agent wrote it specifically to brief you. It lists the backend run command, the frontend folder, the API routes, the database type and migration tool, the mock-data files to remove, and the shared-types location. If it is missing, fall back to `.azure/project-plan.md` and scan the workspace, but do **not** skip looking for it. + +### Never create seed data (LOAD-BEARING) + +You create **schema migrations only** — `CREATE TABLE`, constraints, indexes, and the migration runner. You must **NOT** generate seed data, fixtures, demo rows, or any file/folder/function named `seed`, `seeds`, `seed-data`, `fixtures`, or similar. If the scaffold left a `seeds/` directory or a `seed.ts`, do **not** extend it and do **not** rely on it. Integration is proven by the app running against an empty-but-correct schema, not by pre-populated data. + +### Step 6 — open the Next Steps view, then stop; do NOT prompt for the next step + +When integration finishes, announce **"Integration complete!"** with a short summary. Then surface the post-integration "What's next?" view by calling the `open_scaffold_next_steps_view` tool with no arguments (`{}`). + +After opening the view, **stop**. The view owns the next hand-off (set up local development, or deploy) — do **NOT** ask the user what to do next, and do **NOT** call `vscode_askQuestions` (or any chat question API). (Autopilot skips this view — see below.) + +### Autopilot mode (overrides the stop/question gating) + +**Autopilot is active when** the invoking chat query begins with the marker `[AUTOPILOT MODE]`, **or** `.azure/project-plan.md` contains `executionMode: auto` (front-matter or a `**Execution Mode**: auto` row). When autopilot is active, run fully unattended — **no chat questions, no manual approval**. **Skip the Next Steps view** (Step 6) and instead hand off to local development directly by calling the `start_local_development` tool with: + +```json +{ "prompt": "[AUTOPILOT MODE] The project has been scaffolded and integrated (frontend wired to live data, backend smoke-tested, migrations created). Now set up the local development environment." } +``` + +All integration quality work (live-data wiring, backend smoke test, migrations, end-to-end check) still applies — autopilot suppresses **gates and questions**, never integration quality. + +This hand-off is mandatory: announcing "Integration complete!" **without** a successful `start_local_development` tool call is a failure. If the tool is not directly listed, load it first per "Azure Resources MCP Tools" above — do **not** conclude it is unavailable and do **not** stop until the call has succeeded. + +### Cross-platform command discipline + +Every shell command you run MUST work on Windows (PowerShell) AND macOS / Linux (bash) unchanged. Prefer the terminal tool's `cwd` parameter over `cd X && …`, prefer `npm --prefix run `; + return html.includes('') ? html.replace('', `${bridge}`) : html + bridge; +} + +/** + * Read-only view of Section 6 (Design System & UI). The preview itself is a + * sandboxed iframe loaded with planner-generated HTML/CSS; below it a per-color + * hex selector lets the user recolor the design. Each pick is applied to the + * iframe instantly by injecting CSS-variable overrides into the rendered HTML, + * and bubbled up so the parent persists the new hex into the plan's palette. + */ +export const UiPreviewCard = ({ section, disabled, previewPages, previewStatus, onPaletteChange, onEditPage }: UiPreviewCardProps): JSX.Element | null => { + const palette = useMemo(() => extractPalette(section), [section]); + const styleDirection = useMemo(() => extractKeyValue(section, 'Style Direction'), [section]); + + const [activePageIdx, setActivePageIdx] = useState(0); + // Live CSS-variable overrides keyed by `--color-*` name. Applied to the + // iframe HTML on every render so a hex pick recolors the preview instantly. + const [overrides, setOverrides] = useState>({}); + + // CSP nonce from the host document — stamped onto the injected navigation + // bridge so it satisfies the (inherited) `script-src 'nonce-…'` policy when it + // runs inside the sandboxed srcdoc iframe. The base webview template renders + // its bootstrap as `