issue-flow 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -97
- package/dist/agent-4DHRKZ2Z.js +32 -0
- package/dist/{analyze-Q4ONIWRZ.js → analyze-UEJ2R3H5.js} +42 -41
- package/dist/analyze-UEJ2R3H5.js.map +1 -0
- package/dist/{apply-EEFPY2W4.js → apply-QDYNQMUX.js} +22 -24
- package/dist/apply-QDYNQMUX.js.map +1 -0
- package/dist/artifacts-AMJQJFFV.js +82 -0
- package/dist/artifacts-AMJQJFFV.js.map +1 -0
- package/dist/{bench-WWWXLTFH.js → bench-RNRXVEFK.js} +42 -42
- package/dist/{chunk-RYOUZ6EK.js → chunk-23VHVVKW.js} +3 -3
- package/dist/chunk-2EYLOS5I.js +99 -0
- package/dist/chunk-2EYLOS5I.js.map +1 -0
- package/dist/{chunk-C5TL7T4V.js → chunk-2YM2VH6R.js} +2 -2
- package/dist/{chunk-XUEMATVY.js → chunk-37O2FMAN.js} +28 -25
- package/dist/chunk-37O2FMAN.js.map +1 -0
- package/dist/chunk-44RF3VFG.js +717 -0
- package/dist/chunk-44RF3VFG.js.map +1 -0
- package/dist/chunk-6AOZCWN2.js +21 -0
- package/dist/chunk-6AOZCWN2.js.map +1 -0
- package/dist/chunk-7MJGYPHF.js +1571 -0
- package/dist/chunk-7MJGYPHF.js.map +1 -0
- package/dist/{chunk-SA6HXL4Y.js → chunk-7WBUEBD5.js} +9 -9
- package/dist/chunk-7WBUEBD5.js.map +1 -0
- package/dist/chunk-7ZZUSMBJ.js +35 -0
- package/dist/chunk-7ZZUSMBJ.js.map +1 -0
- package/dist/{chunk-QJ44VG5G.js → chunk-ADH6RJNX.js} +3 -3
- package/dist/{chunk-34OCSKOB.js → chunk-AKL5UPR6.js} +159 -114
- package/dist/chunk-AKL5UPR6.js.map +1 -0
- package/dist/{chunk-7F7LGMVO.js → chunk-BTBJ5UOO.js} +12 -12
- package/dist/{chunk-7F7LGMVO.js.map → chunk-BTBJ5UOO.js.map} +1 -1
- package/dist/{chunk-HOAHMERN.js → chunk-CLZ6RRZL.js} +21 -21
- package/dist/chunk-DBLXLKGU.js +1201 -0
- package/dist/chunk-DBLXLKGU.js.map +1 -0
- package/dist/{chunk-DUS5ZNKL.js → chunk-DIMDAYZS.js} +7 -6
- package/dist/chunk-DZ3DZ3EN.js +278 -0
- package/dist/chunk-DZ3DZ3EN.js.map +1 -0
- package/dist/{chunk-CRGIQFUQ.js → chunk-E2H3JV2E.js} +3 -1
- package/dist/chunk-E2H3JV2E.js.map +1 -0
- package/dist/{chunk-45WZ6GMI.js → chunk-EORDSKWZ.js} +17 -17
- package/dist/chunk-EORDSKWZ.js.map +1 -0
- package/dist/{chunk-LTH6XYZ3.js → chunk-EYKPWHT7.js} +40 -30
- package/dist/chunk-EYKPWHT7.js.map +1 -0
- package/dist/{chunk-OODXFCQV.js → chunk-FU2FQ4JE.js} +14 -16
- package/dist/{chunk-OODXFCQV.js.map → chunk-FU2FQ4JE.js.map} +1 -1
- package/dist/{chunk-V7QOIQYC.js → chunk-G442RDFX.js} +9 -23
- package/dist/{chunk-V7QOIQYC.js.map → chunk-G442RDFX.js.map} +1 -1
- package/dist/{chunk-QPGEFLMY.js → chunk-I64N6RL6.js} +7 -7
- package/dist/{chunk-KRAGAUKD.js → chunk-JBYXJOJJ.js} +201 -64
- package/dist/chunk-JBYXJOJJ.js.map +1 -0
- package/dist/{chunk-SOM4QA6C.js → chunk-JCR5C5A7.js} +93 -18
- package/dist/chunk-JCR5C5A7.js.map +1 -0
- package/dist/{chunk-RNFUVKC3.js → chunk-K5NM26NV.js} +30 -13
- package/dist/chunk-K5NM26NV.js.map +1 -0
- package/dist/{chunk-YVPZUN6X.js → chunk-KUA6KBBD.js} +335 -38
- package/dist/chunk-KUA6KBBD.js.map +1 -0
- package/dist/{chunk-KMCS76ZW.js → chunk-KUL64XUF.js} +44 -12
- package/dist/chunk-KUL64XUF.js.map +1 -0
- package/dist/{chunk-HAKDLR6N.js → chunk-MAJ6QDRL.js} +65 -78
- package/dist/chunk-MAJ6QDRL.js.map +1 -0
- package/dist/{chunk-DGRTJD5R.js → chunk-MML2G7IC.js} +7 -7
- package/dist/chunk-NP47HRX2.js +136 -0
- package/dist/chunk-NP47HRX2.js.map +1 -0
- package/dist/{chunk-3R27MJ5R.js → chunk-PFWHHYEO.js} +3 -3
- package/dist/{chunk-ECU7YO7S.js → chunk-PM5YWJYO.js} +22 -6
- package/dist/chunk-PM5YWJYO.js.map +1 -0
- package/dist/{chunk-E4I6MMHD.js → chunk-PXPTIXJF.js} +154 -101
- package/dist/chunk-PXPTIXJF.js.map +1 -0
- package/dist/{chunk-CWSQVHVV.js → chunk-QJHZ3HYJ.js} +248 -102
- package/dist/chunk-QJHZ3HYJ.js.map +1 -0
- package/dist/{chunk-LI35PIIS.js → chunk-RDPK7LYK.js} +20 -117
- package/dist/chunk-RDPK7LYK.js.map +1 -0
- package/dist/{chunk-PMLE7KAQ.js → chunk-RMIBLFG3.js} +30 -14
- package/dist/chunk-RMIBLFG3.js.map +1 -0
- package/dist/{chunk-62GVVZQO.js → chunk-T736DSZI.js} +32 -316
- package/dist/chunk-T736DSZI.js.map +1 -0
- package/dist/{chunk-TZYINKCC.js → chunk-UDUUUFQF.js} +57 -29
- package/dist/chunk-UDUUUFQF.js.map +1 -0
- package/dist/{chunk-NEWNXZ65.js → chunk-V7GETODQ.js} +36 -28
- package/dist/{chunk-NEWNXZ65.js.map → chunk-V7GETODQ.js.map} +1 -1
- package/dist/{chunk-PPZ3K4YM.js → chunk-VHQMMY2D.js} +2 -2
- package/dist/{chunk-ZVZMWNCG.js → chunk-VJ3PF6B7.js} +50 -16
- package/dist/chunk-VJ3PF6B7.js.map +1 -0
- package/dist/{chunk-L6HSKTQE.js → chunk-W7LZLJAF.js} +4 -4
- package/dist/{chunk-6K2LCFG6.js → chunk-WB4FA2EH.js} +70 -81
- package/dist/chunk-WB4FA2EH.js.map +1 -0
- package/dist/{chunk-LGHND47K.js → chunk-WQSGL5LX.js} +22 -16
- package/dist/chunk-WQSGL5LX.js.map +1 -0
- package/dist/{chunk-ICM463EO.js → chunk-XNK5UN2D.js} +5 -649
- package/dist/chunk-XNK5UN2D.js.map +1 -0
- package/dist/{chunk-7UMMFOL2.js → chunk-Y2KOWABB.js} +39 -24
- package/dist/chunk-Y2KOWABB.js.map +1 -0
- package/dist/{chunk-QF7VEL3M.js → chunk-YC24E66P.js} +568 -158
- package/dist/chunk-YC24E66P.js.map +1 -0
- package/dist/{chunk-EG2MGDP5.js → chunk-Z6RCKCVB.js} +52 -46
- package/dist/chunk-Z6RCKCVB.js.map +1 -0
- package/dist/{chunk-YUNBOUQH.js → chunk-ZPGNVBWY.js} +8 -8
- package/dist/cli.js +132 -62
- package/dist/cli.js.map +1 -1
- package/dist/compat-OJG76J4I.js +24 -0
- package/dist/{config-LEBZZCJP.js → config-6YTWPDBK.js} +20 -17
- package/dist/{contract-JH2WBIO6.js → contract-HWLFFL3F.js} +2 -2
- package/dist/{conventions-XOT6YW5L.js → conventions-5UPOTU42.js} +20 -16
- package/dist/{conventions-XOT6YW5L.js.map → conventions-5UPOTU42.js.map} +1 -1
- package/dist/db-QAZG4LQD.js +264 -0
- package/dist/db-QAZG4LQD.js.map +1 -0
- package/dist/diagnostics-YEFB42E5.js +25 -0
- package/dist/execute-QCT64D37.js +38 -0
- package/dist/{generate-JGW5JSKB.js → generate-QATMDKOK.js} +46 -43
- package/dist/generate-QATMDKOK.js.map +1 -0
- package/dist/{git-A2IP32PQ.js → git-XGOECXWG.js} +2 -3
- package/dist/history-NBPUZVGQ.js +101 -0
- package/dist/history-NBPUZVGQ.js.map +1 -0
- package/dist/init-4LB2YKWP.js +28 -0
- package/dist/{operations-O4FORFIH.js → operations-RUQP2Y2F.js} +78 -52
- package/dist/operations-RUQP2Y2F.js.map +1 -0
- package/dist/{permissions-G4XCAESF.js → permissions-QZPUUBSO.js} +5 -6
- package/dist/plan-2NMSHTMD.js +38 -0
- package/dist/{policy-U5NBFAO5.js → policy-RKKFF5A2.js} +17 -15
- package/dist/{policy-U5NBFAO5.js.map → policy-RKKFF5A2.js.map} +1 -1
- package/dist/pr-QKFO5HI3.js +42 -0
- package/dist/pr-review-H2BFD6F2.js +33 -0
- package/dist/prd-ET6XKYRS.js +37 -0
- package/dist/{ps-76L6ZAZL.js → ps-UIKSOUAQ.js} +26 -15
- package/dist/ps-UIKSOUAQ.js.map +1 -0
- package/dist/{recorder-2BAKPBRA.js → recorder-LOU3PTIE.js} +11 -7
- package/dist/registry-HV7M6MAH.js +17 -0
- package/dist/repository-RCRR6RDE.js +80 -0
- package/dist/resume-BWJZGBLZ.js +278 -0
- package/dist/resume-BWJZGBLZ.js.map +1 -0
- package/dist/review-2MTZLNSS.js +38 -0
- package/dist/routing-RM5ABHHD.js +35 -0
- package/dist/run-XMACQBRJ.js +61 -0
- package/dist/{session-publisher-KAJQRHNZ.js → session-publisher-Q5TNEZPX.js} +3 -3
- package/dist/session-publisher-Q5TNEZPX.js.map +1 -0
- package/dist/{state-manager-UPHO2EA2.js → state-manager-SRN4VJSX.js} +9 -4
- package/dist/state-manager-SRN4VJSX.js.map +1 -0
- package/dist/{usage-KTMYXAPF.js → usage-JOODVE5O.js} +69 -63
- package/dist/usage-JOODVE5O.js.map +1 -0
- package/dist/web-TLMWJ2BM.js +205 -0
- package/dist/web-TLMWJ2BM.js.map +1 -0
- package/package.json +22 -8
- package/prompts/analyze.md +16 -19
- package/prompts/execute.md +73 -144
- package/prompts/generate.md +23 -10
- package/prompts/plan.md +32 -60
- package/prompts/pr-review.md +58 -40
- package/prompts/pr.md +50 -16
- package/prompts/prd.md +26 -19
- package/prompts/review.md +41 -18
- package/web/public/app.js +111 -112
- package/dist/agent-HMZTXCRT.js +0 -30
- package/dist/analyze-Q4ONIWRZ.js.map +0 -1
- package/dist/apply-EEFPY2W4.js.map +0 -1
- package/dist/chunk-34OCSKOB.js.map +0 -1
- package/dist/chunk-45WZ6GMI.js.map +0 -1
- package/dist/chunk-62GVVZQO.js.map +0 -1
- package/dist/chunk-6K2LCFG6.js.map +0 -1
- package/dist/chunk-7UMMFOL2.js.map +0 -1
- package/dist/chunk-CRGIQFUQ.js.map +0 -1
- package/dist/chunk-CWSQVHVV.js.map +0 -1
- package/dist/chunk-E4I6MMHD.js.map +0 -1
- package/dist/chunk-ECU7YO7S.js.map +0 -1
- package/dist/chunk-EG2MGDP5.js.map +0 -1
- package/dist/chunk-HAKDLR6N.js.map +0 -1
- package/dist/chunk-ICM463EO.js.map +0 -1
- package/dist/chunk-KMCS76ZW.js.map +0 -1
- package/dist/chunk-KRAGAUKD.js.map +0 -1
- package/dist/chunk-LGHND47K.js.map +0 -1
- package/dist/chunk-LI35PIIS.js.map +0 -1
- package/dist/chunk-LTH6XYZ3.js.map +0 -1
- package/dist/chunk-PMLE7KAQ.js.map +0 -1
- package/dist/chunk-QF7VEL3M.js.map +0 -1
- package/dist/chunk-RNFUVKC3.js.map +0 -1
- package/dist/chunk-SA6HXL4Y.js.map +0 -1
- package/dist/chunk-SOM4QA6C.js.map +0 -1
- package/dist/chunk-TZYINKCC.js.map +0 -1
- package/dist/chunk-WCCZJL7W.js +0 -141
- package/dist/chunk-WCCZJL7W.js.map +0 -1
- package/dist/chunk-XEYH6ZZI.js +0 -289
- package/dist/chunk-XEYH6ZZI.js.map +0 -1
- package/dist/chunk-XUEMATVY.js.map +0 -1
- package/dist/chunk-XZUEFTUP.js +0 -243
- package/dist/chunk-XZUEFTUP.js.map +0 -1
- package/dist/chunk-YVPZUN6X.js.map +0 -1
- package/dist/chunk-ZVZMWNCG.js.map +0 -1
- package/dist/diagnostics-HTCWF7F4.js +0 -23
- package/dist/execute-LELOSR5T.js +0 -37
- package/dist/generate-JGW5JSKB.js.map +0 -1
- package/dist/init-TO6MUXO4.js +0 -26
- package/dist/operations-O4FORFIH.js.map +0 -1
- package/dist/plan-OXAT344Q.js +0 -34
- package/dist/pr-UZHNKKZC.js +0 -39
- package/dist/pr-review-Q4ACAWDM.js +0 -32
- package/dist/prd-6CYEMLDY.js +0 -33
- package/dist/ps-76L6ZAZL.js.map +0 -1
- package/dist/registry-XLHHYLTR.js +0 -15
- package/dist/resume-URCU6CIJ.js +0 -244
- package/dist/resume-URCU6CIJ.js.map +0 -1
- package/dist/review-LVZT2TMW.js +0 -35
- package/dist/routing-EK6RBZM4.js +0 -33
- package/dist/run-2RXJCJKT.js +0 -56
- package/dist/usage-KTMYXAPF.js.map +0 -1
- package/dist/web-B5UPHHR5.js +0 -172
- package/dist/web-B5UPHHR5.js.map +0 -1
- /package/dist/{agent-HMZTXCRT.js.map → agent-4DHRKZ2Z.js.map} +0 -0
- /package/dist/{bench-WWWXLTFH.js.map → bench-RNRXVEFK.js.map} +0 -0
- /package/dist/{chunk-RYOUZ6EK.js.map → chunk-23VHVVKW.js.map} +0 -0
- /package/dist/{chunk-C5TL7T4V.js.map → chunk-2YM2VH6R.js.map} +0 -0
- /package/dist/{chunk-QJ44VG5G.js.map → chunk-ADH6RJNX.js.map} +0 -0
- /package/dist/{chunk-HOAHMERN.js.map → chunk-CLZ6RRZL.js.map} +0 -0
- /package/dist/{chunk-DUS5ZNKL.js.map → chunk-DIMDAYZS.js.map} +0 -0
- /package/dist/{chunk-QPGEFLMY.js.map → chunk-I64N6RL6.js.map} +0 -0
- /package/dist/{chunk-DGRTJD5R.js.map → chunk-MML2G7IC.js.map} +0 -0
- /package/dist/{chunk-3R27MJ5R.js.map → chunk-PFWHHYEO.js.map} +0 -0
- /package/dist/{chunk-PPZ3K4YM.js.map → chunk-VHQMMY2D.js.map} +0 -0
- /package/dist/{chunk-L6HSKTQE.js.map → chunk-W7LZLJAF.js.map} +0 -0
- /package/dist/{chunk-YUNBOUQH.js.map → chunk-ZPGNVBWY.js.map} +0 -0
- /package/dist/{config-LEBZZCJP.js.map → compat-OJG76J4I.js.map} +0 -0
- /package/dist/{contract-JH2WBIO6.js.map → config-6YTWPDBK.js.map} +0 -0
- /package/dist/{diagnostics-HTCWF7F4.js.map → contract-HWLFFL3F.js.map} +0 -0
- /package/dist/{execute-LELOSR5T.js.map → diagnostics-YEFB42E5.js.map} +0 -0
- /package/dist/{git-A2IP32PQ.js.map → execute-QCT64D37.js.map} +0 -0
- /package/dist/{init-TO6MUXO4.js.map → git-XGOECXWG.js.map} +0 -0
- /package/dist/{permissions-G4XCAESF.js.map → init-4LB2YKWP.js.map} +0 -0
- /package/dist/{plan-OXAT344Q.js.map → permissions-QZPUUBSO.js.map} +0 -0
- /package/dist/{pr-UZHNKKZC.js.map → plan-2NMSHTMD.js.map} +0 -0
- /package/dist/{pr-review-Q4ACAWDM.js.map → pr-QKFO5HI3.js.map} +0 -0
- /package/dist/{prd-6CYEMLDY.js.map → pr-review-H2BFD6F2.js.map} +0 -0
- /package/dist/{recorder-2BAKPBRA.js.map → prd-ET6XKYRS.js.map} +0 -0
- /package/dist/{registry-XLHHYLTR.js.map → recorder-LOU3PTIE.js.map} +0 -0
- /package/dist/{review-LVZT2TMW.js.map → registry-HV7M6MAH.js.map} +0 -0
- /package/dist/{routing-EK6RBZM4.js.map → repository-RCRR6RDE.js.map} +0 -0
- /package/dist/{run-2RXJCJKT.js.map → review-2MTZLNSS.js.map} +0 -0
- /package/dist/{session-publisher-KAJQRHNZ.js.map → routing-RM5ABHHD.js.map} +0 -0
- /package/dist/{state-manager-UPHO2EA2.js.map → run-XMACQBRJ.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/execute.ts","../src/core/engine.ts","../src/ui/progress.ts","../src/ui/summary.ts","../src/ui/text.ts","../src/core/executor.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { createConfig, loadWebConfig, resolvePaths, validateDependencies } from '../config.js';\nimport { runEngine } from '../core/engine.js';\nimport { getSessionPublisher, setSessionPublisher } from '../core/session-publisher.js';\nimport { FilePublisher, NullPublisher } from '../core/session-state.js';\nimport { allStoriesPass, isoNow, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { resolveIssuePaths } from '../storage/resolve.js';\nimport { printError } from '../ui/logger.js';\nimport { getPackageVersion } from '../version.js';\nimport { ensureWebMonitor } from '../web/lock.js';\n\nexport interface ExecuteOptions {\n issue?: string;\n maxIterations?: number;\n retryLimit?: number;\n retryForever?: boolean;\n /** `--restart-web`: replace the detached monitor before direct execution. */\n restartWeb?: boolean;\n /**\n * Conventional-commit scope for the stories of this issue (`issue-71`).\n * Only the multi-issue queue sets it — see `EngineConfig.commitScope`.\n */\n commitScope?: string;\n}\n\nexport async function runExecute(\n positionalMaxIter: number | undefined,\n options: ExecuteOptions,\n): Promise<number> {\n const errors = await validateDependencies();\n if (errors.length > 0) {\n printError('The following required tools are not installed:');\n for (const err of errors) {\n console.log(err);\n }\n return 1;\n }\n\n const maxIterations = options.maxIterations ?? positionalMaxIter;\n\n const config = createConfig({\n issueNumber: options.issue,\n maxIterations,\n retryLimit: options.retryLimit,\n retryForever: options.retryForever,\n commitScope: options.commitScope,\n });\n\n const paths = await resolvePaths(config);\n const webConfig = await loadWebConfig();\n const inheritedPublisher = getSessionPublisher();\n let standalonePublisher: FilePublisher | null = null;\n\n // `run` owns the publisher when it delegates to this command. A direct\n // `execute --issue N --web` has no owner, so install the same file-backed\n // surface here and tear down only what this invocation created.\n if (\n webConfig.enabled &&\n config.issueNumber !== undefined &&\n inheritedPublisher instanceof NullPublisher\n ) {\n const issuePaths = await resolveIssuePaths(config.issueNumber, {\n projectRoot: paths.projectRoot,\n });\n standalonePublisher = new FilePublisher(issuePaths.sessionFile, {\n logLimit: webConfig.logLimit,\n includeLogs: webConfig.includeLogs,\n });\n setSessionPublisher(standalonePublisher);\n const numericIssue = /^\\d+$/.test(config.issueNumber) ? Number(config.issueNumber) : null;\n standalonePublisher.publish({\n type: 'session:start',\n at: isoNow(),\n sessionId: randomUUID(),\n issueNumber: numericIssue,\n phases: ['execute'],\n // The agent is only settled per invocation here, so the run-wide fields\n // stay null; the version is what makes the session attributable to a build.\n environment: {\n node: process.version,\n platform: process.platform,\n agent: null,\n model: null,\n cliVersion: getPackageVersion(),\n },\n });\n standalonePublisher.publish({ type: 'phase:start', at: isoNow(), phase: 'execute' });\n await ensureWebMonitor(\n {\n publisher: standalonePublisher,\n port: webConfig.port,\n host: webConfig.host,\n refreshSeconds: webConfig.refreshSeconds,\n },\n { restart: options.restartWeb === true },\n );\n }\n\n let exitCode: number | null = null;\n try {\n exitCode = await runEngine(config, paths);\n\n // Update pipeline state if all stories pass\n if (exitCode === 0 && config.issueNumber) {\n try {\n const plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan)) {\n plan.pipeline.executionCompleted = true;\n await saveTaskPlan(paths.prdFile, plan);\n }\n } catch {\n // Non-critical — engine already handled state\n }\n }\n\n return exitCode;\n } finally {\n if (standalonePublisher !== null) {\n const success = exitCode === 0;\n standalonePublisher.publish({\n type: 'phase:end',\n at: isoNow(),\n phase: 'execute',\n success,\n ...(success ? {} : { error: 'Execute phase failed' }),\n });\n standalonePublisher.publish({\n type: 'session:end',\n at: isoNow(),\n status: success ? 'completed' : 'failed',\n });\n await standalonePublisher.close();\n setSessionPublisher(undefined);\n }\n }\n}\n","import { existsSync } from 'node:fs';\nimport { cp, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { resolveAgentFor } from '../agents/resolve.js';\nimport { getActiveResilienceConfig, loadGlobalConfig } from '../config.js';\nimport { archiveFolderName, type ChangeType, commitMessage } from '../conventions/git/index.js';\nimport { resolvePolicyPlaceholders } from '../policy/placeholders.js';\nimport { classify } from '../resilience/errors.js';\nimport type { RetryPolicy } from '../resilience/policy.js';\nimport { resolvePolicy } from '../resilience/policy.js';\nimport { fixedBackoffPolicy, withRetry } from '../resilience/retry.js';\nimport type { ClaudeResult, EngineConfig, ResolvedPaths, TaskPlan, UserStory } from '../types.js';\nimport { printError, printInfo, printRetry, printSuccess, printWarning } from '../ui/logger.js';\nimport { printIterationHeader } from '../ui/progress.js';\nimport { printStartupHeader, printSummaryBox } from '../ui/summary.js';\nimport { committedStoryIds, getBaseBranch, isWorkingTreeClean } from '../utils/git.js';\nimport { applyAcceptanceToPlan, resolveIssueDir, runAcceptanceGate } from '../verify/gate.js';\nimport { executeClaude } from './executor.js';\nimport { divideUsage } from './metrics.js';\nimport { applyPlaceholders, loadPrompt } from './prompt-resolver.js';\nimport {\n EXECUTE_PHASE,\n elapsedSecondsSince,\n getPhaseUsageTotals,\n publishIterationMetrics,\n publishStoryMetrics,\n} from './session-metrics.js';\nimport { getSessionPublisher } from './session-publisher.js';\nimport { getShutdownSignal } from './shutdown.js';\nimport {\n allStoriesPass,\n applyStoryMetrics,\n clearLastError,\n hasPendingCorrection,\n initializeState,\n isoNow,\n loadTaskPlan,\n markIssueCompleted,\n markIssueInProgress,\n saveTaskPlan,\n selectActiveStory,\n setLastError,\n trimErrorMessage,\n} from './state-manager.js';\nimport {\n getInactivityTimeout,\n getOutputCallback,\n getStoryStageCallback,\n getStoryUpdateCallback,\n isVerbose,\n} from './verbose.js';\n\n/**\n * Emit a message through the output callback if available, otherwise console.log.\n * Used for bare console.log calls in engine functions so they route through listr2.\n */\nfunction emitLog(message: string): void {\n const cb = getOutputCallback();\n if (cb) {\n // Skip empty lines in listr2 context — they don't render meaningfully\n if (message) {\n cb(message);\n }\n } else {\n console.log(message);\n }\n}\n\n/** What one pass of the execute loop produces, retry or not. */\ninterface ExecuteAttempt {\n result: ClaudeResult;\n /** When the attempt started, for `clearLastError`. */\n startedAt: string;\n /** How long the attempt took, for the metrics split across stories. */\n seconds: number;\n /** The stories as they were before the agent ran, for attribution. */\n storiesBefore: UserStory[];\n}\n\n/**\n * The execute loop's retry budget, unchanged in effect from the hand-rolled\n * loop it replaces: `retryLimit` counts *retries*, so the attempt budget is one\n * more than it, and `retryForever` lifts the count while `backoffMaxSeconds`\n * still caps the wait.\n */\nfunction executeRetryPolicy(config: EngineConfig): RetryPolicy {\n return fixedBackoffPolicy(\n config.retryLimit + 1,\n config.backoffBaseSeconds,\n config.backoffMaxSeconds,\n { retryForever: config.retryForever },\n );\n}\n\n/**\n * Ids of the stories that flipped from `passes: false` to `passes: true`\n * between the two readings of the plan taken around one execute iteration.\n *\n * Stories already passing before the iteration, and stories that only exist in\n * the newer plan, are never attributed: nothing says this iteration paid for\n * them.\n */\nfunction newlyCompletedStoryIds(before: UserStory[], after: UserStory[]): string[] {\n const wasPassing = new Map(before.map((story) => [story.id, story.passes]));\n return after\n .filter((story) => story.passes && wasPassing.get(story.id) === false)\n .map((story) => story.id);\n}\n\nexport interface CommitPlaceholderOptions {\n issueNumber?: string | number | null;\n signoff?: boolean;\n type?: ChangeType;\n}\n\nfunction numericIssue(value: string | number | null | undefined): number | undefined {\n if (value === undefined || value === null || value === '') return undefined;\n const parsed = typeof value === 'number' ? value : Number(value);\n return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;\n}\n\n/**\n * Commit message formats handed to the execute prompt.\n *\n * Built by `commitMessage()` so Conventional Commits is the default even when\n * the repository declared nothing. A scope is the issue id of a queue, which\n * is what makes `git log` on the shared branch readable per issue.\n */\nexport function commitPlaceholders(\n scope?: string,\n convention?: string | null,\n options?: CommitPlaceholderOptions,\n): Record<string, string> {\n const declared = convention !== undefined && convention !== null && convention !== '';\n const type = options?.type ?? 'feat';\n const issueNumber = numericIssue(options?.issueNumber);\n const resolvedScope = scope === undefined || scope === '' ? undefined : scope;\n\n if (declared && options?.type === undefined) {\n const suffix = resolvedScope === undefined ? '' : `(${resolvedScope})`;\n return {\n __COMMIT_MESSAGE__: commitMessage({\n type,\n scope: resolvedScope,\n subject: '[Story ID] - [Story Title]',\n issueNumber,\n signoff: options?.signoff,\n }).replace(`${type}${suffix}:`, `<type>${suffix}:`),\n __FIX_COMMIT_MESSAGE__: commitMessage({\n type: 'fix',\n scope: resolvedScope,\n subject: 'address review findings',\n issueNumber,\n signoff: options?.signoff,\n }),\n };\n }\n\n return {\n __COMMIT_MESSAGE__: commitMessage({\n type,\n scope: resolvedScope,\n subject: '[Story ID] - [Story Title]',\n issueNumber,\n signoff: options?.signoff,\n }),\n __FIX_COMMIT_MESSAGE__: commitMessage({\n type: 'fix',\n scope: resolvedScope,\n subject: 'address review findings',\n issueNumber,\n signoff: options?.signoff,\n }),\n };\n}\n\n/**\n * The watchdog budget of one iteration, from the process-wide setting.\n *\n * Absent means the default; `0` turns the watchdog off. Reading it here rather\n * than threading it through the engine's config keeps it a single value per\n * process, which is what it is.\n */\nfunction inactivityOptions(): { inactivityTimeoutMs?: number } {\n const configured = getInactivityTimeout();\n return configured === undefined ? {} : { inactivityTimeoutMs: configured };\n}\n\n/**\n * Mark as passing every pending story whose commit is already on the branch.\n *\n * Two conditions, and both are required:\n *\n * - the story's id appears in a commit subject of this branch, which is what\n * the execute prompt writes (`<type>(scope): US-001 - Title`);\n * - the working tree is **clean**, so nothing is half-applied. A dirty tree\n * means work in flight, and adopting a story on that basis would call\n * finished something that is not.\n *\n * Returns the ids it adopted. Never throws: a git that cannot answer, or a plan\n * that cannot be written, leaves the loop doing exactly what it did before.\n */\nasync function adoptCommittedStories(tasksPath: string): Promise<string[]> {\n try {\n const plan = await loadTaskPlan(tasksPath);\n const pending = plan.userStories.filter((story) => !story.passes);\n if (pending.length === 0) return [];\n\n if (!(await isWorkingTreeClean())) return [];\n\n const committed = await committedStoryIds(await getBaseBranch());\n const adopted = pending.filter((story) => committed.has(story.id)).map((story) => story.id);\n if (adopted.length === 0) return [];\n\n await saveTaskPlan(tasksPath, {\n ...plan,\n userStories: plan.userStories.map((story) =>\n adopted.includes(story.id) ? { ...story, passes: true } : story,\n ),\n });\n return adopted;\n } catch {\n return [];\n }\n}\n\n/**\n * Initialize the progress file if it doesn't exist.\n */\nasync function ensureProgressFile(progressFile: string): Promise<void> {\n if (!existsSync(progressFile)) {\n const content = `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`;\n await writeFile(progressFile, content, 'utf-8');\n }\n}\n\n/**\n * Archive previous run artifacts if the branch has changed.\n */\nasync function archiveIfBranchChanged(plan: TaskPlan, paths: ResolvedPaths): Promise<void> {\n const { lastBranchFile, archiveDir, prdFile, progressFile } = paths;\n\n if (!existsSync(lastBranchFile)) {\n return;\n }\n\n const currentBranch = plan.branchName ?? '';\n let lastBranch = '';\n\n try {\n lastBranch = (await readFile(lastBranchFile, 'utf-8')).trim();\n } catch {\n return;\n }\n\n if (currentBranch && lastBranch && currentBranch !== lastBranch) {\n const dateStr = new Date().toISOString().split('T')[0];\n const folderName = archiveFolderName(lastBranch);\n const archiveFolder = join(archiveDir, `${dateStr}-${folderName}`);\n\n printInfo(`Archiving previous run: ${lastBranch}`);\n await mkdir(archiveFolder, { recursive: true });\n\n if (existsSync(prdFile)) {\n await cp(prdFile, join(archiveFolder, 'tasks.json'));\n }\n if (existsSync(progressFile)) {\n await cp(progressFile, join(archiveFolder, 'progress.txt'));\n }\n\n printInfo(` Archived to: ${archiveFolder}`);\n\n // Reset progress file for new run\n await writeFile(\n progressFile,\n `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`,\n 'utf-8',\n );\n }\n}\n\n/**\n * Write the current branch to the last-branch tracking file.\n */\nasync function trackBranch(plan: TaskPlan, lastBranchFile: string): Promise<void> {\n const branch = plan.branchName ?? '';\n if (branch) {\n await writeFile(lastBranchFile, `${branch}\\n`, 'utf-8');\n }\n}\n\n/**\n * Run the issue-flow engine loop.\n *\n * This replicates the full execution flow:\n * 1. Load and initialize task plan state\n * 2. Check for early exit (already complete)\n * 3. Archive previous run if branch changed\n * 4. Resolve prompt\n * 5. Main loop: iterate, execute Claude, handle results\n * 6. Print summary\n */\nexport async function runEngine(config: EngineConfig, paths: ResolvedPaths): Promise<number> {\n // Load task plan\n if (!existsSync(paths.prdFile)) {\n printError(`PRD file not found at ${paths.prdFile}`);\n if (config.issueNumber) {\n emitLog(`Have you run the resolve-issue skill for issue #${config.issueNumber} first?`);\n }\n return 1;\n }\n\n let plan = await loadTaskPlan(paths.prdFile);\n plan = initializeState(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Check if already completed. A pending correction (a failed review whose\n // findings haven't been addressed yet) always overrides this, even though\n // every userStories[].passes is already true — otherwise a correction\n // cycle's re-run of execute would exit here without ever looking at what\n // the review found.\n if (plan.issueStatus === 'completed' && allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n emitLog(`Issue already marked complete in ${paths.prdFile}`);\n return 0;\n }\n\n // Warn if marked complete but stories still pending\n if (plan.issueStatus === 'completed' && !allStoriesPass(plan)) {\n printWarning(\n 'Issue marked completed but some stories are still pending. Resetting to in_progress.',\n );\n plan = markIssueInProgress(plan);\n plan = setLastError(\n plan,\n 'invalid_completion_state',\n 'tasks.json claimed the issue was completed before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n }\n\n // Check if all stories already pass\n if (allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n emitLog('All user stories already pass. Marking issue as completed.');\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n return finishWithAcceptance(config, paths, plan);\n }\n\n // Archive previous run if branch changed\n await archiveIfBranchChanged(plan, paths);\n\n // Track current branch\n await trackBranch(plan, paths.lastBranchFile);\n\n // Initialize progress file\n await ensureProgressFile(paths.progressFile);\n\n // Load prompt template. The root is handed over rather than rediscovered:\n // it was resolved once by `resolvePaths()`, and a second `git rev-parse` here\n // would be a subprocess per run for an answer already in hand.\n const promptTemplate = await loadPrompt('execute', { projectRoot: paths.projectRoot });\n\n // The repository's own conventions, resolved once for the whole loop: they\n // cannot change mid-run, and every iteration renders the same projection.\n const policy = await resolvePolicyPlaceholders({ root: paths.projectRoot });\n const signoff = (await loadGlobalConfig()).commit?.signoff === true;\n\n const executeAgent = await resolveAgentFor('execute');\n printStartupHeader(config, plan, {\n provider: executeAgent.provider,\n model: executeAgent.model,\n ...(executeAgent.codex.reasoningEffort ? { detail: executeAgent.codex.reasoningEffort } : {}),\n });\n\n const startTime = Date.now();\n let i = 0;\n let totalRetryCount = 0;\n\n // Main loop\n while (true) {\n // Check iteration limit\n if (config.maxIterations !== undefined && i >= config.maxIterations) {\n break;\n }\n\n i++;\n\n // Safety net for the crash between a story's commit and the agent writing\n // `passes: true` (scenario I). The commit is the durable fact; the plan is\n // written after it, so a process that died in between leaves work that is\n // done and a plan that says it is not — and the next iteration redoes it on\n // top of a commit that already exists.\n //\n // This never *replaces* the agent's `passes`, which stays the primary\n // source: it only closes the window the agent cannot close itself.\n const adopted = await adoptCommittedStories(paths.prdFile);\n if (adopted.length > 0) {\n printInfo(\n `Adopting ${adopted.join(', ')}: already committed on this branch with a clean tree.`,\n );\n plan = await loadTaskPlan(paths.prdFile);\n if (plan.userStories.every((story) => story.passes) && plan.lastReviewFindings === null) {\n // Everything the loop was going to do is already done.\n break;\n }\n }\n\n // One iteration is one attempt of the Claude CLI, retried in place by the\n // project's single retry executor (`resilience/retry.ts`). A retry costs no\n // iteration budget, exactly as the `i--` it replaces cost none. Everything a\n // retried attempt has to redo — re-reading the plan, republishing\n // `iteration:start`, re-rendering the prompt — lives inside `attempt`,\n // because the loop this used to be written as re-ran all of it too.\n const attempted = await withRetry<ExecuteAttempt>(\n async () => {\n // Re-read plan to get latest state\n plan = await loadTaskPlan(paths.prdFile);\n // Publish the plan before naming its active story. This covers direct\n // `issue-flow execute` runs and resumes that never pass through the\n // plan runner, while retaining the empty-plan no-op contract.\n if (plan.userStories.length > 0) {\n getSessionPublisher().publish({\n type: 'stories:update',\n at: isoNow(),\n stories: plan.userStories,\n });\n }\n // Baseline for story attribution: whatever was still pending before the\n // agent ran is what this iteration can claim credit for.\n const storiesBefore = plan.userStories;\n\n // Highest-priority story with passes: false — the same rule\n // prompts/execute.md gives the agent. Computed once, here, and shared by\n // the published event and the verbose terminal header, so every surface\n // agrees on who is active instead of each deriving its own heuristic.\n const activeStoryId = selectActiveStory(plan.userStories)?.id;\n getSessionPublisher().publish({\n type: 'iteration:start',\n at: isoNow(),\n iteration: i,\n storyId: activeStoryId,\n });\n getStoryStageCallback()?.(activeStoryId);\n\n if (isVerbose()) {\n printIterationHeader(i, config.maxIterations, plan.userStories, activeStoryId);\n }\n\n // Apply placeholders to prompt\n const prompt = applyPlaceholders(promptTemplate, {\n __PRD_FILE__: paths.prdFile,\n __PROGRESS_FILE__: paths.progressFile,\n ...policy,\n // The convention comes off the projection above rather than from a second\n // discovery: one resolution per run is the whole point of the cache.\n ...commitPlaceholders(config.commitScope, policy.__COMMIT_CONVENTION__, {\n issueNumber: plan.issueNumber,\n signoff,\n }),\n __STORIES_PER_ITERATION__: String(config.storiesPerIteration ?? 1),\n });\n\n const startedAt = isoNow();\n plan = markIssueInProgress(plan, startedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Execute Claude\n const startedAtMs = Date.now();\n const result = await executeClaude(prompt, {\n ...inactivityOptions(),\n iteration: i,\n correctionCycle: plan.correctionCycle,\n ...(activeStoryId === undefined ? {} : { storyIds: [activeStoryId] }),\n });\n const seconds = elapsedSecondsSince(startedAtMs);\n\n if (result.exitCode !== 0) {\n // A failed iteration still burned tokens: report them on the execute\n // phase, with no attribution to any story.\n publishIterationMetrics(i, result.cost, seconds);\n }\n\n return { result, startedAt, seconds, storiesBefore };\n },\n {\n policy: executeRetryPolicy(config),\n // A `Ctrl+C` during a fifteen-minute backoff must stop in that instant,\n // not fifteen minutes later. `abortableDelay` resolves `false` on the\n // abort, which `withRetry` reports as `aborted` rather than a failure.\n signal: getShutdownSignal(),\n // The exit code and the output are all the evidence the CLI leaves\n // behind, which is exactly what `isTransientFailure()` used to be given\n // here — `classify()` is the same verdict plus the kind.\n evaluate: ({ result }) =>\n result.exitCode === 0\n ? null\n : classify({ source: 'agent', exitCode: result.exitCode, stdout: result.output }),\n onAttempt: async ({ value, attempt, failure, willRetry, delayMs }) => {\n if (failure === null) return;\n\n const errorMessage = trimErrorMessage(value.result.output);\n\n if (!failure.retryable) {\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'fatal_claude_failure', errorMessage);\n if (resolvePolicy(failure.kind, getActiveResilienceConfig()).onExhausted === 'block') {\n plan = {\n ...plan,\n runState: {\n currentPhase: 'execute',\n attempt,\n owner: plan.runState?.owner ?? null,\n status: 'blocked',\n blockedReason: errorMessage,\n lastHeartbeatAt: isoNow(),\n },\n };\n }\n await saveTaskPlan(paths.prdFile, plan);\n return;\n }\n\n // Recorded even on the attempt that spends the last of the budget:\n // the run ends on a transient failure, and the plan has to say so.\n totalRetryCount++;\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'transient_claude_failure', errorMessage);\n await saveTaskPlan(paths.prdFile, plan);\n if (!willRetry) return;\n\n const delaySeconds = delayMs / 1000;\n getSessionPublisher().publish({\n type: 'retry',\n at: isoNow(),\n attempt,\n delaySeconds,\n reason: 'transient_claude_failure',\n kind: failure.kind,\n });\n\n if (isVerbose()) {\n emitLog('');\n }\n printRetry(\n `Transient Claude failure on iteration ${i} (attempt ${attempt}). Retrying in ${delaySeconds}s.`,\n );\n },\n },\n );\n\n const {\n result,\n seconds: iterationSeconds,\n storiesBefore: storiesBeforeIteration,\n } = attempted.value;\n const iterationStartedAt = attempted.value.startedAt;\n\n if (result.exitCode !== 0) {\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'failed',\n i,\n totalRetryCount,\n elapsed,\n plan,\n attempted.exhausted\n ? `Exceeded retry limit (${config.retryLimit}) on transient errors`\n : `Claude CLI failed with exit code ${result.exitCode}`,\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return result.exitCode;\n }\n\n plan = await loadTaskPlan(paths.prdFile);\n plan = clearLastError(plan, iterationStartedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Notify story progress listeners (e.g., listr2 subtasks)\n const storyUpdateCb = getStoryUpdateCallback();\n if (storyUpdateCb) {\n storyUpdateCb(plan.userStories);\n }\n getSessionPublisher().publish({\n type: 'stories:update',\n at: isoNow(),\n stories: plan.userStories,\n });\n\n // Story attribution — an approximation by construction: the CLI reports a\n // single usage for the whole iteration, so the stories that flipped to\n // passing in it split tokens, cost and duration evenly. With none, nothing\n // is attributed and the whole cost stays on the execute phase. Published\n // after stories:update, which rebuilds the stories array.\n const completedStoryIds = newlyCompletedStoryIds(storiesBeforeIteration, plan.userStories);\n if (completedStoryIds.length > 0) {\n const storyShare = divideUsage(result.cost, completedStoryIds.length);\n const storySeconds = Math.round(iterationSeconds / completedStoryIds.length);\n for (const storyId of completedStoryIds) {\n publishStoryMetrics(storyId, storyShare, storySeconds);\n }\n\n // The same shares also land on tasks.json, so the numbers outlive the\n // session and are readable with web monitoring off. Persisting them is\n // observational: a write failure must never change the iteration's\n // outcome, so the plan in memory only advances when the write succeeded.\n const planWithMetrics = applyStoryMetrics(plan, completedStoryIds, storyShare, storySeconds);\n try {\n await saveTaskPlan(paths.prdFile, planWithMetrics);\n plan = planWithMetrics;\n } catch {\n // Metrics are a nice-to-have; the iteration succeeded regardless.\n }\n }\n\n getSessionPublisher().publish({ type: 'iteration:end', at: isoNow(), iteration: i });\n publishIterationMetrics(i, result.cost, iterationSeconds);\n\n // Check for completion signal\n if (result.output.includes('<promise>COMPLETE</promise>')) {\n plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan) && !hasPendingCorrection(plan)) {\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n printSummaryBox(\n 'success',\n i,\n totalRetryCount,\n elapsed,\n plan,\n undefined,\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return finishWithAcceptance(config, paths, plan);\n }\n\n plan = setLastError(\n plan,\n 'invalid_completion_signal',\n hasPendingCorrection(plan)\n ? 'Claude returned <promise>COMPLETE</promise> while lastReviewFindings was still set.'\n : 'Claude returned <promise>COMPLETE</promise> before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n\n emitLog('');\n printWarning(\n hasPendingCorrection(plan)\n ? 'Claude returned a completion signal, but lastReviewFindings is still set. Ignoring completion and continuing.'\n : 'Claude returned a completion signal, but tasks.json still has pending stories. Ignoring completion and continuing.',\n );\n }\n\n if (isVerbose()) {\n printSuccess(`Iteration ${i} complete. Continuing...`);\n }\n }\n\n // Reached max iterations\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'incomplete',\n config.maxIterations ?? i,\n totalRetryCount,\n elapsed,\n plan,\n 'Reached max iterations without completing all tasks.',\n getPhaseUsageTotals(EXECUTE_PHASE),\n );\n return 1;\n}\n\nasync function finishWithAcceptance(\n config: EngineConfig,\n paths: ResolvedPaths,\n plan: TaskPlan,\n): Promise<number> {\n const issueDir = resolveIssueDir(config, paths);\n const outcome = await runAcceptanceGate({\n issueDir,\n cwd: paths.projectRoot,\n addDirs: config.issueNumber === undefined ? undefined : [issueDir],\n skipReviewer: true,\n });\n const applied = applyAcceptanceToPlan(plan, outcome);\n if (applied.failed) {\n await saveTaskPlan(paths.prdFile, applied.plan);\n return 1;\n }\n return 0;\n}\n","import chalk from 'chalk';\nimport { getOutputCallback } from '../core/verbose.js';\nimport type { UserStory } from '../types.js';\nimport { getIcons, useColor, useUnicode } from './logger.js';\n\n/**\n * Print a visual progress bar showing passed/total stories.\n */\nexport function printProgressBar(passed: number, total: number): string {\n const barWidth = 20;\n let pct = 0;\n let filled = 0;\n\n if (total > 0) {\n pct = Math.floor((passed * 100) / total);\n filled = Math.floor((passed * barWidth) / total);\n }\n\n const empty = barWidth - filled;\n const fillChar = useUnicode() ? '\\u2588' : '#';\n const emptyChar = useUnicode() ? '\\u2591' : '-';\n\n const bar = fillChar.repeat(filled) + emptyChar.repeat(empty);\n const text = `${passed}/${total} (${pct}%)`;\n\n if (useColor()) {\n return `${chalk.green(bar)} ${text}`;\n }\n return `${bar} ${text}`;\n}\n\n/**\n * Print the iteration header showing story statuses and progress bar.\n *\n * When a global output callback is set (e.g., inside a listr2 task),\n * output is routed through it instead of console.log.\n *\n * `activeStoryId`, when provided, identifies the story the engine is\n * actually about to work on this iteration (the same id published on\n * `iteration:start` \\u2014 see `core/state-manager.ts`'s `selectActiveStory`),\n * so the header agrees with the session snapshot instead of guessing.\n * Omitted, it falls back to the previous heuristic (\"first non-passing story\n * in array order\"), which existing callers that cannot supply the real id\n * keep relying on.\n */\nexport function printIterationHeader(\n iteration: number,\n maxIter: number | undefined,\n stories: UserStory[],\n activeStoryId?: string,\n): void {\n const icons = getIcons();\n const colored = useColor();\n const cb = getOutputCallback();\n\n const iterLabel = maxIter ? `Iteration ${iteration} of ${maxIter}` : `Iteration ${iteration}`;\n\n const total = stories.length;\n const passed = stories.filter((s) => s.passes).length;\n\n const lines: string[] = [];\n\n if (colored) {\n lines.push(chalk.blue(`\\u2501\\u2501\\u2501 ${icons.start} ${iterLabel} \\u2501\\u2501\\u2501`));\n } else {\n lines.push(`--- ${icons.start} ${iterLabel} ---`);\n }\n\n // Display each story status\n let foundFirstPending = false;\n for (const story of stories) {\n let icon: string;\n let colorFn: (s: string) => string;\n const isActive =\n activeStoryId !== undefined\n ? story.id === activeStoryId\n : !story.passes && !foundFirstPending;\n\n if (story.passes) {\n icon = icons.success;\n colorFn = colored ? chalk.green : (s: string) => s;\n } else if (isActive) {\n icon = icons.pending;\n colorFn = colored ? chalk.yellow : (s: string) => s;\n foundFirstPending = true;\n } else {\n // Not yet reached\n icon = icons.notReached;\n colorFn = colored ? chalk.gray : (s: string) => s;\n }\n\n lines.push(colorFn(` ${icon} ${story.id}: ${story.title}`));\n }\n\n lines.push(` ${printProgressBar(passed, total)}`);\n\n if (cb) {\n // Send as single output to listr2 task context\n cb(lines.join('\\n'));\n } else {\n console.log('');\n for (const line of lines) {\n console.log(line);\n }\n console.log('');\n }\n}\n","import chalk from 'chalk';\nimport { type ClaudeUsage, formatTokens } from '../core/metrics.js';\nimport { groupBy, summarize } from '../telemetry/aggregate.js';\nimport type { EngineConfig, PrReviewRecommendation, TaskPlan } from '../types.js';\nimport {\n formatDuration,\n getIcons,\n getTermWidth,\n printSuccess,\n printWarning,\n useColor,\n useUnicode,\n} from './logger.js';\n\n/**\n * Truncate or pad a string to fit within a given width.\n */\nfunction fitLine(text: string, width: number): string {\n if (text.length > width) {\n return text.substring(0, width);\n }\n return text.padEnd(width);\n}\n\n/**\n * Print a box with border characters around content lines.\n * Lines equal to \"---\" render as separator rows.\n */\nexport function printBox(lines: string[]): void {\n const colored = useColor();\n const unicode = useUnicode();\n const termWidth = getTermWidth();\n\n // Find max content width\n let maxContentWidth = 0;\n for (const line of lines) {\n if (line !== '---' && line.length > maxContentWidth) {\n maxContentWidth = line.length;\n }\n }\n\n // Cap to terminal width (border + padding = 4 chars)\n const available = termWidth - 4;\n if (maxContentWidth > available) {\n maxContentWidth = available;\n }\n if (maxContentWidth < 20) {\n maxContentWidth = 20;\n }\n\n // Box drawing characters\n const tl = unicode ? '\\u256D' : '+';\n const tr = unicode ? '\\u256E' : '+';\n const bl = unicode ? '\\u2570' : '+';\n const br = unicode ? '\\u256F' : '+';\n const h = unicode ? '\\u2500' : '-';\n const v = unicode ? '\\u2502' : '|';\n const sepL = unicode ? '\\u251C' : '+';\n const sepR = unicode ? '\\u2524' : '+';\n\n const hrule = h.repeat(maxContentWidth + 2);\n\n const blue = colored ? chalk.blue : (s: string) => s;\n const _reset = (s: string) => s;\n\n // Top border\n console.log(blue(`${tl}${hrule}${tr}`));\n\n // Content lines\n for (const line of lines) {\n if (line === '---') {\n console.log(blue(`${sepL}${hrule}${sepR}`));\n } else {\n const fitted = fitLine(line, maxContentWidth);\n console.log(`${blue(v)} ${fitted} ${blue(v)}`);\n }\n }\n\n // Bottom border\n console.log(blue(`${bl}${hrule}${br}`));\n}\n\n/**\n * Print the startup header box showing engine configuration.\n */\nexport interface StartupAgentInfo {\n provider: string;\n model?: string | null;\n detail?: string;\n}\n\nexport function printStartupHeader(\n config: EngineConfig,\n plan: TaskPlan,\n agent?: StartupAgentInfo,\n): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const branchName = plan.branchName ?? 'N/A';\n\n const issueLabel = config.issueNumber ? `Issue #${config.issueNumber}` : 'Standalone mode';\n\n const maxIterLabel =\n config.maxIterations !== undefined ? String(config.maxIterations) : 'unlimited';\n\n const retryLabel = config.retryForever\n ? 'unlimited retries'\n : `${config.retryLimit} consecutive retries`;\n\n const lines = [\n `${icons.start} Issue Flow`,\n '---',\n `Issue: ${issueLabel}`,\n `Branch: ${branchName}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${maxIterLabel}`,\n `Retries: ${retryLabel}`,\n ];\n const remaining = storiesTotal - storiesPassing;\n if (remaining > 0) {\n // p50 of execute on the #79 baseline (US-009/US-010 mean, single observation).\n const p50ExecuteSeconds = 518;\n lines.push(\n `Estimate: ~${formatDuration(remaining * p50ExecuteSeconds)} (${remaining} × p50 execute)`,\n );\n }\n if (agent) {\n const model = agent.model ? ` · ${agent.model}` : '';\n const detail = agent.detail ? ` (${agent.detail})` : '';\n lines.push(`Agent: ${agent.provider}${model}${detail}`);\n }\n printBox(lines);\n}\n\n/**\n * Print the final summary box.\n */\nexport function printSummaryBox(\n status: 'success' | 'incomplete' | 'failed',\n iterations: number,\n totalRetries: number,\n elapsedSeconds: number,\n plan: TaskPlan,\n extraInfo?: string,\n /**\n * Tokens and cost spent by this run, already resolved by the caller (the\n * process-owned counters in `core/session-metrics.ts`, never the session\n * snapshot — that one is empty whenever web monitoring is off). Omitted or\n * empty means \"the CLI reported nothing\", and the line is skipped entirely.\n */\n usage?: ClaudeUsage | null,\n usageByAgent?: Record<string, ClaudeUsage>,\n): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const duration = formatDuration(elapsedSeconds);\n\n let statusIcon: string;\n let statusLabel: string;\n\n switch (status) {\n case 'success':\n statusIcon = icons.success;\n statusLabel = 'Completed';\n break;\n case 'incomplete':\n statusIcon = icons.warn;\n statusLabel = 'Incomplete';\n break;\n case 'failed':\n statusIcon = icons.fail;\n statusLabel = 'Failed';\n break;\n }\n\n const boxLines = [\n `${icons.end} Issue Flow Summary`,\n '---',\n `Status: ${statusIcon} ${statusLabel}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${iterations}`,\n `Duration: ${duration}`,\n ];\n\n boxLines.push(...tokenBoxLines(usage, usageByAgent));\n boxLines.push(...executionCostLines(plan));\n\n boxLines.push(`Retries: ${totalRetries}`);\n\n if (extraInfo) {\n boxLines.push('---');\n boxLines.push(extraInfo);\n }\n\n console.log('');\n printBox(boxLines);\n}\n\n/**\n * What the optional `pr-review` phase produced, as far as the summary cares.\n * `null` in `recommendation` means the verdict could not be recovered from\n * disk — the exit code still told us whether changes were requested.\n */\nexport interface RunSummaryPrReview {\n requestedChanges: boolean;\n recommendation: PrReviewRecommendation | null;\n reportPath: string | null;\n}\n\n/**\n * Everything the final `run` summary prints, already resolved by the caller.\n */\nexport interface RunSummaryInfo {\n issueNumber: string;\n /** 'unknown' when the branch could not be detected. */\n branchName: string;\n /** Pipelines run with --no-branch open no Pull Request. */\n noBranch: boolean;\n storyCount: number;\n elapsedSeconds: number;\n /** 'unknown' when no Pull Request could be resolved. */\n prUrl: string;\n /** Only set when the pr-review phase actually ran. */\n prReview?: RunSummaryPrReview | null;\n /**\n * Tokens and cost of the whole pipeline, from the process-owned counters in\n * `core/session-metrics.ts`. Absent or empty omits the line.\n */\n usage?: ClaudeUsage | null;\n /** When more than one agent ran, the summary prints one Tokens line each. */\n usageByAgent?: Record<string, ClaudeUsage>;\n /** Acceptance-contract verdict. Absent when the contract never ran. */\n verification?: { verdict: 'passed' | 'failed' | 'unverified'; level?: string | null } | null;\n}\n\nfunction executionCostLines(plan: TaskPlan, prefix = 'Cost: '): string[] {\n const records = plan.executions ?? [];\n if (records.length === 0) return [];\n const lines: string[] = [];\n const groups = groupBy(records, 'harness');\n let index = 0;\n const pad = ' '.repeat(prefix.length);\n for (const [harness, summary] of groups) {\n const parts: string[] = [];\n if (summary.totalCost.reported > 0) {\n parts.push(`$${summary.totalCost.reported.toFixed(4)} reported`);\n }\n if (summary.totalCost.estimated > 0) {\n parts.push(`$${summary.totalCost.estimated.toFixed(4)} estimated`);\n }\n if (summary.totalCost.unknownExecutions > 0) {\n parts.push(`${summary.totalCost.unknownExecutions} unknown`);\n }\n if (parts.length === 0) {\n const totals = summarize(records).totalCost;\n if (totals.reported === 0 && totals.estimated === 0) {\n parts.push('not reported');\n }\n }\n if (parts.length === 0) continue;\n lines.push(`${index === 0 ? prefix : pad}${harness} · ${parts.join(' · ')}`);\n index += 1;\n }\n return lines;\n}\n\nfunction tokenBoxLines(\n usage?: ClaudeUsage | null,\n usageByAgent?: Record<string, ClaudeUsage>,\n): string[] {\n const agents = usageByAgent ? Object.keys(usageByAgent) : [];\n if (agents.length > 1) {\n const lines: string[] = [];\n for (const [index, id] of agents.entries()) {\n const tokens = formatTokens(usageByAgent?.[id]);\n if (tokens === '') continue;\n lines.push(index === 0 ? `Tokens: ${id} · ${tokens}` : ` ${id} · ${tokens}`);\n }\n return lines;\n }\n const tokens = formatTokens(usage);\n return tokens === '' ? [] : [`Tokens: ${tokens}`];\n}\n\nfunction tokenSummaryLines(\n usage?: ClaudeUsage | null,\n usageByAgent?: Record<string, ClaudeUsage>,\n prefix = ' Tokens: ',\n): string[] {\n const agents = usageByAgent ? Object.keys(usageByAgent) : [];\n if (agents.length > 1) {\n const pad = ' '.repeat(prefix.length);\n const lines: string[] = [];\n for (const [index, id] of agents.entries()) {\n const tokens = formatTokens(usageByAgent?.[id]);\n if (tokens === '') continue;\n lines.push(`${index === 0 ? prefix : pad}${id} · ${tokens}`);\n }\n return lines;\n }\n const tokens = formatTokens(usage);\n return tokens === '' ? [] : [`${prefix}${tokens}`];\n}\n\n/**\n * Detail lines of the final `run` summary (everything below the headline).\n *\n * Kept separate from the printing so the shape is testable without capturing\n * stdout. Without `prReview` the lines are exactly the ones the pipeline has\n * always printed.\n */\nexport function buildRunSummaryLines(info: RunSummaryInfo): string[] {\n const lines = [\n ` Branch: ${info.branchName}${info.noBranch ? ' (current)' : ''}`,\n ` Stories: ${info.storyCount}`,\n ` Duration: ${formatDuration(info.elapsedSeconds)}`,\n ];\n\n lines.push(...tokenSummaryLines(info.usage, info.usageByAgent));\n\n if (!info.noBranch) {\n lines.push(` PR: ${info.prUrl}`);\n }\n\n if (info.verification != null) {\n const label =\n info.verification.verdict === 'passed'\n ? 'passed'\n : info.verification.verdict === 'failed'\n ? 'failed'\n : 'unverified';\n lines.push(` Contract: ${label}`);\n }\n\n const review = info.prReview;\n if (review) {\n // The exit code is the source of truth for the verdict, so a report whose\n // recommendation could not be read still reports REQUEST_CHANGES.\n const verdict =\n review.recommendation ?? (review.requestedChanges ? 'REQUEST_CHANGES' : 'unknown');\n lines.push(` Review: ${verdict}`);\n if (review.reportPath !== null) {\n lines.push(` Report: ${review.reportPath}`);\n }\n }\n\n return lines;\n}\n\n/** One issue of a multi-issue queue, as the consolidated summary reports it. */\nexport interface QueueIssueSummary {\n id: string;\n title: string;\n storyCount: number;\n elapsedSeconds: number;\n /** Tokens and cost of this issue alone — never of the whole queue. */\n usage?: ClaudeUsage | null;\n}\n\n/** Everything the consolidated summary of a queue prints. */\nexport interface QueueSummaryInfo {\n /** Identifier of the queue, i.e. of its primary issue. */\n queueId: string;\n /** Branch every issue shared, `null` when the queue ran with --no-branch. */\n branchName: string | null;\n issues: QueueIssueSummary[];\n /** Issues discovered but left out of the run. */\n excluded: { id: string; title: string }[];\n elapsedSeconds: number;\n /** The single consolidated Pull Request, `null` when none was opened. */\n prUrl: string | null;\n /** Tokens and cost of the whole queue. */\n usage?: ClaudeUsage | null;\n /** Verdict of the pr-review phase, when the queue ran it. */\n prReview?: RunSummaryPrReview | null;\n}\n\n/**\n * Detail lines of a queue's final summary.\n *\n * Per-issue lines carry their own duration and cost, which is the visible half\n * of the per-issue metric scoping: what one issue spent is never folded into\n * another's line.\n */\nexport function buildQueueSummaryLines(info: QueueSummaryInfo): string[] {\n const lines: string[] = [];\n\n lines.push(` Branch: ${info.branchName ?? 'current'}`);\n lines.push(` Issues: ${info.issues.length}`);\n\n for (const issue of info.issues) {\n const tokens = formatTokens(issue.usage);\n const title = issue.title === '' ? '' : ` ${issue.title}`;\n lines.push(\n ` #${issue.id}${title} — ${issue.storyCount} stories, ${formatDuration(issue.elapsedSeconds)}` +\n (tokens === '' ? '' : `, ${tokens}`),\n );\n }\n\n lines.push(` Duration: ${formatDuration(info.elapsedSeconds)}`);\n\n const tokens = formatTokens(info.usage);\n if (tokens !== '') {\n lines.push(` Tokens: ${tokens}`);\n }\n if (info.prUrl !== null) {\n lines.push(` PR: ${info.prUrl}`);\n }\n if (info.excluded.length > 0) {\n lines.push(` Skipped: ${info.excluded.map((entry) => `#${entry.id}`).join(', ')}`);\n }\n\n const review = info.prReview;\n if (review) {\n lines.push(\n ` Review: ${review.recommendation ?? (review.requestedChanges ? 'REQUEST_CHANGES' : 'unknown')}`,\n );\n if (review.reportPath !== null) {\n lines.push(` Report: ${review.reportPath}`);\n }\n }\n\n return lines;\n}\n\n/** Print the consolidated summary of a multi-issue queue. */\nexport function printQueueSummary(info: QueueSummaryInfo): void {\n console.log('');\n if (info.prReview?.requestedChanges === true) {\n printWarning(`Queue finished for issue #${info.queueId}, but the PR review requested changes.`);\n } else {\n printSuccess(`Queue complete for issue #${info.queueId} (${info.issues.length} issues)!`);\n }\n for (const line of buildQueueSummaryLines(info)) {\n console.log(line);\n }\n}\n\n/**\n * Print the final summary of a `run` (the flat listing, not the box used by\n * the execute engine).\n */\nexport function printRunSummary(info: RunSummaryInfo): void {\n console.log('');\n if (info.prReview?.requestedChanges) {\n printWarning(\n `Pipeline finished for issue #${info.issueNumber}, but the PR review requested changes.`,\n );\n } else if (info.verification?.verdict === 'unverified') {\n printWarning(\n `Pipeline finished for issue #${info.issueNumber}, but the acceptance contract is unverified.`,\n );\n } else if (info.verification?.verdict === 'failed') {\n printWarning(\n `Pipeline finished for issue #${info.issueNumber}, but the acceptance contract failed.`,\n );\n } else {\n printSuccess(`Pipeline complete for issue #${info.issueNumber}!`);\n }\n for (const line of buildRunSummaryLines(info)) {\n console.log(line);\n }\n}\n","/**\n * Strip the markdown markers that leak into a terminal that cannot render them.\n *\n * Used by the clean view and by failure excerpts. Verbose mode keeps the\n * original text — this is only for the default surface.\n */\nexport function stripMarkdown(text: string): string {\n return text\n .replace(/```[\\s\\S]*?```/g, ' ')\n .replace(/`([^`]+)`/g, '$1')\n .replace(/\\*\\*([^*]+)\\*\\*/g, '$1')\n .replace(/__([^_]+)__/g, '$1')\n .replace(/(?<!\\*)\\*([^*]+)\\*(?!\\*)/g, '$1')\n .replace(/^#{1,6}\\s+/gm, '')\n .replace(/^\\s*[-*+]\\s+/gm, '')\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n .replace(/[ \\t]{2,}/g, ' ')\n .trim();\n}\n\n/** Last non-empty lines of a failure report, already stripped of markdown. */\nexport function failureExcerpt(output: string, limit = 8): string[] {\n return output\n .split('\\n')\n .map((line) => stripMarkdown(line))\n .filter((line) => line.length > 0)\n .slice(-limit);\n}\n","import { invokeSelectedAgent } from '../agents/invoke.js';\nimport type { ClaudeResult } from '../types.js';\nimport { failureExcerpt } from '../ui/text.js';\nimport { getOutputCallback, isVerbose } from './verbose.js';\n\nexport interface ExecuteClaudeOptions {\n /**\n * Silence tolerated before the agent is considered stuck. `0` disables the\n * watchdog, which is the behaviour every release before it had.\n */\n inactivityTimeoutMs?: number;\n iteration?: number;\n correctionCycle?: number;\n storyIds?: string[];\n}\n\n/**\n * Execute the resolved agent with a prompt piped to stdin.\n *\n * The default (Claude, unconfigured) is still\n * `claude --dangerously-skip-permissions --print --output-format stream-json --verbose`\n * with the prompt on stdin and `timeout: 0`. Callers see `exitCode`, the\n * assistant text as `output`, and usage. On failure the raw diagnostics stay\n * unwrapped so `isTransientFailure()` can read them.\n */\nexport async function executeClaude(\n prompt: string,\n options: ExecuteClaudeOptions = {},\n): Promise<ClaudeResult> {\n let selected: Awaited<ReturnType<typeof invokeSelectedAgent>>;\n try {\n selected = await invokeSelectedAgent({\n prompt,\n phase: 'execute',\n timeout: 0,\n permission: 'autonomous',\n inactivityTimeoutMs: options.inactivityTimeoutMs,\n iteration: options.iteration,\n correctionCycle: options.correctionCycle,\n storyIds: options.storyIds,\n });\n } catch (err) {\n return {\n exitCode: 1,\n output: err instanceof Error ? err.message : String(err),\n cost: null,\n };\n }\n const { run } = selected;\n\n let output: string;\n let cost = run.usage;\n\n if (!run.success || run.exitCode !== 0) {\n output = run.rawOutput || run.error || '';\n cost = null;\n } else {\n output = run.result || run.rawOutput;\n }\n\n emitAgentOutput(output, !(run.success && run.exitCode === 0));\n\n return {\n exitCode: run.exitCode === 0 && run.success ? 0 : run.exitCode === 0 ? 1 : run.exitCode,\n output,\n cost,\n };\n}\n\n/**\n * Clean mode never dumps the agent report. Verbose breaks it line by line.\n * A failure always prints a short excerpt — the user should not need\n * `--verbose` to see why a story stopped.\n */\nfunction emitAgentOutput(output: string, failed: boolean): void {\n const onOutput = getOutputCallback();\n if (!onOutput) return;\n const trimmed = output.trim();\n if (!trimmed) return;\n\n if (isVerbose()) {\n for (const line of trimmed.split('\\n')) {\n if (line.trim()) onOutput(line);\n }\n return;\n }\n\n if (failed) {\n for (const line of failureExcerpt(trimmed)) {\n onOutput(line);\n }\n }\n}\n"],"mappings":"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","names":["chalk","chalk","tokens","result","elapsed","numericIssue"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/conventions/git/types.ts","../src/conventions/git/slug.ts","../src/conventions/git/branch.ts","../src/conventions/git/change-type.ts","../src/conventions/git/commit.ts","../src/conventions/git/pull-request.ts","../src/policy/resolve.ts","../src/policy/discovery.ts","../src/policy/parsers/docs.ts","../src/policy/parsers/git.ts","../src/policy/parsers/labels.ts","../src/policy/parsers/templates.ts","../src/policy/parsers/issue-forms.ts","../src/policy/types.ts"],"sourcesContent":["/**\n * Canonical Git convention types. No function in this directory accepts a\n * provider, agent or model — that leakage is unrepresentable here.\n */\n\n/** Conventional-commit vocabulary shared by branch, commit and PR title. */\nexport const CHANGE_TYPES = [\n 'feat',\n 'fix',\n 'docs',\n 'refactor',\n 'perf',\n 'test',\n 'build',\n 'ci',\n 'chore',\n 'style',\n 'revert',\n] as const;\n\nexport type ChangeType = (typeof CHANGE_TYPES)[number];\n\n/** Types that may prefix a branch. `style` and `revert` are commit-only. */\nexport const BRANCH_CHANGE_TYPES = [\n 'feat',\n 'fix',\n 'docs',\n 'refactor',\n 'perf',\n 'test',\n 'build',\n 'ci',\n 'chore',\n] as const;\n\nexport type BranchChangeType = (typeof BRANCH_CHANGE_TYPES)[number];\n\n/** Where {@link resolveChangeType} took the type from. */\nexport type ChangeTypeSource = 'declared' | 'issue-type' | 'label' | 'title' | 'fallback';\n\nexport const DEFAULT_BRANCH_CONVENTION = '{type}/{N}-{slug}';\n\nexport const DEFAULT_COMMIT_PATTERN = '<type>(<scope>): <subject>';\n\nexport const DEFAULT_PR_TITLE_PATTERN = '<type>(<scope>): <subject>';\n\nexport const SLUG_MAX_LENGTH = 40;\n\nexport const BRANCH_MAX_LENGTH = 60;\n\n/** Default label → type map. Overridable via `policy.git.typeMap`. */\nexport const DEFAULT_LABEL_TYPE_MAP: Readonly<Record<string, ChangeType>> = {\n bug: 'fix',\n documentation: 'docs',\n docs: 'docs',\n refactor: 'refactor',\n 'tech-debt': 'refactor',\n infra: 'ci',\n 'ci-cd': 'ci',\n enhancement: 'feat',\n architecture: 'feat',\n investigation: 'chore',\n};\n\nexport const FORBIDDEN_PROVIDER_NAMES = ['claude', 'codex', 'cursor', 'antigravity'] as const;\n\nexport interface ChangeTypeInput {\n issueType?: string | null;\n labels?: readonly string[];\n title?: string;\n titleConvention?: string | null;\n typeMap?: Readonly<Record<string, string>> | null;\n /** Explicit type from a declared convention that already pins one. */\n declaredType?: ChangeType | null;\n}\n\nexport interface ChangeTypeResult {\n type: ChangeType;\n source: ChangeTypeSource;\n /** Set when Issue Type and labels disagree; Issue Type still wins. */\n conflict?: { issueType: ChangeType; label: ChangeType };\n}\n\nexport interface BranchInput {\n type: ChangeType;\n issueNumber?: number | null;\n title: string;\n convention?: string;\n existingRefs?: readonly { name: string; oid: string }[];\n currentOid?: string;\n}\n\nexport interface ParsedBranch {\n type: ChangeType | 'issue' | null;\n issueNumber: number | null;\n slug: string;\n raw: string;\n}\n\nexport interface CommitInput {\n type: ChangeType;\n scope?: string | null;\n subject: string;\n body?: string;\n issueNumber?: number | null;\n storyId?: string | null;\n breaking?: string | null;\n signoff?: string | boolean | null;\n}\n\nexport interface PrTitleInput {\n type: ChangeType;\n scope?: string | null;\n subject: string;\n /** When consolidating several issues, the types of the set. */\n types?: readonly ChangeType[];\n scopes?: readonly (string | null | undefined)[];\n}\n\nexport interface IssueReference {\n number: number;\n complete: boolean;\n container?: boolean;\n allChildrenComplete?: boolean;\n}\n\nexport interface IssueRefInput {\n references: readonly IssueReference[];\n}\n\nexport function isChangeType(value: string): value is ChangeType {\n return (CHANGE_TYPES as readonly string[]).includes(value);\n}\n\nexport function isBranchChangeType(value: string): value is BranchChangeType {\n return (BRANCH_CHANGE_TYPES as readonly string[]).includes(value);\n}\n\n/** Provider names are valid subjects, never types or scopes. */\nexport function isForbiddenProviderToken(value: string): boolean {\n return (FORBIDDEN_PROVIDER_NAMES as readonly string[]).includes(value.toLowerCase());\n}\n","import { SLUG_MAX_LENGTH } from './types.js';\n\nconst COMBINING = /[\\u0300-\\u036f]/g;\nconst NON_SLUG = /[^a-z0-9]+/g;\n\n/**\n * Deterministic slug: NFD, strip diacritics, lowercase, hyphenate, collapse,\n * trim edges, drop a trailing `.lock`, and truncate on a word boundary.\n */\nexport function slugify(title: string, maxLength: number = SLUG_MAX_LENGTH): string {\n const withoutLock = title.replace(/\\.lock$/i, '');\n const normalized = withoutLock.normalize('NFD').replace(COMBINING, '').toLowerCase();\n let slug = normalized.replace(NON_SLUG, '-').replace(/^-+|-+$/g, '');\n slug = slug.replace(/\\.{2,}/g, '.').replace(/^\\.+|\\.+$/g, '');\n slug = slug.replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '');\n\n if (slug.length <= maxLength) return slug;\n const cut = slug.slice(0, maxLength);\n const lastHyphen = cut.lastIndexOf('-');\n if (lastHyphen >= Math.floor(maxLength / 2)) {\n return cut.slice(0, lastHyphen).replace(/-+$/g, '');\n }\n return cut.replace(/-+$/g, '');\n}\n","import { slugify } from './slug.js';\nimport {\n BRANCH_MAX_LENGTH,\n type BranchInput,\n type ChangeType,\n DEFAULT_BRANCH_CONVENTION,\n isChangeType,\n type ParsedBranch,\n} from './types.js';\n\nconst LEGACY_PREFIX = 'issue';\n\nfunction branchType(type: ChangeType): string {\n return type === 'style' || type === 'revert' ? 'chore' : type;\n}\n\nfunction applyConvention(\n convention: string,\n type: string,\n issueNumber: number | null | undefined,\n slug: string,\n): string {\n const hasNumber = issueNumber !== undefined && issueNumber !== null;\n let result = convention\n .replaceAll('{type}', type)\n .replaceAll('{N}', hasNumber ? String(issueNumber) : '')\n .replaceAll('{slug}', slug);\n\n result = result.replace(/\\/{2,}/g, '/').replace(/-{2,}/g, '-');\n result = result.replace(/\\/-/g, '/').replace(/-\\//g, '/');\n result = result.replace(/^\\/+|\\/+$/g, '').replace(/^-+|-+$/g, '');\n\n // `{type}/{N}-{slug}` without a number becomes `{type}/{slug}` or `{type}`.\n if (!hasNumber) {\n result = result.replace(`${type}/-`, `${type}/`).replace(/\\/$/g, '');\n }\n if (slug === '') {\n result = result.replace(/\\/-$/, '').replace(/-$/, '');\n }\n return result.replace(/\\/{2,}/g, '/').replace(/^\\/+|\\/+$/g, '');\n}\n\nfunction truncateBranch(name: string, max: number): string {\n if (name.length <= max) return name;\n const slash = name.indexOf('/');\n const prefix = slash === -1 ? '' : name.slice(0, slash + 1);\n const rest = slash === -1 ? name : name.slice(slash + 1);\n const budget = max - prefix.length;\n if (budget < 1) return name.slice(0, max);\n const cut = rest.slice(0, budget);\n const lastHyphen = cut.lastIndexOf('-');\n const trimmed = lastHyphen >= Math.floor(budget / 2) ? cut.slice(0, lastHyphen) : cut;\n return `${prefix}${trimmed.replace(/-+$/g, '')}`;\n}\n\nfunction collide(\n name: string,\n existingRefs: readonly { name: string; oid: string }[] | undefined,\n currentOid: string | undefined,\n): string {\n if (existingRefs === undefined || existingRefs.length === 0) return name;\n const byName = new Map(existingRefs.map((ref) => [ref.name, ref.oid]));\n const existing = byName.get(name);\n if (existing === undefined) return name;\n if (currentOid !== undefined && existing === currentOid) return name;\n\n for (let n = 2; n < 100; n += 1) {\n const candidate = `${name}-${n}`;\n const oid = byName.get(candidate);\n if (oid === undefined || (currentOid !== undefined && oid === currentOid)) {\n return candidate;\n }\n }\n return `${name}-${Date.now()}`;\n}\n\n/**\n * Deterministic branch name. Same issue, same title, same convention — same\n * bytes, regardless of who runs it.\n */\nexport function branchName(input: BranchInput): string {\n const type = branchType(input.type);\n const convention = input.convention ?? DEFAULT_BRANCH_CONVENTION;\n const slug = slugify(input.title);\n const raw = applyConvention(convention, type, input.issueNumber, slug);\n const truncated = truncateBranch(raw, BRANCH_MAX_LENGTH);\n return collide(truncated, input.existingRefs, input.currentOid);\n}\n\n/**\n * Extract type and issue number from a branch, including the historical\n * `issue/{N}-*` form so existing worktrees keep archiving correctly.\n */\nexport function parseBranch(name: string): ParsedBranch {\n const raw = name.trim();\n const match = raw.match(/^([^/]+)\\/(?:(\\d+)(?:-(.*))?|(.*))$/);\n if (match === null) {\n return { type: null, issueNumber: null, slug: raw, raw };\n }\n const prefix = match[1] ?? '';\n const numbered = match[2];\n const numberedSlug = match[3] ?? '';\n const unnumberedSlug = match[4] ?? '';\n const type: ParsedBranch['type'] =\n prefix === LEGACY_PREFIX ? 'issue' : isChangeType(prefix) ? prefix : null;\n if (numbered !== undefined) {\n return { type, issueNumber: Number(numbered), slug: numberedSlug, raw };\n }\n return { type, issueNumber: null, slug: unnumberedSlug, raw };\n}\n\n/** Folder-safe archive name that still carries the issue number. */\nexport function archiveFolderName(branch: string): string {\n const parsed = parseBranch(branch);\n if (parsed.issueNumber !== null && parsed.slug !== '') {\n return `${parsed.issueNumber}-${parsed.slug}`.replace(/[<>:\"|?*\\\\]/g, '_');\n }\n if (parsed.issueNumber !== null) {\n return String(parsed.issueNumber);\n }\n return branch.replace(/^[^/]+\\//, '').replace(/[<>:\"|?*\\\\]/g, '_');\n}\n","import {\n type ChangeType,\n type ChangeTypeInput,\n type ChangeTypeResult,\n DEFAULT_LABEL_TYPE_MAP,\n isChangeType,\n} from './types.js';\n\nconst ISSUE_TYPE_MAP: Readonly<Record<string, ChangeType>> = {\n bug: 'fix',\n feature: 'feat',\n task: 'chore',\n epic: 'chore',\n idea: 'chore',\n research: 'chore',\n documentation: 'docs',\n};\n\nconst TITLE_PREFIX_MAP: Readonly<Record<string, ChangeType>> = {\n bug: 'fix',\n fix: 'fix',\n feature: 'feat',\n enhancement: 'feat',\n architecture: 'feat',\n refactor: 'refactor',\n docs: 'docs',\n documentation: 'docs',\n chore: 'chore',\n perf: 'perf',\n test: 'test',\n ci: 'ci',\n};\n\nfunction normalizeKey(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction typeFromIssueType(issueType: string): ChangeType | null {\n const key = normalizeKey(issueType);\n if (isChangeType(key)) return key;\n return ISSUE_TYPE_MAP[key] ?? null;\n}\n\nfunction mergedTypeMap(overlay: ChangeTypeInput['typeMap']): Record<string, ChangeType> {\n const merged: Record<string, ChangeType> = { ...DEFAULT_LABEL_TYPE_MAP };\n if (overlay === undefined || overlay === null) return merged;\n for (const [label, type] of Object.entries(overlay)) {\n if (isChangeType(type)) {\n merged[normalizeKey(label)] = type;\n }\n }\n return merged;\n}\n\nfunction typeFromLabels(\n labels: readonly string[],\n typeMap: Record<string, ChangeType>,\n): ChangeType | null {\n for (const label of labels) {\n const key = normalizeKey(label);\n const mapped = typeMap[key] ?? typeMap[key.replace(/^type:/, '')];\n if (mapped !== undefined) return mapped;\n }\n return null;\n}\n\nfunction typeFromTitle(title: string): ChangeType | null {\n const match = title.match(/^\\s*\\[([^\\]]+)\\]/);\n if (match?.[1] === undefined) return null;\n const key = normalizeKey(match[1]);\n if (isChangeType(key)) return key;\n return TITLE_PREFIX_MAP[key] ?? null;\n}\n\n/**\n * Five-rung ladder, most structured first. The source is recorded so a fallback\n * can be printed in the execution header before the first commit.\n */\nexport function resolveChangeType(input: ChangeTypeInput): ChangeTypeResult {\n if (input.declaredType !== undefined && input.declaredType !== null) {\n return { type: input.declaredType, source: 'declared' };\n }\n\n const labels = input.labels ?? [];\n const typeMap = mergedTypeMap(input.typeMap);\n const fromLabels = typeFromLabels(labels, typeMap);\n const fromIssueType =\n input.issueType !== undefined && input.issueType !== null && input.issueType !== ''\n ? typeFromIssueType(input.issueType)\n : null;\n\n if (fromIssueType !== null) {\n const issueKey = normalizeKey(input.issueType ?? '');\n // Task (and other generic types) are refined by labels.\n if (issueKey === 'task' && fromLabels !== null) {\n return { type: fromLabels, source: 'label' };\n }\n if (fromLabels !== null && fromLabels !== fromIssueType) {\n return {\n type: fromIssueType,\n source: 'issue-type',\n conflict: { issueType: fromIssueType, label: fromLabels },\n };\n }\n return { type: fromIssueType, source: 'issue-type' };\n }\n\n if (fromLabels !== null) {\n return { type: fromLabels, source: 'label' };\n }\n\n if (input.titleConvention !== null && input.title !== undefined) {\n const fromTitle = typeFromTitle(input.title);\n if (fromTitle !== null) {\n return { type: fromTitle, source: 'title' };\n }\n } else if (input.title !== undefined) {\n // A title prefix is still a structured signal when the repository uses one\n // even without declaring `issues.titleConvention`.\n const fromTitle = typeFromTitle(input.title);\n if (fromTitle !== null) {\n return { type: fromTitle, source: 'title' };\n }\n }\n\n return { type: 'feat', source: 'fallback' };\n}\n","import { type ChangeType, type CommitInput, isForbiddenProviderToken } from './types.js';\n\nconst HEADER_MAX = 72;\nconst BODY_WIDTH = 72;\nconst STORY_ID = /^US-\\d+$/i;\n\nfunction wrap(text: string, width: number): string {\n const paragraphs = text.replace(/\\r\\n/g, '\\n').split('\\n');\n return paragraphs\n .map((paragraph) => {\n if (paragraph.trim() === '') return '';\n const words = paragraph.split(/\\s+/);\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n const next = current === '' ? word : `${current} ${word}`;\n if (next.length > width && current !== '') {\n lines.push(current);\n current = word;\n } else {\n current = next;\n }\n }\n if (current !== '') lines.push(current);\n return lines.join('\\n');\n })\n .join('\\n');\n}\n\nfunction sanitizeScope(scope: string | null | undefined): string | undefined {\n if (scope === undefined || scope === null) return undefined;\n const trimmed = scope.trim();\n if (trimmed === '' || isForbiddenProviderToken(trimmed)) return undefined;\n return trimmed;\n}\n\nfunction sanitizeType(type: ChangeType): ChangeType {\n return isForbiddenProviderToken(type) ? 'chore' : type;\n}\n\nfunction headerLine(\n type: ChangeType,\n scope: string | undefined,\n breaking: boolean,\n subject: string,\n): string {\n const bang = breaking ? '!' : '';\n const scoped = scope === undefined ? `${type}${bang}` : `${type}(${scope})${bang}`;\n const cleaned = subject.replace(/\\.$/, '').trim();\n const prefix = `${scoped}: `;\n const budget = HEADER_MAX - prefix.length;\n const clipped =\n budget < 1 ? '' : cleaned.length > budget ? cleaned.slice(0, budget).trimEnd() : cleaned;\n return `${prefix}${clipped}`;\n}\n\n/**\n * Conventional Commit. Footer uses `Refs` only — closing is a Pull Request\n * decision. A `Closes` on a commit would close the issue on a direct push.\n */\nexport function commitMessage(input: CommitInput): string {\n const type = sanitizeType(input.type);\n const scope = sanitizeScope(input.scope);\n const breaking = input.breaking !== undefined && input.breaking !== null && input.breaking !== '';\n const lines = [headerLine(type, scope, breaking, input.subject)];\n\n if (input.body !== undefined && input.body !== '') {\n lines.push('', wrap(input.body, BODY_WIDTH));\n }\n\n const footers: string[] = [];\n if (input.issueNumber !== undefined && input.issueNumber !== null) {\n footers.push(`Refs #${input.issueNumber}`);\n }\n if (input.storyId !== undefined && input.storyId !== null && STORY_ID.test(input.storyId)) {\n footers.push(`Story: ${input.storyId}`);\n }\n if (breaking) {\n footers.push(`BREAKING CHANGE: ${input.breaking}`);\n }\n if (input.signoff === true) {\n footers.push('Signed-off-by:');\n } else if (typeof input.signoff === 'string' && input.signoff !== '') {\n footers.push(`Signed-off-by: ${input.signoff}`);\n }\n\n if (footers.length > 0) {\n lines.push('', ...footers);\n }\n\n return lines.join('\\n');\n}\n","import {\n type ChangeType,\n type IssueRefInput,\n isForbiddenProviderToken,\n type PrTitleInput,\n} from './types.js';\n\nconst IMPACT: readonly ChangeType[] = ['feat', 'fix'];\n\nfunction sanitizeScope(scope: string | null | undefined): string | undefined {\n if (scope === undefined || scope === null) return undefined;\n const trimmed = scope.trim();\n if (trimmed === '' || isForbiddenProviderToken(trimmed)) return undefined;\n return trimmed;\n}\n\nfunction highestImpact(types: readonly ChangeType[]): ChangeType {\n for (const type of IMPACT) {\n if (types.includes(type)) return type;\n }\n return types[0] ?? 'feat';\n}\n\nfunction scopesAgree(scopes: readonly (string | null | undefined)[]): string | undefined {\n const unique = [\n ...new Set(scopes.map((scope) => sanitizeScope(scope)).filter((scope) => scope !== undefined)),\n ];\n return unique.length === 1 ? unique[0] : undefined;\n}\n\n/** `<type>(<scope>): <subject>` — what makes a GitHub squash-merge a Conventional Commit. */\nexport function pullRequestTitle(input: PrTitleInput): string {\n const type =\n input.types !== undefined && input.types.length > 0 ? highestImpact(input.types) : input.type;\n const scope =\n input.scopes !== undefined && input.scopes.length > 0\n ? scopesAgree(input.scopes)\n : sanitizeScope(input.scope);\n const subject = input.subject.replace(/\\.$/, '').trim();\n if (isForbiddenProviderToken(type)) {\n return scope === undefined ? `chore: ${subject}` : `chore(${scope}): ${subject}`;\n }\n return scope === undefined ? `${type}: ${subject}` : `${type}(${scope}): ${subject}`;\n}\n\n/**\n * Deterministic `Closes` / `Refs` lines. The verb is a function of plan state,\n * never of issue kind alone: a container is closed only when every child is.\n */\nexport function issueReferenceLines(input: IssueRefInput): string {\n return input.references\n .map((ref) => {\n const closes = ref.container === true ? ref.allChildrenComplete === true : ref.complete;\n return `${closes ? 'Closes' : 'Refs'} #${ref.number}`;\n })\n .join('\\n');\n}\n","import { isAbsolute, normalize, sep } from 'node:path';\nimport { loadPolicyConfig, mergeConfigLayers } from '../config.js';\nimport type { PolicyConfig, PolicyConfigInput } from '../schemas.js';\nimport { printWarning } from '../ui/logger.js';\nimport { getProjectRoot } from '../utils/git.js';\nimport {\n discoverBaseBranch,\n discoverCodeowners,\n discoverDocuments,\n discoverGitConventions,\n discoverGitHubSlug,\n discoverIssueTemplates,\n discoverIssueTypes,\n discoverLabels,\n discoverOrganizationForms,\n discoverOrganizationTemplates,\n discoverPullRequestTemplates,\n} from './discovery.js';\nimport {\n POLICY_SCHEMA_VERSION,\n type PolicyExec,\n type PolicyGit,\n type PolicyIssues,\n type PolicyPullRequests,\n type PolicySource,\n type RepositoryPolicy,\n} from './types.js';\n\n/**\n * Resolution of the repository policy: discovery, precedence, scope and cache.\n */\n\nexport interface LoadRepositoryPolicyOptions {\n /** Repository root. Defaults to the git project root. */\n root?: string;\n /** Subdirectory the policy applies to, for monorepos. Root when omitted. */\n scope?: string | null;\n /** CLI overrides of the `policy` key. */\n cli?: PolicyConfigInput;\n /** Environment source. Defaults to process.env. */\n env?: NodeJS.ProcessEnv;\n /** Warning sink. Defaults to printWarning. */\n warn?: (message: string) => void;\n /** External command seam, for tests. Defaults to `utils/shell.ts`'s `run`. */\n exec?: PolicyExec;\n /** Set to false to bypass the per-process cache. Defaults to true. */\n cache?: boolean;\n}\n\n/**\n * Normalize a scope into a repository-relative POSIX path, or null.\n *\n * An absolute path, a path escaping the root and `.` all mean \"the root\": a\n * scope is a hint about where in a monorepo the work is happening, never a way\n * to read outside the repository.\n */\nexport function normalizeScope(scope: string | null | undefined): string | null {\n if (scope === null || scope === undefined) return null;\n\n const trimmed = scope.trim();\n if (trimmed === '' || trimmed === '.' || isAbsolute(trimmed)) return null;\n\n const normalized = normalize(trimmed)\n .split(sep)\n .join('/')\n .replace(/^\\.\\//, '')\n .replace(/\\/+$/, '');\n if (normalized === '' || normalized === '.' || normalized.startsWith('..')) return null;\n\n return normalized;\n}\n\n/** An enabled policy with nothing in it — also the shape of a disabled one. */\nfunction emptyPolicy(\n root: string,\n scope: string | null,\n enabled: boolean,\n sources: PolicySource[],\n): RepositoryPolicy {\n return {\n schemaVersion: POLICY_SCHEMA_VERSION,\n root,\n scope,\n enabled,\n issues: { templates: [], types: [], labels: [], titleConvention: null },\n pullRequests: { template: null, templates: [], baseBranch: null, titleConvention: null },\n git: {\n branchConvention: null,\n commitConvention: null,\n pullRequestTitleConvention: null,\n issueReference: null,\n typeMap: null,\n allowedTypes: null,\n scopes: null,\n },\n docs: [],\n codeowners: null,\n sources,\n };\n}\n\n/** Provenance entry for a discovery pass the configuration turned off. */\nfunction disabledSource(kind: PolicySource['kind']): PolicySource {\n return {\n kind,\n origin: 'config',\n path: null,\n status: 'disabled',\n detail: 'disabled by configuration',\n };\n}\n\n/** Which `sources` entry a declared configuration key is accounted under. */\nconst DECLARATION_KINDS = {\n issues: 'issue-templates',\n pullRequests: 'pull-request-template',\n git: 'git-conventions',\n} as const satisfies Record<string, PolicySource['kind']>;\n\n/**\n * Resolve the policy of `root` for `scope`, uncached.\n *\n * The ladder, exactly as `mergeConfigLayers` applies it:\n *\n * Issue Flow defaults < discovered repository policies\n * < \"policy\" key of .issue-flow.json < ISSUE_FLOW_POLICY_* < CLI flags\n *\n * The three explicit layers are already collapsed by `loadPolicyConfig()`, so\n * what arrives here is \"the defaults\" and \"what the user declared\", with the\n * discovery in between. A declaration therefore corrects a wrong discovery\n * without having to disable it, and `discovery.*: false` turns a whole pass off\n * for the case where the discovery is not merely wrong but unwanted.\n */\nasync function resolvePolicy(\n root: string,\n scope: string | null,\n options: LoadRepositoryPolicyOptions,\n): Promise<RepositoryPolicy> {\n const warn = options.warn ?? printWarning;\n const config: PolicyConfig = await loadPolicyConfig({\n projectRoot: root,\n env: options.env,\n cli: options.cli,\n warn,\n });\n\n if (!config.enabled) {\n // Not a single stat() or round-trip: \"off\" has to be free, otherwise it is\n // not really a way out of a discovery that is misbehaving.\n return emptyPolicy(root, scope, false, [\n { kind: 'docs', origin: 'config', path: null, status: 'disabled', detail: 'policy.enabled' },\n ]);\n }\n\n const toggles = config.discovery;\n\n const [templateDiscovery, prTemplates, documents, codeowners, gitConventions] = await Promise.all(\n [\n toggles.issueTemplates\n ? discoverIssueTemplates(root)\n : Promise.resolve({ templates: [], sources: [disabledSource('issue-templates')] }),\n toggles.pullRequestTemplate\n ? discoverPullRequestTemplates(root)\n : Promise.resolve({ templates: [], sources: [disabledSource('pull-request-template')] }),\n toggles.docs\n ? discoverDocuments(root, scope)\n : Promise.resolve({ documents: [], sources: [disabledSource('docs')] }),\n toggles.codeowners\n ? discoverCodeowners(root)\n : Promise.resolve({ content: null, sources: [disabledSource('codeowners')] }),\n discoverGitConventions(root),\n ],\n );\n\n // The organization defaults are only worth asking for when the local tree has\n // none — that is precisely the case local discovery cannot see.\n const wantsOrgTemplates = toggles.issueTemplates && templateDiscovery.templates.length === 0;\n const [baseBranch, slug] = await Promise.all([\n discoverBaseBranch(root, options.exec),\n toggles.issueTypes || wantsOrgTemplates\n ? discoverGitHubSlug(root, options.exec)\n : Promise.resolve(null),\n ]);\n\n const [labels, issueTypes, orgTemplates, orgForms] = await Promise.all([\n toggles.labels\n ? discoverLabels(root, options.exec)\n : Promise.resolve({ labels: [], sources: [disabledSource('labels')] }),\n toggles.issueTypes\n ? discoverIssueTypes(root, slug?.owner ?? null, options.exec)\n : Promise.resolve({ types: [], sources: [disabledSource('issue-types')] }),\n wantsOrgTemplates\n ? discoverOrganizationTemplates(root, slug, options.exec)\n : Promise.resolve({ templates: [], sources: [] }),\n // Two calls, because GitHub answers the two kinds of organization default\n // through different surfaces: `issueTemplates` covers markdown templates and\n // is blind to Issue Forms, which only exist as files in the org's `.github`\n // repository. A repository whose organization publishes forms would\n // otherwise look like one with no templates at all.\n wantsOrgTemplates\n ? discoverOrganizationForms(root, slug?.owner ?? null, options.exec)\n : Promise.resolve({ templates: [], sources: [] }),\n ]);\n\n const sources: PolicySource[] = [\n ...templateDiscovery.sources,\n ...orgTemplates.sources,\n ...orgForms.sources,\n ...issueTypes.sources,\n ...labels.sources,\n ...prTemplates.sources,\n ...baseBranch.sources,\n ...documents.sources,\n ...codeowners.sources,\n ...gitConventions.sources,\n ];\n\n // Only the base branch is inferable today; the conventions have no reliable\n // signal in a repository and are therefore declared, never guessed.\n const discoveredPullRequests: Partial<PolicyPullRequests> = {};\n if (baseBranch.baseBranch !== null) {\n discoveredPullRequests.baseBranch = baseBranch.baseBranch;\n }\n\n const issues = mergeConfigLayers<PolicyIssues>({\n defaults: { titleConvention: null },\n project: config.issues,\n });\n const pullRequests = mergeConfigLayers<PolicyPullRequests>({\n defaults: { baseBranch: null, titleConvention: null },\n discovered: discoveredPullRequests,\n project: config.pullRequests,\n });\n const discoveredGit: Partial<PolicyGit> = {};\n if (gitConventions.commitConvention !== null) {\n discoveredGit.commitConvention = gitConventions.commitConvention;\n }\n if (gitConventions.pullRequestTitleConvention !== null) {\n discoveredGit.pullRequestTitleConvention = gitConventions.pullRequestTitleConvention;\n }\n if (gitConventions.allowedTypes !== null) {\n discoveredGit.allowedTypes = gitConventions.allowedTypes;\n }\n if (gitConventions.scopes !== null) {\n discoveredGit.scopes = gitConventions.scopes;\n }\n\n const git = mergeConfigLayers<PolicyGit>({\n defaults: {\n branchConvention: null,\n commitConvention: null,\n pullRequestTitleConvention: null,\n issueReference: null,\n typeMap: null,\n allowedTypes: null,\n scopes: null,\n },\n discovered: discoveredGit,\n project: config.git,\n });\n\n for (const group of ['issues', 'pullRequests', 'git'] as const) {\n for (const key of Object.keys(config[group])) {\n sources.push({\n kind: DECLARATION_KINDS[group],\n origin: 'config',\n path: null,\n status: 'found',\n detail: `${group}.${key} declared`,\n });\n }\n }\n\n return {\n schemaVersion: POLICY_SCHEMA_VERSION,\n root,\n scope,\n enabled: true,\n issues: {\n templates: [...templateDiscovery.templates, ...orgTemplates.templates, ...orgForms.templates],\n types: issueTypes.types,\n labels: labels.labels,\n titleConvention: issues.titleConvention ?? null,\n },\n pullRequests: {\n template: prTemplates.templates[0]?.content ?? null,\n templates: prTemplates.templates,\n baseBranch: pullRequests.baseBranch ?? null,\n titleConvention: pullRequests.titleConvention ?? null,\n },\n git: {\n branchConvention: git.branchConvention ?? null,\n commitConvention: git.commitConvention ?? null,\n pullRequestTitleConvention: git.pullRequestTitleConvention ?? null,\n issueReference: git.issueReference ?? null,\n typeMap: git.typeMap ?? null,\n allowedTypes: git.allowedTypes ?? gitConventions.allowedTypes,\n scopes: git.scopes ?? gitConventions.scopes,\n },\n docs: documents.documents,\n codeowners: codeowners.content,\n sources,\n };\n}\n\n/**\n * Per-process cache, keyed by `(root, scope)`.\n *\n * Discovery walks the filesystem and may talk to `gh`; a pipeline that resolved\n * it once per phase would pay that several times over for an answer that cannot\n * change mid-run. The promise — not its result — is cached, so two concurrent\n * callers share a single discovery instead of racing two.\n */\nconst cache = new Map<string, Promise<RepositoryPolicy>>();\n\n/** Drop every cached resolution. Exported for tests and long-lived processes. */\nexport function resetPolicyCache(): void {\n cache.clear();\n}\n\n/**\n * The repository policy applying to `scope`, resolved once per process.\n *\n * Never throws for a repository that declares nothing: the result is an empty\n * policy, with no warning, and every consumer keeps its own defaults. The only\n * error it can raise is the one `getProjectRoot()` already raises when there is\n * no repository at all — and passing `root` avoids even that.\n */\nexport async function loadRepositoryPolicy(\n options: LoadRepositoryPolicyOptions = {},\n): Promise<RepositoryPolicy> {\n const root = options.root ?? (await getProjectRoot());\n const scope = normalizeScope(options.scope);\n\n if (options.cache === false) {\n return resolvePolicy(root, scope, options);\n }\n\n const key = `${root}\u0000${scope ?? ''}`;\n const cached = cache.get(key);\n if (cached !== undefined) {\n return cached;\n }\n\n const pending = resolvePolicy(root, scope, options);\n cache.set(key, pending);\n try {\n return await pending;\n } catch (err) {\n // A rejected promise must not be served to every later caller.\n cache.delete(key);\n throw err;\n }\n}\n","import { readdir, readFile, stat } from 'node:fs/promises';\nimport { join, relative, sep } from 'node:path';\nimport { run } from '../utils/shell.js';\nimport { classifyDocument, extractReferencedDocuments } from './parsers/docs.js';\nimport {\n COMMITLINT_FILE_NAMES,\n type DiscoveredGitConventions,\n parseChangesetConfig,\n parseCommitlintText,\n parseHuskyCommitMsg,\n parsePackageJsonCommitlint,\n parseReleasePlease,\n parseSemanticPullRequestWorkflow,\n parseSemanticRelease,\n} from './parsers/git.js';\nimport { parseIssueTypes, parseLabels } from './parsers/labels.js';\nimport {\n parseIssueTemplateFile,\n parseOrganizationForms,\n parseOrganizationTemplates,\n} from './parsers/templates.js';\nimport {\n type IssueTemplate,\n type LabelDefinition,\n MAX_POLICY_DOCUMENT_BYTES,\n type PolicyDocument,\n type PolicyExec,\n type PolicySource,\n type PullRequestTemplate,\n} from './types.js';\n\n/**\n * Locating the policy sources of a repository on disk and, when `gh` can\n * answer, on GitHub.\n *\n * Every function here is best-effort by construction: an unreadable directory,\n * a missing binary, a network that never answers and a repository that simply\n * declares nothing all produce the same thing — an empty result plus, when the\n * source *could* have answered, a `PolicySource` recording why it did not.\n * Discovery must never be able to break a flow that works offline today.\n */\n\n/**\n * Timeout of every `gh` and `git` invocation. Matches the `init` prerequisite\n * probes; the point is that no discovery call can hang a pipeline.\n */\nexport const DISCOVERY_TIMEOUT_MS = 10_000;\n\n/** The directories GitHub itself looks in, in the order it looks. */\nconst POLICY_DIRECTORIES = ['.github', '', 'docs'] as const;\n\nconst defaultExec: PolicyExec = (command, args, options) =>\n run(command, args, { cwd: options.cwd, timeout: options.timeout });\n\n/** Repository-relative path with POSIX separators, for stable output. */\nexport function toRelativePath(root: string, absolute: string): string {\n return relative(root, absolute).split(sep).join('/');\n}\n\n/** Directory entries, or [] when the directory is absent or unreadable. */\nasync function listDirectory(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries.filter((entry) => !entry.isDirectory()).map((entry) => entry.name);\n } catch {\n return [];\n }\n}\n\nasync function isDirectory(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Read a file, capped at {@link MAX_POLICY_DOCUMENT_BYTES}.\n *\n * Returns null when the file is absent or unreadable. The second element says\n * whether the content was truncated, so the caller can record it in `sources`\n * instead of silently handing a half document to an agent.\n */\nasync function readCapped(path: string): Promise<{ content: string; truncated: boolean } | null> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n return null;\n }\n\n if (Buffer.byteLength(raw, 'utf-8') <= MAX_POLICY_DOCUMENT_BYTES) {\n return { content: raw, truncated: false };\n }\n const clipped = Buffer.from(raw, 'utf-8')\n .subarray(0, MAX_POLICY_DOCUMENT_BYTES)\n .toString('utf-8');\n return { content: clipped, truncated: true };\n}\n\n/** Find an entry of `dir` whose name matches one of `names`, case-insensitively. */\nasync function findFile(dir: string, names: string[]): Promise<string | null> {\n const entries = await listDirectory(dir);\n const wanted = names.map((name) => name.toLowerCase());\n for (const name of wanted) {\n const hit = entries.find((entry) => entry.toLowerCase() === name);\n if (hit !== undefined) return hit;\n }\n return null;\n}\n\n// ── Issue Templates and Forms ───────────────────────────────────────────────\n\nconst TEMPLATE_EXTENSIONS = ['.yml', '.yaml', '.md', '.markdown'];\n\n/** The chooser configuration is not a template. */\nfunction isTemplateFile(name: string): boolean {\n const lower = name.toLowerCase();\n if (lower === 'config.yml' || lower === 'config.yaml') return false;\n return TEMPLATE_EXTENSIONS.some((extension) => lower.endsWith(extension));\n}\n\nexport interface IssueTemplateDiscovery {\n templates: IssueTemplate[];\n sources: PolicySource[];\n}\n\n/**\n * Issue Templates and Forms of the local tree.\n *\n * Searched in `.github/ISSUE_TEMPLATE/`, the repository root and `docs/`, plus\n * the single-file `ISSUE_TEMPLATE.md` variant of each — the three locations\n * GitHub honours. Files are sorted by name so two runs over the same tree\n * produce the same order.\n */\nexport async function discoverIssueTemplates(root: string): Promise<IssueTemplateDiscovery> {\n const templates: IssueTemplate[] = [];\n const sources: PolicySource[] = [];\n\n for (const base of POLICY_DIRECTORIES) {\n const baseDir = base === '' ? root : join(root, base);\n\n const templateDir = (await findDirectory(baseDir, 'ISSUE_TEMPLATE')) ?? null;\n if (templateDir !== null) {\n const names = (await listDirectory(templateDir)).filter(isTemplateFile).sort();\n for (const name of names) {\n const filePath = join(templateDir, name);\n const file = await readCapped(filePath);\n if (file === null) continue;\n const relPath = toRelativePath(root, filePath);\n templates.push(parseIssueTemplateFile(relPath, file.content));\n sources.push({\n kind: 'issue-templates',\n origin: 'filesystem',\n path: relPath,\n status: 'found',\n detail: file.truncated ? 'content truncated' : null,\n });\n }\n }\n\n const singleFile = await findFile(baseDir, [\n 'ISSUE_TEMPLATE.md',\n 'ISSUE_TEMPLATE.yml',\n 'ISSUE_TEMPLATE.yaml',\n 'ISSUE_TEMPLATE.markdown',\n ]);\n if (singleFile !== null) {\n const filePath = join(baseDir, singleFile);\n const file = await readCapped(filePath);\n if (file !== null) {\n const relPath = toRelativePath(root, filePath);\n templates.push(parseIssueTemplateFile(relPath, file.content));\n sources.push({\n kind: 'issue-templates',\n origin: 'filesystem',\n path: relPath,\n status: 'found',\n detail: file.truncated ? 'content truncated' : null,\n });\n }\n }\n }\n\n return { templates, sources };\n}\n\n/** Case-insensitive lookup of a subdirectory, returning its real path. */\nasync function findDirectory(parent: string, name: string): Promise<string | null> {\n let entries: string[];\n try {\n entries = (await readdir(parent, { withFileTypes: true }))\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name);\n } catch {\n return null;\n }\n const hit = entries.find((entry) => entry.toLowerCase() === name.toLowerCase());\n return hit === undefined ? null : join(parent, hit);\n}\n\n// ── Pull Request template ───────────────────────────────────────────────────\n\nconst PR_TEMPLATE_FILES = [\n 'PULL_REQUEST_TEMPLATE.md',\n 'PULL_REQUEST_TEMPLATE.markdown',\n 'PULL_REQUEST_TEMPLATE.txt',\n 'PULL_REQUEST_TEMPLATE',\n];\n\nexport interface PullRequestTemplateDiscovery {\n templates: PullRequestTemplate[];\n sources: PolicySource[];\n}\n\n/**\n * Pull Request templates, in every layout GitHub supports: the single file in\n * `.github/`, the root or `docs/`, and the `PULL_REQUEST_TEMPLATE/` directory\n * that holds several named ones.\n *\n * The first template found is the default one; the rest are kept so a caller\n * can offer the choice the repository set up.\n */\nexport async function discoverPullRequestTemplates(\n root: string,\n): Promise<PullRequestTemplateDiscovery> {\n const templates: PullRequestTemplate[] = [];\n const sources: PolicySource[] = [];\n\n const collect = async (filePath: string): Promise<void> => {\n const file = await readCapped(filePath);\n if (file === null) return;\n const relPath = toRelativePath(root, filePath);\n templates.push({\n path: relPath,\n name: relPath.split('/').pop() ?? relPath,\n content: file.content,\n });\n sources.push({\n kind: 'pull-request-template',\n origin: 'filesystem',\n path: relPath,\n status: 'found',\n detail: file.truncated ? 'content truncated' : null,\n });\n };\n\n for (const base of POLICY_DIRECTORIES) {\n const baseDir = base === '' ? root : join(root, base);\n\n const single = await findFile(baseDir, PR_TEMPLATE_FILES);\n if (single !== null && !(await isDirectory(join(baseDir, single)))) {\n await collect(join(baseDir, single));\n }\n\n const templateDir = await findDirectory(baseDir, 'PULL_REQUEST_TEMPLATE');\n if (templateDir !== null) {\n for (const name of (await listDirectory(templateDir)).sort()) {\n if (!/\\.(md|markdown|txt)$/i.test(name)) continue;\n await collect(join(templateDir, name));\n }\n }\n }\n\n return { templates, sources };\n}\n\n// ── CODEOWNERS ──────────────────────────────────────────────────────────────\n\nexport interface CodeownersDiscovery {\n content: string | null;\n sources: PolicySource[];\n}\n\nexport async function discoverCodeowners(root: string): Promise<CodeownersDiscovery> {\n for (const base of POLICY_DIRECTORIES) {\n const baseDir = base === '' ? root : join(root, base);\n const name = await findFile(baseDir, ['CODEOWNERS']);\n if (name === null) continue;\n\n const file = await readCapped(join(baseDir, name));\n if (file === null) continue;\n\n const relPath = toRelativePath(root, join(baseDir, name));\n return {\n content: file.content,\n sources: [\n {\n kind: 'codeowners',\n origin: 'filesystem',\n path: relPath,\n status: 'found',\n detail: file.truncated ? 'content truncated' : null,\n },\n ],\n };\n }\n\n return { content: null, sources: [] };\n}\n\n// ── Policy documents ────────────────────────────────────────────────────────\n\n/** Root-only documents: GitHub reads these from one place, not per directory. */\nconst ROOT_DOCUMENT_FILES = ['CONTRIBUTING.md', 'CODE_OF_CONDUCT.md'];\n\n/** Per-directory agent instructions, composed from the root down to the scope. */\nconst SCOPED_DOCUMENT_FILES = ['AGENTS.md', 'CLAUDE.md'];\n\nexport interface DocumentDiscovery {\n documents: PolicyDocument[];\n sources: PolicySource[];\n}\n\n/**\n * The scope ladder: `''`, then every ancestor of `scope`, then `scope` itself.\n * Composing in this order is what makes the more specific document win — it is\n * simply the later one.\n */\nexport function scopeLadder(scope: string | null): string[] {\n if (scope === null || scope === '') return [''];\n\n const segments = scope.split('/').filter((segment) => segment !== '');\n const ladder = [''];\n let current = '';\n for (const segment of segments) {\n current = current === '' ? segment : `${current}/${segment}`;\n ladder.push(current);\n }\n return ladder;\n}\n\n/**\n * Agent instructions and governance documents applying to `scope`.\n *\n * `AGENTS.md` (the open standard) and `CLAUDE.md` are read at every level of\n * the ladder, root first, so a monorepo's `apps/api/AGENTS.md` arrives after —\n * and therefore wins over — the one at the root. `CONTRIBUTING.md` and\n * `CODE_OF_CONDUCT.md` are read once, at the root, because that is where\n * GitHub reads them from.\n *\n * Documents linked from an `AGENTS.md` or a `CLAUDE.md` are followed one level;\n * see {@link extractReferencedDocuments} for why that is a link walk rather than\n * a scan of `docs/`.\n */\nexport async function discoverDocuments(\n root: string,\n scope: string | null,\n): Promise<DocumentDiscovery> {\n const documents: PolicyDocument[] = [];\n const sources: PolicySource[] = [];\n const seen = new Set<string>();\n\n const collect = async (\n filePath: string,\n kind: PolicyDocument['kind'],\n docScope: string,\n referencedFrom: string | null,\n ): Promise<PolicyDocument | null> => {\n const relPath = toRelativePath(root, filePath);\n if (seen.has(relPath)) return null;\n\n const file = await readCapped(filePath);\n if (file === null) return null;\n seen.add(relPath);\n\n const document: PolicyDocument = {\n path: relPath,\n kind,\n scope: docScope,\n referencedFrom,\n content: file.content,\n };\n documents.push(document);\n sources.push({\n kind: 'docs',\n origin: 'filesystem',\n path: relPath,\n status: 'found',\n detail: file.truncated ? 'content truncated' : null,\n });\n return document;\n };\n\n for (const base of POLICY_DIRECTORIES) {\n const baseDir = base === '' ? root : join(root, base);\n for (const wanted of ROOT_DOCUMENT_FILES) {\n const name = await findFile(baseDir, [wanted]);\n if (name === null) continue;\n const kind = classifyDocument(name);\n if (kind === null) continue;\n await collect(join(baseDir, name), kind, '', null);\n }\n }\n\n const indexes: PolicyDocument[] = [];\n for (const level of scopeLadder(scope)) {\n const levelDir = level === '' ? root : join(root, level);\n for (const wanted of SCOPED_DOCUMENT_FILES) {\n const name = await findFile(levelDir, [wanted]);\n if (name === null) continue;\n const kind = classifyDocument(name);\n if (kind === null) continue;\n const document = await collect(join(levelDir, name), kind, level, null);\n // Both agent-instruction files are indexes. A `CLAUDE.md` whose entire\n // content is \"Read and follow the instructions in AGENTS.md\" is a real and\n // common shape: stopping at it would report a repository that declares\n // nothing, when in fact it forwards everything.\n if (document !== null && (kind === 'agents' || kind === 'claude')) {\n indexes.push(document);\n }\n }\n }\n\n // One level only: a referenced document that itself links onwards does not\n // drag its own bibliography into the context.\n for (const index of indexes) {\n for (const target of extractReferencedDocuments(index.content, index.path)) {\n await collect(join(root, target), 'referenced', index.scope, index.path);\n }\n }\n\n return { documents, sources };\n}\n\n// ── git ─────────────────────────────────────────────────────────────────────\n\nexport interface GitConventionDiscovery {\n commitConvention: string | null;\n pullRequestTitleConvention: string | null;\n allowedTypes: string[] | null;\n scopes: string[] | null;\n sources: PolicySource[];\n}\n\nfunction asPolicySources(discovered: DiscoveredGitConventions): PolicySource[] {\n return discovered.sources.map((entry) => ({\n kind: 'git-conventions' as const,\n origin: 'filesystem' as const,\n path: entry.path,\n status: 'found' as const,\n detail: entry.detail,\n }));\n}\n\n/**\n * Discover commit/PR conventions the repository already declares.\n *\n * Declarative files are parsed; `.js`/`.ts` configs are read as text only.\n */\nexport async function discoverGitConventions(root: string): Promise<GitConventionDiscovery> {\n let merged: DiscoveredGitConventions = {\n commitConvention: null,\n pullRequestTitleConvention: null,\n allowedTypes: null,\n scopes: null,\n sources: [],\n };\n\n const take = (extra: DiscoveredGitConventions | null): void => {\n if (extra === null) return;\n merged = {\n commitConvention: merged.commitConvention ?? extra.commitConvention,\n pullRequestTitleConvention:\n merged.pullRequestTitleConvention ?? extra.pullRequestTitleConvention,\n allowedTypes: merged.allowedTypes ?? extra.allowedTypes,\n scopes: merged.scopes ?? extra.scopes,\n sources: [...merged.sources, ...extra.sources],\n };\n };\n\n const pkg = await readCapped(join(root, 'package.json'));\n if (pkg !== null) {\n take(parsePackageJsonCommitlint(pkg.content));\n }\n\n for (const name of COMMITLINT_FILE_NAMES) {\n const found = await findFile(root, [name]);\n if (found === null) continue;\n const file = await readCapped(join(root, found));\n if (file === null) continue;\n take(parseCommitlintText(file.content, found));\n }\n\n for (const name of ['release-please-config.json', '.release-please-manifest.json']) {\n const found = await findFile(root, [name]);\n if (found === null) continue;\n const file = await readCapped(join(root, found));\n if (file === null) continue;\n take(parseReleasePlease(file.content, found));\n }\n\n for (const name of [\n '.releaserc',\n '.releaserc.json',\n '.releaserc.yaml',\n '.releaserc.yml',\n 'release.config.js',\n ]) {\n const found = await findFile(root, [name]);\n if (found === null) continue;\n take(parseSemanticRelease(found));\n }\n\n const changeset = await findFile(join(root, '.changeset'), ['config.json']);\n if (changeset !== null) {\n take(parseChangesetConfig(`.changeset/${changeset}`));\n }\n\n const husky = await findFile(join(root, '.husky'), ['commit-msg']);\n if (husky !== null) {\n take(parseHuskyCommitMsg(`.husky/${husky}`));\n }\n\n const workflowDir = join(root, '.github', 'workflows');\n for (const name of await listDirectory(workflowDir)) {\n if (!/\\.ya?ml$/i.test(name)) continue;\n const file = await readCapped(join(workflowDir, name));\n if (file === null) continue;\n take(parseSemanticPullRequestWorkflow(file.content, `.github/workflows/${name}`));\n }\n\n return {\n commitConvention: merged.commitConvention,\n pullRequestTitleConvention: merged.pullRequestTitleConvention,\n allowedTypes: merged.allowedTypes,\n scopes: merged.scopes,\n sources: asPolicySources(merged),\n };\n}\n\nexport interface BaseBranchDiscovery {\n baseBranch: string | null;\n sources: PolicySource[];\n}\n\n/**\n * The repository's base branch, as git actually knows it.\n *\n * Unlike `utils/git.ts`'s `getBaseBranch()`, this never falls back to `'main'`:\n * a discovery layer that invents a value is indistinguishable from one that\n * found it, and `sources` would be lying. An undetermined base branch is null,\n * and the configuration layer above is free to declare one.\n */\nexport async function discoverBaseBranch(\n root: string,\n exec: PolicyExec = defaultExec,\n): Promise<BaseBranchDiscovery> {\n const options = { cwd: root, timeout: DISCOVERY_TIMEOUT_MS };\n\n try {\n const remoteHead = await exec(\n 'git',\n ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'],\n options,\n );\n if (remoteHead.exitCode === 0) {\n const name = remoteHead.stdout.trim().replace(/^origin\\//, '');\n if (name !== '') {\n return {\n baseBranch: name,\n sources: [\n {\n kind: 'base-branch',\n origin: 'git',\n path: null,\n status: 'found',\n detail: 'origin/HEAD',\n },\n ],\n };\n }\n }\n\n for (const candidate of ['main', 'master']) {\n const check = await exec(\n 'git',\n ['rev-parse', '--verify', '--quiet', `refs/heads/${candidate}`],\n options,\n );\n if (check.exitCode === 0) {\n return {\n baseBranch: candidate,\n sources: [\n {\n kind: 'base-branch',\n origin: 'git',\n path: null,\n status: 'found',\n detail: `refs/heads/${candidate}`,\n },\n ],\n };\n }\n }\n } catch {\n return {\n baseBranch: null,\n sources: [\n {\n kind: 'base-branch',\n origin: 'git',\n path: null,\n status: 'unavailable',\n detail: 'git could not be executed',\n },\n ],\n };\n }\n\n return { baseBranch: null, sources: [] };\n}\n\n/**\n * `owner` and `repo` of the `origin` remote, with their original case.\n *\n * Deliberately derived from git rather than from `gh repo view`: the identity\n * is already on disk, and spending a network round-trip on it would break the\n * \"at most one `gh` call per kind of data\" budget for nothing.\n */\nexport async function discoverGitHubSlug(\n root: string,\n exec: PolicyExec = defaultExec,\n): Promise<{ owner: string; repo: string } | null> {\n let url = '';\n try {\n const result = await exec('git', ['remote', 'get-url', 'origin'], {\n cwd: root,\n timeout: DISCOVERY_TIMEOUT_MS,\n });\n if (result.exitCode !== 0) return null;\n url = result.stdout.trim();\n } catch {\n return null;\n }\n if (url === '') return null;\n\n // Both the scp-like shorthand and every URL scheme end in `<owner>/<repo>`.\n const match = /[/:]([^/:\\s]+)\\/([^/\\s]+?)(?:\\.git)?\\/?$/.exec(url);\n if (match?.[1] === undefined || match[2] === undefined) return null;\n return { owner: match[1], repo: match[2] };\n}\n\n// ── GitHub, via gh ──────────────────────────────────────────────────────────\n\n/** One `gh` call, JSON-decoded. Returns null for every kind of failure. */\nasync function ghJson(\n root: string,\n args: string[],\n exec: PolicyExec,\n): Promise<{ value: unknown } | { error: string }> {\n let result: { stdout: string; stderr: string; exitCode: number };\n try {\n result = await exec('gh', args, { cwd: root, timeout: DISCOVERY_TIMEOUT_MS });\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) };\n }\n if (result.exitCode !== 0) {\n const stderr = result.stderr.trim().split('\\n')[0] ?? '';\n return { error: stderr === '' ? `gh exited with ${result.exitCode}` : stderr };\n }\n try {\n return { value: JSON.parse(result.stdout) as unknown };\n } catch {\n return { error: 'gh returned unparseable JSON' };\n }\n}\n\n/** How many labels a single `gh label list` page returns. */\nconst LABEL_PAGE_SIZE = 200;\n\nexport interface LabelDiscovery {\n labels: LabelDefinition[];\n sources: PolicySource[];\n}\n\n/**\n * The labels that exist in the repository.\n *\n * A machine with no `gh`, no authentication or no network degrades to an empty\n * list and a single `unavailable` source — never to a warning, and never to a\n * failure: reading labels is an enrichment, not a prerequisite.\n */\nexport async function discoverLabels(\n root: string,\n exec: PolicyExec = defaultExec,\n): Promise<LabelDiscovery> {\n const outcome = await ghJson(\n root,\n ['label', 'list', '--json', 'name,description,color', '--limit', String(LABEL_PAGE_SIZE)],\n exec,\n );\n\n if ('error' in outcome) {\n return {\n labels: [],\n sources: [\n { kind: 'labels', origin: 'gh', path: null, status: 'unavailable', detail: outcome.error },\n ],\n };\n }\n\n const labels = parseLabels(outcome.value);\n return {\n labels,\n sources: [\n {\n kind: 'labels',\n origin: 'gh',\n path: null,\n status: 'found',\n detail: `${labels.length} label(s)`,\n },\n ],\n };\n}\n\nexport interface IssueTypeDiscovery {\n types: string[];\n sources: PolicySource[];\n}\n\n/**\n * Issue Types of the organization owning the repository.\n *\n * Requires the owner, which comes from the git remote; a repository with no\n * remote simply has no organization to ask about, which is an ordinary state\n * and not an `unavailable` source.\n */\nexport async function discoverIssueTypes(\n root: string,\n owner: string | null,\n exec: PolicyExec = defaultExec,\n): Promise<IssueTypeDiscovery> {\n if (owner === null || owner === '') {\n return { types: [], sources: [] };\n }\n\n const outcome = await ghJson(root, ['api', `orgs/${owner}/issue-types`], exec);\n if ('error' in outcome) {\n return {\n types: [],\n sources: [\n {\n kind: 'issue-types',\n origin: 'gh',\n path: null,\n // A personal account (404) and a plan without Issue Types (403) are\n // the common answers here, so the detail carries what gh said.\n status: 'unavailable',\n detail: outcome.error,\n },\n ],\n };\n }\n\n const types = parseIssueTypes(outcome.value);\n return {\n types,\n sources: [\n {\n kind: 'issue-types',\n origin: 'gh',\n path: null,\n status: 'found',\n detail: `${types.length} type(s)`,\n },\n ],\n };\n}\n\n/**\n * The `issueTemplates` connection, as one GraphQL document.\n *\n * Owner and repository travel as GraphQL variables rather than being spliced\n * into the query text: they come from a git remote, which is user-controlled\n * input, and a query built by concatenation is a query someone can rewrite.\n */\nconst ORGANIZATION_TEMPLATES_QUERY = `query($owner:String!,$name:String!){\n repository(owner:$owner,name:$name){\n issueTemplates{\n name\n title\n about\n filename\n body\n assignees(first:10){nodes{login}}\n labels(first:20){nodes{name}}\n }\n }\n}`;\n\n/**\n * The organization's `.github` repository, read as a tree.\n *\n * `issueTemplates` above only ever returns **markdown** templates: GitHub does\n * not expose organization-level Issue *Forms* through it, and a repository whose\n * organization publishes `.yml` forms therefore looks like a repository with no\n * templates at all. Reading the tree of the org's `.github` repository is the\n * only way to see them.\n *\n * One round-trip for names *and* contents, which is why it is a tree query\n * rather than the contents endpoint (a directory listing there carries no file\n * bodies, costing one call per template).\n */\nconst ORGANIZATION_FORMS_QUERY = `query($owner:String!){\n repository(owner:$owner,name:\".github\"){\n object(expression:\"HEAD:.github/ISSUE_TEMPLATE\"){\n ... on Tree {\n entries { name type object { ... on Blob { text } } }\n }\n }\n }\n}`;\n\n/**\n * Issue Forms published by the organization's `.github` repository.\n *\n * Answers an empty list for every ordinary case — no organization, no `.github`\n * repository, no `ISSUE_TEMPLATE` directory — so it is only ever an enrichment.\n */\nexport async function discoverOrganizationForms(\n root: string,\n owner: string | null,\n exec: PolicyExec = defaultExec,\n): Promise<IssueTemplateDiscovery> {\n if (owner === null || owner === '') {\n return { templates: [], sources: [] };\n }\n\n const outcome = await ghJson(\n root,\n ['api', 'graphql', '-f', `query=${ORGANIZATION_FORMS_QUERY}`, '-f', `owner=${owner}`],\n exec,\n );\n if ('error' in outcome) {\n return {\n templates: [],\n sources: [\n {\n kind: 'issue-templates',\n origin: 'gh',\n path: null,\n status: 'unavailable',\n detail: outcome.error,\n },\n ],\n };\n }\n\n const templates = parseOrganizationForms(outcome.value);\n if (templates.length === 0) {\n return { templates, sources: [] };\n }\n return {\n templates,\n sources: templates.map((template) => ({\n kind: 'issue-templates' as const,\n origin: 'gh' as const,\n path: null,\n status: 'found' as const,\n detail: `organization form \"${template.path}\"`,\n })),\n };\n}\n\n/**\n * Issue Templates served by GitHub, including the ones the organization's\n * `.github` repository provides.\n *\n * Only consulted when the local tree has none: that is precisely the case local\n * discovery cannot see, and consulting it otherwise would spend a round-trip to\n * re-learn what is already on disk.\n *\n * GraphQL, not REST: the REST API exposes no issue-template endpoint at all,\n * and the connection returns the bodies inline, so the organization defaults\n * cost a single round-trip instead of one listing plus one call per template.\n */\nexport async function discoverOrganizationTemplates(\n root: string,\n slug: { owner: string; repo: string } | null,\n exec: PolicyExec = defaultExec,\n): Promise<IssueTemplateDiscovery> {\n if (slug === null) {\n return { templates: [], sources: [] };\n }\n\n const outcome = await ghJson(\n root,\n [\n 'api',\n 'graphql',\n '-f',\n `query=${ORGANIZATION_TEMPLATES_QUERY}`,\n '-f',\n `owner=${slug.owner}`,\n '-f',\n `name=${slug.repo}`,\n ],\n exec,\n );\n if ('error' in outcome) {\n return {\n templates: [],\n sources: [\n {\n kind: 'issue-templates',\n origin: 'gh',\n path: null,\n status: 'unavailable',\n detail: outcome.error,\n },\n ],\n };\n }\n\n const templates = parseOrganizationTemplates(outcome.value);\n if (templates.length === 0) {\n return { templates, sources: [] };\n }\n return {\n templates,\n sources: templates.map((template) => ({\n kind: 'issue-templates' as const,\n origin: 'gh' as const,\n path: null,\n status: 'found' as const,\n detail: `organization default \"${template.name}\"`,\n })),\n };\n}\n","import { posix } from 'node:path';\nimport type { PolicyDocumentKind } from '../types.js';\n\n/**\n * Classification and link extraction for the prose documents that carry\n * repository policy.\n */\n\n/** Which kind of policy document a file name denotes, or null. */\nexport function classifyDocument(fileName: string): PolicyDocumentKind | null {\n switch (fileName.toLowerCase()) {\n case 'agents.md':\n return 'agents';\n case 'claude.md':\n return 'claude';\n case 'contributing.md':\n return 'contributing';\n case 'code_of_conduct.md':\n case 'code-of-conduct.md':\n return 'code-of-conduct';\n default:\n return null;\n }\n}\n\n/** How many referenced documents a single index may pull in. */\nexport const MAX_REFERENCED_DOCUMENTS = 20;\n\nconst MARKDOWN_LINK = /\\[[^\\]\\n]*\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g;\n\n/**\n * Repository-relative paths of the markdown documents an index links to.\n *\n * `AGENTS.md` is an index, not a corpus: following its links one level respects\n * what the repository chose to point at, where scanning `docs/` blindly would\n * pull in changelogs, ADR archives and translated copies — a large context cost\n * for content the repository never nominated as policy.\n *\n * Only in-repository markdown targets survive: an absolute URL, a mailto, an\n * anchor, a path that escapes the root, or a link to a non-markdown asset are\n * all dropped. `fromPath` is the repository-relative path of the linking\n * document, used to resolve relative links.\n */\nexport function extractReferencedDocuments(content: string, fromPath: string): string[] {\n const fromDir = posix.dirname(fromPath.replace(/\\\\/g, '/'));\n const found: string[] = [];\n\n for (const match of content.matchAll(MARKDOWN_LINK)) {\n const raw = match[1];\n if (raw === undefined) continue;\n\n const target = raw.split('#')[0]?.split('?')[0]?.trim() ?? '';\n if (target === '') continue;\n // Absolute URLs, protocol-relative URLs and mail links point outside the\n // repository; a Windows-style drive letter is not a repository path either.\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(target) || target.startsWith('//')) continue;\n if (!/\\.(md|markdown)$/i.test(target)) continue;\n\n const resolved = posix.normalize(\n target.startsWith('/')\n ? target.slice(1)\n : fromDir === '.'\n ? target\n : posix.join(fromDir, target),\n );\n if (resolved.startsWith('..') || resolved === '' || resolved === '.') continue;\n if (resolved === fromPath || found.includes(resolved)) continue;\n\n found.push(resolved);\n if (found.length >= MAX_REFERENCED_DOCUMENTS) break;\n }\n\n return found;\n}\n","import type { ChangeType } from '../../conventions/git/index.js';\nimport { isChangeType } from '../../conventions/git/index.js';\n\n/**\n * Textual readers for Git conventions declared by the repository.\n *\n * `.js` / `.ts` / `.mjs` / `.cjs` are scanned as text. They are never\n * `import()`ed — that would execute arbitrary code from the target repository.\n */\n\nexport interface DiscoveredGitConventions {\n commitConvention: string | null;\n pullRequestTitleConvention: string | null;\n allowedTypes: string[] | null;\n scopes: string[] | null;\n sources: { path: string; detail: string }[];\n}\n\nconst COMMITLINT_NAMES = [\n '.commitlintrc',\n '.commitlintrc.json',\n '.commitlintrc.yaml',\n '.commitlintrc.yml',\n '.commitlintrc.js',\n '.commitlintrc.cjs',\n '.commitlintrc.mjs',\n '.commitlintrc.ts',\n 'commitlint.config.js',\n 'commitlint.config.cjs',\n 'commitlint.config.mjs',\n 'commitlint.config.ts',\n];\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n\nfunction extractQuotedStrings(block: string): string[] {\n const matches = block.match(/['\"]([a-z][a-z0-9-]*)['\"]/g) ?? [];\n return matches.map((token) => token.slice(1, -1));\n}\n\nfunction extractEnum(source: string, rule: 'type-enum' | 'scope-enum'): string[] {\n const escaped = rule.replace('-', '\\\\-');\n const match = source.match(new RegExp(`${escaped}[\\\\s\\\\S]{0,800}?\\\\[([\\\\s\\\\S]*?)\\\\]`, 'i'));\n if (match?.[1] === undefined) return [];\n return extractQuotedStrings(match[1]).filter((value) => value !== 'always' && value !== 'never');\n}\n\nfunction parseCommitlintSource(source: string, path: string): DiscoveredGitConventions {\n const types = extractEnum(source, 'type-enum').filter(isChangeType);\n const scopes = extractEnum(source, 'scope-enum');\n const conventional = /conventional|commitlint/i.test(source) || types.length > 0;\n return {\n commitConvention: conventional ? 'conventional' : null,\n pullRequestTitleConvention: null,\n allowedTypes: types.length > 0 ? unique(types) : null,\n scopes: scopes.length > 0 ? unique(scopes) : null,\n sources: [{ path, detail: conventional ? 'commitlint' : 'commitlint (unrecognised)' }],\n };\n}\n\nfunction parsePackageCommitlint(pkg: unknown): DiscoveredGitConventions | null {\n if (pkg === null || typeof pkg !== 'object' || Array.isArray(pkg)) return null;\n const commitlint = (pkg as { commitlint?: unknown }).commitlint;\n if (commitlint === undefined || commitlint === null) return null;\n const source = JSON.stringify(commitlint);\n return parseCommitlintSource(source, 'package.json#commitlint');\n}\n\nfunction parseSemanticPrWorkflow(source: string, path: string): DiscoveredGitConventions | null {\n if (!/amannn\\/action-semantic-pull-request/.test(source)) return null;\n const typesBlock = source.match(/types:\\s*[|>]?\\s*\\n((?:\\s{2,}[a-z][a-z0-9-]*\\s*\\n)+)/i);\n const scopesBlock = source.match(/scopes:\\s*[|>]?\\s*\\n((?:\\s{2,}[a-z][a-z0-9-]*\\s*\\n)+)/i);\n const types =\n typesBlock?.[1]\n ?.split('\\n')\n .map((line) => line.trim())\n .filter((line) => isChangeType(line)) ?? [];\n const scopes =\n scopesBlock?.[1]\n ?.split('\\n')\n .map((line) => line.trim())\n .filter((line) => /^[a-z][a-z0-9-]*$/.test(line)) ?? [];\n return {\n commitConvention: 'conventional',\n pullRequestTitleConvention: 'conventional',\n allowedTypes: types.length > 0 ? unique(types) : null,\n scopes: scopes.length > 0 ? unique(scopes) : null,\n sources: [{ path, detail: 'amannn/action-semantic-pull-request' }],\n };\n}\n\nexport function parseCommitlintText(source: string, path: string): DiscoveredGitConventions {\n return parseCommitlintSource(source, path);\n}\n\nexport function parsePackageJsonCommitlint(raw: string): DiscoveredGitConventions | null {\n try {\n return parsePackageCommitlint(JSON.parse(raw) as unknown);\n } catch {\n return null;\n }\n}\n\nexport function parseReleasePlease(_raw: string, path: string): DiscoveredGitConventions {\n return {\n commitConvention: 'conventional',\n pullRequestTitleConvention: null,\n allowedTypes: null,\n scopes: null,\n sources: [{ path, detail: 'release-please (Conventional Commits)' }],\n };\n}\n\nexport function parseSemanticRelease(path: string): DiscoveredGitConventions {\n return {\n commitConvention: 'conventional',\n pullRequestTitleConvention: null,\n allowedTypes: null,\n scopes: null,\n sources: [{ path, detail: 'semantic-release' }],\n };\n}\n\nexport function parseChangesetConfig(path: string): DiscoveredGitConventions {\n return {\n commitConvention: null,\n pullRequestTitleConvention: null,\n allowedTypes: null,\n scopes: null,\n sources: [{ path, detail: 'changesets release flow' }],\n };\n}\n\nexport function parseHuskyCommitMsg(path: string): DiscoveredGitConventions {\n return {\n commitConvention: null,\n pullRequestTitleConvention: null,\n allowedTypes: null,\n scopes: null,\n sources: [{ path, detail: 'husky commit-msg hook' }],\n };\n}\n\nexport function parseSemanticPullRequestWorkflow(\n source: string,\n path: string,\n): DiscoveredGitConventions | null {\n return parseSemanticPrWorkflow(source, path);\n}\n\nexport const COMMITLINT_FILE_NAMES = COMMITLINT_NAMES;\n\nexport type { ChangeType };\n","import type { LabelDefinition } from '../types.js';\n\n/**\n * Parse `gh label list --json name,description,color`.\n *\n * These are the labels that *really exist*. The distinction matters: a pipeline\n * that invents a label either fails to apply it or, worse, creates it — and a\n * taxonomy nobody agreed to is harder to undo than a missing label.\n *\n * Never throws: a payload that is not an array of label-shaped objects yields\n * an empty list, indistinguishable to the caller from \"gh answered nothing\".\n */\nexport function parseLabels(payload: unknown): LabelDefinition[] {\n if (!Array.isArray(payload)) return [];\n\n const labels: LabelDefinition[] = [];\n for (const entry of payload) {\n if (entry === null || typeof entry !== 'object') continue;\n const record = entry as Record<string, unknown>;\n const name = typeof record.name === 'string' ? record.name.trim() : '';\n if (name === '') continue;\n\n const description = typeof record.description === 'string' ? record.description.trim() : '';\n const color = typeof record.color === 'string' ? record.color.trim() : '';\n\n labels.push({\n name,\n description: description === '' ? null : description,\n color: color === '' ? null : color,\n });\n }\n return labels;\n}\n\n/**\n * Parse `gh api orgs/{org}/issue-types`.\n *\n * Issue Types are an organization-level taxonomy exposed only on some plans, so\n * an empty result is the normal case rather than a failure.\n */\nexport function parseIssueTypes(payload: unknown): string[] {\n const entries = Array.isArray(payload)\n ? payload\n : Array.isArray((payload as { issue_types?: unknown })?.issue_types)\n ? (payload as { issue_types: unknown[] }).issue_types\n : [];\n\n const types: string[] = [];\n for (const entry of entries) {\n const name =\n typeof entry === 'string'\n ? entry\n : entry !== null && typeof entry === 'object'\n ? (entry as Record<string, unknown>).name\n : undefined;\n if (typeof name !== 'string') continue;\n const trimmed = name.trim();\n if (trimmed !== '' && !types.includes(trimmed)) {\n types.push(trimmed);\n }\n }\n return types;\n}\n","import { basename, extname } from 'node:path';\nimport type { IssueTemplate } from '../types.js';\nimport { emptyTemplateMetadata, extractFrontMatter, parseTemplateMetadata } from './issue-forms.js';\n\n/**\n * Turn a template file into an {@link IssueTemplate}.\n *\n * The format is decided by the extension, not by the content: `.yml`/`.yaml` is\n * an Issue Form whose whole document is metadata, everything else is a legacy\n * markdown template whose metadata — if any — lives in a front matter block.\n */\nexport function parseIssueTemplateFile(relPath: string, content: string): IssueTemplate {\n const extension = extname(relPath).toLowerCase();\n const isForm = extension === '.yml' || extension === '.yaml';\n\n const metadataSource = isForm ? content : extractFrontMatter(content);\n const metadata =\n metadataSource === null ? emptyTemplateMetadata() : parseTemplateMetadata(metadataSource);\n\n return {\n path: relPath,\n format: isForm ? 'form' : 'markdown',\n origin: 'filesystem',\n // A template with no `name:` is still addressable by its file name, which\n // is what GitHub falls back to for legacy markdown templates.\n name: metadata.name ?? basename(relPath, extension),\n about: metadata.about,\n title: metadata.title,\n labels: metadata.labels,\n type: metadata.type,\n assignees: metadata.assignees,\n content,\n };\n}\n\nfunction asString(value: unknown): string | null {\n return typeof value === 'string' && value.trim() !== '' ? value : null;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Read a GraphQL connection (`{ nodes: [{ name }] }`) as a list of names, also\n * accepting a plain array of strings so a shape change does not break parsing.\n */\nfunction asNameList(value: unknown, key: 'name' | 'login'): string[] {\n const entries = Array.isArray(value)\n ? value\n : isRecord(value) && Array.isArray(value.nodes)\n ? value.nodes\n : [];\n\n return entries\n .map((entry) =>\n typeof entry === 'string' ? entry : asString(isRecord(entry) ? entry[key] : null),\n )\n .filter((entry): entry is string => entry !== null && entry !== '');\n}\n\n/**\n * Parse the `repository.issueTemplates` connection of the GitHub GraphQL API.\n *\n * This is what makes the organization's `.github` repository visible: a\n * repository with no `.github/ISSUE_TEMPLATE/` of its own still serves the\n * organization defaults on github.com, and no amount of local filesystem\n * discovery can see them. GraphQL is used rather than REST because REST simply\n * has no endpoint for issue templates — and because the connection answers with\n * the bodies included, which keeps the whole discovery to a single round-trip.\n *\n * Never throws: an error payload, a missing repository or anything that is not\n * a list of template-shaped objects yields an empty list, which the caller\n * treats exactly like \"GitHub answered nothing\".\n */\nexport function parseOrganizationTemplates(payload: unknown): IssueTemplate[] {\n const repository = isRecord(payload) && isRecord(payload.data) ? payload.data.repository : null;\n const entries = isRecord(repository) ? repository.issueTemplates : null;\n if (!Array.isArray(entries)) return [];\n\n const templates: IssueTemplate[] = [];\n for (const entry of entries) {\n if (!isRecord(entry)) continue;\n const name = asString(entry.name);\n if (name === null) continue;\n\n templates.push({\n // The filename is the stable identity; the display name is not unique.\n path: asString(entry.filename) ?? name,\n format: 'markdown',\n origin: 'organization',\n name,\n about: asString(entry.about),\n title: asString(entry.title),\n labels: asNameList(entry.labels, 'name'),\n // GraphQL exposes no Issue Type on a template, so it stays unknown here\n // rather than being guessed from the name.\n type: null,\n assignees: asNameList(entry.assignees, 'login'),\n content: asString(entry.body) ?? '',\n });\n }\n return templates;\n}\n\n/**\n * Parse the organization `.github` repository's `ISSUE_TEMPLATE` tree.\n *\n * These are the Issue **Forms** an organization publishes, which the\n * `issueTemplates` connection cannot see. Each entry is a real file, so it is\n * parsed exactly like a local one — the only difference is where it came from,\n * and the caller marks that on `origin`.\n */\nexport function parseOrganizationForms(payload: unknown): IssueTemplate[] {\n const repository = isRecord(payload) && isRecord(payload.data) ? payload.data.repository : null;\n const tree = isRecord(repository) ? repository.object : null;\n const entries = isRecord(tree) && Array.isArray(tree.entries) ? tree.entries : [];\n\n const templates: IssueTemplate[] = [];\n for (const entry of entries) {\n if (!isRecord(entry)) continue;\n const name = asString(entry.name);\n if (name === null || entry.type !== 'blob') continue;\n // The chooser configuration is not a template, same as on the filesystem.\n if (/^config\\.(yml|yaml)$/i.test(name)) continue;\n if (!/\\.(yml|yaml|md|markdown)$/i.test(name)) continue;\n\n const text = isRecord(entry.object) ? asString(entry.object.text) : null;\n if (text === null) continue;\n\n templates.push({ ...parseIssueTemplateFile(name, text), origin: 'organization' });\n }\n\n return templates.sort((a, b) => a.path.localeCompare(b.path));\n}\n","/**\n * A deliberately small YAML reader for Issue Form and Issue Template metadata.\n *\n * Issue Flow does not need a YAML engine: it needs six top-level keys (`name`,\n * `description`/`about`, `title`, `labels`, `type`, `assignees`) out of a file\n * whose remaining structure — the `body:` array of form elements — it has no\n * use for. Pulling a parser dependency in to read those six keys would trade a\n * supply-chain surface for nothing.\n *\n * The reader therefore works on top-level keys only: it locates every line that\n * starts a key at indentation zero, and parses the region of the ones it cares\n * about. Anything nested (a `body:` element, its `attributes:`) is skipped\n * whole, which is why `- type: markdown` inside `body:` can never be mistaken\n * for the top-level `type:` of an Issue Type.\n */\n\n/** The metadata block shared by Issue Forms (`.yml`) and templates (`.md`). */\nexport interface TemplateMetadata {\n name: string | null;\n about: string | null;\n title: string | null;\n labels: string[];\n type: string | null;\n assignees: string[];\n}\n\nexport function emptyTemplateMetadata(): TemplateMetadata {\n return { name: null, about: null, title: null, labels: [], type: null, assignees: [] };\n}\n\nconst TOP_LEVEL_KEY = /^([A-Za-z_][A-Za-z0-9_-]*):(?:\\s+(.*))?$/;\n\ninterface KeyRegion {\n key: string;\n /** Text on the key's own line, after the colon. Empty when the value is a block. */\n inline: string;\n /** Lines below the key, up to the next top-level key. */\n block: string[];\n}\n\n/**\n * Split a YAML document into its top-level key regions.\n *\n * Exported for the templates parser, which reads the same regions out of a\n * markdown front matter block.\n */\nexport function topLevelRegions(source: string): Map<string, KeyRegion> {\n const regions = new Map<string, KeyRegion>();\n const lines = source.split(/\\r?\\n/);\n\n let current: KeyRegion | null = null;\n for (const line of lines) {\n // A line that begins with whitespace, a dash or a comment can never open a\n // top-level key, so it always belongs to the region already open.\n const match = /^[^\\s#-]/.test(line) ? TOP_LEVEL_KEY.exec(line) : null;\n if (match?.[1] !== undefined) {\n current = { key: match[1], inline: (match[2] ?? '').trim(), block: [] };\n // First occurrence wins, matching how a YAML loader would report a\n // duplicate key as a document error rather than silently taking the last.\n if (!regions.has(current.key)) {\n regions.set(current.key, current);\n }\n continue;\n }\n current?.block.push(line);\n }\n\n return regions;\n}\n\n/** Strip a trailing `# comment` that is not inside quotes. */\nfunction stripComment(value: string): string {\n let quote: string | null = null;\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n if (quote !== null) {\n if (char === quote) quote = null;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n if (char === '#' && (i === 0 || /\\s/.test(value[i - 1] ?? ''))) {\n return value.slice(0, i);\n }\n }\n return value;\n}\n\n/** Unquote a scalar, handling the two YAML quoting styles. */\nfunction unquote(value: string): string {\n const trimmed = value.trim();\n if (trimmed.length >= 2) {\n const first = trimmed[0];\n const last = trimmed[trimmed.length - 1];\n if (first === '\"' && last === '\"') {\n return trimmed.slice(1, -1).replace(/\\\\([\"\\\\])/g, '$1');\n }\n if (first === \"'\" && last === \"'\") {\n return trimmed.slice(1, -1).replace(/''/g, \"'\");\n }\n }\n return trimmed;\n}\n\n/** Split a flow sequence body (`a, \"b, c\", d`) on its top-level commas. */\nfunction splitFlow(inner: string): string[] {\n const parts: string[] = [];\n let buffer = '';\n let quote: string | null = null;\n\n for (const char of inner) {\n if (quote !== null) {\n if (char === quote) quote = null;\n buffer += char;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n buffer += char;\n continue;\n }\n if (char === ',') {\n parts.push(buffer);\n buffer = '';\n continue;\n }\n buffer += char;\n }\n parts.push(buffer);\n\n return parts.map(unquote).filter((part) => part !== '');\n}\n\n/** Read a region as a scalar, returning null when it holds no usable value. */\nfunction readScalar(region: KeyRegion | undefined): string | null {\n if (region === undefined) return null;\n\n const inline = stripComment(region.inline).trim();\n if (inline !== '' && inline !== '|' && inline !== '>' && inline !== '|-' && inline !== '>-') {\n const value = unquote(inline);\n return value === '' ? null : value;\n }\n\n // Block scalar (`|`, `>`) or a value that simply starts on the next line.\n const collected = region.block\n .filter((line) => line.trim() !== '')\n .map((line) => line.trim())\n .join(inline.startsWith('>') ? ' ' : '\\n')\n .trim();\n return collected === '' ? null : collected;\n}\n\n/** Read a region as a sequence, accepting both the flow and the block style. */\nfunction readSequence(region: KeyRegion | undefined): string[] {\n if (region === undefined) return [];\n\n const inline = stripComment(region.inline).trim();\n if (inline.startsWith('[')) {\n const closing = inline.lastIndexOf(']');\n return splitFlow(inline.slice(1, closing === -1 ? undefined : closing));\n }\n if (inline !== '') {\n // A bare scalar where a list was expected — GitHub accepts `labels: bug`.\n const single = unquote(inline);\n return single === '' ? [] : [single];\n }\n\n const items: string[] = [];\n for (const line of region.block) {\n const trimmed = line.trim();\n if (trimmed === '' || trimmed.startsWith('#')) continue;\n if (!trimmed.startsWith('- ') && trimmed !== '-') break;\n const value = unquote(stripComment(trimmed.slice(1)).trim());\n // `- key: value` is a mapping, not a label — a list of those is not a\n // taxonomy and taking its first line would invent one.\n if (value === '' || /^[A-Za-z_][A-Za-z0-9_-]*:\\s/.test(value)) continue;\n items.push(value);\n }\n return items;\n}\n\n/**\n * Read the metadata of an Issue Form or Issue Template body.\n *\n * Never throws: a file that is not YAML at all yields empty metadata, which is\n * the same thing the caller does with a template it cannot understand.\n */\nexport function parseTemplateMetadata(source: string): TemplateMetadata {\n const regions = topLevelRegions(source);\n\n return {\n name: readScalar(regions.get('name')),\n // Issue Forms spell it `description`, legacy markdown templates `about`.\n about: readScalar(regions.get('about')) ?? readScalar(regions.get('description')),\n title: readScalar(regions.get('title')),\n labels: readSequence(regions.get('labels')),\n type: readScalar(regions.get('type')),\n assignees: readSequence(regions.get('assignees')),\n };\n}\n\n/**\n * Extract the YAML front matter of a markdown template.\n *\n * Returns null when the file does not open with a `---` fence, which is the\n * common case for a plain `.md` template with no metadata at all.\n */\nexport function extractFrontMatter(source: string): string | null {\n const normalized = source.replace(/^\\uFEFF/, '');\n if (!/^---[ \\t]*\\r?\\n/.test(normalized)) return null;\n\n const rest = normalized.slice(normalized.indexOf('\\n') + 1);\n const closing = /^---[ \\t]*$/m.exec(rest);\n if (closing?.index === undefined) return null;\n\n return rest.slice(0, closing.index);\n}\n","/**\n * The repository policy layer: what the *consumer* repository already declares\n * about how issues, Pull Requests, branches and agents are supposed to work.\n *\n * Every field is discovered, never invented. A repository that declares nothing\n * produces an empty policy — which is exactly the behaviour Issue Flow had\n * before this layer existed.\n */\n\n/**\n * Version of the {@link RepositoryPolicy} shape. Bumped whenever a consumer\n * reading `issue-flow policy --json` would have to change to keep working;\n * purely additive fields do not bump it.\n */\nexport const POLICY_SCHEMA_VERSION = 1;\n\n/** What a {@link PolicySource} is accounting for. */\nexport type PolicySourceKind =\n | 'issue-templates'\n | 'issue-types'\n | 'labels'\n | 'pull-request-template'\n | 'base-branch'\n | 'docs'\n | 'codeowners'\n | 'git-conventions';\n\n/** Where a {@link PolicySource} came from. */\nexport type PolicySourceOrigin = 'filesystem' | 'gh' | 'git' | 'config' | 'env' | 'cli';\n\n/**\n * Outcome of consulting a source.\n *\n * `found` and `disabled` are ordinary states. `unavailable` is the one that\n * matters for debugging: the source *could* have answered but did not — no\n * `gh`, no network, a timeout — and the policy is therefore incomplete rather\n * than empty. Nothing absent is recorded: a repository without a\n * `CONTRIBUTING.md` would otherwise drown `sources` in negative entries.\n */\nexport type PolicySourceStatus = 'found' | 'unavailable' | 'disabled';\n\n/**\n * Provenance of one piece of the resolved policy.\n *\n * Not an accessory: without it there is no way to explain why a decision was\n * taken, nor to debug a wrong discovery.\n */\nexport interface PolicySource {\n kind: PolicySourceKind;\n origin: PolicySourceOrigin;\n /** Repository-relative path (POSIX separators), or null for non-file sources. */\n path: string | null;\n status: PolicySourceStatus;\n /** Human-readable note: the gh command that failed, the reason, a count. */\n detail: string | null;\n}\n\n/** An Issue Template or Issue Form declared by the repository. */\nexport interface IssueTemplate {\n /** Repository-relative path, or the org-level template name when remote. */\n path: string;\n /** `form` for a GitHub Issue Form (`.yml`), `markdown` for a legacy template. */\n format: 'form' | 'markdown';\n /** Where the template was found — the local tree or the organization defaults. */\n origin: 'filesystem' | 'organization';\n name: string | null;\n about: string | null;\n /** Pre-filled title, which is also the closest thing to a title convention. */\n title: string | null;\n labels: string[];\n /** GitHub Issue Type declared by the template (`type:` key), when present. */\n type: string | null;\n assignees: string[];\n /** Raw file content, truncated at {@link MAX_POLICY_DOCUMENT_BYTES}. */\n content: string;\n}\n\n/** A label that really exists in the repository. */\nexport interface LabelDefinition {\n name: string;\n description: string | null;\n color: string | null;\n}\n\n/** A Pull Request template file. */\nexport interface PullRequestTemplate {\n path: string;\n name: string;\n content: string;\n}\n\n/** What a {@link PolicyDocument} is. */\nexport type PolicyDocumentKind =\n | 'agents'\n | 'claude'\n | 'contributing'\n | 'code-of-conduct'\n | 'referenced';\n\n/** A prose document that carries repository policy. */\nexport interface PolicyDocument {\n path: string;\n kind: PolicyDocumentKind;\n /**\n * Directory the document governs, repository-relative; `''` is the root.\n * Documents are ordered from the root down to the requested scope, so the\n * later entry is the more specific one.\n */\n scope: string;\n /** Repository-relative path of the document that linked to this one. */\n referencedFrom: string | null;\n /** File content, truncated at {@link MAX_POLICY_DOCUMENT_BYTES}. */\n content: string;\n}\n\n/** Conventions of the repository around issues. */\nexport interface PolicyIssues {\n templates: IssueTemplate[];\n /** Issue Types of the organization, when the plan exposes them. */\n types: string[];\n /** Labels that really exist in the repository, never a guessed taxonomy. */\n labels: LabelDefinition[];\n titleConvention: string | null;\n}\n\n/** Conventions of the repository around Pull Requests. */\nexport interface PolicyPullRequests {\n /** Content of the default Pull Request template, or null. */\n template: string | null;\n /** Every template found, for the multi-template directory layout. */\n templates: PullRequestTemplate[];\n baseBranch: string | null;\n titleConvention: string | null;\n}\n\n/** Conventions of the repository around git itself. */\nexport interface PolicyGit {\n branchConvention: string | null;\n commitConvention: string | null;\n pullRequestTitleConvention: string | null;\n issueReference: string | null;\n typeMap: Record<string, string> | null;\n allowedTypes: string[] | null;\n scopes: string[] | null;\n}\n\nexport const EMPTY_POLICY_GIT: PolicyGit = {\n branchConvention: null,\n commitConvention: null,\n pullRequestTitleConvention: null,\n issueReference: null,\n typeMap: null,\n allowedTypes: null,\n scopes: null,\n};\n\n/** The resolved policy of a repository, at a given scope. */\nexport interface RepositoryPolicy {\n schemaVersion: typeof POLICY_SCHEMA_VERSION;\n /** Absolute path of the repository root the policy was resolved against. */\n root: string;\n /** Repository-relative subdirectory the policy was resolved for, or null. */\n scope: string | null;\n /** False when `policy.enabled` is off — every section is then empty. */\n enabled: boolean;\n issues: PolicyIssues;\n pullRequests: PolicyPullRequests;\n git: PolicyGit;\n docs: PolicyDocument[];\n /** Content of the CODEOWNERS file, or null. */\n codeowners: string | null;\n sources: PolicySource[];\n}\n\n/** Result of an external command, mirroring `utils/shell.ts`'s ExecResult. */\nexport interface PolicyExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Seam for every external command the discovery shells out to (`gh`, `git`).\n * Injectable so the suite can exercise both the answer and the absence without\n * a real binary.\n */\nexport type PolicyExec = (\n command: string,\n args: string[],\n options: { cwd: string; timeout: number },\n) => Promise<PolicyExecResult>;\n\n/**\n * Upper bound on the bytes read from any single policy document or template.\n *\n * Discovery feeds an agent's context window: an unbounded `AGENTS.md` would\n * cost more than it explains. Truncation is recorded in `sources`.\n */\nexport const MAX_POLICY_DOCUMENT_BYTES = 64 * 1024;\n"],"mappings":"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","names":["sanitizeScope","unique","sep","sep"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/storage/resolve.ts","../src/storage/compat.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { basename, join, resolve } from 'node:path';\nimport { bindTelemetry } from '../telemetry/recorder.js';\nimport { printInfo } from '../ui/logger.js';\nimport { getProjectRoot } from '../utils/git.js';\nimport { type MigrationResult, migrateLegacyStorage, resolveStorageMode } from './compat.js';\nimport {\n type GetGlobalRootOptions,\n getGlobalRoot,\n getIssuePaths,\n getProjectDir,\n getQueuePaths,\n ISSUES_DIR_NAME,\n type IssuePaths,\n PROVIDERS_HEALTH_FILENAME,\n type QueuePaths,\n RUN_LOCK_FILENAME,\n} from './paths.js';\n\n/**\n * The single entry point every pipeline command uses to learn where an issue's\n * artifacts live.\n *\n * `paths.ts` and `compat.ts` stay pure and explicit — they take a `projectId` or\n * a `projectRoot` and never decide anything on their own. This module is the\n * opposite end: it knows the current repository, resolves the storage mode,\n * triggers the legacy migration when one is due, and caches all of that for the\n * lifetime of the process, so a call site is reduced to one line.\n *\n * It deliberately does **not** create the issue directory. Callers that write\n * keep doing their own `mkdir(..., { recursive: true })`, which preserves the\n * rule in `storage/CLAUDE.md` that path resolution never touches the\n * filesystem's shape.\n */\n\nexport interface ResolveIssuePathsOptions extends GetGlobalRootOptions {\n /**\n * Repository root. Defaults to {@link getProjectRoot}, i.e. the git toplevel\n * of the current working directory — which is what makes the result identical\n * from the repo root and from any subdirectory.\n */\n projectRoot?: string;\n}\n\n/** Everything the process needs to know about a project, resolved once. */\ninterface ProjectResolution {\n projectId: string;\n legacyDir: string;\n}\n\n/**\n * Cached project resolutions, keyed by `<globalRoot>::<projectRoot>`.\n *\n * `projectRoot` is the identity of the project, but the global root takes part\n * in the key as well: `ISSUE_FLOW_HOME` decides *where* the resolution lands,\n * so two different roots must never share an entry (that would silently hand a\n * test the previous test's tree).\n *\n * The cached value is the in-flight promise rather than its result, so two\n * commands resolving concurrently share a single git call instead of racing\n * into two migrations.\n */\nconst projectCache = new Map<string, Promise<ProjectResolution>>();\n\n/**\n * Issues whose global directory has already been checked in this process, so\n * the per-issue fallback below stats each issue at most once.\n */\nconst checkedIssues = new Set<string>();\n\n/**\n * Drop every cached resolution.\n *\n * Exported for tests: the cache is keyed by project and global root, so a suite\n * that moves `ISSUE_FLOW_HOME` between cases must reset it in `beforeEach`.\n */\nexport function resetStorageResolutionCache(): void {\n projectCache.clear();\n checkedIssues.clear();\n}\n\nasync function directoryExists(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Tell the user that their artifacts moved, and that nothing was taken away.\n *\n * A migration that copied nothing stays silent: `migrateLegacyStorage` is\n * called speculatively (once per project, then once per issue seen for the\n * first time), and every one of those runs after the first copies zero files.\n * Printing on those would turn a one-time notice into noise on every command.\n *\n * The \"one notice per process\" guarantee falls out of the US-001 cache: the\n * project-level migration runs once, and the per-issue fallback only reaches a\n * second migration when an issue really is still legacy-only — in which case a\n * notice is the correct output, not a duplicate.\n */\nfunction announceMigration(result: MigrationResult): void {\n if (result.copied.length === 0) return;\n\n const count = result.copied.length;\n const target = join(result.globalDir, ISSUES_DIR_NAME);\n\n printInfo(\n `Migrated ${count} file${count === 1 ? '' : 's'} from ${result.legacyDir} to ${target}`,\n );\n printInfo(\n `The legacy directory was not modified or removed — ${result.legacyDir} is kept as-is, read-only, for compatibility.`,\n );\n}\n\n/**\n * Resolve the project id, migrating the legacy tree when it is the only thing\n * that exists yet.\n *\n * A migration failure is not swallowed: `migrateLegacyStorage` already names the\n * issue and file that failed and states that the legacy directory was left\n * untouched, which is exactly what the user needs to fix it and retry.\n */\nasync function resolveProject(\n projectRoot: string,\n options: GetGlobalRootOptions,\n): Promise<ProjectResolution> {\n // resolveStorageMode returns the project id *and* the remote in a single git\n // call — calling getProjectId() afterwards would shell out to\n // `git remote get-url origin` a second time for the same answer.\n const status = await resolveStorageMode(projectRoot, options);\n\n if (status.mode === 'needs-migration') {\n announceMigration(await migrateLegacyStorage(projectRoot, options));\n }\n\n return {\n projectId: status.projectId,\n legacyDir: status.legacyDir,\n };\n}\n\n/** Cached half of {@link resolveIssuePaths}: one git call per project, per process. */\nfunction getProjectResolution(\n projectRoot: string,\n options: GetGlobalRootOptions,\n): Promise<ProjectResolution> {\n const key = `${getGlobalRoot(options)}::${projectRoot}`;\n\n const cached = projectCache.get(key);\n if (cached) return cached;\n\n // A rejected resolution is evicted so the next command retries instead of\n // inheriting a permanently failed promise.\n const pending = resolveProject(projectRoot, options).catch((err) => {\n projectCache.delete(key);\n throw err;\n });\n\n projectCache.set(key, pending);\n return pending;\n}\n\n/** Project-level directories of the current repository inside the global tree. */\nexport interface ProjectStoragePaths {\n /** Deterministic id derived from the repository's remote (or its path). */\n projectId: string;\n /** `<globalRoot>/projects/<projectId>`. */\n projectDir: string;\n /** `<projectDir>/issues` — the parent of every issue directory. */\n issuesDir: string;\n /**\n * `<projectDir>/run.lock` — who is running in this project right now.\n *\n * Project-level rather than per issue on purpose: two runs in one repository\n * share a working tree and a branch, so \"a different issue\" is not a\n * different lock.\n */\n runLockFile: string;\n /** `<projectDir>/providers.json` — persisted health/cooldown per agent provider. */\n providersHealthFile: string;\n}\n\n/**\n * Resolve the project-level directories, without naming an issue.\n *\n * The issue-agnostic half of {@link resolveIssuePaths}, for the two questions\n * that are about the project rather than about one issue: \"can I write here?\"\n * (`LocalFileIssueProvider.isAvailable`) and \"which identifiers are taken?\"\n * (`highestLocalNumber`, which walks `issuesDir`). It shares the same cache, so\n * asking here and then resolving an issue still costs a single git call.\n *\n * Like the rest of this module it creates nothing — a caller that needs the\n * directory to exist does its own `mkdir(..., { recursive: true })`.\n */\nexport async function resolveProjectPaths(\n options: ResolveIssuePathsOptions = {},\n): Promise<ProjectStoragePaths> {\n const { projectRoot: projectRootOption, ...rootOptions } = options;\n const projectRoot = resolve(projectRootOption ?? (await getProjectRoot()));\n\n const project = await getProjectResolution(projectRoot, rootOptions);\n const projectDir = getProjectDir(project.projectId, rootOptions);\n\n return {\n projectId: project.projectId,\n projectDir,\n issuesDir: join(projectDir, ISSUES_DIR_NAME),\n runLockFile: join(projectDir, RUN_LOCK_FILENAME),\n providersHealthFile: join(projectDir, PROVIDERS_HEALTH_FILENAME),\n };\n}\n\n/**\n * Resolve the paths of a multi-issue execution queue in the current project.\n *\n * Shares the project cache with {@link resolveIssuePaths}, so a run that\n * resolves both still costs a single git call. There is no legacy tree for\n * queues — the concept did not exist before — so no migration is attempted.\n */\nexport async function resolveQueuePaths(\n queueId: string | number,\n options: ResolveIssuePathsOptions = {},\n): Promise<QueuePaths> {\n const { projectRoot: projectRootOption, ...rootOptions } = options;\n const projectRoot = resolve(projectRootOption ?? (await getProjectRoot()));\n\n const project = await getProjectResolution(projectRoot, rootOptions);\n return getQueuePaths(project.projectId, queueId, rootOptions);\n}\n\n/**\n * Resolve every path of `issueNumber` under the global storage, migrating the\n * legacy `<projectRoot>/issues/` tree first when needed.\n *\n * The migration is triggered in two situations:\n *\n * 1. project level — the global project directory does not exist at all and the\n * legacy one does (`mode === 'needs-migration'`);\n * 2. issue level — the project directory exists (so the mode is already\n * `global`) but *this* issue is only present in the legacy tree. That\n * happens whenever a project was migrated before an older issue was ever\n * read, or when a collaborator on a previous version added an issue to the\n * legacy directory afterwards. Re-running the migration is cheap and safe:\n * it skips every destination that already exists.\n */\nexport async function resolveIssuePaths(\n issueNumber: string | number,\n options: ResolveIssuePathsOptions = {},\n): Promise<IssuePaths> {\n const { projectRoot: projectRootOption, ...rootOptions } = options;\n const projectRoot = resolve(projectRootOption ?? (await getProjectRoot()));\n\n const project = await getProjectResolution(projectRoot, rootOptions);\n const paths = getIssuePaths(project.projectId, issueNumber, rootOptions);\n\n if (!checkedIssues.has(paths.issueDir)) {\n // `getIssuePaths` already validated and normalized the identifier, so the\n // last segment of issueDir is the safe form to look for under the legacy\n // tree.\n const legacyIssueDir = join(project.legacyDir, basename(paths.issueDir));\n\n if (!(await directoryExists(paths.issueDir)) && (await directoryExists(legacyIssueDir))) {\n announceMigration(await migrateLegacyStorage(projectRoot, rootOptions));\n }\n\n // Marked only once the check completed: a failed migration must be retried\n // by the next command, not remembered as done.\n checkedIssues.add(paths.issueDir);\n }\n\n bindTelemetry({ tasksPath: paths.tasksFile });\n return paths;\n}\n","import type { Dirent } from 'node:fs';\nimport { copyFile, mkdir, readdir, readFile, stat } from 'node:fs/promises';\nimport { join, resolve, sep } from 'node:path';\nimport { isoNow } from '../core/state-manager.js';\nimport { writeFileAtomic } from '../utils/fs.js';\nimport { getRemoteUrl, normalizeRemoteUrl } from '../utils/git.js';\nimport {\n type GetGlobalRootOptions,\n getProjectDir,\n ISSUES_DIR_NAME,\n projectIdFromRemote,\n} from './paths.js';\nimport {\n type ProjectMetadata,\n projectMetadataSchema,\n STORAGE_SCHEMA_VERSION,\n type UserStoryNumberingDecision,\n} from './schemas.js';\n\n/**\n * Coexistence between the legacy per-project layout (`<projectRoot>/issues/`)\n * and the global storage tree (`~/.issue-flow/projects/<project-id>/`).\n *\n * The single rule of this module: **the legacy directory is read-only.** Nothing\n * here removes or rewrites a byte under `<projectRoot>/issues/` — not even\n * behind an opt-in flag — so adopting the global storage can never cost a user\n * their history. Migration is a copy, and a copy that refuses to overwrite.\n */\n\n/** Directory holding the legacy per-project artifacts. */\nexport const LEGACY_ISSUES_DIR_NAME = 'issues';\n\n/** File holding the per-project metadata inside the global storage. */\nexport const METADATA_FILENAME = 'metadata.json';\n\n/**\n * - `global`: the global directory is the source of truth (it already exists,\n * or neither layout does and a fresh project starts there).\n * - `needs-migration`: only the legacy directory exists, so its content has not\n * been copied over yet.\n */\nexport type StorageMode = 'global' | 'needs-migration';\n\nexport interface StorageStatus {\n mode: StorageMode;\n /** Deterministic id, derived from {@link projectIdFromRemote}. */\n projectId: string;\n /** `<globalRoot>/projects/<projectId>`. */\n globalDir: string;\n /** `<projectRoot>/issues`. */\n legacyDir: string;\n /** Whether `globalDir` currently exists on disk. */\n globalExists: boolean;\n /** Whether `legacyDir` currently exists on disk. */\n legacyExists: boolean;\n /**\n * Normalized `origin` remote of `projectRoot`, or `null` without one.\n * Resolved once here so `migrateLegacyStorage` can reuse it instead of\n * shelling out to git a second time for `metadata.json`.\n */\n remoteUrl: string | null;\n}\n\nexport interface MigrationResult {\n projectId: string;\n globalDir: string;\n legacyDir: string;\n /** Mode observed *before* the migration ran. */\n previousMode: StorageMode;\n /** Paths copied, relative to `legacyDir`. */\n copied: string[];\n /** Paths left alone because the destination already had a file. */\n skipped: string[];\n /** Absolute path of the metadata file written by this run. */\n metadataFile: string;\n /** Metadata as persisted. */\n metadata: ProjectMetadata;\n}\n\nexport interface MigrateLegacyStorageOptions extends GetGlobalRootOptions {\n /** Timestamp source, injectable so tests can assert createdAt/updatedAt. */\n now?: () => string;\n}\n\nasync function directoryExists(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Describe where a project's artifacts live, without touching anything.\n *\n * Read-only by construction: it stats the two candidate directories and reports\n * what it found. It never creates a directory, so a caller can ask the question\n * (a status command, a warning banner) without committing the user to the new\n * layout.\n *\n * An existing global directory always wins: once artifacts are there, that is\n * the source of truth, and a legacy directory left behind is simply preserved\n * rather than re-read or re-migrated.\n */\nexport async function resolveStorageMode(\n projectRoot: string,\n options: GetGlobalRootOptions = {},\n): Promise<StorageStatus> {\n const remoteUrl = normalizeRemoteUrl(await getRemoteUrl(projectRoot));\n const projectId = projectIdFromRemote(remoteUrl, projectRoot);\n const globalDir = getProjectDir(projectId, options);\n const legacyDir = join(resolve(projectRoot), LEGACY_ISSUES_DIR_NAME);\n\n const [globalExists, legacyExists] = await Promise.all([\n directoryExists(globalDir),\n directoryExists(legacyDir),\n ]);\n\n return {\n // Only one state calls for work: legacy content that has nowhere to be read\n // from yet. Everything else — including \"neither exists\" — is already the\n // global layout.\n mode: legacyExists && !globalExists ? 'needs-migration' : 'global',\n projectId,\n globalDir,\n legacyDir,\n globalExists,\n legacyExists,\n remoteUrl,\n };\n}\n\n/**\n * Wrap an IO failure with the issue and file it happened on, so a partial\n * migration is diagnosable instead of a bare `EACCES`.\n */\nfunction migrationFailure(issue: string, relativePath: string, err: unknown): Error {\n const reason = err instanceof Error ? err.message : String(err);\n\n return new Error(\n `Failed to migrate '${relativePath}' (issue '${issue}'): ${reason}. ` +\n 'The legacy directory was left untouched — fix the cause and run the migration again.',\n );\n}\n\n/** First path segment of a relative path — the issue a file belongs to. */\nfunction issueOf(relativePath: string): string {\n return relativePath.split(sep)[0] || '.';\n}\n\n/**\n * Copy one directory level, recursing into subdirectories.\n *\n * Symlinks and other non-regular entries are skipped on purpose: following them\n * could copy content from outside the legacy directory into the global tree.\n */\nasync function copyTree(\n sourceRoot: string,\n targetRoot: string,\n relativeDir: string,\n result: { copied: string[]; skipped: string[] },\n): Promise<void> {\n const source = join(sourceRoot, relativeDir);\n const target = join(targetRoot, relativeDir);\n\n let entries: Dirent[];\n try {\n entries = await readdir(source, { withFileTypes: true });\n } catch (err) {\n throw migrationFailure(issueOf(relativeDir), relativeDir || '.', err);\n }\n\n try {\n // recursive: true also makes re-running a no-op on an existing directory.\n await mkdir(target, { recursive: true });\n } catch (err) {\n throw migrationFailure(issueOf(relativeDir), relativeDir || '.', err);\n }\n\n for (const entry of entries) {\n const relativePath = join(relativeDir, entry.name);\n\n if (entry.isDirectory()) {\n await copyTree(sourceRoot, targetRoot, relativePath, result);\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n\n const to = join(targetRoot, relativePath);\n try {\n // Idempotency and safety in one check: a destination that already exists\n // is never overwritten, so a second run copies nothing and a hand-edited\n // artifact in the global tree survives.\n if (await pathExists(to)) {\n result.skipped.push(relativePath);\n continue;\n }\n await copyFile(join(sourceRoot, relativePath), to);\n result.copied.push(relativePath);\n } catch (err) {\n throw migrationFailure(issueOf(relativePath), relativePath, err);\n }\n }\n}\n\n/**\n * Read `metadata.json`, tolerating every failure.\n *\n * A missing, corrupt or schema-invalid file must not block a migration: the\n * caller simply writes a fresh one. The only thing worth recovering is\n * `createdAt`/`lastAttemptAt` from a valid previous file.\n */\nasync function readExistingMetadata(file: string): Promise<ProjectMetadata | null> {\n let raw: string;\n try {\n raw = await readFile(file, 'utf-8');\n } catch {\n return null;\n }\n\n try {\n const parsed = projectMetadataSchema.safeParse(JSON.parse(raw));\n return parsed.success ? parsed.data : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Copy `<projectRoot>/issues/` into the project's global directory and stamp\n * its `metadata.json`.\n *\n * Non-destructive and idempotent, by design rather than by convention:\n *\n * - the source is only ever read — there is no removal option in this release;\n * - a destination file that already exists is skipped, never overwritten, so a\n * second run reports everything as skipped and changes nothing but\n * `updatedAt`;\n * - a failure mid-way leaves the legacy directory intact and names the issue\n * and file that failed, so the run can be repeated after the fix and will\n * resume by skipping what already made it across.\n *\n * Called on a project with no legacy directory it is still useful: it creates\n * the project directory and its metadata.\n */\nexport async function migrateLegacyStorage(\n projectRoot: string,\n options: MigrateLegacyStorageOptions = {},\n): Promise<MigrationResult> {\n const status = await resolveStorageMode(projectRoot, { env: options.env });\n const result = { copied: [] as string[], skipped: [] as string[] };\n\n try {\n await mkdir(status.globalDir, { recursive: true });\n } catch (err) {\n throw migrationFailure('.', status.globalDir, err);\n }\n\n if (status.legacyExists) {\n await copyTree(status.legacyDir, join(status.globalDir, ISSUES_DIR_NAME), '', result);\n }\n\n const now = (options.now ?? isoNow)();\n const metadataFile = join(status.globalDir, METADATA_FILENAME);\n const existing = await readExistingMetadata(metadataFile);\n\n const metadata: ProjectMetadata = {\n schemaVersion: STORAGE_SCHEMA_VERSION,\n projectId: status.projectId,\n root: resolve(projectRoot),\n remoteUrl: status.remoteUrl,\n // The project was first seen whenever it was first written, not now.\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n lastAttemptAt: existing?.lastAttemptAt ?? null,\n };\n\n await writeFileAtomic(metadataFile, `${JSON.stringify(metadata, null, 2)}\\n`);\n\n return {\n projectId: status.projectId,\n globalDir: status.globalDir,\n legacyDir: status.legacyDir,\n previousMode: status.mode,\n ...result,\n metadataFile,\n metadata,\n };\n}\n\nexport interface RecordUserStoryNumberingOptions extends GetGlobalRootOptions {\n /** Timestamp source, injectable so tests can assert `updatedAt`. */\n now?: () => string;\n}\n\n/**\n * Persist a `plan` run's User Story numbering decision into the project's\n * `metadata.json`, for audit (issue #36) — this is a read-modify-write on the\n * same file {@link migrateLegacyStorage} stamps, never a second file.\n *\n * The decision itself is never read back to resolve a *later* one: the next\n * `plan` run always re-scans `tasks.json` from scratch (see\n * `storage/user-story-numbering.ts`). Losing this field only costs an audit\n * trail entry, never correctness.\n *\n * A missing `metadata.json` (a project whose first command ever is a numbered\n * `plan`, with no legacy directory to trigger a migration) is created here\n * from scratch, exactly like {@link migrateLegacyStorage} would.\n */\nexport async function recordUserStoryNumbering(\n projectRoot: string,\n decision: UserStoryNumberingDecision,\n options: RecordUserStoryNumberingOptions = {},\n): Promise<void> {\n const status = await resolveStorageMode(projectRoot, { env: options.env });\n const metadataFile = join(status.globalDir, METADATA_FILENAME);\n const existing = await readExistingMetadata(metadataFile);\n const now = (options.now ?? isoNow)();\n\n const metadata: ProjectMetadata = {\n schemaVersion: STORAGE_SCHEMA_VERSION,\n projectId: status.projectId,\n root: resolve(projectRoot),\n remoteUrl: status.remoteUrl,\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n lastAttemptAt: existing?.lastAttemptAt ?? null,\n userStoryNumbering: decision,\n };\n\n await mkdir(status.globalDir, { recursive: true });\n await writeFileAtomic(metadataFile, `${JSON.stringify(metadata, null, 2)}\\n`);\n}\n"],"mappings":"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","names":["stat","join","resolve","directoryExists","stat","join","resolve"]}
|