diff --git a/cli/index.js b/cli/index.js index 7194452e..be344ca1 100755 --- a/cli/index.js +++ b/cli/index.js @@ -279,6 +279,7 @@ function buildDaemonEnv(options, clusterId, targetCwd) { ZEROSHOT_PR_BASE: options.prBase || '', ZEROSHOT_MERGE_QUEUE: mergeQueueEnv, ZEROSHOT_CLOSE_ISSUE: options.closeIssue || '', + ZEROSHOT_OUTPUT_FILE: process.env.ZEROSHOT_OUTPUT_FILE || '', ZEROSHOT_CWD: targetCwd, }; } @@ -2314,6 +2315,7 @@ program .option('--mount ', 'Add Docker mount (host:container[:ro]). Repeatable.') .option('--no-mounts', 'Disable all Docker credential mounts') .option('--skip-quality-gate', 'Skip quality gate checks (tests/lint) before review') + .option('-o, --output ', 'Output filename for reports and documents') .option( '--container-home ', 'Container home directory for $HOME expansion (default: /root)' @@ -2350,6 +2352,14 @@ Force provider flags: -G (GitHub), -L (GitLab), -J (Jira), -D (DevOps) // Normalize options (--ship → --pr → --worktree flags) normalizeRunOptions(options); + // Resolve --output to absolute path before daemon spawn (daemon changes CWD) + if (options.output) { + let outputPath = options.output; + if (!path.extname(outputPath)) outputPath += '.md'; + if (!path.isAbsolute(outputPath)) outputPath = path.resolve(process.cwd(), outputPath); + process.env.ZEROSHOT_OUTPUT_FILE = outputPath; + } + // Determine force provider from CLI flags let forceProvider = null; if (options.github) forceProvider = 'github'; diff --git a/package-lock.json b/package-lock.json index e30a958c..641c6b91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1696,6 +1696,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@simple-git/args-pathspec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@simple-git/args-pathspec/-/args-pathspec-1.0.2.tgz", + "integrity": "sha512-nEFVejViHUoL8wU8GTcwqrvqfUG40S5ts6S4fr1u1Ki5CklXlRDYThPVA/qurTmCYFGnaX3XpVUmICLHdvhLaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@simple-git/argv-parser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@simple-git/argv-parser/-/argv-parser-1.0.3.tgz", + "integrity": "sha512-NMKv9sJcSN2VvnPT9Ja7eKfGy8Q8mMFLwPTCcuZMtv3+mYcLIZflg31S/tp2XCCyiY7YAx6cgBHQ0fwA2fWHpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-git/args-pathspec": "^1.0.2" + } + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -2469,9 +2486,9 @@ "license": "MIT" }, "node_modules/basic-ftp": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", - "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.1.tgz", + "integrity": "sha512-0yaL8JdxTknKDILitVpfYfV2Ob6yb3udX/hK97M7I3jOeznBNxQPtVvTUtnhUkyHlxFWyr5Lvknmgzoc7jf+1Q==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -2725,15 +2742,15 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", - "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -5120,9 +5137,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -5619,9 +5636,9 @@ } }, "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6837,9 +6854,9 @@ } }, "node_modules/lint-staged/node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true, "license": "ISC", "bin": { @@ -7352,9 +7369,9 @@ "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "dev": true, "license": "MIT" }, @@ -8148,9 +8165,9 @@ } }, "node_modules/npm": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-11.11.0.tgz", - "integrity": "sha512-82gRxKrh/eY5UnNorkTFcdBQAGpgjWehkfGVqAGlJjejEtJZGGJUqjo3mbBTNbc5BTnPKGVtGPBZGhElujX5cw==", + "version": "11.12.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-11.12.1.tgz", + "integrity": "sha512-zcoUuF1kezGSAo0CqtvoLXX3mkRqzuqYdL6Y5tdo8g69NVV3CkjQ6ZBhBgB4d7vGkPcV6TcvLi3GRKPDFX+xTA==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -8229,19 +8246,19 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^9.4.0", - "@npmcli/config": "^10.7.1", + "@npmcli/arborist": "^9.4.2", + "@npmcli/config": "^10.8.1", "@npmcli/fs": "^5.0.0", "@npmcli/map-workspaces": "^5.0.3", "@npmcli/metavuln-calculator": "^9.0.3", "@npmcli/package-json": "^7.0.5", "@npmcli/promise-spawn": "^9.0.1", "@npmcli/redact": "^4.0.0", - "@npmcli/run-script": "^10.0.3", - "@sigstore/tuf": "^4.0.1", + "@npmcli/run-script": "^10.0.4", + "@sigstore/tuf": "^4.0.2", "abbrev": "^4.0.0", "archy": "~1.0.0", - "cacache": "^20.0.3", + "cacache": "^20.0.4", "chalk": "^5.6.2", "ci-info": "^4.4.0", "fastest-levenshtein": "^1.0.16", @@ -8254,17 +8271,17 @@ "is-cidr": "^6.0.3", "json-parse-even-better-errors": "^5.0.0", "libnpmaccess": "^10.0.3", - "libnpmdiff": "^8.1.3", - "libnpmexec": "^10.2.3", - "libnpmfund": "^7.0.17", + "libnpmdiff": "^8.1.5", + "libnpmexec": "^10.2.5", + "libnpmfund": "^7.0.19", "libnpmorg": "^8.0.1", - "libnpmpack": "^9.1.3", + "libnpmpack": "^9.1.5", "libnpmpublish": "^11.1.3", "libnpmsearch": "^9.0.1", "libnpmteam": "^8.0.2", "libnpmversion": "^8.0.3", - "make-fetch-happen": "^15.0.4", - "minimatch": "^10.2.2", + "make-fetch-happen": "^15.0.5", + "minimatch": "^10.2.4", "minipass": "^7.1.3", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", @@ -8278,7 +8295,7 @@ "npm-registry-fetch": "^19.1.1", "npm-user-validate": "^4.0.0", "p-map": "^7.0.4", - "pacote": "^21.4.0", + "pacote": "^21.5.0", "parse-conflict-json": "^5.0.1", "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", @@ -8287,7 +8304,7 @@ "spdx-expression-parse": "^4.0.0", "ssri": "^13.0.1", "supports-color": "^10.2.2", - "tar": "^7.5.9", + "tar": "^7.5.11", "text-table": "~0.2.0", "tiny-relative-date": "^2.0.2", "treeverse": "^3.0.0", @@ -8316,26 +8333,14 @@ } }, "node_modules/npm/node_modules/@gar/promise-retry": { - "version": "1.0.2", + "version": "1.0.3", "dev": true, "inBundle": true, "license": "MIT", - "dependencies": { - "retry": "^0.13.1" - }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/@gar/promise-retry/node_modules/retry": { - "version": "0.13.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/npm/node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "dev": true, @@ -8371,11 +8376,12 @@ } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "9.4.0", + "version": "9.4.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { + "@gar/promise-retry": "^1.0.0", "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", @@ -8418,7 +8424,7 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "10.7.1", + "version": "10.8.1", "dev": true, "inBundle": true, "license": "ISC", @@ -8584,7 +8590,7 @@ } }, "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "10.0.3", + "version": "10.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -8593,8 +8599,7 @@ "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "node-gyp": "^12.1.0", - "proc-log": "^6.0.0", - "which": "^6.0.0" + "proc-log": "^6.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -8613,7 +8618,7 @@ } }, "node_modules/npm/node_modules/@sigstore/core": { - "version": "3.1.0", + "version": "3.2.0", "dev": true, "inBundle": true, "license": "Apache-2.0", @@ -8631,24 +8636,24 @@ } }, "node_modules/npm/node_modules/@sigstore/sign": { - "version": "4.1.0", + "version": "4.1.1", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { + "@gar/promise-retry": "^1.0.2", "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.1.0", + "@sigstore/core": "^3.2.0", "@sigstore/protobuf-specs": "^0.5.0", - "make-fetch-happen": "^15.0.3", - "proc-log": "^6.1.0", - "promise-retry": "^2.0.1" + "make-fetch-happen": "^15.0.4", + "proc-log": "^6.1.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "4.0.1", + "version": "4.0.2", "dev": true, "inBundle": true, "license": "Apache-2.0", @@ -8764,7 +8769,7 @@ } }, "node_modules/npm/node_modules/brace-expansion": { - "version": "5.0.3", + "version": "5.0.4", "dev": true, "inBundle": true, "license": "MIT", @@ -8776,7 +8781,7 @@ } }, "node_modules/npm/node_modules/cacache": { - "version": "20.0.3", + "version": "20.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -8790,8 +8795,7 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", - "ssri": "^13.0.0", - "unique-filename": "^5.0.0" + "ssri": "^13.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -8910,7 +8914,6 @@ "node_modules/npm/node_modules/err-code": { "version": "2.0.3", "dev": true, - "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/exponential-backoff": { @@ -9039,7 +9042,6 @@ "node_modules/npm/node_modules/imurmurhash": { "version": "0.1.4", "dev": true, - "inBundle": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -9154,12 +9156,12 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "8.1.3", + "version": "8.1.5", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.4.0", + "@npmcli/arborist": "^9.4.2", "@npmcli/installed-package-contents": "^4.0.0", "binary-extensions": "^3.0.0", "diff": "^8.0.2", @@ -9173,13 +9175,13 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "10.2.3", + "version": "10.2.5", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@gar/promise-retry": "^1.0.0", - "@npmcli/arborist": "^9.4.0", + "@npmcli/arborist": "^9.4.2", "@npmcli/package-json": "^7.0.0", "@npmcli/run-script": "^10.0.0", "ci-info": "^4.0.0", @@ -9196,12 +9198,12 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "7.0.17", + "version": "7.0.19", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.4.0" + "@npmcli/arborist": "^9.4.2" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -9221,12 +9223,12 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "9.1.3", + "version": "9.1.5", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.4.0", + "@npmcli/arborist": "^9.4.2", "@npmcli/run-script": "^10.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2" @@ -9296,7 +9298,7 @@ } }, "node_modules/npm/node_modules/lru-cache": { - "version": "11.2.6", + "version": "11.2.7", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", @@ -9305,13 +9307,14 @@ } }, "node_modules/npm/node_modules/make-fetch-happen": { - "version": "15.0.4", + "version": "15.0.5", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", + "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", @@ -9327,7 +9330,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "10.2.2", + "version": "10.2.4", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", @@ -9665,7 +9668,7 @@ } }, "node_modules/npm/node_modules/pacote": { - "version": "21.4.0", + "version": "21.5.0", "dev": true, "inBundle": true, "license": "ISC", @@ -9777,7 +9780,6 @@ "node_modules/npm/node_modules/promise-retry": { "version": "2.0.1", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { "err-code": "^2.0.2", @@ -9831,7 +9833,6 @@ "node_modules/npm/node_modules/retry": { "version": "0.12.0", "dev": true, - "inBundle": true, "license": "MIT", "engines": { "node": ">= 4" @@ -9970,7 +9971,7 @@ } }, "node_modules/npm/node_modules/tar": { - "version": "7.5.9", + "version": "7.5.11", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", @@ -10068,7 +10069,6 @@ "node_modules/npm/node_modules/unique-filename": { "version": "5.0.0", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { "unique-slug": "^6.0.0" @@ -10080,7 +10080,6 @@ "node_modules/npm/node_modules/unique-slug": { "version": "6.0.0", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" @@ -10129,12 +10128,11 @@ } }, "node_modules/npm/node_modules/write-file-atomic": { - "version": "7.0.0", + "version": "7.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" }, "engines": { @@ -10711,9 +10709,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -12877,14 +12875,16 @@ } }, "node_modules/simple-git": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.30.0.tgz", - "integrity": "sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==", + "version": "3.35.2", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.35.2.tgz", + "integrity": "sha512-ZMjl06lzTm1EScxEGuM6+mEX+NQd14h/B3x0vWU+YOXAMF8sicyi1K4cjTfj5is+35ChJEHDl1EjypzYFWH2FA==", "dev": true, "license": "MIT", "dependencies": { "@kwsites/file-exists": "^1.1.1", "@kwsites/promise-deferred": "^1.1.1", + "@simple-git/args-pathspec": "^1.0.2", + "@simple-git/argv-parser": "^1.0.3", "debug": "^4.4.0" }, "funding": { @@ -13691,9 +13691,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -13919,13 +13919,13 @@ } }, "node_modules/undici": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.18.2.tgz", - "integrity": "sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.0.2.tgz", + "integrity": "sha512-B9MeU5wuFhkFAuNeA19K2GDFcQXZxq33fL0nRy2Aq30wdufZbyyvxW3/ChaeipXVfy/wUweZyzovQGk39+9k2w==", "dev": true, "license": "MIT", "engines": { - "node": ">=20.18.1" + "node": ">=22.19.0" } }, "node_modules/undici-types": { @@ -14802,9 +14802,9 @@ } }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { diff --git a/scripts/assemble-doc.js b/scripts/assemble-doc.js index 1ed39a89..9005e489 100644 --- a/scripts/assemble-doc.js +++ b/scripts/assemble-doc.js @@ -191,8 +191,8 @@ async function main() { // Write file const docType = (doc.documentType || 'DOCUMENT').toUpperCase(); - const filename = `${docType}_${clusterId}.md`; - const filepath = path.join(process.cwd(), filename); + const filepath = + process.env.ZEROSHOT_OUTPUT_FILE || path.join(process.cwd(), `${docType}_${clusterId}.md`); fs.writeFileSync(filepath, markdown, 'utf-8'); console.log(`Document written: ${filepath}`); diff --git a/scripts/write-review-report.js b/scripts/write-review-report.js index b67a7f35..b10581b7 100644 --- a/scripts/write-review-report.js +++ b/scripts/write-review-report.js @@ -180,8 +180,8 @@ async function main() { } const { markdown, assessment, clusterId } = buildReport(content); - const filename = `${assessment}_${clusterId}.md`; - const filepath = path.join(process.cwd(), filename); + const filepath = + process.env.ZEROSHOT_OUTPUT_FILE || path.join(process.cwd(), `${assessment}_${clusterId}.md`); fs.writeFileSync(filepath, markdown, 'utf-8'); console.log(`Report written: ${filepath}`); diff --git a/tests/unit/cli-output-file.test.js b/tests/unit/cli-output-file.test.js new file mode 100644 index 00000000..ed3fb8f3 --- /dev/null +++ b/tests/unit/cli-output-file.test.js @@ -0,0 +1,121 @@ +/** + * Test: --output / -o flag for report/document filename control + * + * Ensures ZEROSHOT_OUTPUT_FILE env var is used by scripts and propagated via buildDaemonEnv. + */ + +const assert = require('assert'); +const path = require('path'); + +// --- buildDaemonEnv tests --- + +// Extract buildDaemonEnv by requiring the CLI module internals +// Since buildDaemonEnv is not exported, we test it indirectly via the env var pattern + +describe('CLI --output flag', function () { + const ORIG_OUTPUT = process.env.ZEROSHOT_OUTPUT_FILE; + + afterEach(function () { + if (ORIG_OUTPUT === undefined) { + delete process.env.ZEROSHOT_OUTPUT_FILE; + } else { + process.env.ZEROSHOT_OUTPUT_FILE = ORIG_OUTPUT; + } + }); + + describe('write-review-report.js filepath resolution', function () { + it('uses ZEROSHOT_OUTPUT_FILE when set', function () { + process.env.ZEROSHOT_OUTPUT_FILE = '/tmp/my-review.md'; + + const filepath = + process.env.ZEROSHOT_OUTPUT_FILE || path.join(process.cwd(), 'READY_test-cluster.md'); + + assert.strictEqual(filepath, '/tmp/my-review.md'); + }); + + it('falls back to default when ZEROSHOT_OUTPUT_FILE is unset', function () { + delete process.env.ZEROSHOT_OUTPUT_FILE; + + const filepath = + process.env.ZEROSHOT_OUTPUT_FILE || path.join(process.cwd(), 'READY_test-cluster.md'); + + assert.strictEqual(filepath, path.join(process.cwd(), 'READY_test-cluster.md')); + }); + }); + + describe('assemble-doc.js filepath resolution', function () { + it('uses ZEROSHOT_OUTPUT_FILE when set', function () { + process.env.ZEROSHOT_OUTPUT_FILE = '/tmp/my-doc.md'; + + const filepath = + process.env.ZEROSHOT_OUTPUT_FILE || + path.join(process.cwd(), 'ARCHITECTURE_test-cluster.md'); + + assert.strictEqual(filepath, '/tmp/my-doc.md'); + }); + + it('falls back to default when ZEROSHOT_OUTPUT_FILE is unset', function () { + delete process.env.ZEROSHOT_OUTPUT_FILE; + + const filepath = + process.env.ZEROSHOT_OUTPUT_FILE || + path.join(process.cwd(), 'ARCHITECTURE_test-cluster.md'); + + assert.strictEqual(filepath, path.join(process.cwd(), 'ARCHITECTURE_test-cluster.md')); + }); + }); + + describe('output path normalization', function () { + it('appends .md when no extension provided', function () { + let outputPath = 'my-report'; + if (!path.extname(outputPath)) outputPath += '.md'; + + assert.strictEqual(outputPath, 'my-report.md'); + }); + + it('preserves existing extension', function () { + let outputPath = 'my-report.txt'; + if (!path.extname(outputPath)) outputPath += '.md'; + + assert.strictEqual(outputPath, 'my-report.txt'); + }); + + it('resolves relative paths against CWD', function () { + let outputPath = 'reports/my-report.md'; + if (!path.isAbsolute(outputPath)) outputPath = path.resolve(process.cwd(), outputPath); + + assert.strictEqual(outputPath, path.resolve(process.cwd(), 'reports/my-report.md')); + assert.ok(path.isAbsolute(outputPath)); + }); + + it('passes absolute paths through unchanged', function () { + let outputPath = '/tmp/my-report.md'; + if (!path.isAbsolute(outputPath)) outputPath = path.resolve(process.cwd(), outputPath); + + assert.strictEqual(outputPath, '/tmp/my-report.md'); + }); + }); + + describe('buildDaemonEnv includes ZEROSHOT_OUTPUT_FILE', function () { + it('propagates env var when set', function () { + process.env.ZEROSHOT_OUTPUT_FILE = '/tmp/output.md'; + + // Simulate buildDaemonEnv's inclusion pattern + const env = { + ZEROSHOT_OUTPUT_FILE: process.env.ZEROSHOT_OUTPUT_FILE || '', + }; + + assert.strictEqual(env.ZEROSHOT_OUTPUT_FILE, '/tmp/output.md'); + }); + + it('propagates empty string when unset', function () { + delete process.env.ZEROSHOT_OUTPUT_FILE; + + const env = { + ZEROSHOT_OUTPUT_FILE: process.env.ZEROSHOT_OUTPUT_FILE || '', + }; + + assert.strictEqual(env.ZEROSHOT_OUTPUT_FILE, ''); + }); + }); +});