@g-abhishek/gitx 0.1.4 → 0.1.6
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 +82 -13
- package/dist/ai/claudeAi.d.ts.map +1 -1
- package/dist/ai/claudeAi.js +4 -30
- package/dist/ai/claudeAi.js.map +1 -1
- package/dist/ai/claudeCliAi.d.ts.map +1 -1
- package/dist/ai/claudeCliAi.js +4 -21
- package/dist/ai/claudeCliAi.js.map +1 -1
- package/dist/ai/openAiAi.d.ts.map +1 -1
- package/dist/ai/openAiAi.js +4 -30
- package/dist/ai/openAiAi.js.map +1 -1
- package/dist/ai/reviewHelpers.d.ts +24 -0
- package/dist/ai/reviewHelpers.d.ts.map +1 -1
- package/dist/ai/reviewHelpers.js +123 -39
- package/dist/ai/reviewHelpers.js.map +1 -1
- package/dist/cli/commands/pr/cherryPick.d.ts +25 -0
- package/dist/cli/commands/pr/cherryPick.d.ts.map +1 -0
- package/dist/cli/commands/pr/cherryPick.js +317 -0
- package/dist/cli/commands/pr/cherryPick.js.map +1 -0
- package/dist/cli/commands/pr/fixComments.d.ts +5 -2
- package/dist/cli/commands/pr/fixComments.d.ts.map +1 -1
- package/dist/cli/commands/pr/fixComments.js +5 -82
- package/dist/cli/commands/pr/fixComments.js.map +1 -1
- package/dist/cli/commands/pr/index.d.ts.map +1 -1
- package/dist/cli/commands/pr/index.js +6 -2
- package/dist/cli/commands/pr/index.js.map +1 -1
- package/dist/cli/commands/pr/port.d.ts +34 -0
- package/dist/cli/commands/pr/port.d.ts.map +1 -0
- package/dist/cli/commands/pr/port.js +453 -0
- package/dist/cli/commands/pr/port.js.map +1 -0
- package/dist/cli/commands/pr/resolve.d.ts +3 -0
- package/dist/cli/commands/pr/resolve.d.ts.map +1 -0
- package/dist/cli/commands/pr/resolve.js +92 -0
- package/dist/cli/commands/pr/resolve.js.map +1 -0
- package/dist/cli/commands/pr/review.js +1 -1
- package/dist/cli/commands/pr/review.js.map +1 -1
- package/dist/cli/commands/sync.d.ts +12 -11
- package/dist/cli/commands/sync.d.ts.map +1 -1
- package/dist/cli/commands/sync.js +13 -101
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/utils/gitOps.d.ts +11 -4
- package/dist/utils/gitOps.d.ts.map +1 -1
- package/dist/utils/gitOps.js +53 -37
- package/dist/utils/gitOps.js.map +1 -1
- package/dist/workflows/pr.d.ts +1 -1
- package/dist/workflows/pr.d.ts.map +1 -1
- package/dist/workflows/pr.js +82 -19
- package/dist/workflows/pr.js.map +1 -1
- package/package.json +1 -1
package/dist/ai/openAiAi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openAiAi.js","sourceRoot":"","sources":["../../src/ai/openAiAi.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAW/C,MAAM,UAAU,GAAG,4CAA4C,CAAC;AAChE,MAAM,aAAa,GAAG,QAAQ,CAAC;AAC/B,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB,iFAAiF;AAEjF,SAAS,QAAQ,CAAC,QAAiB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,QAAQ,IAAI,aAAa,CAAC;AACnE,CAAC;AAoBD,KAAK,UAAU,UAAU,CACvB,MAAc,EACd,UAAkB,EAClB,MAAc,EACd,KAAa;IAEb,MAAM,IAAI,GAAsB;QAC9B,KAAK;QACL,UAAU,EAAE,UAAU;QACtB,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;YACnC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;SACtC;KACF,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,CAAqB,UAAU,EAAE,IAAI,EAAE;YACtE,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,MAAM,EAAE;gBACjC,cAAc,EAAE,kBAAkB;aACnC;YACD,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACzD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;YACpC,MAAM,GAAG,GACN,GAAG,CAAC,QAAQ,EAAE,IAA4C,EAAE,KAAK;gBAClE,GAAG,CAAC,OAAO,CAAC;YACd,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM,IAAI,SAAS,CACjB,yDAAyD,EACzD,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAC5B,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM,IAAI,SAAS,CACjB,sDAAsD,EACtD,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAC5B,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,SAAS,CACjB,qBAAqB,MAAM,IAAI,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,EAC3D,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAC5B,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,4BAA4B,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE;YAC7D,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC1D,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,SAAS,SAAS,CAAI,IAAY,EAAE,QAAW;IAC7C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAM,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF,MAAM,OAAO,QAAQ;IACF,MAAM,CAAS;IACf,KAAK,CAAS;IAE/B;;;OAGG;IACH,YAAY,MAAe,EAAE,KAAc;QACzC,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACpD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,SAAS,CACjB,kFAAkF,EAClF,EAAE,QAAQ,EAAE,CAAC,EAAE,CAChB,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,0EAA0E;IAC1E,MAAM,CAAC,WAAW,CAAC,GAAY;QAC7B,OAAO,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,MAAM,MAAM,GAAG;;;;;;;EAOjB,CAAC;QAEC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,SAAS,CAAiC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnE,OAAO;YACL,IAAI,EAAE,KAAK;YACX,MAAM,EAAG,MAAM,CAAC,MAA0C,IAAI,SAAS;YACvE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,yBAAyB;YACpD,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;YACxE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;SACvD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAgB;QACjC,MAAM,GAAG,GAAG,OAKX,CAAC;QAEF,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,IAAI,cAAc,CAAC;QAC5C,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC;QAC5E,MAAM,mBAAmB,GACvB,GAAG,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC;YAC1D,CAAC,CAAC,gCAAgC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;iBAC7D,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;iBACrC,IAAI,CAAC,MAAM,CAAC,EAAE;YACnB,CAAC,CAAC,EAAE,CAAC;QAET,MAAM,MAAM,GAAG;;;;;;2EAMwD,CAAC;QAExE,MAAM,UAAU,GAAG,SAAS,QAAQ;YAC5B,eAAe;;EAEzB,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QAE/B,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAAkC,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAE9D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QAC5F,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,IAAa;QAC/B,MAAM,CAAC,GAAG,IAMT,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,QAAQ,CAAC;QAChC,MAAM,mBAAmB,GACvB,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC;YACtD,CAAC,CAAC,+BAA+B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;iBAC1D,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;iBACrC,IAAI,CAAC,MAAM,CAAC,EAAE;YACnB,CAAC,CAAC,+DAA+D,CAAC;QAEtE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;mDAmBgC,CAAC;QAEhD,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,IAAI,IAAI,EAAE;WACjC,MAAM;cACH,CAAC,CAAC,KAAK,IAAI,EAAE;oBACP,CAAC,CAAC,WAAW,IAAI,EAAE,GAAG,mBAAmB,EAAE,CAAC;QAE5D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAAmC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACxF,OAAO;YACL,MAAM;YACN,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;SACvD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAa;QAClC,MAAM,CAAC,GAAG,IAA+D,CAAC;QAC1E,MAAM,WAAW,GACf,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;iBACZ,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;iBACzE,IAAI,CAAC,MAAM,CAAC;YACf,YAAY,CAAC;QAEf,MAAM,MAAM,GAAG;;;;;;EAMjB,CAAC;QAEC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,aAAa,WAAW,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3F,MAAM,MAAM,GAAG,SAAS,CAAsC,IAAI,EAAE;YAClE,OAAO,EAAE,EAAE;YACX,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,uBAAuB;YAClD,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;SAC5E,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAgB;QACjC,MAAM,CAAC,GAAG,OAKT,CAAC;QAEF,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;aACpC,GAAG,CACF,CAAC,EAAE,EAAE,EAAE,CACL,IAAI,EAAE,CAAC,MAAM,IAAI,UAAU,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,CAChG;aACA,IAAI,CAAC,MAAM,CAAC,CAAC;QAEhB,MAAM,mBAAmB,GACvB,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC;YACtD,CAAC,CAAC,+BAA+B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;iBAC1D,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,OAAO,EAAE,CAAC;iBACjD,IAAI,CAAC,MAAM,CAAC,EAAE;YACnB,CAAC,CAAC,EAAE,CAAC;QAET,MAAM,MAAM,GAAG;;;;;;;;;;yEAUsD,CAAC;QAEtE,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,OAAO,IAAI,EAAE;WACxC,CAAC,CAAC,MAAM,IAAI,EAAE;;;EAGvB,YAAY,GAAG,mBAAmB,EAAE,CAAC;QAEnC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAAkC,IAAI,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,CAAC;QACxF,OAAO;YACL,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE;SAClF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAgB;QAC7B,MAAM,GAAG,GAAG,OAKX,CAAC;QAEF,MAAM,WAAW,GAAG,GAAG,CAAC,IAAI;YAC1B,CAAC,CAAC,wBAAwB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;YACnD,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,eAAe,GACnB,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;YACrC,CAAC,CAAC,kCAAkC,GAAG,CAAC,QAAQ;iBAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;iBACrE,IAAI,CAAC,IAAI,CAAC,EAAE;YACjB,CAAC,CAAC,EAAE,CAAC;QAET,MAAM,MAAM,GAAG;;;;;;;;;;;;;gDAa6B,CAAC;QAE7C,MAAM,UAAU,GAAG,aAAa,GAAG,CAAC,OAAO,IAAI,EAAE;kBACnC,GAAG,CAAC,MAAM,IAAI,EAAE,GAAG,WAAW,GAAG,eAAe,EAAE,CAAC;QAEjE,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAA8B,IAAI,EAAE;YAC1D,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,EAAE;YACV,SAAS,EAAE,EAAE;YACb,OAAO,EAAE,SAAS;SACnB,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,gCAAgC;YAC3D,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;YACzD,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YAClE,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,iBAAiB,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;gBACjF,CAAC,CAAE,MAAM,CAAC,OAAyC;gBACnD,CAAC,CAAC,SAAS;SACd,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,OAAiB,EAAE,IAAY,EAAE,IAAa;QACpE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;iDAkB8B,CAAC;QAE9C,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,IAAI;YACtB,CAAC,CAAC,0CAA0C,IAAI,8BAA8B,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE;YACpG,CAAC,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,4BAA4B,UAAU,OAAO,WAAW,EAAE,CAAC;QAC9E,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAAoD,IAAI,EAAE,EAAE,CAAC,CAAC;QACtF,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,eAAe;YAC9C,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;SAChC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,eAAuB;QAC7D,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;mGAmBgF,CAAC;QAEhG,MAAM,UAAU,GAAG,SAAS,QAAQ,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;QAC7E,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAA6D,IAAI,EAAE,EAAE,CAAC,CAAC;QAC/F,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,eAAe;YAC5C,UAAU,EAAE,MAAM,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;YACxD,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,oBAAoB;SAChE,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,qBAAqB,CAAC,IAAY;QACtC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;mFAoBgE,CAAC;QAEhF,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACjG,MAAM,MAAM,GAAG,SAAS,CAAwD,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1F,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,qBAAqB;YACxD,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,SAAS;SACvC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,OAAyE;QAEzE,MAAM,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACnH,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,uBAAuB,EAAE,EACzB,uBAAuB,CAAC,OAAO,CAAC,EAChC,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK,CACX,CAAC;QACF,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,WAAW,CACf,OAAoE;QAEpE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChG,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,cAAc,EAAE,EAChB,cAAc,CAAC,OAAO,CAAC,EACvB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK,CACX,CAAC;QACF,OAAO,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,GAAG,CACP,QAAgB,EAChB,OAA0C;QAE1C,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChG,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5G,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;CACF","sourcesContent":["/**\n * OpenAiAi — OpenAI Chat Completions API integration.\n *\n * Authentication: OPENAI_API_KEY env var or stored config key.\n * Model: defaults to gpt-4o. Override via GITX_AI_MODEL env var.\n *\n * All methods use the same structured JSON prompt pattern as ClaudeAi.\n */\n\nimport axios, { isAxiosError } from \"axios\";\nimport { GitxError } from \"../utils/errors.js\";\nimport type {\n AiAnalyzeTaskResponse,\n AiClient,\n AiGenerateDiffsResponse,\n AiGeneratePlanResponse,\n AiReviewPRResponse,\n AiSuggestFixesResponse,\n AiSummarizeChangesResponse,\n} from \"./types.js\";\n\nconst OPENAI_API = \"https://api.openai.com/v1/chat/completions\";\nconst DEFAULT_MODEL = \"gpt-4o\";\nconst MAX_TOKENS = 4096;\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction getModel(override?: string): string {\n return process.env[\"GITX_AI_MODEL\"] ?? override ?? DEFAULT_MODEL;\n}\n\ninterface ChatMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\ninterface OpenAiRequestBody {\n model: string;\n max_tokens: number;\n messages: ChatMessage[];\n}\n\ninterface OpenAiResponseBody {\n choices: Array<{\n message: { role: string; content: string };\n finish_reason: string;\n }>;\n}\n\nasync function callOpenAi(\n system: string,\n userPrompt: string,\n apiKey: string,\n model: string\n): Promise<string> {\n const body: OpenAiRequestBody = {\n model,\n max_tokens: MAX_TOKENS,\n messages: [\n { role: \"system\", content: system },\n { role: \"user\", content: userPrompt },\n ],\n };\n\n try {\n const { data } = await axios.post<OpenAiResponseBody>(OPENAI_API, body, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n timeout: 60_000,\n });\n\n return data.choices[0]?.message?.content?.trim() ?? \"\";\n } catch (err) {\n if (isAxiosError(err)) {\n const status = err.response?.status;\n const msg =\n (err.response?.data as Record<string, unknown> | undefined)?.error ??\n err.message;\n if (status === 401) {\n throw new GitxError(\n \"OpenAI API authentication failed. Check OPENAI_API_KEY.\",\n { exitCode: 1, cause: err }\n );\n }\n if (status === 429) {\n throw new GitxError(\n \"OpenAI rate limit exceeded. Wait a moment and retry.\",\n { exitCode: 1, cause: err }\n );\n }\n throw new GitxError(\n `OpenAI API error (${status ?? \"network\"}): ${String(msg)}`,\n { exitCode: 1, cause: err }\n );\n }\n throw new GitxError(`Unexpected OpenAI error: ${String(err)}`, {\n exitCode: 1,\n cause: err,\n });\n }\n}\n\nfunction extractJson(text: string): string {\n const fenced = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (fenced?.[1]) return fenced[1].trim();\n const start = text.search(/[{[]/);\n const endBrace = text.lastIndexOf(\"}\");\n const endBracket = text.lastIndexOf(\"]\");\n const end = Math.max(endBrace, endBracket);\n if (start !== -1 && end !== -1 && end > start) return text.slice(start, end + 1);\n return text.trim();\n}\n\nfunction parseJson<T>(text: string, fallback: T): T {\n try {\n return JSON.parse(extractJson(text)) as T;\n } catch {\n return fallback;\n }\n}\n\n// ─── OpenAiAi ─────────────────────────────────────────────────────────────────\n\nexport class OpenAiAi implements AiClient {\n private readonly apiKey: string;\n private readonly model: string;\n\n /**\n * @param apiKey OpenAI API key. Falls back to OPENAI_API_KEY env var.\n * @param model Model override. Falls back to GITX_AI_MODEL then gpt-4o.\n */\n constructor(apiKey?: string, model?: string) {\n const key = apiKey ?? process.env[\"OPENAI_API_KEY\"];\n if (!key) {\n throw new GitxError(\n \"No OpenAI API key available. Run `gitx config set openai` or set OPENAI_API_KEY.\",\n { exitCode: 2 }\n );\n }\n this.apiKey = key;\n this.model = getModel(model);\n }\n\n /** Check whether an OpenAI API key is available without instantiating. */\n static isAvailable(key?: string): boolean {\n return Boolean(key ?? process.env[\"OPENAI_API_KEY\"]);\n }\n\n async analyzeTask(input: string): Promise<AiAnalyzeTaskResponse> {\n const system = `You are an expert software engineer. Analyze the given development task and respond with ONLY valid JSON matching this exact structure (no prose, no markdown):\n{\n \"task\": \"<the original task string>\",\n \"intent\": \"<one of: refactor | bugfix | feature | chore | unknown>\",\n \"summary\": \"<one sentence explaining what needs to be done>\",\n \"assumptions\": [\"<assumption 1>\", \"<assumption 2>\"],\n \"risks\": [\"<risk 1>\", \"<risk 2>\"]\n}`;\n\n const text = await callOpenAi(system, `Task: ${input}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiAnalyzeTaskResponse>>(text, {});\n return {\n task: input,\n intent: (parsed.intent as AiAnalyzeTaskResponse[\"intent\"]) ?? \"unknown\",\n summary: parsed.summary ?? \"Unable to analyze task.\",\n assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],\n risks: Array.isArray(parsed.risks) ? parsed.risks : [],\n };\n }\n\n async generatePlan(context: unknown): Promise<AiGeneratePlanResponse> {\n const ctx = context as {\n task?: string;\n analysis?: AiAnalyzeTaskResponse;\n repoFiles?: string[];\n fileContents?: Record<string, string>;\n };\n\n const taskDesc = ctx.task ?? \"Unknown task\";\n const analysisSummary = ctx.analysis?.summary ?? \"\";\n const fileList = ctx.repoFiles?.slice(0, 50).join(\"\\n\") ?? \"(not provided)\";\n const fileContentsSection =\n ctx.fileContents && Object.keys(ctx.fileContents).length > 0\n ? `\\n\\nRelevant file contents:\\n${Object.entries(ctx.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert software engineer creating a step-by-step implementation plan. Respond with ONLY valid JSON:\n{\n \"steps\": [\n { \"id\": \"step-1\", \"title\": \"<short title>\", \"description\": \"<detailed description>\" }\n ]\n}\nKeep steps atomic and ordered. Each step should touch one logical concern.`;\n\n const userPrompt = `Task: ${taskDesc}\nAnalysis: ${analysisSummary}\nRepo files (top 50):\n${fileList}${fileContentsSection}`;\n\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiGeneratePlanResponse>>(text, { steps: [] });\n const steps = Array.isArray(parsed.steps) ? parsed.steps : [];\n\n if (steps.length === 0) {\n return { steps: [{ id: \"step-1\", title: \"Analyze & implement\", description: taskDesc }] };\n }\n return { steps };\n }\n\n async generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse> {\n const s = step as {\n id?: string;\n title?: string;\n description?: string;\n task?: string;\n fileContents?: Record<string, string>;\n };\n\n const stepId = s.id ?? \"step-1\";\n const fileContentsSection =\n s.fileContents && Object.keys(s.fileContents).length > 0\n ? `\\n\\nCurrent file contents:\\n${Object.entries(s.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\\n\\n(No existing file contents — create new files as needed.)\";\n\n const system = `You are an expert software engineer. Generate unified diffs for the given implementation step.\nRespond with ONLY valid JSON:\n{\n \"stepId\": \"<step id>\",\n \"diffs\": [\n {\n \"path\": \"<relative file path>\",\n \"unifiedDiff\": \"<valid unified diff starting with --- a/path and +++ b/path>\"\n }\n ]\n}\n\nRules for unified diffs:\n- Start with: --- a/<path>\\\\n+++ b/<path>\n- Use @@ -<start>,<count> +<start>,<count> @@ context headers\n- Lines starting with ' ' are context (unchanged)\n- Lines starting with '-' are removed\n- Lines starting with '+' are added\n- For new files use: --- /dev/null\\\\n+++ b/<path>\n- Always include 3 lines of context around changes`;\n\n const userPrompt = `Task: ${s.task ?? \"\"}\nStep ID: ${stepId}\nStep Title: ${s.title ?? \"\"}\nStep Description: ${s.description ?? \"\"}${fileContentsSection}`;\n\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiGenerateDiffsResponse>>(text, { stepId, diffs: [] });\n return {\n stepId,\n diffs: Array.isArray(parsed.diffs) ? parsed.diffs : [],\n };\n }\n\n async summarizeChanges(diff: unknown): Promise<AiSummarizeChangesResponse> {\n const d = diff as { diffs?: AiGenerateDiffsResponse[]; rawDiff?: string };\n const diffContent =\n d.rawDiff ??\n (d.diffs ?? [])\n .flatMap((dr) => dr.diffs.map((f) => `File: ${f.path}\\n${f.unifiedDiff}`))\n .join(\"\\n\\n\") ??\n \"(no diffs)\";\n\n const system = `You are a technical writer. Summarize code changes for a pull request. Respond with ONLY valid JSON:\n{\n \"summary\": \"<2-3 sentence plain-English summary of what changed and why>\",\n \"filesChanged\": [\n { \"path\": \"<file path>\", \"changeType\": \"<add | modify | delete>\" }\n ]\n}`;\n\n const text = await callOpenAi(system, `Changes:\\n${diffContent}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiSummarizeChangesResponse>>(text, {\n summary: \"\",\n filesChanged: [],\n });\n return {\n summary: parsed.summary ?? \"Code changes applied.\",\n filesChanged: Array.isArray(parsed.filesChanged) ? parsed.filesChanged : [],\n };\n }\n\n async suggestFixes(comment: unknown): Promise<AiSuggestFixesResponse> {\n const c = comment as {\n comments?: Array<{ body: string; path?: string; line?: number; author?: string }>;\n prTitle?: string;\n prBody?: string;\n fileContents?: Record<string, string>;\n };\n\n const commentsText = (c.comments ?? [])\n .map(\n (co) =>\n `[${co.author ?? \"reviewer\"}${co.path ? ` on ${co.path}:${co.line ?? \"\"}` : \"\"}]: ${co.body}`\n )\n .join(\"\\n\\n\");\n\n const fileContentsSection =\n c.fileContents && Object.keys(c.fileContents).length > 0\n ? `\\n\\nCurrent file contents:\\n${Object.entries(c.fileContents)\n .map(([p, content]) => `--- ${p} ---\\n${content}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer suggesting fixes for pull request review comments. Respond with ONLY valid JSON:\n{\n \"suggestedEdits\": [\n {\n \"path\": \"<file path>\",\n \"rationale\": \"<why this change addresses the comment>\",\n \"unifiedDiff\": \"<valid unified diff>\"\n }\n ]\n}\nIf a comment doesn't require a code change, omit it from suggestedEdits.`;\n\n const userPrompt = `PR Title: ${c.prTitle ?? \"\"}\nPR Body: ${c.prBody ?? \"\"}\n\nReview Comments:\n${commentsText}${fileContentsSection}`;\n\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiSuggestFixesResponse>>(text, { suggestedEdits: [] });\n return {\n suggestedEdits: Array.isArray(parsed.suggestedEdits) ? parsed.suggestedEdits : [],\n };\n }\n\n async reviewPR(context: unknown): Promise<AiReviewPRResponse> {\n const ctx = context as {\n prTitle?: string;\n prBody?: string;\n diff?: string;\n comments?: Array<{ body: string; author: string; path?: string }>;\n };\n\n const diffSection = ctx.diff\n ? `\\n\\nDiff (unified):\\n${ctx.diff.slice(0, 8000)}`\n : \"\";\n const commentsSection =\n ctx.comments && ctx.comments.length > 0\n ? `\\n\\nExisting review comments:\\n${ctx.comments\n .map((c) => `[${c.author}${c.path ? ` @ ${c.path}` : \"\"}]: ${c.body}`)\n .join(\"\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer. Review the given pull request thoroughly and respond with ONLY valid JSON:\n{\n \"summary\": \"<2-4 sentence overall assessment>\",\n \"issues\": [\n { \"severity\": \"<critical|warning|suggestion>\", \"description\": \"<specific issue>\", \"file\": \"<optional file>\", \"line\": null }\n ],\n \"positives\": [\"<good thing 1>\", \"<good thing 2>\"],\n \"verdict\": \"<approve|request_changes|comment>\"\n}\n\nSeverity guide:\n- critical: bugs, security issues, data loss risk\n- warning: code quality, performance, missing error handling\n- suggestion: style, naming, minor improvements`;\n\n const userPrompt = `PR Title: ${ctx.prTitle ?? \"\"}\nPR Description: ${ctx.prBody ?? \"\"}${diffSection}${commentsSection}`;\n\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiReviewPRResponse>>(text, {\n summary: \"\",\n issues: [],\n positives: [],\n verdict: \"comment\",\n });\n\n return {\n summary: parsed.summary ?? \"Review could not be generated.\",\n issues: Array.isArray(parsed.issues) ? parsed.issues : [],\n positives: Array.isArray(parsed.positives) ? parsed.positives : [],\n verdict: ([\"approve\", \"request_changes\", \"comment\"].includes(parsed.verdict ?? \"\"))\n ? (parsed.verdict as AiReviewPRResponse[\"verdict\"])\n : \"comment\",\n };\n }\n\n async generatePrContent(commits: string[], diff: string, stat?: string): Promise<import(\"./types.js\").AiPrContentResponse> {\n const system = `You are an expert software engineer writing pull request descriptions.\nYou are given a list of commits on the branch and the unified diff of all changes.\n\nThe input may contain:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changed files.\nDo not ignore files that appear in the list but are absent from the truncated diff.\n\nProduce a clear, informative PR title and description:\n\nRules:\n- title: short, human-readable, present-tense. No conventional-commit prefix. Max 72 chars.\n- body: 2-4 sentences describing WHAT changed and WHY. Cover ALL files from the list.\n Plain English, no bullet points.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"title\":\"<PR title>\",\"body\":\"<PR description>\"}`;\n\n const commitList = commits.slice(0, 20).join(\"\\n\");\n const diffSection = stat\n ? `=== Changed files (complete list) ===\\n${stat}\\n\\n=== Detailed diff ===\\n${diff.slice(0, 16000)}`\n : `Diff:\\n${diff.slice(0, 16000)}`;\n const userPrompt = `Commits on this branch:\\n${commitList}\\n\\n${diffSection}`;\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiPrContentResponse>>(text, {});\n return {\n title: parsed.title?.trim() ?? \"Update branch\",\n body: parsed.body?.trim() ?? \"\",\n };\n }\n\n async resolveConflict(filePath: string, conflictContent: string): Promise<import(\"./types.js\").AiConflictResolutionResponse> {\n const system = `You are an expert software engineer resolving git merge conflicts.\n\nThe file contains standard git conflict markers:\n <<<<<<< HEAD — changes on the current branch\n ======= — separator\n >>>>>>> theirs — incoming changes\n\nYour task:\n1. Understand BOTH sides of every conflict.\n2. Produce a single correct version preserving the intent of BOTH changes where possible.\n3. If the sides are genuinely contradictory, set confidence to \"low\".\n\nRules:\n- Remove ALL conflict markers from the output.\n- Do NOT add explanatory comments.\n- Keep all non-conflicting code exactly as-is.\n- Output must be syntactically valid.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"resolved\":\"<full resolved file content>\",\"confidence\":\"high|low\",\"explanation\":\"<one sentence>\"}`;\n\n const userPrompt = `File: ${filePath}\\n\\n${conflictContent.slice(0, 20000)}`;\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiConflictResolutionResponse>>(text, {});\n return {\n resolved: parsed.resolved ?? conflictContent,\n confidence: parsed.confidence === \"low\" ? \"low\" : \"high\",\n explanation: parsed.explanation?.trim() ?? \"Conflict resolved.\",\n };\n }\n async generateCommitMessage(diff: string): Promise<import(\"./types.js\").AiCommitMessageResponse> {\n const system = `You are an expert software engineer writing git commit messages.\nYou receive either a plain unified diff OR a structured input with:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changes.\nDo not ignore files that appear in the list but are missing from the truncated diff.\n\nProduce ONE CONVENTIONAL COMMIT covering all the changes:\n\nRules:\n- subject: \"<type>(<scope>): <imperative description>\"\n - type: feat | fix | refactor | chore | docs | test | perf | ci | style | build\n - scope: the primary area affected; omit if changes span many unrelated areas\n - description: imperative mood, no period, 72 chars max for the whole subject line\n - if several distinct features or fixes are present, pick the most impactful for the subject\n- body: cover EVERY significant change visible in the file list. For each distinct change,\n one sentence on what was done and why. Plain English, no bullet lists, no repetition of the subject.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"subject\":\"<subject line>\",\"body\":\"<body covering all changes, or empty string>\"}`;\n\n const text = await callOpenAi(system, `Diff:\\n${diff.slice(0, 20000)}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiCommitMessageResponse>>(text, {});\n return {\n subject: parsed.subject?.trim() ?? \"chore: update files\",\n body: parsed.body?.trim() || undefined,\n };\n }\n\n async reviewPRDetailed(\n context: Parameters<import(\"./types.js\").AiClient[\"reviewPRDetailed\"]>[0]\n ): Promise<import(\"./types.js\").AiDetailedReviewResponse> {\n const { buildSeniorReviewSystem, buildSeniorReviewPrompt, parseSeniorReview } = await import(\"./reviewHelpers.js\");\n const text = await callOpenAi(\n buildSeniorReviewSystem(),\n buildSeniorReviewPrompt(context),\n this.apiKey,\n this.model\n );\n return parseSeniorReview(text);\n }\n\n async generateFix(\n context: Parameters<import(\"./types.js\").AiClient[\"generateFix\"]>[0]\n ): Promise<import(\"./types.js\").AiFixResponse> {\n const { buildFixSystem, buildFixPrompt, parseFixResponse } = await import(\"./reviewHelpers.js\");\n const text = await callOpenAi(\n buildFixSystem(),\n buildFixPrompt(context),\n this.apiKey,\n this.model\n );\n return parseFixResponse(text, context.filePath, context.line);\n }\n\n async ask(\n question: string,\n context: import(\"./types.js\").AiAskContext\n ): Promise<import(\"./types.js\").AiAskResponse> {\n const { buildAskSystem, buildAskPrompt, parseAskResponse } = await import(\"./reviewHelpers.js\");\n const text = await callOpenAi(buildAskSystem(), buildAskPrompt(question, context), this.apiKey, this.model);\n return parseAskResponse(text);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"openAiAi.js","sourceRoot":"","sources":["../../src/ai/openAiAi.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAW/C,MAAM,UAAU,GAAG,4CAA4C,CAAC;AAChE,MAAM,aAAa,GAAG,QAAQ,CAAC;AAC/B,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB,iFAAiF;AAEjF,SAAS,QAAQ,CAAC,QAAiB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,QAAQ,IAAI,aAAa,CAAC;AACnE,CAAC;AAoBD,KAAK,UAAU,UAAU,CACvB,MAAc,EACd,UAAkB,EAClB,MAAc,EACd,KAAa;IAEb,MAAM,IAAI,GAAsB;QAC9B,KAAK;QACL,UAAU,EAAE,UAAU;QACtB,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;YACnC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;SACtC;KACF,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,CAAqB,UAAU,EAAE,IAAI,EAAE;YACtE,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,MAAM,EAAE;gBACjC,cAAc,EAAE,kBAAkB;aACnC;YACD,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACzD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;YACpC,MAAM,GAAG,GACN,GAAG,CAAC,QAAQ,EAAE,IAA4C,EAAE,KAAK;gBAClE,GAAG,CAAC,OAAO,CAAC;YACd,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM,IAAI,SAAS,CACjB,yDAAyD,EACzD,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAC5B,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM,IAAI,SAAS,CACjB,sDAAsD,EACtD,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAC5B,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,SAAS,CACjB,qBAAqB,MAAM,IAAI,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,EAC3D,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAC5B,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,4BAA4B,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE;YAC7D,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC1D,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,SAAS,SAAS,CAAI,IAAY,EAAE,QAAW;IAC7C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAM,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF,MAAM,OAAO,QAAQ;IACF,MAAM,CAAS;IACf,KAAK,CAAS;IAE/B;;;OAGG;IACH,YAAY,MAAe,EAAE,KAAc;QACzC,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACpD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,SAAS,CACjB,kFAAkF,EAClF,EAAE,QAAQ,EAAE,CAAC,EAAE,CAChB,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,0EAA0E;IAC1E,MAAM,CAAC,WAAW,CAAC,GAAY;QAC7B,OAAO,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,MAAM,MAAM,GAAG;;;;;;;EAOjB,CAAC;QAEC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,SAAS,CAAiC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnE,OAAO;YACL,IAAI,EAAE,KAAK;YACX,MAAM,EAAG,MAAM,CAAC,MAA0C,IAAI,SAAS;YACvE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,yBAAyB;YACpD,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;YACxE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;SACvD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAgB;QACjC,MAAM,GAAG,GAAG,OAKX,CAAC;QAEF,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,IAAI,cAAc,CAAC;QAC5C,MAAM,eAAe,GAAG,GAAG,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC;QAC5E,MAAM,mBAAmB,GACvB,GAAG,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC;YAC1D,CAAC,CAAC,gCAAgC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;iBAC7D,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;iBACrC,IAAI,CAAC,MAAM,CAAC,EAAE;YACnB,CAAC,CAAC,EAAE,CAAC;QAET,MAAM,MAAM,GAAG;;;;;;2EAMwD,CAAC;QAExE,MAAM,UAAU,GAAG,SAAS,QAAQ;YAC5B,eAAe;;EAEzB,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QAE/B,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAAkC,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAE9D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QAC5F,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,IAAa;QAC/B,MAAM,CAAC,GAAG,IAMT,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,QAAQ,CAAC;QAChC,MAAM,mBAAmB,GACvB,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC;YACtD,CAAC,CAAC,+BAA+B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;iBAC1D,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;iBACrC,IAAI,CAAC,MAAM,CAAC,EAAE;YACnB,CAAC,CAAC,+DAA+D,CAAC;QAEtE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;mDAmBgC,CAAC;QAEhD,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,IAAI,IAAI,EAAE;WACjC,MAAM;cACH,CAAC,CAAC,KAAK,IAAI,EAAE;oBACP,CAAC,CAAC,WAAW,IAAI,EAAE,GAAG,mBAAmB,EAAE,CAAC;QAE5D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAAmC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACxF,OAAO;YACL,MAAM;YACN,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;SACvD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAa;QAClC,MAAM,CAAC,GAAG,IAA+D,CAAC;QAC1E,MAAM,WAAW,GACf,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;iBACZ,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;iBACzE,IAAI,CAAC,MAAM,CAAC;YACf,YAAY,CAAC;QAEf,MAAM,MAAM,GAAG;;;;;;EAMjB,CAAC;QAEC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,aAAa,WAAW,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3F,MAAM,MAAM,GAAG,SAAS,CAAsC,IAAI,EAAE;YAClE,OAAO,EAAE,EAAE;YACX,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,uBAAuB;YAClD,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;SAC5E,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAgB;QACjC,MAAM,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,GACnF,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,OAAwD,CAAC;QACrE,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,uBAAuB,EAAE,EACzB,uBAAuB,CAAC,GAAG,CAAC,EAC5B,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK,CACX,CAAC;QACF,OAAO,yBAAyB,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAgB;QAC7B,MAAM,GAAG,GAAG,OAKX,CAAC;QAEF,MAAM,WAAW,GAAG,GAAG,CAAC,IAAI;YAC1B,CAAC,CAAC,wBAAwB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;YACnD,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,eAAe,GACnB,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;YACrC,CAAC,CAAC,kCAAkC,GAAG,CAAC,QAAQ;iBAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;iBACrE,IAAI,CAAC,IAAI,CAAC,EAAE;YACjB,CAAC,CAAC,EAAE,CAAC;QAET,MAAM,MAAM,GAAG;;;;;;;;;;;;;gDAa6B,CAAC;QAE7C,MAAM,UAAU,GAAG,aAAa,GAAG,CAAC,OAAO,IAAI,EAAE;kBACnC,GAAG,CAAC,MAAM,IAAI,EAAE,GAAG,WAAW,GAAG,eAAe,EAAE,CAAC;QAEjE,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAA8B,IAAI,EAAE;YAC1D,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,EAAE;YACV,SAAS,EAAE,EAAE;YACb,OAAO,EAAE,SAAS;SACnB,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,gCAAgC;YAC3D,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;YACzD,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YAClE,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,iBAAiB,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;gBACjF,CAAC,CAAE,MAAM,CAAC,OAAyC;gBACnD,CAAC,CAAC,SAAS;SACd,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,OAAiB,EAAE,IAAY,EAAE,IAAa;QACpE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;iDAkB8B,CAAC;QAE9C,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,IAAI;YACtB,CAAC,CAAC,0CAA0C,IAAI,8BAA8B,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE;YACpG,CAAC,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,4BAA4B,UAAU,OAAO,WAAW,EAAE,CAAC;QAC9E,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAAoD,IAAI,EAAE,EAAE,CAAC,CAAC;QACtF,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,eAAe;YAC9C,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;SAChC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,eAAuB;QAC7D,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;mGAmBgF,CAAC;QAEhG,MAAM,UAAU,GAAG,SAAS,QAAQ,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;QAC7E,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,SAAS,CAA6D,IAAI,EAAE,EAAE,CAAC,CAAC;QAC/F,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,eAAe;YAC5C,UAAU,EAAE,MAAM,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;YACxD,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,oBAAoB;SAChE,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,qBAAqB,CAAC,IAAY;QACtC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;mFAoBgE,CAAC;QAEhF,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACjG,MAAM,MAAM,GAAG,SAAS,CAAwD,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1F,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,qBAAqB;YACxD,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,SAAS;SACvC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,OAAyE;QAEzE,MAAM,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACnH,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,uBAAuB,EAAE,EACzB,uBAAuB,CAAC,OAAO,CAAC,EAChC,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK,CACX,CAAC;QACF,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,WAAW,CACf,OAAoE;QAEpE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChG,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,cAAc,EAAE,EAChB,cAAc,CAAC,OAAO,CAAC,EACvB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK,CACX,CAAC;QACF,OAAO,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,GAAG,CACP,QAAgB,EAChB,OAA0C;QAE1C,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChG,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5G,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;CACF","sourcesContent":["/**\n * OpenAiAi — OpenAI Chat Completions API integration.\n *\n * Authentication: OPENAI_API_KEY env var or stored config key.\n * Model: defaults to gpt-4o. Override via GITX_AI_MODEL env var.\n *\n * All methods use the same structured JSON prompt pattern as ClaudeAi.\n */\n\nimport axios, { isAxiosError } from \"axios\";\nimport { GitxError } from \"../utils/errors.js\";\nimport type {\n AiAnalyzeTaskResponse,\n AiClient,\n AiGenerateDiffsResponse,\n AiGeneratePlanResponse,\n AiReviewPRResponse,\n AiSuggestFixesResponse,\n AiSummarizeChangesResponse,\n} from \"./types.js\";\n\nconst OPENAI_API = \"https://api.openai.com/v1/chat/completions\";\nconst DEFAULT_MODEL = \"gpt-4o\";\nconst MAX_TOKENS = 4096;\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction getModel(override?: string): string {\n return process.env[\"GITX_AI_MODEL\"] ?? override ?? DEFAULT_MODEL;\n}\n\ninterface ChatMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\ninterface OpenAiRequestBody {\n model: string;\n max_tokens: number;\n messages: ChatMessage[];\n}\n\ninterface OpenAiResponseBody {\n choices: Array<{\n message: { role: string; content: string };\n finish_reason: string;\n }>;\n}\n\nasync function callOpenAi(\n system: string,\n userPrompt: string,\n apiKey: string,\n model: string\n): Promise<string> {\n const body: OpenAiRequestBody = {\n model,\n max_tokens: MAX_TOKENS,\n messages: [\n { role: \"system\", content: system },\n { role: \"user\", content: userPrompt },\n ],\n };\n\n try {\n const { data } = await axios.post<OpenAiResponseBody>(OPENAI_API, body, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n timeout: 60_000,\n });\n\n return data.choices[0]?.message?.content?.trim() ?? \"\";\n } catch (err) {\n if (isAxiosError(err)) {\n const status = err.response?.status;\n const msg =\n (err.response?.data as Record<string, unknown> | undefined)?.error ??\n err.message;\n if (status === 401) {\n throw new GitxError(\n \"OpenAI API authentication failed. Check OPENAI_API_KEY.\",\n { exitCode: 1, cause: err }\n );\n }\n if (status === 429) {\n throw new GitxError(\n \"OpenAI rate limit exceeded. Wait a moment and retry.\",\n { exitCode: 1, cause: err }\n );\n }\n throw new GitxError(\n `OpenAI API error (${status ?? \"network\"}): ${String(msg)}`,\n { exitCode: 1, cause: err }\n );\n }\n throw new GitxError(`Unexpected OpenAI error: ${String(err)}`, {\n exitCode: 1,\n cause: err,\n });\n }\n}\n\nfunction extractJson(text: string): string {\n const fenced = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (fenced?.[1]) return fenced[1].trim();\n const start = text.search(/[{[]/);\n const endBrace = text.lastIndexOf(\"}\");\n const endBracket = text.lastIndexOf(\"]\");\n const end = Math.max(endBrace, endBracket);\n if (start !== -1 && end !== -1 && end > start) return text.slice(start, end + 1);\n return text.trim();\n}\n\nfunction parseJson<T>(text: string, fallback: T): T {\n try {\n return JSON.parse(extractJson(text)) as T;\n } catch {\n return fallback;\n }\n}\n\n// ─── OpenAiAi ─────────────────────────────────────────────────────────────────\n\nexport class OpenAiAi implements AiClient {\n private readonly apiKey: string;\n private readonly model: string;\n\n /**\n * @param apiKey OpenAI API key. Falls back to OPENAI_API_KEY env var.\n * @param model Model override. Falls back to GITX_AI_MODEL then gpt-4o.\n */\n constructor(apiKey?: string, model?: string) {\n const key = apiKey ?? process.env[\"OPENAI_API_KEY\"];\n if (!key) {\n throw new GitxError(\n \"No OpenAI API key available. Run `gitx config set openai` or set OPENAI_API_KEY.\",\n { exitCode: 2 }\n );\n }\n this.apiKey = key;\n this.model = getModel(model);\n }\n\n /** Check whether an OpenAI API key is available without instantiating. */\n static isAvailable(key?: string): boolean {\n return Boolean(key ?? process.env[\"OPENAI_API_KEY\"]);\n }\n\n async analyzeTask(input: string): Promise<AiAnalyzeTaskResponse> {\n const system = `You are an expert software engineer. Analyze the given development task and respond with ONLY valid JSON matching this exact structure (no prose, no markdown):\n{\n \"task\": \"<the original task string>\",\n \"intent\": \"<one of: refactor | bugfix | feature | chore | unknown>\",\n \"summary\": \"<one sentence explaining what needs to be done>\",\n \"assumptions\": [\"<assumption 1>\", \"<assumption 2>\"],\n \"risks\": [\"<risk 1>\", \"<risk 2>\"]\n}`;\n\n const text = await callOpenAi(system, `Task: ${input}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiAnalyzeTaskResponse>>(text, {});\n return {\n task: input,\n intent: (parsed.intent as AiAnalyzeTaskResponse[\"intent\"]) ?? \"unknown\",\n summary: parsed.summary ?? \"Unable to analyze task.\",\n assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],\n risks: Array.isArray(parsed.risks) ? parsed.risks : [],\n };\n }\n\n async generatePlan(context: unknown): Promise<AiGeneratePlanResponse> {\n const ctx = context as {\n task?: string;\n analysis?: AiAnalyzeTaskResponse;\n repoFiles?: string[];\n fileContents?: Record<string, string>;\n };\n\n const taskDesc = ctx.task ?? \"Unknown task\";\n const analysisSummary = ctx.analysis?.summary ?? \"\";\n const fileList = ctx.repoFiles?.slice(0, 50).join(\"\\n\") ?? \"(not provided)\";\n const fileContentsSection =\n ctx.fileContents && Object.keys(ctx.fileContents).length > 0\n ? `\\n\\nRelevant file contents:\\n${Object.entries(ctx.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert software engineer creating a step-by-step implementation plan. Respond with ONLY valid JSON:\n{\n \"steps\": [\n { \"id\": \"step-1\", \"title\": \"<short title>\", \"description\": \"<detailed description>\" }\n ]\n}\nKeep steps atomic and ordered. Each step should touch one logical concern.`;\n\n const userPrompt = `Task: ${taskDesc}\nAnalysis: ${analysisSummary}\nRepo files (top 50):\n${fileList}${fileContentsSection}`;\n\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiGeneratePlanResponse>>(text, { steps: [] });\n const steps = Array.isArray(parsed.steps) ? parsed.steps : [];\n\n if (steps.length === 0) {\n return { steps: [{ id: \"step-1\", title: \"Analyze & implement\", description: taskDesc }] };\n }\n return { steps };\n }\n\n async generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse> {\n const s = step as {\n id?: string;\n title?: string;\n description?: string;\n task?: string;\n fileContents?: Record<string, string>;\n };\n\n const stepId = s.id ?? \"step-1\";\n const fileContentsSection =\n s.fileContents && Object.keys(s.fileContents).length > 0\n ? `\\n\\nCurrent file contents:\\n${Object.entries(s.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\\n\\n(No existing file contents — create new files as needed.)\";\n\n const system = `You are an expert software engineer. Generate unified diffs for the given implementation step.\nRespond with ONLY valid JSON:\n{\n \"stepId\": \"<step id>\",\n \"diffs\": [\n {\n \"path\": \"<relative file path>\",\n \"unifiedDiff\": \"<valid unified diff starting with --- a/path and +++ b/path>\"\n }\n ]\n}\n\nRules for unified diffs:\n- Start with: --- a/<path>\\\\n+++ b/<path>\n- Use @@ -<start>,<count> +<start>,<count> @@ context headers\n- Lines starting with ' ' are context (unchanged)\n- Lines starting with '-' are removed\n- Lines starting with '+' are added\n- For new files use: --- /dev/null\\\\n+++ b/<path>\n- Always include 3 lines of context around changes`;\n\n const userPrompt = `Task: ${s.task ?? \"\"}\nStep ID: ${stepId}\nStep Title: ${s.title ?? \"\"}\nStep Description: ${s.description ?? \"\"}${fileContentsSection}`;\n\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiGenerateDiffsResponse>>(text, { stepId, diffs: [] });\n return {\n stepId,\n diffs: Array.isArray(parsed.diffs) ? parsed.diffs : [],\n };\n }\n\n async summarizeChanges(diff: unknown): Promise<AiSummarizeChangesResponse> {\n const d = diff as { diffs?: AiGenerateDiffsResponse[]; rawDiff?: string };\n const diffContent =\n d.rawDiff ??\n (d.diffs ?? [])\n .flatMap((dr) => dr.diffs.map((f) => `File: ${f.path}\\n${f.unifiedDiff}`))\n .join(\"\\n\\n\") ??\n \"(no diffs)\";\n\n const system = `You are a technical writer. Summarize code changes for a pull request. Respond with ONLY valid JSON:\n{\n \"summary\": \"<2-3 sentence plain-English summary of what changed and why>\",\n \"filesChanged\": [\n { \"path\": \"<file path>\", \"changeType\": \"<add | modify | delete>\" }\n ]\n}`;\n\n const text = await callOpenAi(system, `Changes:\\n${diffContent}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiSummarizeChangesResponse>>(text, {\n summary: \"\",\n filesChanged: [],\n });\n return {\n summary: parsed.summary ?? \"Code changes applied.\",\n filesChanged: Array.isArray(parsed.filesChanged) ? parsed.filesChanged : [],\n };\n }\n\n async suggestFixes(comment: unknown): Promise<AiSuggestFixesResponse> {\n const { buildSuggestFixesSystem, buildSuggestFixesPrompt, parseSuggestFixesResponse } =\n await import(\"./reviewHelpers.js\");\n const ctx = comment as Parameters<typeof buildSuggestFixesPrompt>[0];\n const text = await callOpenAi(\n buildSuggestFixesSystem(),\n buildSuggestFixesPrompt(ctx),\n this.apiKey,\n this.model\n );\n return parseSuggestFixesResponse(text);\n }\n\n async reviewPR(context: unknown): Promise<AiReviewPRResponse> {\n const ctx = context as {\n prTitle?: string;\n prBody?: string;\n diff?: string;\n comments?: Array<{ body: string; author: string; path?: string }>;\n };\n\n const diffSection = ctx.diff\n ? `\\n\\nDiff (unified):\\n${ctx.diff.slice(0, 8000)}`\n : \"\";\n const commentsSection =\n ctx.comments && ctx.comments.length > 0\n ? `\\n\\nExisting review comments:\\n${ctx.comments\n .map((c) => `[${c.author}${c.path ? ` @ ${c.path}` : \"\"}]: ${c.body}`)\n .join(\"\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer. Review the given pull request thoroughly and respond with ONLY valid JSON:\n{\n \"summary\": \"<2-4 sentence overall assessment>\",\n \"issues\": [\n { \"severity\": \"<critical|warning|suggestion>\", \"description\": \"<specific issue>\", \"file\": \"<optional file>\", \"line\": null }\n ],\n \"positives\": [\"<good thing 1>\", \"<good thing 2>\"],\n \"verdict\": \"<approve|request_changes|comment>\"\n}\n\nSeverity guide:\n- critical: bugs, security issues, data loss risk\n- warning: code quality, performance, missing error handling\n- suggestion: style, naming, minor improvements`;\n\n const userPrompt = `PR Title: ${ctx.prTitle ?? \"\"}\nPR Description: ${ctx.prBody ?? \"\"}${diffSection}${commentsSection}`;\n\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiReviewPRResponse>>(text, {\n summary: \"\",\n issues: [],\n positives: [],\n verdict: \"comment\",\n });\n\n return {\n summary: parsed.summary ?? \"Review could not be generated.\",\n issues: Array.isArray(parsed.issues) ? parsed.issues : [],\n positives: Array.isArray(parsed.positives) ? parsed.positives : [],\n verdict: ([\"approve\", \"request_changes\", \"comment\"].includes(parsed.verdict ?? \"\"))\n ? (parsed.verdict as AiReviewPRResponse[\"verdict\"])\n : \"comment\",\n };\n }\n\n async generatePrContent(commits: string[], diff: string, stat?: string): Promise<import(\"./types.js\").AiPrContentResponse> {\n const system = `You are an expert software engineer writing pull request descriptions.\nYou are given a list of commits on the branch and the unified diff of all changes.\n\nThe input may contain:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changed files.\nDo not ignore files that appear in the list but are absent from the truncated diff.\n\nProduce a clear, informative PR title and description:\n\nRules:\n- title: short, human-readable, present-tense. No conventional-commit prefix. Max 72 chars.\n- body: 2-4 sentences describing WHAT changed and WHY. Cover ALL files from the list.\n Plain English, no bullet points.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"title\":\"<PR title>\",\"body\":\"<PR description>\"}`;\n\n const commitList = commits.slice(0, 20).join(\"\\n\");\n const diffSection = stat\n ? `=== Changed files (complete list) ===\\n${stat}\\n\\n=== Detailed diff ===\\n${diff.slice(0, 16000)}`\n : `Diff:\\n${diff.slice(0, 16000)}`;\n const userPrompt = `Commits on this branch:\\n${commitList}\\n\\n${diffSection}`;\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiPrContentResponse>>(text, {});\n return {\n title: parsed.title?.trim() ?? \"Update branch\",\n body: parsed.body?.trim() ?? \"\",\n };\n }\n\n async resolveConflict(filePath: string, conflictContent: string): Promise<import(\"./types.js\").AiConflictResolutionResponse> {\n const system = `You are an expert software engineer resolving git merge conflicts.\n\nThe file contains standard git conflict markers:\n <<<<<<< HEAD — changes on the current branch\n ======= — separator\n >>>>>>> theirs — incoming changes\n\nYour task:\n1. Understand BOTH sides of every conflict.\n2. Produce a single correct version preserving the intent of BOTH changes where possible.\n3. If the sides are genuinely contradictory, set confidence to \"low\".\n\nRules:\n- Remove ALL conflict markers from the output.\n- Do NOT add explanatory comments.\n- Keep all non-conflicting code exactly as-is.\n- Output must be syntactically valid.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"resolved\":\"<full resolved file content>\",\"confidence\":\"high|low\",\"explanation\":\"<one sentence>\"}`;\n\n const userPrompt = `File: ${filePath}\\n\\n${conflictContent.slice(0, 20000)}`;\n const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiConflictResolutionResponse>>(text, {});\n return {\n resolved: parsed.resolved ?? conflictContent,\n confidence: parsed.confidence === \"low\" ? \"low\" : \"high\",\n explanation: parsed.explanation?.trim() ?? \"Conflict resolved.\",\n };\n }\n async generateCommitMessage(diff: string): Promise<import(\"./types.js\").AiCommitMessageResponse> {\n const system = `You are an expert software engineer writing git commit messages.\nYou receive either a plain unified diff OR a structured input with:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changes.\nDo not ignore files that appear in the list but are missing from the truncated diff.\n\nProduce ONE CONVENTIONAL COMMIT covering all the changes:\n\nRules:\n- subject: \"<type>(<scope>): <imperative description>\"\n - type: feat | fix | refactor | chore | docs | test | perf | ci | style | build\n - scope: the primary area affected; omit if changes span many unrelated areas\n - description: imperative mood, no period, 72 chars max for the whole subject line\n - if several distinct features or fixes are present, pick the most impactful for the subject\n- body: cover EVERY significant change visible in the file list. For each distinct change,\n one sentence on what was done and why. Plain English, no bullet lists, no repetition of the subject.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"subject\":\"<subject line>\",\"body\":\"<body covering all changes, or empty string>\"}`;\n\n const text = await callOpenAi(system, `Diff:\\n${diff.slice(0, 20000)}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiCommitMessageResponse>>(text, {});\n return {\n subject: parsed.subject?.trim() ?? \"chore: update files\",\n body: parsed.body?.trim() || undefined,\n };\n }\n\n async reviewPRDetailed(\n context: Parameters<import(\"./types.js\").AiClient[\"reviewPRDetailed\"]>[0]\n ): Promise<import(\"./types.js\").AiDetailedReviewResponse> {\n const { buildSeniorReviewSystem, buildSeniorReviewPrompt, parseSeniorReview } = await import(\"./reviewHelpers.js\");\n const text = await callOpenAi(\n buildSeniorReviewSystem(),\n buildSeniorReviewPrompt(context),\n this.apiKey,\n this.model\n );\n return parseSeniorReview(text);\n }\n\n async generateFix(\n context: Parameters<import(\"./types.js\").AiClient[\"generateFix\"]>[0]\n ): Promise<import(\"./types.js\").AiFixResponse> {\n const { buildFixSystem, buildFixPrompt, parseFixResponse } = await import(\"./reviewHelpers.js\");\n const text = await callOpenAi(\n buildFixSystem(),\n buildFixPrompt(context),\n this.apiKey,\n this.model\n );\n return parseFixResponse(text, context.filePath, context.line);\n }\n\n async ask(\n question: string,\n context: import(\"./types.js\").AiAskContext\n ): Promise<import(\"./types.js\").AiAskResponse> {\n const { buildAskSystem, buildAskPrompt, parseAskResponse } = await import(\"./reviewHelpers.js\");\n const text = await callOpenAi(buildAskSystem(), buildAskPrompt(question, context), this.apiKey, this.model);\n return parseAskResponse(text);\n }\n}\n"]}
|
|
@@ -63,4 +63,28 @@ export declare function buildAskPrompt(question: string, ctx: AiAskContext): str
|
|
|
63
63
|
* Falls back to using the raw text as the answer if JSON parsing fails.
|
|
64
64
|
*/
|
|
65
65
|
export declare function parseAskResponse(raw: string): AiAskResponse;
|
|
66
|
+
export interface SuggestFixesContext {
|
|
67
|
+
comments: Array<{
|
|
68
|
+
body: string;
|
|
69
|
+
path?: string;
|
|
70
|
+
line?: number;
|
|
71
|
+
author?: string;
|
|
72
|
+
}>;
|
|
73
|
+
prTitle?: string;
|
|
74
|
+
prBody?: string;
|
|
75
|
+
/** Full unified diff of the PR — tells the AI what changed vs. the base */
|
|
76
|
+
diff?: string;
|
|
77
|
+
/** File contents keyed by relative path (with line numbers prefixed) */
|
|
78
|
+
fileContents?: Record<string, string>;
|
|
79
|
+
}
|
|
80
|
+
export interface SuggestFixesResponse {
|
|
81
|
+
suggestedEdits: Array<{
|
|
82
|
+
path: string;
|
|
83
|
+
rationale: string;
|
|
84
|
+
unifiedDiff: string;
|
|
85
|
+
}>;
|
|
86
|
+
}
|
|
87
|
+
export declare function buildSuggestFixesSystem(): string;
|
|
88
|
+
export declare function buildSuggestFixesPrompt(ctx: SuggestFixesContext): string;
|
|
89
|
+
export declare function parseSuggestFixesResponse(raw: string): SuggestFixesResponse;
|
|
66
90
|
//# sourceMappingURL=reviewHelpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reviewHelpers.d.ts","sourceRoot":"","sources":["../../src/ai/reviewHelpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIvG,wBAAgB,uBAAuB,IAAI,MAAM,CAwChD;AAwJD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE;IACP,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzF,GACA,MAAM,
|
|
1
|
+
{"version":3,"file":"reviewHelpers.d.ts","sourceRoot":"","sources":["../../src/ai/reviewHelpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIvG,wBAAgB,uBAAuB,IAAI,MAAM,CAwChD;AAwJD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE;IACP,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzF,GACA,MAAM,CA6GR;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,CAkCxE;AAID;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAsBvC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAgCT;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAgD5F;AAuCD;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAgCvC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAoE1E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAa3D;AAID,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjF;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CA0BhD;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,CAmCxE;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAa3E"}
|
package/dist/ai/reviewHelpers.js
CHANGED
|
@@ -181,63 +181,77 @@ export function buildSeniorReviewPrompt(context) {
|
|
|
181
181
|
}
|
|
182
182
|
// ── Parse which lines actually changed per file ───────────────────────────
|
|
183
183
|
const hunkRanges = parseHunkRanges(context.diff);
|
|
184
|
-
// ──
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
184
|
+
// ── Budget constants ──────────────────────────────────────────────────────
|
|
185
|
+
// Claude has a 200k-token context window. We stay well within that while
|
|
186
|
+
// sending enough code for a thorough review.
|
|
187
|
+
//
|
|
188
|
+
// Strategy:
|
|
189
|
+
// • Files ≤ FULL_FILE_THRESHOLD lines → send the ENTIRE file (best context)
|
|
190
|
+
// • Larger files → smart section extraction around hunks
|
|
191
|
+
// with generous context above (function boundary) and below (CONTEXT_LINES_BELOW)
|
|
192
|
+
// • Hard per-file cap for huge files → PER_FILE_LINE_CAP lines of excerpts
|
|
193
|
+
const FULL_FILE_THRESHOLD = 400; // files ≤ this many lines are sent whole
|
|
194
|
+
const CONTEXT_LINES_BELOW = 60; // lines below each hunk in extraction mode
|
|
195
|
+
const PER_FILE_LINE_CAP = 800; // hard cap on excerpt lines for very large files
|
|
196
|
+
const DIFF_BUDGET = 30_000; // unified diff character budget (was 5k — way too small)
|
|
197
|
+
const CTX_FILE_MAX = 4_000; // max chars per supporting context file (was 1.5k)
|
|
192
198
|
const changedEntries = Object.entries(context.changedFiles);
|
|
193
199
|
if (changedEntries.length > 0) {
|
|
194
|
-
parts.push(`\n### Changed
|
|
200
|
+
parts.push(`\n### Changed files (line numbers are exact positions in the new file)`);
|
|
195
201
|
for (const [path, content] of changedEntries) {
|
|
202
|
+
const fileLines = content.split("\n");
|
|
196
203
|
const hunks = hunkRanges.get(path) ?? [];
|
|
197
204
|
let excerpt;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
excerpt =
|
|
202
|
-
.slice(0, 60)
|
|
205
|
+
let deliveryNote;
|
|
206
|
+
if (fileLines.length <= FULL_FILE_THRESHOLD) {
|
|
207
|
+
// Small file — send the whole thing. The AI gets complete context with no gaps.
|
|
208
|
+
excerpt = fileLines
|
|
203
209
|
.map((l, i) => `${String(i + 1).padStart(5, " ")} | ${l}`)
|
|
204
210
|
.join("\n");
|
|
205
|
-
|
|
206
|
-
excerpt += "\n … (file continues — only first 60 lines shown as fallback)";
|
|
211
|
+
deliveryNote = `full file, ${fileLines.length} lines`;
|
|
207
212
|
}
|
|
208
|
-
else {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
`\n … (${excerptLines.length - PER_FILE_LINE_CAP} more lines not shown` +
|
|
218
|
-
` — this function is unusually large; review the diff for remaining changes)`;
|
|
213
|
+
else if (hunks.length === 0) {
|
|
214
|
+
// No hunk data (binary / rename-only) — show first 100 lines as fallback
|
|
215
|
+
excerpt = fileLines
|
|
216
|
+
.slice(0, 100)
|
|
217
|
+
.map((l, i) => `${String(i + 1).padStart(5, " ")} | ${l}`)
|
|
218
|
+
.join("\n");
|
|
219
|
+
if (fileLines.length > 100)
|
|
220
|
+
excerpt += `\n … (file continues — only first 100 lines shown; no hunk data available)`;
|
|
221
|
+
deliveryNote = `first 100 of ${fileLines.length} lines (no hunk data)`;
|
|
219
222
|
}
|
|
220
223
|
else {
|
|
221
|
-
|
|
224
|
+
// Large file — extract sections around changed hunks with generous context
|
|
225
|
+
excerpt = extractChangedSections(content, hunks, CONTEXT_LINES_BELOW);
|
|
226
|
+
// Cap at PER_FILE_LINE_CAP complete lines — never mid-line
|
|
227
|
+
const excerptLines = excerpt.split("\n");
|
|
228
|
+
if (excerptLines.length > PER_FILE_LINE_CAP) {
|
|
229
|
+
excerpt =
|
|
230
|
+
excerptLines.slice(0, PER_FILE_LINE_CAP).join("\n") +
|
|
231
|
+
`\n … (${excerptLines.length - PER_FILE_LINE_CAP} more excerpt lines omitted` +
|
|
232
|
+
` — file has ${fileLines.length} total lines; see the diff below for full change)`;
|
|
233
|
+
}
|
|
234
|
+
deliveryNote = `${hunks.length} hunk${hunks.length > 1 ? "s" : ""}, ${fileLines.length} total lines`;
|
|
222
235
|
}
|
|
223
|
-
|
|
224
|
-
? ` (${hunks.length} change hunk${hunks.length > 1 ? "s" : ""})`
|
|
225
|
-
: "";
|
|
226
|
-
parts.push(`\n#### ${path}${hunkDesc}\n\`\`\`\n${finalExcerpt}\n\`\`\``);
|
|
236
|
+
parts.push(`\n#### ${path} (${deliveryNote})\n\`\`\`\n${excerpt}\n\`\`\``);
|
|
227
237
|
}
|
|
228
238
|
}
|
|
229
|
-
// ──
|
|
239
|
+
// ── Unified diff (the raw patch — gives the AI the exact before/after for every line)
|
|
230
240
|
if (context.diff.trim()) {
|
|
231
241
|
const diffSlice = context.diff.slice(0, DIFF_BUDGET);
|
|
232
242
|
const diffTrunc = diffSlice.length < context.diff.length;
|
|
233
|
-
parts.push(`\n### Unified diff${diffTrunc ?
|
|
243
|
+
parts.push(`\n### Unified diff${diffTrunc ? ` (truncated to ${DIFF_BUDGET} chars — see file sections above for full content)` : ""}\n\`\`\`diff\n${diffSlice}\n\`\`\``);
|
|
234
244
|
}
|
|
235
245
|
// ── Supporting context files (unchanged files the changes depend on) ──────
|
|
236
246
|
const ctxEntries = Object.entries(context.contextFiles);
|
|
237
247
|
if (ctxEntries.length > 0) {
|
|
238
248
|
parts.push(`\n### Supporting context files (unchanged — imported by changed files)`);
|
|
239
249
|
for (const [path, content] of ctxEntries) {
|
|
240
|
-
|
|
250
|
+
const ctxLines = content.split("\n");
|
|
251
|
+
const ctxExcerpt = content.length <= CTX_FILE_MAX
|
|
252
|
+
? content
|
|
253
|
+
: content.slice(0, CTX_FILE_MAX) + `\n… (truncated — ${ctxLines.length} total lines)`;
|
|
254
|
+
parts.push(`\n#### ${path}\n\`\`\`\n${ctxExcerpt}\n\`\`\``);
|
|
241
255
|
}
|
|
242
256
|
}
|
|
243
257
|
// ── Existing PR comments ──────────────────────────────────────────────────
|
|
@@ -415,15 +429,18 @@ const GITX_COMMAND_REFERENCE = `
|
|
|
415
429
|
| gitx config show | Display current configuration (secrets redacted) |
|
|
416
430
|
| gitx config set <key> [value] | Set a single config value (provider, token, model, etc.) |
|
|
417
431
|
| gitx commit [-m msg] [--push] [--dry-run] | AI-generate commit message → commit (optionally push) |
|
|
418
|
-
| gitx push [-b branch] [--dry-run] | Stage → AI-commit → push in one step |
|
|
419
|
-
| gitx sync [--base branch] [--strategy merge|rebase] [--continue] [--abort] |
|
|
432
|
+
| gitx push [-b branch] [--staged] [--dry-run] | Stage → AI-commit → push in one step; --staged uses already-staged files only |
|
|
433
|
+
| gitx sync [--base branch] [--strategy merge|rebase] [--continue] [--abort] | Fetch + merge/rebase base into current branch; AI auto-resolves conflicts. Run "gitx pr resolve" first if you have open review comments. |
|
|
434
|
+
| gitx port <target…> [--base branch] [--no-pr] [--draft] [--continue] [--abort] | Cherry-pick commits onto other branches with incremental detection |
|
|
420
435
|
| gitx implement "<task>" [--mode plan|guided|semi-auto|auto] [--dry-run] | AI-plan and implement a task end-to-end |
|
|
421
436
|
| gitx pr list [--state open|closed|all] | List pull requests |
|
|
422
437
|
| gitx pr create [--title T] [--body B] [--draft] [--dry-run] | AI-generate PR title/body → open PR |
|
|
423
|
-
| gitx pr review <number> [--no-comment] [--
|
|
424
|
-
| gitx pr
|
|
438
|
+
| gitx pr review <number> [--no-comment] [--inline] | Senior-dev AI review — posts inline comments to the PR |
|
|
439
|
+
| gitx pr resolve <number> [--no-commit] [--no-push] [--dry-run] | AI-fix review comments in code; --no-commit applies fixes without committing |
|
|
425
440
|
| gitx pr merge <number> [--strategy squash|merge|rebase] [--delete-branch] | Merge a PR |
|
|
426
441
|
| gitx pr close <number> [-f] | Close a PR |
|
|
442
|
+
| gitx pr cherry-pick <number> [--dry-run] [--no-confirm] | Cherry-pick all commits from a PR into the current branch |
|
|
443
|
+
| gitx pr port <number> <target1> [target2...] [--no-pr] [--draft] [--dry-run] [--no-confirm] | Port a PR's commits onto one or more target branches and open PRs (current branch untouched) |
|
|
427
444
|
| gitx ask "<question>" [--pr] | Ask a question about the repo using AI + live git context |
|
|
428
445
|
|
|
429
446
|
## Supported Providers
|
|
@@ -556,4 +573,71 @@ export function parseAskResponse(raw) {
|
|
|
556
573
|
return { answer: raw.trim(), suggestedCommands: [] };
|
|
557
574
|
}
|
|
558
575
|
}
|
|
576
|
+
export function buildSuggestFixesSystem() {
|
|
577
|
+
return `You are a senior software engineer resolving pull request review comments by making precise code fixes.
|
|
578
|
+
|
|
579
|
+
You are given:
|
|
580
|
+
1. The PR title and description (for context)
|
|
581
|
+
2. The unified diff of the PR (shows exactly what changed vs. the base branch)
|
|
582
|
+
3. The current file contents of every file that has comments (with line numbers)
|
|
583
|
+
4. The review comments, each tagged with the file and line they target
|
|
584
|
+
|
|
585
|
+
Your job:
|
|
586
|
+
- For each comment that requires a code change, produce a minimal, correct unified diff that fixes it
|
|
587
|
+
- The diff MUST apply cleanly to the CURRENT file content shown (not the base)
|
|
588
|
+
- Preserve the existing code style, indentation, and patterns
|
|
589
|
+
- If a comment is a question or praise (no code change needed), omit it from suggestedEdits
|
|
590
|
+
- Do NOT fix things not mentioned in the comments — minimal targeted changes only
|
|
591
|
+
|
|
592
|
+
Respond with ONLY valid JSON (no markdown fences):
|
|
593
|
+
{
|
|
594
|
+
"suggestedEdits": [
|
|
595
|
+
{
|
|
596
|
+
"path": "<relative file path>",
|
|
597
|
+
"rationale": "<one sentence: which comment this fixes and how>",
|
|
598
|
+
"unifiedDiff": "<valid unified diff that applies to the current file content>"
|
|
599
|
+
}
|
|
600
|
+
]
|
|
601
|
+
}`;
|
|
602
|
+
}
|
|
603
|
+
export function buildSuggestFixesPrompt(ctx) {
|
|
604
|
+
const parts = [];
|
|
605
|
+
parts.push(`PR Title: ${ctx.prTitle ?? "(none)"}`);
|
|
606
|
+
if (ctx.prBody?.trim()) {
|
|
607
|
+
parts.push(`\nPR Description:\n${ctx.prBody.trim()}`);
|
|
608
|
+
}
|
|
609
|
+
// Unified diff — gives the AI the before/after context for every changed line
|
|
610
|
+
const DIFF_BUDGET = 30_000;
|
|
611
|
+
if (ctx.diff?.trim()) {
|
|
612
|
+
const diffSlice = ctx.diff.slice(0, DIFF_BUDGET);
|
|
613
|
+
const truncated = diffSlice.length < ctx.diff.length;
|
|
614
|
+
parts.push(`\n### PR Unified Diff${truncated ? " (truncated)" : ""}\n\`\`\`diff\n${diffSlice}\n\`\`\``);
|
|
615
|
+
}
|
|
616
|
+
// Review comments
|
|
617
|
+
const commentsText = ctx.comments
|
|
618
|
+
.map((c) => `[${c.author ?? "reviewer"}${c.path ? ` on ${c.path}:${c.line ?? "?"}` : ""}]:\n${c.body}`)
|
|
619
|
+
.join("\n\n---\n\n");
|
|
620
|
+
parts.push(`\n### Review Comments\n${commentsText}`);
|
|
621
|
+
// Current file contents (with line numbers so the diff is anchored correctly)
|
|
622
|
+
if (ctx.fileContents && Object.keys(ctx.fileContents).length > 0) {
|
|
623
|
+
parts.push(`\n### Current File Contents (line numbers are exact — use them for your diffs)`);
|
|
624
|
+
for (const [path, content] of Object.entries(ctx.fileContents)) {
|
|
625
|
+
parts.push(`\n#### ${path}\n\`\`\`\n${content}\n\`\`\``);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return parts.join("\n");
|
|
629
|
+
}
|
|
630
|
+
export function parseSuggestFixesResponse(raw) {
|
|
631
|
+
try {
|
|
632
|
+
const parsed = JSON.parse(raw);
|
|
633
|
+
return {
|
|
634
|
+
suggestedEdits: Array.isArray(parsed.suggestedEdits)
|
|
635
|
+
? parsed.suggestedEdits.filter((e) => typeof e?.path === "string" && typeof e?.unifiedDiff === "string")
|
|
636
|
+
: [],
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
catch {
|
|
640
|
+
return { suggestedEdits: [] };
|
|
641
|
+
}
|
|
642
|
+
}
|
|
559
643
|
//# sourceMappingURL=reviewHelpers.js.map
|