create-cartwright 0.1.0 → 2.0.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 +21 -2
- package/dist/approve.d.ts +2 -0
- package/dist/approve.js +16 -0
- package/dist/approve.js.map +1 -0
- package/dist/approve.test.d.ts +1 -0
- package/dist/approve.test.js +23 -0
- package/dist/approve.test.js.map +1 -0
- package/dist/brief.d.ts +26 -0
- package/dist/brief.js +25 -0
- package/dist/brief.js.map +1 -0
- package/dist/brief.test.d.ts +1 -0
- package/dist/brief.test.js +23 -0
- package/dist/brief.test.js.map +1 -0
- package/dist/generate/index.d.ts +4 -0
- package/dist/generate/index.js +42 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/generate/index.test.d.ts +1 -0
- package/dist/generate/index.test.js +47 -0
- package/dist/generate/index.test.js.map +1 -0
- package/dist/index.js +122 -82
- package/dist/index.js.map +1 -1
- package/dist/inject.d.ts +2 -0
- package/dist/inject.js +21 -0
- package/dist/inject.js.map +1 -0
- package/dist/inject.test.d.ts +1 -0
- package/dist/inject.test.js +37 -0
- package/dist/inject.test.js.map +1 -0
- package/dist/interview.d.ts +8 -0
- package/dist/interview.js +73 -0
- package/dist/interview.js.map +1 -0
- package/dist/interview.test.d.ts +1 -0
- package/dist/interview.test.js +50 -0
- package/dist/interview.test.js.map +1 -0
- package/dist/key-step.d.ts +12 -0
- package/dist/key-step.js +22 -0
- package/dist/key-step.js.map +1 -0
- package/dist/key-step.test.d.ts +1 -0
- package/dist/key-step.test.js +56 -0
- package/dist/key-step.test.js.map +1 -0
- package/dist/llm.d.ts +2 -0
- package/dist/llm.js +51 -0
- package/dist/llm.js.map +1 -0
- package/dist/llm.test.d.ts +1 -0
- package/dist/llm.test.js +32 -0
- package/dist/llm.test.js.map +1 -0
- package/dist/scaffold.d.ts +48 -0
- package/dist/scaffold.js +171 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/scaffold.test.d.ts +1 -0
- package/dist/scaffold.test.js +109 -0
- package/dist/scaffold.test.js.map +1 -0
- package/package.json +5 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EACL,KAAK,EACL,KAAK,EACL,IAAI,EACJ,MAAM,EACN,OAAO,EACP,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,QAAQ,GACT,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,sCAAsC,CAAC;AAE7D,+EAA+E;AAC/E,wEAAwE;AACxE,6EAA6E;AAC7E,sDAAsD;AACtD,MAAM,WAAW,GAAG,QAAQ,CAAC;AAE7B,+CAA+C;AAC/C,kFAAkF;AAClF,0EAA0E;AAC1E,gFAAgF;AAChF,MAAM,WAAW,GAA2B;IAC1C,MAAM,EAAE,WAAW;IACnB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,OAAO,EAIL,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,uBAAuB,EACvB,2BAA2B,EAC3B,cAAc,EACd,UAAU,EACV,UAAU,EACV,YAAY,EACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,SAAS,YAAY,CAAI,KAAiB;IACxC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,CAAC,YAAY,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB,EAAE,WAAmB;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAChD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAC9B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,uBAAuB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC/D,IAAI,OAAO,KAAK,QAAQ;QAAE,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAC5B,SAAiB,EACjB,QAAsB;IAEtB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAChD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAC9B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAChE,IAAI,OAAO,KAAK,QAAQ;QAAE,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE;YACP,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;YACpC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACtB,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YACvB,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YAC5B,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YAC7B,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACvB,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACtB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC5B,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YACjC,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;SAC9B;KACF,CAAC,CAAC;IAEH,sEAAsE;IACtE,4CAA4C;IAC5C,IAAI,YAAY,GAAiB,SAAS,CAAC;IAC3C,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,KAAK,CACX,EAAE,CAAC,GAAG,CACJ,uBAAuB,MAAM,CAAC,QAAQ,qBAAqB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACvF,CACF,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,CAAC;IAED,KAAK,CACH,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAC3E,CAAC;IAEF,2EAA2E;IAC3E,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,oBAAoB,CAAC;IAC3D,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG;QAC5B,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,YAAY,CACV,MAAM,IAAI,CAAC;YACT,OAAO,EAAE,eAAe;YACxB,YAAY,EAAE,WAAW;YACzB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CACd,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;gBACzB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,gEAAgE;SACvE,CAAC,CACH,CAAC;IAEN,2EAA2E;IAC3E,MAAM,UAAU,GAAG,MAAM,CAAC,EAA0B,CAAC;IACrD,MAAM,QAAQ,GACZ,UAAU;QACV,CAAC,MAAM,CAAC,GAAG;YACT,CAAC,CAAC,OAAO;YACT,CAAC,CAAE,YAAY,CACX,MAAM,MAAM,CAAC;gBACX,OAAO,EAAE,WAAW;gBACpB,OAAO,EAAE;oBACP;wBACE,KAAK,EAAE,OAAO;wBACd,KAAK,EAAE,sCAAsC;qBAC9C;oBACD;wBACE,KAAK,EAAE,UAAU;wBACjB,KAAK,EAAE,0CAA0C;qBAClD;oBACD,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,qBAAqB,EAAE;iBAClD;gBACD,YAAY,EAAE,OAAO;aACtB,CAAC,CACU,CAAC,CAAC;IAEtB,IAAI,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxD,MAAM,CAAC,qBAAqB,QAAQ,oCAAoC,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,2EAA2E;IAC3E,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,MAAM,MAAM,GACV,MAAM;QACN,CAAC,MAAM,CAAC,GAAG;YACT,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,YAAY,CACV,MAAM,OAAO,CAAC;gBACZ,OAAO,EACL,sEAAsE;gBACxE,YAAY,EAAE,IAAI;aACnB,CAAC,CACH,CAAC,CAAC;IAET,4EAA4E;IAC5E,IAAI,cAAc,GAAG,SAAS,CAAC;IAC/B,IAAI,iBAAiB,GAAG,SAAS,CAAC;IAClC,IAAI,iBAAiB,GAAG,SAAS,CAAC;IAElC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CACrE,MAAM,OAAO,CAAC;QACZ,OAAO,EAAE,kEAAkE;QAC3E,YAAY,EAAE,IAAI;KACnB,CAAC,CACH,CAAC,CAAC;IAEH,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC;YACnC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc;YAC3C,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,MAAM,QAAQ,CAAC,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC;YAC3F,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,MAAM,OAAO,CAAC,EAAE,OAAO,EAAE,gDAAgD,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;SAC1I,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC3B,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,EAAE,gCAAgC,EAAE,CAAC,CAAC,CAAC;YAE9F,cAAc,GAAG,MAAM,YAAY,CAAC;gBAClC,MAAM,EAAE,OAAO,CAAC,GAAG;gBACnB,aAAa;gBACb,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC;gBACrF,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;aAC1C,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,cAAc,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC;YAC1D,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,OAAO,CAAC,EAAE,OAAO,EAAE,2CAA2C,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAErH,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,MAAM,CAAC,oBAAoB,CAAC,CAAC;gBAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,iBAAiB,GAAG,cAAc,CAAC,IAAI,CAAC;YACxC,iBAAiB,GAAG,cAAc,CAAC,SAAS,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,oBAAoB,EAAE,CAAC;IACxC,MAAM,cAAc,GACjB,MAAM,CAAC,EAAiC,IAAI,QAAQ,CAAC;IACxD,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,IAAI,QAAQ,CAAC;IAC5C,MAAM,WAAW,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,YAAY,CAAC;IAE9D,2EAA2E;IAC3E,MAAM,SAAS,GAAG,iBAAiB,IAAI,WAAW,CAAC;IACnD,MAAM,gBAAgB,GAAG,iBAAiB,IAAI,WAAW,CAAC;IAC1D,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IAEpD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,cAAc,SAAS,mBAAmB,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,2EAA2E;IAC3E,MAAM,YAAY,GAAG,OAAO,EAAE,CAAC;IAC/B,MAAM,UAAU,GACd,YAAY,KAAK,WAAW;QAC1B,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,GAAG,YAAY,MAAM,WAAW,EAAE,CAAC;IACzC,YAAY,CAAC,KAAK,CAAC,iCAAiC,UAAU,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC;QACH,MAAM,gBAAgB,CAAC,GAAG,aAAa,IAAI,WAAW,EAAE,EAAE;YACxD,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;QACH,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,wBAAwB,UAAU,IAAI,CAAC,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,2EAA2E;IAC3E,MAAM,UAAU,GAAG,kBAAkB,EAAE,CAAC;IACxC,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAErC,IAAI,cAAc,EAAE,CAAC;QACnB,gBAAgB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAC5C,mFAAmF;QACnF,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAChD,CAAC;IAED,uEAAuE;IACvE,qEAAqE;IACrE,uEAAuE;IACvE,0DAA0D;IAC1D,qBAAqB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IAC/C,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,CACF,aAAa,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,wDAAwD,EAC1F,MAAM,CACP,CAAC;IACJ,CAAC;IAED,2EAA2E;IAC3E,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,uCAAuC,CAAC,EAAE,MAAM,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,cAAc,GAAG,OAAO,EAAE,CAAC;QACjC,cAAc,CAAC,KAAK,CAAC,gCAAgC,cAAc,GAAG,CAAC,CAAC;QACxE,MAAM,EAAE,GAAG,UAAU,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACjD,IAAI,EAAE,EAAE,CAAC;YACP,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,IAAI,CACjB,EAAE,CAAC,MAAM,CACP,0BAA0B,cAAc,iBAAiB,WAAW,YAAY,CACjF,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,MAAM,MAAM,GACV,cAAc,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC;IAExD,MAAM,MAAM,GAAG,MAAM;QACnB,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,+EAA+E,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,qEAAqE,CAAC,EAAE;QACtL,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,KAAK,GAAG;QACZ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;YACX,YAAY,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;QACjE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,kDAAkD;QAClE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,kDAAkD;QAClE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,EAAE;QAC1D,EAAE;QACF,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC;QACtB,QAAQ,SAAS,EAAE;QACnB,iCAAiC,EAAE,CAAC,GAAG,CAAC,+BAA+B,CAAC,EAAE;QAC1E,iCAAiC,EAAE,CAAC,GAAG,CAAC,mCAAmC,CAAC,EAAE;QAC9E,KAAK,MAAM,uBAAuB,EAAE,CAAC,GAAG,CAAC,yBAAyB,CAAC,EAAE;QACrE,EAAE;QACF,YAAY,CAAC,QAAQ,CAAC;QACtB,MAAM;QACN,EAAE;QACF,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC;QAC/B,EAAE,CAAC,GAAG,CAAC,sEAAsE,CAAC;QAC9E,EAAE,CAAC,GAAG,CAAC,kDAAkD,CAAC;QAC1D,EAAE;QACF,EAAE,CAAC,GAAG,CAAC,kEAAkE,CAAC;QAC1E,EAAE,CAAC,GAAG,CAAC,2DAA2D,CAAC;KACpE;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,KAAK,CAAC,KAAK,CAAC,CAAC;AACf,CAAC;AAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAClB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/inject.d.ts
ADDED
package/dist/inject.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { generateThemeCss, generatePromptModule, generateSeedData } from "./generate";
|
|
4
|
+
export function injectBriefFiles(targetDir, brief) {
|
|
5
|
+
// Opret mapper
|
|
6
|
+
const cssDir = join(targetDir, "themes");
|
|
7
|
+
const promptsDir = join(targetDir, "lib", "ai", "prompts");
|
|
8
|
+
const seedsDir = join(targetDir, "industry-templates", brief.slug);
|
|
9
|
+
[cssDir, promptsDir, seedsDir].forEach((dir) => {
|
|
10
|
+
if (!existsSync(dir)) {
|
|
11
|
+
mkdirSync(dir, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
// Skriv filer
|
|
15
|
+
writeFileSync(join(cssDir, `${brief.slug}.css`), generateThemeCss(brief));
|
|
16
|
+
writeFileSync(join(promptsDir, `${brief.slug}.ts`), generatePromptModule(brief));
|
|
17
|
+
writeFileSync(join(seedsDir, "seed-data.ts"), generateSeedData(brief));
|
|
18
|
+
// TODO: Opdater industry-templates/index.ts for at registrere den nye seed, men
|
|
19
|
+
// det falder måske under advanced M2 scope, eller vi kan lave et simpelt append her:
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=inject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inject.js","sourceRoot":"","sources":["../src/inject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEtF,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,KAAgB;IAClE,eAAe;IACf,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,oBAAoB,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnE,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAC7C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,cAAc;IACd,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,MAAM,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1E,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;IACjF,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IAEvE,iFAAiF;IACjF,qFAAqF;AACvF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { injectBriefFiles } from "./inject";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
vi.mock("node:fs", () => ({
|
|
5
|
+
existsSync: vi.fn(),
|
|
6
|
+
mkdirSync: vi.fn(),
|
|
7
|
+
writeFileSync: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
describe("injectBriefFiles", () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
it("opretter mapper og skriver filer", () => {
|
|
14
|
+
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
15
|
+
const brief = {
|
|
16
|
+
storeName: "Test",
|
|
17
|
+
slug: "test-slug",
|
|
18
|
+
tagline: "Test tag",
|
|
19
|
+
sells: "Ting",
|
|
20
|
+
audience: "Folk",
|
|
21
|
+
tone: "Sjov",
|
|
22
|
+
country: "DK",
|
|
23
|
+
currency: "DKK",
|
|
24
|
+
palette: { primary: "#112233", background: "#ffeedd" },
|
|
25
|
+
categories: [],
|
|
26
|
+
products: []
|
|
27
|
+
};
|
|
28
|
+
injectBriefFiles("/tmp/target", brief);
|
|
29
|
+
expect(fs.mkdirSync).toHaveBeenCalledTimes(3);
|
|
30
|
+
expect(fs.writeFileSync).toHaveBeenCalledTimes(3);
|
|
31
|
+
const writeCalls = vi.mocked(fs.writeFileSync).mock.calls;
|
|
32
|
+
expect(writeCalls[0][0]).toContain("themes");
|
|
33
|
+
expect(writeCalls[1][0]).toContain("prompts");
|
|
34
|
+
expect(writeCalls[2][0]).toContain("industry-templates");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=inject.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inject.test.js","sourceRoot":"","sources":["../src/inject.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAG9B,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACxB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;IACnB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE;IAClB,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE;CACvB,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEhD,MAAM,KAAK,GAAc;YACvB,SAAS,EAAE,MAAM;YACjB,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,UAAU;YACnB,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE;YACtD,UAAU,EAAE,EAAE;YACd,QAAQ,EAAE,EAAE;SACb,CAAC;QAEF,gBAAgB,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;QAEvC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAElD,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QAC1D,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACvD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACxD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ShopBrief } from "./brief";
|
|
2
|
+
export interface InterviewDeps {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
initialPrompt: string;
|
|
5
|
+
askUser: (question: string) => Promise<string>;
|
|
6
|
+
logMsg: (msg: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function runInterview(deps: InterviewDeps): Promise<ShopBrief>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { generateJson } from "./llm";
|
|
2
|
+
const interviewSchema = {
|
|
3
|
+
type: "object",
|
|
4
|
+
properties: {
|
|
5
|
+
isComplete: { type: "boolean" },
|
|
6
|
+
nextQuestion: { type: "string", description: "The next question to ask if not complete." },
|
|
7
|
+
brief: {
|
|
8
|
+
type: "object",
|
|
9
|
+
description: "The complete shop brief. Only provided when isComplete is true.",
|
|
10
|
+
properties: {
|
|
11
|
+
storeName: { type: "string" },
|
|
12
|
+
slug: { type: "string" },
|
|
13
|
+
tagline: { type: "string" },
|
|
14
|
+
sells: { type: "string" },
|
|
15
|
+
audience: { type: "string" },
|
|
16
|
+
tone: { type: "string" },
|
|
17
|
+
country: { type: "string" },
|
|
18
|
+
currency: { type: "string" },
|
|
19
|
+
palette: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
primary: { type: "string" },
|
|
23
|
+
background: { type: "string" },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
categories: {
|
|
27
|
+
type: "array",
|
|
28
|
+
items: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
name: { type: "string" },
|
|
32
|
+
slug: { type: "string" },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
products: {
|
|
37
|
+
type: "array",
|
|
38
|
+
items: {
|
|
39
|
+
type: "object",
|
|
40
|
+
properties: {
|
|
41
|
+
name: { type: "string" },
|
|
42
|
+
categorySlug: { type: "string" },
|
|
43
|
+
priceMinor: { type: "integer" },
|
|
44
|
+
blurb: { type: "string" },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
required: ["isComplete", "nextQuestion"]
|
|
52
|
+
};
|
|
53
|
+
export async function runInterview(deps) {
|
|
54
|
+
const history = [];
|
|
55
|
+
history.push(`Brugerens indledende forespørgsel: ${deps.initialPrompt}`);
|
|
56
|
+
const systemInstructions = `
|
|
57
|
+
Du er en e-commerce ekspert. Din opgave er at indsamle nok information til at bygge et 'ShopBrief'.
|
|
58
|
+
Stil ét spørgsmål ad gangen for at udfylde de manglende felter.
|
|
59
|
+
Når du har nok info til at gætte resten kompetent (eller brugeren beder dig om at udfylde resten selv), så sæt isComplete = true og udfyld brief-objektet komplet.
|
|
60
|
+
`;
|
|
61
|
+
while (true) {
|
|
62
|
+
const prompt = `${systemInstructions}\n\nSamtalehistorik:\n${history.join("\n")}`;
|
|
63
|
+
deps.logMsg("Tænker...");
|
|
64
|
+
const res = await generateJson(deps.apiKey, prompt, interviewSchema);
|
|
65
|
+
if (res.isComplete && res.brief) {
|
|
66
|
+
return res.brief;
|
|
67
|
+
}
|
|
68
|
+
const answer = await deps.askUser(res.nextQuestion);
|
|
69
|
+
history.push(`AI: ${res.nextQuestion}`);
|
|
70
|
+
history.push(`Bruger: ${answer}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=interview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interview.js","sourceRoot":"","sources":["../src/interview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAUrC,MAAM,eAAe,GAAG;IACtB,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAC/B,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2CAA2C,EAAE;QAC1F,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,iEAAiE;YAC9E,UAAU,EAAE;gBACV,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC7B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACxB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACxB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC3B,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC5B,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC/B;iBACF;gBACD,UAAU,EAAE;oBACV,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BACxB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;yBACzB;qBACF;iBACF;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BACxB,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BAChC,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;4BAC/B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;yBAC1B;qBACF;iBACF;aACF;SACF;KACF;IACD,QAAQ,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC;CACzC,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAmB;IACpD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,sCAAsC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;IAEzE,MAAM,kBAAkB,GAAG;;;;CAI5B,CAAC;IAEA,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,GAAG,kBAAkB,yBAAyB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAElF,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,CAAQ,CAAC;QAE5E,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC,KAAkB,CAAC;QAChC,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC;IACpC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { runInterview } from "./interview";
|
|
3
|
+
import * as llm from "./llm";
|
|
4
|
+
vi.mock("./llm", () => ({
|
|
5
|
+
generateJson: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
describe("runInterview", () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
vi.clearAllMocks();
|
|
10
|
+
});
|
|
11
|
+
it("returnerer ShopBrief når isComplete er true", async () => {
|
|
12
|
+
vi.mocked(llm.generateJson).mockResolvedValueOnce({
|
|
13
|
+
isComplete: true,
|
|
14
|
+
nextQuestion: "",
|
|
15
|
+
brief: { storeName: "Test", slug: "test" } // For testens skyld er validation løs her
|
|
16
|
+
});
|
|
17
|
+
const res = await runInterview({
|
|
18
|
+
apiKey: "key",
|
|
19
|
+
initialPrompt: "Jeg vil lave en kaffeshop",
|
|
20
|
+
askUser: async () => "svar",
|
|
21
|
+
logMsg: () => { }
|
|
22
|
+
});
|
|
23
|
+
expect(res).toEqual({ storeName: "Test", slug: "test" });
|
|
24
|
+
});
|
|
25
|
+
it("stiller spørgsmål og opsamler svar indtil isComplete", async () => {
|
|
26
|
+
vi.mocked(llm.generateJson)
|
|
27
|
+
.mockResolvedValueOnce({
|
|
28
|
+
isComplete: false,
|
|
29
|
+
nextQuestion: "Hvilken type kaffe?",
|
|
30
|
+
})
|
|
31
|
+
.mockResolvedValueOnce({
|
|
32
|
+
isComplete: true,
|
|
33
|
+
nextQuestion: "",
|
|
34
|
+
brief: { storeName: "Kaffe", slug: "kaffe" }
|
|
35
|
+
});
|
|
36
|
+
const askUser = vi.fn().mockResolvedValueOnce("Specialkaffe");
|
|
37
|
+
const res = await runInterview({
|
|
38
|
+
apiKey: "key",
|
|
39
|
+
initialPrompt: "kaffe",
|
|
40
|
+
askUser,
|
|
41
|
+
logMsg: () => { }
|
|
42
|
+
});
|
|
43
|
+
expect(askUser).toHaveBeenCalledWith("Hvilken type kaffe?");
|
|
44
|
+
expect(res).toEqual({ storeName: "Kaffe", slug: "kaffe" });
|
|
45
|
+
// Check at prompten i 2. kald indeholder brugerens svar
|
|
46
|
+
const secondCallArg = vi.mocked(llm.generateJson).mock.calls[1][1];
|
|
47
|
+
expect(secondCallArg).toContain("Specialkaffe");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=interview.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interview.test.js","sourceRoot":"","sources":["../src/interview.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAE7B,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IACtB,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;CACtB,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,qBAAqB,CAAC;YAChD,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,EAAE;YAChB,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,0CAA0C;SACtF,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC;YAC7B,MAAM,EAAE,KAAK;YACb,aAAa,EAAE,2BAA2B;YAC1C,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM;YAC3B,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;SACjB,CAAC,CAAC;QAEH,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;aACxB,qBAAqB,CAAC;YACrB,UAAU,EAAE,KAAK;YACjB,YAAY,EAAE,qBAAqB;SACpC,CAAC;aACD,qBAAqB,CAAC;YACrB,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,EAAE;YAChB,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE;SAC7C,CAAC,CAAC;QAEL,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAC9D,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC;YAC7B,MAAM,EAAE,KAAK;YACb,aAAa,EAAE,OAAO;YACtB,OAAO;YACP,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;SACjB,CAAC,CAAC;QAEH,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,qBAAqB,CAAC,CAAC;QAC5D,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAE3D,wDAAwD;QACxD,MAAM,aAAa,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;QAC7E,MAAM,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type KeyModeResult = {
|
|
2
|
+
type: "key";
|
|
3
|
+
key: string;
|
|
4
|
+
} | {
|
|
5
|
+
type: "manual";
|
|
6
|
+
};
|
|
7
|
+
export interface KeyStepDeps {
|
|
8
|
+
getEnvKey: () => string | undefined;
|
|
9
|
+
promptKey: () => Promise<string>;
|
|
10
|
+
confirmManual: () => Promise<boolean>;
|
|
11
|
+
}
|
|
12
|
+
export declare function resolveKeyMode(deps: KeyStepDeps): Promise<KeyModeResult>;
|
package/dist/key-step.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { validateKey } from "./llm";
|
|
2
|
+
export async function resolveKeyMode(deps) {
|
|
3
|
+
let currentKey = deps.getEnvKey();
|
|
4
|
+
if (currentKey) {
|
|
5
|
+
const isValid = await validateKey(currentKey);
|
|
6
|
+
if (isValid)
|
|
7
|
+
return { type: "key", key: currentKey };
|
|
8
|
+
}
|
|
9
|
+
while (true) {
|
|
10
|
+
currentKey = await deps.promptKey();
|
|
11
|
+
if (!currentKey) {
|
|
12
|
+
const isManualOk = await deps.confirmManual();
|
|
13
|
+
if (isManualOk)
|
|
14
|
+
return { type: "manual" };
|
|
15
|
+
throw new Error("abort");
|
|
16
|
+
}
|
|
17
|
+
const isValid = await validateKey(currentKey);
|
|
18
|
+
if (isValid)
|
|
19
|
+
return { type: "key", key: currentKey };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=key-step.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-step.js","sourceRoot":"","sources":["../src/key-step.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAUpC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAiB;IACpD,IAAI,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAElC,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;QAC9C,IAAI,OAAO;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,EAAE,CAAC;QACZ,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACpC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,IAAI,UAAU;gBAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;QAC9C,IAAI,OAAO;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;IACvD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { resolveKeyMode } from "./key-step";
|
|
3
|
+
import * as llm from "./llm";
|
|
4
|
+
vi.mock("./llm", () => ({
|
|
5
|
+
validateKey: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
describe("resolveKeyMode", () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
vi.clearAllMocks();
|
|
10
|
+
delete process.env.GEMINI_API_KEY;
|
|
11
|
+
});
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
delete process.env.GEMINI_API_KEY;
|
|
14
|
+
});
|
|
15
|
+
it("returnerer key hvis valid env key", async () => {
|
|
16
|
+
process.env.GEMINI_API_KEY = "env-key";
|
|
17
|
+
vi.mocked(llm.validateKey).mockResolvedValue(true);
|
|
18
|
+
const res = await resolveKeyMode({
|
|
19
|
+
getEnvKey: () => process.env.GEMINI_API_KEY,
|
|
20
|
+
promptKey: async () => "prompt-key",
|
|
21
|
+
confirmManual: async () => false,
|
|
22
|
+
});
|
|
23
|
+
expect(res).toEqual({ type: "key", key: "env-key" });
|
|
24
|
+
});
|
|
25
|
+
it("prompter hvis invalid env key og returnerer ny key", async () => {
|
|
26
|
+
process.env.GEMINI_API_KEY = "bad-env-key";
|
|
27
|
+
vi.mocked(llm.validateKey).mockResolvedValueOnce(false); // env fejler
|
|
28
|
+
vi.mocked(llm.validateKey).mockResolvedValueOnce(true); // prompt virker
|
|
29
|
+
const res = await resolveKeyMode({
|
|
30
|
+
getEnvKey: () => process.env.GEMINI_API_KEY,
|
|
31
|
+
promptKey: async () => "prompt-key",
|
|
32
|
+
confirmManual: async () => false,
|
|
33
|
+
});
|
|
34
|
+
expect(res).toEqual({ type: "key", key: "prompt-key" });
|
|
35
|
+
expect(llm.validateKey).toHaveBeenCalledTimes(2);
|
|
36
|
+
});
|
|
37
|
+
it("falder tilbage til manual hvis prompt er tomt", async () => {
|
|
38
|
+
process.env.GEMINI_API_KEY = "bad-env-key";
|
|
39
|
+
vi.mocked(llm.validateKey).mockResolvedValueOnce(false);
|
|
40
|
+
const res = await resolveKeyMode({
|
|
41
|
+
getEnvKey: () => process.env.GEMINI_API_KEY,
|
|
42
|
+
promptKey: async () => "",
|
|
43
|
+
confirmManual: async () => true,
|
|
44
|
+
});
|
|
45
|
+
expect(res).toEqual({ type: "manual" });
|
|
46
|
+
});
|
|
47
|
+
it("aborts hvis bruger afviser manual mode", async () => {
|
|
48
|
+
vi.mocked(llm.validateKey).mockResolvedValueOnce(false);
|
|
49
|
+
await expect(resolveKeyMode({
|
|
50
|
+
getEnvKey: () => undefined,
|
|
51
|
+
promptKey: async () => "",
|
|
52
|
+
confirmManual: async () => false,
|
|
53
|
+
})).rejects.toThrow(/abort/i);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=key-step.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-step.test.js","sourceRoot":"","sources":["../src/key-step.test.ts"],"names":[],"mappings":"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"}
|
package/dist/llm.d.ts
ADDED
package/dist/llm.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent";
|
|
2
|
+
export async function validateKey(key) {
|
|
3
|
+
try {
|
|
4
|
+
const res = await fetch(`${GEMINI_API_URL}?key=${key}`, {
|
|
5
|
+
method: "POST",
|
|
6
|
+
headers: { "Content-Type": "application/json" },
|
|
7
|
+
body: JSON.stringify({
|
|
8
|
+
contents: [{ role: "user", parts: [{ text: "Hello" }] }],
|
|
9
|
+
}),
|
|
10
|
+
});
|
|
11
|
+
if (!res.ok) {
|
|
12
|
+
if (res.status === 400 || res.status === 401 || res.status === 403) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
throw new Error(`Unexpected status ${res.status}`);
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error instanceof Error && error.message.includes("status")) {
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function generateJson(key, prompt, jsonSchema) {
|
|
27
|
+
const res = await fetch(`${GEMINI_API_URL}?key=${key}`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: { "Content-Type": "application/json" },
|
|
30
|
+
body: JSON.stringify({
|
|
31
|
+
contents: [{ role: "user", parts: [{ text: prompt }] }],
|
|
32
|
+
generationConfig: {
|
|
33
|
+
responseMimeType: "application/json",
|
|
34
|
+
responseSchema: jsonSchema,
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
if (!res.ok) {
|
|
39
|
+
if (res.status === 429) {
|
|
40
|
+
throw new Error("HTTP 429: Rate limit exceeded for Gemini API.");
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`HTTP ${res.status}: Failed to generate content.`);
|
|
43
|
+
}
|
|
44
|
+
const data = (await res.json());
|
|
45
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
46
|
+
if (!text) {
|
|
47
|
+
throw new Error("No text content in Gemini response.");
|
|
48
|
+
}
|
|
49
|
+
return JSON.parse(text);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=llm.js.map
|
package/dist/llm.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG,0FAA0F,CAAC;AAElH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,cAAc,QAAQ,GAAG,EAAE,EAAE;YACtD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;aACzD,CAAC;SACH,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnE,OAAO,KAAK,CAAC;YACf,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/D,MAAM,KAAK,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,MAAc,EAAE,UAAmB;IACjF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,cAAc,QAAQ,GAAG,EAAE,EAAE;QACtD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YACvD,gBAAgB,EAAE;gBAChB,gBAAgB,EAAE,kBAAkB;gBACpC,cAAc,EAAE,UAAU;aAC3B;SACF,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,+BAA+B,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAQ,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IAC7D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/llm.test.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { generateJson, validateKey } from "./llm";
|
|
3
|
+
describe("generateJson", () => {
|
|
4
|
+
it("parser JSON ud af Gemini-svaret", async () => {
|
|
5
|
+
const fakeBody = {
|
|
6
|
+
candidates: [{ content: { parts: [{ text: '{"ok":true}' }] } }],
|
|
7
|
+
};
|
|
8
|
+
vi.stubGlobal("fetch", vi.fn(async () => new Response(JSON.stringify(fakeBody), { status: 200 })));
|
|
9
|
+
const out = await generateJson("test-key", "byg noget", { type: "object" });
|
|
10
|
+
expect(out).toEqual({ ok: true });
|
|
11
|
+
});
|
|
12
|
+
it("kaster ved HTTP-fejl", async () => {
|
|
13
|
+
vi.stubGlobal("fetch", vi.fn(async () => new Response("nej", { status: 429 })));
|
|
14
|
+
await expect(generateJson("k", "p", {})).rejects.toThrow(/429|rate/i);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe("validateKey", () => {
|
|
18
|
+
it("returnerer true hvis auth virker", async () => {
|
|
19
|
+
const fakeBody = {
|
|
20
|
+
candidates: [{ content: { parts: [{ text: '{"ok":true}' }] } }],
|
|
21
|
+
};
|
|
22
|
+
vi.stubGlobal("fetch", vi.fn(async () => new Response(JSON.stringify(fakeBody), { status: 200 })));
|
|
23
|
+
const out = await validateKey("test-key");
|
|
24
|
+
expect(out).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it("returnerer false hvis unauthorized (400 / 401 / 403)", async () => {
|
|
27
|
+
vi.stubGlobal("fetch", vi.fn(async () => new Response("Bad Request", { status: 400 })));
|
|
28
|
+
const out = await validateKey("bad-key");
|
|
29
|
+
expect(out).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=llm.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm.test.js","sourceRoot":"","sources":["../src/llm.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAElD,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,QAAQ,GAAG;YACf,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;SAChE,CAAC;QACF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACnG,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5E,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QAChF,MAAM,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,QAAQ,GAAG;YACf,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;SAChE,CAAC;QACF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACnG,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,QAAQ,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACxF,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type Database = "turso" | "postgres" | "sqlite";
|
|
2
|
+
export type PackageManager = "pnpm" | "npm" | "yarn" | "bun";
|
|
3
|
+
/**
|
|
4
|
+
* Industry templates the CLI knows about. Each maps to:
|
|
5
|
+
* - the seed-data slug in industry-templates/<slug>/seed-data.ts
|
|
6
|
+
* - a set of default brand.mode + brand.features values
|
|
7
|
+
*
|
|
8
|
+
* Customers can still override any field after scaffold by editing
|
|
9
|
+
* brand.config.ts directly. These are starting points, not constraints.
|
|
10
|
+
*/
|
|
11
|
+
export type TemplateSlug = "website-corporate" | "coffee" | "sunglasses" | "agent-marketplace" | "generic";
|
|
12
|
+
export declare const TEMPLATE_SLUGS: ReadonlyArray<TemplateSlug>;
|
|
13
|
+
/**
|
|
14
|
+
* Per-template defaults written into brand.config.ts after download.
|
|
15
|
+
* Keys mirror brand.config.ts shape (mode + features.*).
|
|
16
|
+
*/
|
|
17
|
+
export type TemplateDefaults = {
|
|
18
|
+
mode: "website" | "webshop" | "agent-marketplace";
|
|
19
|
+
features: {
|
|
20
|
+
webshop: boolean;
|
|
21
|
+
acp: boolean;
|
|
22
|
+
a2a: boolean;
|
|
23
|
+
adminAgenticDashboard: boolean;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export declare const TEMPLATE_DEFAULTS: Readonly<Record<TemplateSlug, TemplateDefaults>>;
|
|
27
|
+
export declare function isTemplateSlug(value: unknown): value is TemplateSlug;
|
|
28
|
+
export declare function detectPackageManager(): PackageManager;
|
|
29
|
+
export declare function generateAuthSecret(): string;
|
|
30
|
+
export declare function patchEnvLocal(targetDir: string, authSecret: string): void;
|
|
31
|
+
export declare function titleCase(projectName: string): string;
|
|
32
|
+
export declare function patchBrandConfigContent(original: string, projectName: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Apply the per-template defaults to a brand.config.ts source string.
|
|
35
|
+
* Patches:
|
|
36
|
+
* - industryTemplate: "<slug>"
|
|
37
|
+
* - mode: "<mode>"
|
|
38
|
+
* - features.webshop, features.acp, features.a2a, features.adminAgenticDashboard
|
|
39
|
+
*
|
|
40
|
+
* The replacements are regex-anchored to the exact field shape produced by
|
|
41
|
+
* the upstream brand.config.ts. If that shape ever changes the regexes here
|
|
42
|
+
* will silently no-op (no replacement) — the corresponding unit test catches
|
|
43
|
+
* that case.
|
|
44
|
+
*/
|
|
45
|
+
export declare function patchBrandConfigForTemplate(original: string, template: TemplateSlug): string;
|
|
46
|
+
export declare function tryGitInit(targetDir: string): boolean;
|
|
47
|
+
export declare function tryInstall(targetDir: string, pm: PackageManager): boolean;
|
|
48
|
+
export declare function databaseNote(db: Database): string;
|