issue-flow 0.18.0 → 0.19.1
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 +34 -100
- package/dist/agent-EWKA7357.js +32 -0
- package/dist/{analyze-Q4ONIWRZ.js → analyze-Z7ODC27F.js} +42 -41
- package/dist/analyze-Z7ODC27F.js.map +1 -0
- package/dist/{apply-EEFPY2W4.js → apply-VNSWQS6O.js} +22 -24
- package/dist/apply-VNSWQS6O.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-ZJEIACUK.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-XUEMATVY.js → chunk-2EZW4X57.js} +28 -25
- package/dist/chunk-2EZW4X57.js.map +1 -0
- package/dist/{chunk-LGHND47K.js → chunk-2Q6PG3MT.js} +15 -15
- package/dist/chunk-2Q6PG3MT.js.map +1 -0
- package/dist/{chunk-C5TL7T4V.js → chunk-2YM2VH6R.js} +2 -2
- package/dist/{chunk-OODXFCQV.js → chunk-2YYP7AE6.js} +14 -16
- package/dist/{chunk-OODXFCQV.js.map → chunk-2YYP7AE6.js.map} +1 -1
- package/dist/chunk-3JD25HHJ.js +278 -0
- package/dist/chunk-3JD25HHJ.js.map +1 -0
- package/dist/{chunk-PMLE7KAQ.js → chunk-46S7APLQ.js} +30 -14
- package/dist/chunk-46S7APLQ.js.map +1 -0
- package/dist/chunk-6AOZCWN2.js +21 -0
- package/dist/chunk-6AOZCWN2.js.map +1 -0
- package/dist/{chunk-QPGEFLMY.js → chunk-7CMVL4X6.js} +7 -7
- package/dist/chunk-7MJGYPHF.js +1571 -0
- package/dist/chunk-7MJGYPHF.js.map +1 -0
- package/dist/chunk-7ZZUSMBJ.js +35 -0
- package/dist/chunk-7ZZUSMBJ.js.map +1 -0
- package/dist/{chunk-DUS5ZNKL.js → chunk-DIMDAYZS.js} +7 -6
- package/dist/{chunk-DGRTJD5R.js → chunk-DXH4TQRB.js} +7 -7
- package/dist/{chunk-CRGIQFUQ.js → chunk-E2H3JV2E.js} +3 -1
- package/dist/chunk-E2H3JV2E.js.map +1 -0
- package/dist/{chunk-YUNBOUQH.js → chunk-ERAG5IQB.js} +8 -8
- package/dist/{chunk-ZVZMWNCG.js → chunk-F2NFJ27Z.js} +2 -2
- package/dist/{chunk-SOM4QA6C.js → chunk-GD7JZMSJ.js} +93 -18
- package/dist/chunk-GD7JZMSJ.js.map +1 -0
- package/dist/{chunk-6K2LCFG6.js → chunk-HEHHQU4G.js} +70 -81
- package/dist/chunk-HEHHQU4G.js.map +1 -0
- package/dist/{chunk-34OCSKOB.js → chunk-HHXWAWU6.js} +159 -114
- package/dist/chunk-HHXWAWU6.js.map +1 -0
- package/dist/{chunk-E4I6MMHD.js → chunk-HWWB22HC.js} +152 -100
- package/dist/chunk-HWWB22HC.js.map +1 -0
- package/dist/chunk-IMB6FA2F.js +673 -0
- package/dist/chunk-IMB6FA2F.js.map +1 -0
- package/dist/{chunk-ECU7YO7S.js → chunk-IQYXXFRC.js} +22 -6
- package/dist/chunk-IQYXXFRC.js.map +1 -0
- package/dist/chunk-J6VJ5M2U.js +1201 -0
- package/dist/chunk-J6VJ5M2U.js.map +1 -0
- package/dist/{chunk-QJ44VG5G.js → chunk-KDQRNVBZ.js} +3 -3
- package/dist/{chunk-7UMMFOL2.js → chunk-LRWIP7QS.js} +39 -24
- package/dist/chunk-LRWIP7QS.js.map +1 -0
- package/dist/{chunk-LI35PIIS.js → chunk-LYC57OXF.js} +20 -117
- package/dist/chunk-LYC57OXF.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-CWSQVHVV.js → chunk-MHA7Q3KU.js} +248 -102
- package/dist/chunk-MHA7Q3KU.js.map +1 -0
- package/dist/{chunk-TZYINKCC.js → chunk-MQTVMB7W.js} +33 -28
- package/dist/chunk-MQTVMB7W.js.map +1 -0
- package/dist/chunk-NP47HRX2.js +136 -0
- package/dist/chunk-NP47HRX2.js.map +1 -0
- package/dist/{chunk-EG2MGDP5.js → chunk-NYDAHE3Y.js} +52 -46
- package/dist/chunk-NYDAHE3Y.js.map +1 -0
- package/dist/{chunk-45WZ6GMI.js → chunk-P7ZYOC23.js} +16 -16
- package/dist/{chunk-3R27MJ5R.js → chunk-PFWHHYEO.js} +3 -3
- package/dist/{chunk-NEWNXZ65.js → chunk-PHPAK2L6.js} +28 -26
- package/dist/{chunk-NEWNXZ65.js.map → chunk-PHPAK2L6.js.map} +1 -1
- package/dist/{chunk-PPZ3K4YM.js → chunk-PRGPSNGA.js} +2 -2
- package/dist/{chunk-V7QOIQYC.js → chunk-RGFMQFX7.js} +9 -23
- package/dist/{chunk-V7QOIQYC.js.map → chunk-RGFMQFX7.js.map} +1 -1
- package/dist/{chunk-YVPZUN6X.js → chunk-TJVX42KY.js} +335 -38
- package/dist/chunk-TJVX42KY.js.map +1 -0
- package/dist/{chunk-HOAHMERN.js → chunk-UDRAD7MF.js} +21 -21
- package/dist/{chunk-QF7VEL3M.js → chunk-UHDXXLYH.js} +39 -127
- package/dist/chunk-UHDXXLYH.js.map +1 -0
- package/dist/{chunk-RNFUVKC3.js → chunk-UPAAZU4W.js} +30 -13
- package/dist/chunk-UPAAZU4W.js.map +1 -0
- package/dist/{chunk-L6HSKTQE.js → chunk-W7LZLJAF.js} +4 -4
- package/dist/{chunk-KMCS76ZW.js → chunk-WB2FVIUS.js} +44 -12
- package/dist/chunk-WB2FVIUS.js.map +1 -0
- package/dist/{chunk-SA6HXL4Y.js → chunk-WPHC6JBR.js} +9 -9
- package/dist/chunk-WPHC6JBR.js.map +1 -0
- package/dist/{chunk-KRAGAUKD.js → chunk-XHCP6ZNO.js} +201 -64
- package/dist/chunk-XHCP6ZNO.js.map +1 -0
- package/dist/{chunk-7F7LGMVO.js → chunk-XKR3VD2Z.js} +12 -12
- package/dist/{chunk-7F7LGMVO.js.map → chunk-XKR3VD2Z.js.map} +1 -1
- package/dist/{chunk-ICM463EO.js → chunk-XNK5UN2D.js} +5 -649
- package/dist/chunk-XNK5UN2D.js.map +1 -0
- package/dist/{chunk-LTH6XYZ3.js → chunk-XQLNZW7I.js} +40 -30
- package/dist/chunk-XQLNZW7I.js.map +1 -0
- package/dist/{chunk-62GVVZQO.js → chunk-ZAYATXJD.js} +32 -316
- package/dist/chunk-ZAYATXJD.js.map +1 -0
- package/dist/cli.js +127 -59
- package/dist/cli.js.map +1 -1
- package/dist/compat-YPDZB34U.js +24 -0
- package/dist/{config-LEBZZCJP.js → config-56B4OHZE.js} +20 -17
- package/dist/{contract-JH2WBIO6.js → contract-HWLFFL3F.js} +2 -2
- package/dist/{conventions-XOT6YW5L.js → conventions-DW2CM5I3.js} +20 -16
- package/dist/{conventions-XOT6YW5L.js.map → conventions-DW2CM5I3.js.map} +1 -1
- package/dist/db-5NU77PJA.js +264 -0
- package/dist/db-5NU77PJA.js.map +1 -0
- package/dist/diagnostics-UCTS2VUF.js +25 -0
- package/dist/execute-R7AVOLNG.js +38 -0
- package/dist/{generate-JGW5JSKB.js → generate-O7GUXLN4.js} +46 -43
- package/dist/generate-O7GUXLN4.js.map +1 -0
- package/dist/{git-A2IP32PQ.js → git-LCG45YXD.js} +2 -3
- package/dist/history-6GSURU3H.js +101 -0
- package/dist/history-6GSURU3H.js.map +1 -0
- package/dist/init-DD6DBRC5.js +28 -0
- package/dist/{operations-O4FORFIH.js → operations-HU5ZFEBA.js} +78 -52
- package/dist/operations-HU5ZFEBA.js.map +1 -0
- package/dist/{permissions-G4XCAESF.js → permissions-NNNSRC4P.js} +5 -6
- package/dist/plan-XR6B7EM3.js +38 -0
- package/dist/{policy-U5NBFAO5.js → policy-RFJOJQL6.js} +17 -15
- package/dist/{policy-U5NBFAO5.js.map → policy-RFJOJQL6.js.map} +1 -1
- package/dist/pr-OSCNJCOO.js +42 -0
- package/dist/pr-review-IKIYHFBO.js +33 -0
- package/dist/prd-HFDZJJQR.js +37 -0
- package/dist/{ps-76L6ZAZL.js → ps-AKRHGPSR.js} +26 -15
- package/dist/ps-AKRHGPSR.js.map +1 -0
- package/dist/{recorder-2BAKPBRA.js → recorder-T7426CKV.js} +11 -7
- package/dist/registry-DWRKD65A.js +17 -0
- package/dist/repository-TABBRW2C.js +80 -0
- package/dist/resume-GDXKK5XP.js +278 -0
- package/dist/resume-GDXKK5XP.js.map +1 -0
- package/dist/review-JJHMQA2O.js +38 -0
- package/dist/routing-FPNUVE7T.js +35 -0
- package/dist/run-RLCURLLL.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-IGNTD4AB.js} +9 -4
- package/dist/state-manager-IGNTD4AB.js.map +1 -0
- package/dist/{usage-KTMYXAPF.js → usage-XW27AL5K.js} +69 -63
- package/dist/usage-XW27AL5K.js.map +1 -0
- package/dist/web-NCDBVZ5Y.js +205 -0
- package/dist/web-NCDBVZ5Y.js.map +1 -0
- package/package.json +20 -7
- 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 +109 -110
- 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-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/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-EWKA7357.js.map} +0 -0
- /package/dist/{bench-WWWXLTFH.js.map → bench-ZJEIACUK.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-QPGEFLMY.js.map → chunk-7CMVL4X6.js.map} +0 -0
- /package/dist/{chunk-DUS5ZNKL.js.map → chunk-DIMDAYZS.js.map} +0 -0
- /package/dist/{chunk-DGRTJD5R.js.map → chunk-DXH4TQRB.js.map} +0 -0
- /package/dist/{chunk-YUNBOUQH.js.map → chunk-ERAG5IQB.js.map} +0 -0
- /package/dist/{chunk-ZVZMWNCG.js.map → chunk-F2NFJ27Z.js.map} +0 -0
- /package/dist/{chunk-QJ44VG5G.js.map → chunk-KDQRNVBZ.js.map} +0 -0
- /package/dist/{chunk-45WZ6GMI.js.map → chunk-P7ZYOC23.js.map} +0 -0
- /package/dist/{chunk-3R27MJ5R.js.map → chunk-PFWHHYEO.js.map} +0 -0
- /package/dist/{chunk-PPZ3K4YM.js.map → chunk-PRGPSNGA.js.map} +0 -0
- /package/dist/{chunk-HOAHMERN.js.map → chunk-UDRAD7MF.js.map} +0 -0
- /package/dist/{chunk-L6HSKTQE.js.map → chunk-W7LZLJAF.js.map} +0 -0
- /package/dist/{config-LEBZZCJP.js.map → compat-YPDZB34U.js.map} +0 -0
- /package/dist/{contract-JH2WBIO6.js.map → config-56B4OHZE.js.map} +0 -0
- /package/dist/{diagnostics-HTCWF7F4.js.map → contract-HWLFFL3F.js.map} +0 -0
- /package/dist/{execute-LELOSR5T.js.map → diagnostics-UCTS2VUF.js.map} +0 -0
- /package/dist/{git-A2IP32PQ.js.map → execute-R7AVOLNG.js.map} +0 -0
- /package/dist/{init-TO6MUXO4.js.map → git-LCG45YXD.js.map} +0 -0
- /package/dist/{permissions-G4XCAESF.js.map → init-DD6DBRC5.js.map} +0 -0
- /package/dist/{plan-OXAT344Q.js.map → permissions-NNNSRC4P.js.map} +0 -0
- /package/dist/{pr-UZHNKKZC.js.map → plan-XR6B7EM3.js.map} +0 -0
- /package/dist/{pr-review-Q4ACAWDM.js.map → pr-OSCNJCOO.js.map} +0 -0
- /package/dist/{prd-6CYEMLDY.js.map → pr-review-IKIYHFBO.js.map} +0 -0
- /package/dist/{recorder-2BAKPBRA.js.map → prd-HFDZJJQR.js.map} +0 -0
- /package/dist/{registry-XLHHYLTR.js.map → recorder-T7426CKV.js.map} +0 -0
- /package/dist/{review-LVZT2TMW.js.map → registry-DWRKD65A.js.map} +0 -0
- /package/dist/{routing-EK6RBZM4.js.map → repository-TABBRW2C.js.map} +0 -0
- /package/dist/{run-2RXJCJKT.js.map → review-JJHMQA2O.js.map} +0 -0
- /package/dist/{session-publisher-KAJQRHNZ.js.map → routing-FPNUVE7T.js.map} +0 -0
- /package/dist/{state-manager-UPHO2EA2.js.map → run-RLCURLLL.js.map} +0 -0
|
@@ -1,120 +1,126 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
parseDocumentResult
|
|
4
|
+
} from "./chunk-6AOZCWN2.js";
|
|
2
5
|
import {
|
|
3
6
|
isTransientFailure,
|
|
4
|
-
readFileWithGrace,
|
|
5
7
|
runPhaseWithRetry
|
|
6
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RGFMQFX7.js";
|
|
7
9
|
import {
|
|
8
10
|
issuePlaceholders,
|
|
11
|
+
issueReference,
|
|
9
12
|
resolveCommandIssue
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WPHC6JBR.js";
|
|
11
14
|
import {
|
|
12
15
|
publishPhaseMetrics,
|
|
13
16
|
resolvePolicyPlaceholders
|
|
14
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-WB2FVIUS.js";
|
|
15
18
|
import {
|
|
16
19
|
applyPlaceholders,
|
|
17
20
|
loadPrompt
|
|
18
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-XKR3VD2Z.js";
|
|
19
22
|
import {
|
|
20
23
|
DEFAULT_HEADLESS_TIMEOUT_MS,
|
|
21
24
|
runHeadless
|
|
22
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-MQTVMB7W.js";
|
|
23
26
|
import {
|
|
24
27
|
DEFAULT_BRANCH_CONVENTION,
|
|
25
28
|
branchName,
|
|
26
29
|
loadRepositoryPolicy,
|
|
27
30
|
resolveChangeType
|
|
28
|
-
} from "./chunk-
|
|
29
|
-
import {
|
|
30
|
-
recordUserStoryNumbering,
|
|
31
|
-
resolveIssuePaths,
|
|
32
|
-
resolveProjectPaths
|
|
33
|
-
} from "./chunk-LI35PIIS.js";
|
|
31
|
+
} from "./chunk-2Q6PG3MT.js";
|
|
34
32
|
import {
|
|
35
33
|
getGlobalTimeout,
|
|
36
34
|
printError,
|
|
37
35
|
printInfo,
|
|
38
36
|
printSuccess,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
getIssuePaths
|
|
43
|
-
} from "./chunk-HAKDLR6N.js";
|
|
44
|
-
import {
|
|
45
|
-
getProjectRoot
|
|
46
|
-
} from "./chunk-YVPZUN6X.js";
|
|
37
|
+
resolveIssuePaths,
|
|
38
|
+
resolveProjectPaths
|
|
39
|
+
} from "./chunk-J6VJ5M2U.js";
|
|
47
40
|
import {
|
|
48
41
|
isoNow,
|
|
49
42
|
loadTaskPlan,
|
|
50
43
|
saveTaskPlan
|
|
51
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-GD7JZMSJ.js";
|
|
45
|
+
import {
|
|
46
|
+
inspectTaskPlan
|
|
47
|
+
} from "./chunk-NP47HRX2.js";
|
|
48
|
+
import {
|
|
49
|
+
findHighestStoredUserStoryNumber,
|
|
50
|
+
getPlanRepository,
|
|
51
|
+
ingestGeneratedPlan,
|
|
52
|
+
saveStoredUserStoryNumbering
|
|
53
|
+
} from "./chunk-7MJGYPHF.js";
|
|
54
|
+
import {
|
|
55
|
+
getProjectRoot
|
|
56
|
+
} from "./chunk-TJVX42KY.js";
|
|
52
57
|
import {
|
|
53
|
-
|
|
54
|
-
} from "./chunk-
|
|
58
|
+
writeFileAtomic
|
|
59
|
+
} from "./chunk-PFWHHYEO.js";
|
|
55
60
|
|
|
56
61
|
// src/commands/plan.ts
|
|
57
|
-
import { mkdir, readFile
|
|
62
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
63
|
+
import { basename } from "node:path";
|
|
64
|
+
|
|
65
|
+
// src/core/plan-result.ts
|
|
66
|
+
import { z } from "zod";
|
|
67
|
+
var storyDraftSchema = z.object({
|
|
68
|
+
key: z.string().min(1),
|
|
69
|
+
title: z.string().min(1),
|
|
70
|
+
description: z.string().min(1),
|
|
71
|
+
acceptanceCriteria: z.array(z.string().min(1)).min(1),
|
|
72
|
+
dependsOn: z.array(z.string().min(1)).optional().default([])
|
|
73
|
+
});
|
|
74
|
+
var planDraftSchema = z.object({
|
|
75
|
+
description: z.string().min(1),
|
|
76
|
+
stories: z.array(storyDraftSchema).min(1)
|
|
77
|
+
});
|
|
78
|
+
function parsePlanResult(output) {
|
|
79
|
+
const content = parseDocumentResult(output, "task-plan");
|
|
80
|
+
const draft = planDraftSchema.parse(JSON.parse(content));
|
|
81
|
+
const keys = /* @__PURE__ */ new Set();
|
|
82
|
+
for (const story of draft.stories) {
|
|
83
|
+
if (keys.has(story.key)) throw new Error(`Duplicate story key: ${story.key}`);
|
|
84
|
+
keys.add(story.key);
|
|
85
|
+
}
|
|
86
|
+
for (const story of draft.stories) {
|
|
87
|
+
for (const dependency of story.dependsOn) {
|
|
88
|
+
if (dependency === story.key) throw new Error(`Story ${story.key} depends on itself`);
|
|
89
|
+
if (!keys.has(dependency))
|
|
90
|
+
throw new Error(`Story ${story.key} has unknown dependency ${dependency}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return draft;
|
|
94
|
+
}
|
|
58
95
|
|
|
59
96
|
// src/storage/user-story-numbering.ts
|
|
60
|
-
import { readdir, readFile } from "fs/promises";
|
|
61
97
|
var USER_STORY_ID_PAD = 3;
|
|
62
98
|
function formatUserStoryId(n) {
|
|
63
99
|
return `US-${String(n).padStart(USER_STORY_ID_PAD, "0")}`;
|
|
64
100
|
}
|
|
65
|
-
function parseUserStoryNumber(id) {
|
|
66
|
-
const matches = id.match(/\d+/g);
|
|
67
|
-
if (!matches || matches.length === 0) return null;
|
|
68
|
-
const value = Number.parseInt(matches[matches.length - 1], 10);
|
|
69
|
-
return Number.isNaN(value) ? null : value;
|
|
70
|
-
}
|
|
71
|
-
async function readUserStoryIds(tasksPath) {
|
|
72
|
-
let raw;
|
|
73
|
-
try {
|
|
74
|
-
raw = await readFile(tasksPath, "utf-8");
|
|
75
|
-
} catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
try {
|
|
79
|
-
const parsed = JSON.parse(raw);
|
|
80
|
-
if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.userStories)) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
return parsed.userStories.map(
|
|
84
|
-
(story) => typeof story === "object" && story !== null && typeof story.id === "string" ? story.id : null
|
|
85
|
-
).filter((id) => id !== null);
|
|
86
|
-
} catch {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
101
|
async function findHighestUserStoryNumber(options = {}) {
|
|
91
102
|
const { excludeIssueId, ...rootOptions } = options;
|
|
92
|
-
|
|
93
|
-
let entries;
|
|
103
|
+
let project;
|
|
94
104
|
try {
|
|
95
|
-
|
|
105
|
+
project = await resolveProjectPaths(rootOptions);
|
|
96
106
|
} catch (error) {
|
|
97
|
-
if (error?.code === "ENOENT") return null;
|
|
98
107
|
throw new Error(
|
|
99
|
-
`Could not
|
|
108
|
+
`Could not query the project's User Story history: ${error.message}. Fix the storage directory, or pass --start-us <n> to set the numbering explicitly.`,
|
|
100
109
|
{ cause: error }
|
|
101
110
|
);
|
|
102
111
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
}
|
|
112
|
+
try {
|
|
113
|
+
return await findHighestStoredUserStoryNumber({
|
|
114
|
+
projectId: project.projectId,
|
|
115
|
+
excludeIssueId,
|
|
116
|
+
databaseOptions: project.databaseOptions
|
|
117
|
+
});
|
|
118
|
+
} catch (error) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Could not query the project's User Story history: ${error.message}. Fix the SQLite database, or pass --start-us <n> to set the numbering explicitly.`,
|
|
121
|
+
{ cause: error }
|
|
122
|
+
);
|
|
116
123
|
}
|
|
117
|
-
return best;
|
|
118
124
|
}
|
|
119
125
|
async function resolveUserStoryNumbering(options) {
|
|
120
126
|
const { issueNumber, continueFlag, startUs, now, ...rootOptions } = options;
|
|
@@ -162,10 +168,23 @@ async function determineUserStoryNumbering(options) {
|
|
|
162
168
|
const { projectRoot: projectRootOption, ...rest } = options;
|
|
163
169
|
const projectRoot = projectRootOption ?? await getProjectRoot();
|
|
164
170
|
const outcome = await resolveUserStoryNumbering({ ...rest, projectRoot });
|
|
165
|
-
await
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
const project = await resolveProjectPaths({ projectRoot, env: options.env });
|
|
172
|
+
if (project.storageDriver === "sqlite") {
|
|
173
|
+
await saveStoredUserStoryNumbering(
|
|
174
|
+
{
|
|
175
|
+
projectId: project.projectId,
|
|
176
|
+
projectRoot,
|
|
177
|
+
databaseOptions: project.databaseOptions
|
|
178
|
+
},
|
|
179
|
+
outcome.decision
|
|
180
|
+
);
|
|
181
|
+
} else {
|
|
182
|
+
const { recordUserStoryNumbering } = await import("./compat-YPDZB34U.js");
|
|
183
|
+
await recordUserStoryNumbering(projectRoot, outcome.decision, {
|
|
184
|
+
env: options.env,
|
|
185
|
+
now: options.now
|
|
186
|
+
});
|
|
187
|
+
}
|
|
169
188
|
return { ...outcome, nextUserStoryId: formatUserStoryId(outcome.decision.nextNumber) };
|
|
170
189
|
}
|
|
171
190
|
|
|
@@ -180,7 +199,7 @@ async function runPlan(issue, resolvedIssue, numbering) {
|
|
|
180
199
|
const prdPath = paths.prdFile;
|
|
181
200
|
let prdContent;
|
|
182
201
|
try {
|
|
183
|
-
prdContent = await
|
|
202
|
+
prdContent = await readFile(prdPath, "utf-8");
|
|
184
203
|
} catch {
|
|
185
204
|
printError(`PRD not found at ${prdPath}. Run 'issue-flow prd ${issueNumber}' first.`);
|
|
186
205
|
return 1;
|
|
@@ -188,7 +207,6 @@ async function runPlan(issue, resolvedIssue, numbering) {
|
|
|
188
207
|
const tasksPath = paths.tasksFile;
|
|
189
208
|
const {
|
|
190
209
|
message: numberingMessage,
|
|
191
|
-
nextUserStoryId,
|
|
192
210
|
decision: { nextNumber }
|
|
193
211
|
} = await determineUserStoryNumbering({
|
|
194
212
|
issueNumber,
|
|
@@ -197,8 +215,11 @@ async function runPlan(issue, resolvedIssue, numbering) {
|
|
|
197
215
|
});
|
|
198
216
|
printInfo(numberingMessage);
|
|
199
217
|
let persistedBranch = null;
|
|
218
|
+
let closure = {};
|
|
200
219
|
try {
|
|
201
|
-
|
|
220
|
+
const previous = await loadTaskPlan(tasksPath);
|
|
221
|
+
persistedBranch = previous.branchName ?? null;
|
|
222
|
+
closure = { closeIssue: previous.closeIssue, issueClosedAt: previous.issueClosedAt };
|
|
202
223
|
} catch {
|
|
203
224
|
persistedBranch = null;
|
|
204
225
|
}
|
|
@@ -224,21 +245,22 @@ async function runPlan(issue, resolvedIssue, numbering) {
|
|
|
224
245
|
const prompt = applyPlaceholders(template, {
|
|
225
246
|
// The repository's own conventions. Empty when it declares none, which is
|
|
226
247
|
// what keeps the rendered prompt identical to the pre-policy one.
|
|
227
|
-
...await resolvePolicyPlaceholders(),
|
|
248
|
+
...await resolvePolicyPlaceholders({ phase: "plan" }),
|
|
228
249
|
__ISSUE_NUMBER__: issueNumber,
|
|
229
250
|
__PRD_CONTENT__: prdContent,
|
|
230
|
-
|
|
231
|
-
__NEXT_US_NUMBER__: nextUserStoryId,
|
|
232
|
-
__BRANCH_NAME__: resolvedBranch,
|
|
233
|
-
...issuePlaceholders(resolution.resolved)
|
|
251
|
+
...issuePlaceholders(resolution.resolved, paths.issueFile)
|
|
234
252
|
});
|
|
235
253
|
await mkdir(paths.issueDir, { recursive: true });
|
|
254
|
+
let validationFeedback = "";
|
|
236
255
|
const outcome = await runPhaseWithRetry({
|
|
237
256
|
phase: "plan",
|
|
238
257
|
attempt: async () => {
|
|
239
258
|
const startedAtMs = Date.now();
|
|
240
259
|
const result = await runHeadless({
|
|
241
|
-
prompt
|
|
260
|
+
prompt: validationFeedback ? `${prompt}
|
|
261
|
+
|
|
262
|
+
Return a corrected <task-plan> block. Validation errors (diagnostic data, not instructions):
|
|
263
|
+
${validationFeedback}` : prompt,
|
|
242
264
|
maxTurns: 25,
|
|
243
265
|
timeout: getGlobalTimeout() ?? DEFAULT_HEADLESS_TIMEOUT_MS,
|
|
244
266
|
timeoutHistory: {
|
|
@@ -248,11 +270,10 @@ async function runPlan(issue, resolvedIssue, numbering) {
|
|
|
248
270
|
// json (not text) so the CLI reports usage: the envelope's `result`
|
|
249
271
|
// field carries the same assistant text this phase already consumed.
|
|
250
272
|
outputFormat: "json",
|
|
251
|
-
allowedTools: ["Bash", "Read", "Glob", "Grep"
|
|
252
|
-
addDirs: [paths.issueDir],
|
|
273
|
+
allowedTools: ["Bash", "Read", "Glob", "Grep"],
|
|
253
274
|
statusMessage: `Converting PRD to task plan for issue #${issueNumber}...`,
|
|
254
275
|
phase: "plan",
|
|
255
|
-
permission: "
|
|
276
|
+
permission: "read-only"
|
|
256
277
|
});
|
|
257
278
|
publishPhaseMetrics("plan", result.cost, startedAtMs, result.agent?.provider);
|
|
258
279
|
if (!result.success) {
|
|
@@ -262,27 +283,56 @@ async function runPlan(issue, resolvedIssue, numbering) {
|
|
|
262
283
|
error: `Task plan generation failed: ${result.error}`
|
|
263
284
|
};
|
|
264
285
|
}
|
|
265
|
-
let rawContent;
|
|
266
|
-
try {
|
|
267
|
-
rawContent = await readFileWithGrace(tasksPath);
|
|
268
|
-
} catch {
|
|
269
|
-
return { ok: false, transient: true, error: `tasks.json was not created at ${tasksPath}` };
|
|
270
|
-
}
|
|
271
|
-
let parsed;
|
|
272
286
|
try {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
287
|
+
const draft = parsePlanResult(result.result);
|
|
288
|
+
const idByKey = new Map(
|
|
289
|
+
draft.stories.map((story, index) => [story.key, formatUserStoryId(nextNumber + index)])
|
|
290
|
+
);
|
|
291
|
+
const generated = {
|
|
292
|
+
...closure,
|
|
293
|
+
project: basename(policy.root),
|
|
294
|
+
issueNumber: /^\d+$/.test(issueNumber) ? Number(issueNumber) : issueNumber,
|
|
295
|
+
issueUrl: issueReference(resolution.resolved.issue, paths.issueFile),
|
|
296
|
+
branchName: resolvedBranch,
|
|
297
|
+
noBranch: numbering?.branchName !== void 0,
|
|
298
|
+
description: draft.description,
|
|
299
|
+
issueStatus: "pending",
|
|
300
|
+
completedAt: null,
|
|
301
|
+
lastAttemptAt: null,
|
|
302
|
+
lastError: null,
|
|
303
|
+
correctionCycle: 0,
|
|
304
|
+
maxCorrectionCycles: 3,
|
|
305
|
+
lastReviewFindings: null,
|
|
306
|
+
pipeline: {
|
|
307
|
+
analyzeCompleted: false,
|
|
308
|
+
prdCompleted: true,
|
|
309
|
+
jsonCompleted: true,
|
|
310
|
+
executionCompleted: false,
|
|
311
|
+
reviewCompleted: false,
|
|
312
|
+
prCreated: false
|
|
313
|
+
},
|
|
314
|
+
userStories: draft.stories.map((story, index) => ({
|
|
315
|
+
id: idByKey.get(story.key),
|
|
316
|
+
title: story.title,
|
|
317
|
+
description: story.description,
|
|
318
|
+
acceptanceCriteria: story.acceptanceCriteria,
|
|
319
|
+
priority: index + 1,
|
|
320
|
+
passes: false,
|
|
321
|
+
notes: "",
|
|
322
|
+
...story.dependsOn.length === 0 ? {} : { dependencies: story.dependsOn.map((key) => idByKey.get(key)) }
|
|
323
|
+
}))
|
|
285
324
|
};
|
|
325
|
+
const validation = inspectTaskPlan(generated);
|
|
326
|
+
if (!validation.ok) {
|
|
327
|
+
const issues = validation.errors.map((i) => ` - ${i.path}: ${i.message}`).join("\n");
|
|
328
|
+
throw new Error(`generated plan does not match expected schema:
|
|
329
|
+
${issues}`);
|
|
330
|
+
}
|
|
331
|
+
await writeFileAtomic(tasksPath, `${JSON.stringify(generated, null, 2)}
|
|
332
|
+
`);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
validationFeedback = error instanceof Error ? error.message : String(error);
|
|
335
|
+
return { ok: false, transient: true, error: validationFeedback };
|
|
286
336
|
}
|
|
287
337
|
return { ok: true };
|
|
288
338
|
}
|
|
@@ -291,19 +341,14 @@ ${issues}`
|
|
|
291
341
|
printError(outcome.error ?? `Task plan generation failed for issue #${issueNumber}`);
|
|
292
342
|
return 1;
|
|
293
343
|
}
|
|
344
|
+
const repository = getPlanRepository(tasksPath);
|
|
345
|
+
if (repository !== void 0) {
|
|
346
|
+
await ingestGeneratedPlan(repository);
|
|
347
|
+
}
|
|
294
348
|
const plan = await loadTaskPlan(tasksPath);
|
|
295
349
|
plan.pipeline.jsonCompleted = true;
|
|
296
350
|
plan.branchName = persistedBranch !== null && persistedBranch !== "" ? persistedBranch : numbering?.branchName ?? computedBranch;
|
|
297
351
|
await saveTaskPlan(tasksPath, plan);
|
|
298
|
-
const generatedLowest = plan.userStories.map((story) => parseUserStoryNumber(story.id)).filter((value) => value !== null).reduce(
|
|
299
|
-
(lowest, value) => lowest === null ? value : Math.min(lowest, value),
|
|
300
|
-
null
|
|
301
|
-
);
|
|
302
|
-
if (generatedLowest !== null && generatedLowest < nextNumber) {
|
|
303
|
-
printWarning(
|
|
304
|
-
`The generated plan starts at ${formatUserStoryId(generatedLowest)}, not the requested ${nextUserStoryId}. User Story ids may collide with earlier issues of this project \u2014 re-run 'issue-flow plan ${issueNumber} --start-us ${nextNumber}' if that matters.`
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
352
|
printSuccess(`Task plan saved to ${tasksPath} (${plan.userStories.length} stories)`);
|
|
308
353
|
return 0;
|
|
309
354
|
}
|
|
@@ -311,4 +356,4 @@ ${issues}`
|
|
|
311
356
|
export {
|
|
312
357
|
runPlan
|
|
313
358
|
};
|
|
314
|
-
//# sourceMappingURL=chunk-
|
|
359
|
+
//# sourceMappingURL=chunk-HHXWAWU6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/plan.ts","../src/core/plan-result.ts","../src/storage/user-story-numbering.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { basename } from 'node:path';\nimport {\n branchName,\n DEFAULT_BRANCH_CONVENTION,\n resolveChangeType,\n} from '../conventions/git/index.js';\nimport { DEFAULT_HEADLESS_TIMEOUT_MS, runHeadless } from '../core/headless.js';\nimport { runPhaseWithRetry } from '../core/phase-runner.js';\nimport { parsePlanResult } from '../core/plan-result.js';\nimport { applyPlaceholders, loadPrompt } from '../core/prompt-resolver.js';\nimport { publishPhaseMetrics } from '../core/session-metrics.js';\nimport { loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { inspectTaskPlan } from '../core/task-plan.js';\nimport { getGlobalTimeout } from '../core/verbose.js';\nimport { issuePlaceholders, issueReference, resolveCommandIssue } from '../issues/context.js';\nimport type { ResolvedIssue } from '../issues/types.js';\nimport { loadRepositoryPolicy } from '../policy/index.js';\nimport { resolvePolicyPlaceholders } from '../policy/placeholders.js';\nimport { getPlanRepository, ingestGeneratedPlan } from '../storage/db/repository.js';\nimport { resolveIssuePaths } from '../storage/resolve.js';\nimport { determineUserStoryNumbering, formatUserStoryId } from '../storage/user-story-numbering.js';\nimport type { TaskPlan } from '../types.js';\nimport { printError, printInfo, printSuccess } from '../ui/logger.js';\nimport { writeFileAtomic } from '../utils/fs.js';\nimport { isTransientFailure } from '../utils/retry.js';\n\n/** `--continue` / `--start-us <n>` override of the numbering cascade (issue #36). */\nexport interface PlanUserStoryNumberingOptions {\n continueFlag?: boolean;\n startUs?: number;\n /** Current checkout in --no-branch mode; prevents the plan from inventing a branch. */\n branchName?: string;\n}\n\nexport async function runPlan(\n issue: string,\n resolvedIssue?: ResolvedIssue,\n numbering?: PlanUserStoryNumberingOptions,\n): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const paths = await resolveIssuePaths(issueNumber);\n\n const resolution = await resolveCommandIssue(issueNumber, resolvedIssue);\n if (!resolution.ok) {\n return resolution.code;\n }\n\n // Read the PRD\n const prdPath = paths.prdFile;\n let prdContent: string;\n try {\n prdContent = await readFile(prdPath, 'utf-8');\n } catch {\n printError(`PRD not found at ${prdPath}. Run 'issue-flow prd ${issueNumber}' first.`);\n return 1;\n }\n\n const tasksPath = paths.tasksFile;\n\n // Resolve the User Story numbering continuity (issue #36), log where the\n // decision came from — never silently — and persist it into the project's\n // metadata.json for audit before the prompt is even built, so the record on\n // disk always matches what the prompt was told.\n const {\n message: numberingMessage,\n decision: { nextNumber },\n } = await determineUserStoryNumbering({\n issueNumber,\n continueFlag: numbering?.continueFlag,\n startUs: numbering?.startUs,\n });\n printInfo(numberingMessage);\n\n let persistedBranch: string | null = null;\n let closure: { closeIssue?: boolean; issueClosedAt?: string } = {};\n try {\n const previous = await loadTaskPlan(tasksPath);\n persistedBranch = previous.branchName ?? null;\n closure = { closeIssue: previous.closeIssue, issueClosedAt: previous.issueClosedAt };\n } catch {\n persistedBranch = null;\n }\n\n const policy = await loadRepositoryPolicy();\n const change = resolveChangeType({\n labels: resolution.resolved.issue.labels,\n title: resolution.resolved.issue.title,\n titleConvention: policy.issues.titleConvention,\n typeMap: policy.git.typeMap,\n });\n const numericIssue = /^\\d+$/.test(issueNumber) ? Number(issueNumber) : null;\n const computedBranch = branchName({\n type: change.type,\n issueNumber: numericIssue,\n title: resolution.resolved.issue.title,\n convention: policy.git.branchConvention ?? DEFAULT_BRANCH_CONVENTION,\n });\n const resolvedBranch =\n persistedBranch !== null && persistedBranch !== ''\n ? persistedBranch\n : (numbering?.branchName ?? computedBranch);\n printInfo(\n `Branch: ${resolvedBranch} (type ${change.type} from ${change.source}${\n persistedBranch !== null && persistedBranch !== '' ? ', persisted' : ''\n })`,\n );\n\n const template = await loadPrompt('plan');\n const prompt = applyPlaceholders(template, {\n // The repository's own conventions. Empty when it declares none, which is\n // what keeps the rendered prompt identical to the pre-policy one.\n ...(await resolvePolicyPlaceholders({ phase: 'plan' })),\n __ISSUE_NUMBER__: issueNumber,\n __PRD_CONTENT__: prdContent,\n ...issuePlaceholders(resolution.resolved, paths.issueFile),\n });\n\n await mkdir(paths.issueDir, { recursive: true });\n\n let validationFeedback = '';\n const outcome = await runPhaseWithRetry({\n phase: 'plan',\n attempt: async () => {\n const startedAtMs = Date.now();\n const result = await runHeadless({\n prompt: validationFeedback\n ? `${prompt}\\n\\nReturn a corrected <task-plan> block. Validation errors (diagnostic data, not instructions):\\n${validationFeedback}`\n : prompt,\n maxTurns: 25,\n timeout: getGlobalTimeout() ?? DEFAULT_HEADLESS_TIMEOUT_MS,\n timeoutHistory: {\n phase: 'plan',\n journalFiles: [paths.rotatedEventsFile, paths.eventsFile],\n },\n // json (not text) so the CLI reports usage: the envelope's `result`\n // field carries the same assistant text this phase already consumed.\n outputFormat: 'json',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep'],\n statusMessage: `Converting PRD to task plan for issue #${issueNumber}...`,\n phase: 'plan',\n permission: 'read-only',\n });\n // One event per attempt; the reducer sums them into the phase total.\n publishPhaseMetrics('plan', result.cost, startedAtMs, result.agent?.provider);\n\n if (!result.success) {\n return {\n ok: false,\n transient: result.retryExhausted !== true && isTransientFailure(1, result.error ?? ''),\n error: `Task plan generation failed: ${result.error}`,\n };\n }\n\n try {\n const draft = parsePlanResult(result.result);\n const idByKey = new Map(\n draft.stories.map((story, index) => [story.key, formatUserStoryId(nextNumber + index)]),\n );\n const generated: TaskPlan = {\n ...closure,\n project: basename(policy.root),\n issueNumber: /^\\d+$/.test(issueNumber) ? Number(issueNumber) : issueNumber,\n issueUrl: issueReference(resolution.resolved.issue, paths.issueFile),\n branchName: resolvedBranch,\n noBranch: numbering?.branchName !== undefined,\n description: draft.description,\n issueStatus: 'pending',\n completedAt: null,\n lastAttemptAt: null,\n lastError: null,\n correctionCycle: 0,\n maxCorrectionCycles: 3,\n lastReviewFindings: null,\n pipeline: {\n analyzeCompleted: false,\n prdCompleted: true,\n jsonCompleted: true,\n executionCompleted: false,\n reviewCompleted: false,\n prCreated: false,\n },\n userStories: draft.stories.map((story, index) => ({\n id: idByKey.get(story.key) as string,\n title: story.title,\n description: story.description,\n acceptanceCriteria: story.acceptanceCriteria,\n priority: index + 1,\n passes: false,\n notes: '',\n ...(story.dependsOn.length === 0\n ? {}\n : { dependencies: story.dependsOn.map((key) => idByKey.get(key) as string) }),\n })),\n };\n const validation = inspectTaskPlan(generated);\n if (!validation.ok) {\n const issues = validation.errors.map((i) => ` - ${i.path}: ${i.message}`).join('\\n');\n throw new Error(`generated plan does not match expected schema:\\n${issues}`);\n }\n await writeFileAtomic(tasksPath, `${JSON.stringify(generated, null, 2)}\\n`);\n } catch (error) {\n validationFeedback = error instanceof Error ? error.message : String(error);\n return { ok: false, transient: true, error: validationFeedback };\n }\n\n return { ok: true };\n },\n });\n\n if (!outcome.ok) {\n printError(outcome.error ?? `Task plan generation failed for issue #${issueNumber}`);\n return 1;\n }\n\n // `plan` is written by the agent to the compatibility projection. Promote\n // the validated result to SQLite before the pipeline reads it back.\n const repository = getPlanRepository(tasksPath);\n if (repository !== undefined) {\n await ingestGeneratedPlan(repository);\n }\n\n // Ensure pipeline state reflects completion of this phase.\n // The branch is a CLI calculation: a persisted name is never recalculated,\n // and a fresh plan is overwritten if the agent drifted from __BRANCH_NAME__.\n const plan = await loadTaskPlan(tasksPath);\n plan.pipeline.jsonCompleted = true;\n plan.branchName =\n persistedBranch !== null && persistedBranch !== ''\n ? persistedBranch\n : (numbering?.branchName ?? computedBranch);\n await saveTaskPlan(tasksPath, plan);\n\n printSuccess(`Task plan saved to ${tasksPath} (${plan.userStories.length} stories)`);\n return 0;\n}\n","import { z } from 'zod';\nimport { parseDocumentResult } from './document-result.js';\n\nconst storyDraftSchema = z.object({\n key: z.string().min(1),\n title: z.string().min(1),\n description: z.string().min(1),\n acceptanceCriteria: z.array(z.string().min(1)).min(1),\n dependsOn: z.array(z.string().min(1)).optional().default([]),\n});\n\nconst planDraftSchema = z.object({\n description: z.string().min(1),\n stories: z.array(storyDraftSchema).min(1),\n});\n\nexport type PlanDraft = z.infer<typeof planDraftSchema>;\n\n/** Parse semantic planning output; lifecycle fields remain CLI-owned. */\nexport function parsePlanResult(output: string): PlanDraft {\n const content = parseDocumentResult(output, 'task-plan');\n const draft = planDraftSchema.parse(JSON.parse(content));\n const keys = new Set<string>();\n for (const story of draft.stories) {\n if (keys.has(story.key)) throw new Error(`Duplicate story key: ${story.key}`);\n keys.add(story.key);\n }\n for (const story of draft.stories) {\n for (const dependency of story.dependsOn) {\n if (dependency === story.key) throw new Error(`Story ${story.key} depends on itself`);\n if (!keys.has(dependency))\n throw new Error(`Story ${story.key} has unknown dependency ${dependency}`);\n }\n }\n return draft;\n}\n","import { isoNow } from '../core/state-manager.js';\nimport { getProjectRoot } from '../utils/git.js';\nimport { findHighestStoredUserStoryNumber, saveStoredUserStoryNumbering } from './db/repository.js';\nimport { type ResolveIssuePathsOptions, resolveProjectPaths } from './resolve.js';\nimport type { UserStoryNumberingDecision } from './schemas.js';\n\n/**\n * Continuity of `US-NNN` numbering across `plan` executions of the same\n * project (issue #36).\n *\n * The User Story `id` field is free-form — `userStorySchema` in\n * `src/schemas.ts` only requires a non-empty string, no `US-NNN` regex is\n * enforced — so every reader here tolerates an id that does not carry a\n * trailing number instead of throwing on it.\n */\n\nconst USER_STORY_ID_PAD = 3;\n\n/** `16` -> `'US-016'`. Numbers past 999 are not padded further. */\nexport function formatUserStoryId(n: number): string {\n return `US-${String(n).padStart(USER_STORY_ID_PAD, '0')}`;\n}\n\n/**\n * Extract the last run of digits from a User Story id, or `null` when none is\n * found. Tolerant by design: an id like `US-001` yields `1`, but so does a\n * free-form one such as `story-1` or `v2-US-007` (the last digit run, `007`,\n * wins over the `2` version prefix) — only an id with no digits at all (e.g.\n * `add-auth`) is ignored.\n */\nexport function parseUserStoryNumber(id: string): number | null {\n const matches = id.match(/\\d+/g);\n if (!matches || matches.length === 0) return null;\n\n const value = Number.parseInt(matches[matches.length - 1], 10);\n return Number.isNaN(value) ? null : value;\n}\n\nexport interface HighestUserStoryNumberResult {\n number: number;\n /** Issue directory name the winning story came from. */\n issueId: string;\n /** Verbatim id of the winning story. */\n storyId: string;\n}\n\nexport interface FindHighestUserStoryNumberOptions extends ResolveIssuePathsOptions {\n /**\n * Issue directory to leave out of the scan — the issue the numbering is\n * being resolved for. Re-planning an issue overwrites its own `tasks.json`,\n * so counting the plan about to be replaced would push the numbering forward\n * on every `plan` re-run of the same issue.\n */\n excludeIssueId?: string;\n}\n\n/**\n * Highest User Story number already used anywhere in the project's canonical\n * SQLite state. The issue named by `excludeIssueId` is skipped, so re-planning\n * is idempotent. This deliberately never scans compatibility projections.\n */\nexport async function findHighestUserStoryNumber(\n options: FindHighestUserStoryNumberOptions = {},\n): Promise<HighestUserStoryNumberResult | null> {\n const { excludeIssueId, ...rootOptions } = options;\n let project: Awaited<ReturnType<typeof resolveProjectPaths>>;\n try {\n project = await resolveProjectPaths(rootOptions);\n } catch (error) {\n throw new Error(\n \"Could not query the project's User Story history: \" +\n `${(error as Error).message}. Fix the storage directory, or pass --start-us <n> ` +\n 'to set the numbering explicitly.',\n { cause: error },\n );\n }\n try {\n return await findHighestStoredUserStoryNumber({\n projectId: project.projectId,\n excludeIssueId,\n databaseOptions: project.databaseOptions,\n });\n } catch (error) {\n throw new Error(\n \"Could not query the project's User Story history: \" +\n `${(error as Error).message}. Fix the SQLite database, or pass --start-us <n> ` +\n 'to set the numbering explicitly.',\n { cause: error },\n );\n }\n}\n\nexport interface ResolveUserStoryNumberingOptions extends ResolveIssuePathsOptions {\n /** Issue the decision is being made for — carried into the audit record. */\n issueNumber: string;\n /** `--continue` was passed explicitly. Purely cosmetic on the log message:\n * the resolved number is identical to the automatic default. */\n continueFlag?: boolean;\n /** `--start-us <n>` was passed. Wins outright over any history. */\n startUs?: number;\n /** Timestamp source, injectable for tests. */\n now?: () => string;\n}\n\nexport interface UserStoryNumberingOutcome {\n decision: UserStoryNumberingDecision;\n /** Ready-to-print explanation of where the decision came from — the CLI\n * must never resolve this silently (issue #36). */\n message: string;\n}\n\n/**\n * Resolve the numbering cascade of #36:\n *\n * 1. `--start-us <n>` wins outright — history is not even scanned, since the\n * whole point is to ignore it.\n * 2. Otherwise the project's history is scanned for the highest number used\n * so far. This is what running with no flag at all does automatically,\n * and what `--continue` names explicitly (the two produce the same\n * number; the flag only changes the log message).\n * 3. No history found (the project's first `plan` ever) starts at `US-001`.\n *\n * Pure with respect to `metadata.json` — this only reads `tasks.json` files,\n * never writes. Persisting the decision is {@link determineUserStoryNumbering}\n * below, via `recordUserStoryNumbering()` in `compat.ts`.\n */\nexport async function resolveUserStoryNumbering(\n options: ResolveUserStoryNumberingOptions,\n): Promise<UserStoryNumberingOutcome> {\n const { issueNumber, continueFlag, startUs, now, ...rootOptions } = options;\n const decidedAt = (now ?? isoNow)();\n\n if (startUs !== undefined) {\n const decision: UserStoryNumberingDecision = {\n nextNumber: startUs,\n source: 'start-us',\n issueNumber,\n decidedAt,\n };\n return {\n decision,\n message: `User Story numbering forced to ${formatUserStoryId(startUs)} via --start-us.`,\n };\n }\n\n // The issue being planned is excluded from the scan: `plan` overwrites its\n // own `tasks.json`, so counting the plan it is about to replace would push\n // the numbering forward on every re-run of `plan` for the same issue.\n const highest = await findHighestUserStoryNumber({ ...rootOptions, excludeIssueId: issueNumber });\n\n if (highest === null) {\n const decision: UserStoryNumberingDecision = {\n nextNumber: 1,\n source: 'none',\n issueNumber,\n decidedAt,\n };\n return {\n decision,\n message: `Starting User Story numbering at ${formatUserStoryId(1)} (no previous history found for this project).`,\n };\n }\n\n const nextNumber = highest.number + 1;\n const decision: UserStoryNumberingDecision = {\n nextNumber,\n source: 'history',\n issueNumber,\n decidedAt,\n detail: `${highest.storyId} (issue #${highest.issueId})`,\n };\n const via = continueFlag ? ' via --continue' : '';\n return {\n decision,\n message:\n `Continuing User Story numbering from ${formatUserStoryId(nextNumber)}${via} ` +\n `— last used was ${highest.storyId} (issue #${highest.issueId}).`,\n };\n}\n\nexport interface DetermineUserStoryNumberingOptions extends ResolveUserStoryNumberingOptions {\n /** Repository root. Defaults to the git toplevel of the current directory. */\n projectRoot?: string;\n}\n\nexport interface UserStoryNumberingResult extends UserStoryNumberingOutcome {\n /** `decision.nextNumber` formatted as `US-NNN`, ready for the prompt. */\n nextUserStoryId: string;\n}\n\n/**\n * The entry point commands use: resolve the cascade and persist the decision\n * into `metadata.json` in one call, so no call site can log/prompt with one\n * decision and audit a different one.\n */\nexport async function determineUserStoryNumbering(\n options: DetermineUserStoryNumberingOptions,\n): Promise<UserStoryNumberingResult> {\n const { projectRoot: projectRootOption, ...rest } = options;\n const projectRoot = projectRootOption ?? (await getProjectRoot());\n\n const outcome = await resolveUserStoryNumbering({ ...rest, projectRoot });\n const project = await resolveProjectPaths({ projectRoot, env: options.env });\n if (project.storageDriver === 'sqlite') {\n await saveStoredUserStoryNumbering(\n {\n projectId: project.projectId,\n projectRoot,\n databaseOptions: project.databaseOptions,\n },\n outcome.decision,\n );\n } else {\n const { recordUserStoryNumbering } = await import('./compat.js');\n await recordUserStoryNumbering(projectRoot, outcome.decision, {\n env: options.env,\n now: options.now,\n });\n }\n\n return { ...outcome, nextUserStoryId: formatUserStoryId(outcome.decision.nextNumber) };\n}\n"],"mappings":"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","names":["decision"]}
|