From a86e939d9ab6b7c4623bc5ef6ddb1c5976ceb5b1 Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Wed, 3 Jun 2026 03:03:31 +0200 Subject: [PATCH 1/8] refactor(api-key-service): reduce cognitive complexity from 39 to 25 - Extract validation into validateCreateOptions() - Extract error mapping into mapCreateError() with switch statement - Extract network error enhancement into enhanceNetworkError() - Extract creation failed message into buildCreationFailedMessage() - Add comprehensive tests for ApiKeyService.create() - All 23 tests pass --- coverage/base.css | 224 ++++++++++++++++ coverage/block-navigation.js | 87 ++++++ coverage/clover.xml | 6 + coverage/coverage-final.json | 1 + coverage/favicon.png | Bin 0 -> 445 bytes coverage/index.html | 101 +++++++ coverage/prettify.css | 1 + coverage/prettify.js | 2 + coverage/sort-arrow-sprite.png | Bin 0 -> 138 bytes coverage/sorter.js | 210 +++++++++++++++ eslint.config.mjs | 2 +- package-lock.json | 357 +++++++++++++++++++++++++ package.json | 1 + src/services/api-key-service.ts | 181 +++++++------ tests/services/api-key-service.test.ts | 256 ++++++++++++++++++ 15 files changed, 1346 insertions(+), 83 deletions(-) create mode 100644 coverage/base.css create mode 100644 coverage/block-navigation.js create mode 100644 coverage/clover.xml create mode 100644 coverage/coverage-final.json create mode 100644 coverage/favicon.png create mode 100644 coverage/index.html create mode 100644 coverage/prettify.css create mode 100644 coverage/prettify.js create mode 100644 coverage/sort-arrow-sprite.png create mode 100644 coverage/sorter.js create mode 100644 tests/services/api-key-service.test.ts diff --git a/coverage/base.css b/coverage/base.css new file mode 100644 index 0000000..f418035 --- /dev/null +++ b/coverage/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/block-navigation.js b/coverage/block-navigation.js new file mode 100644 index 0000000..530d1ed --- /dev/null +++ b/coverage/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selector that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/clover.xml b/coverage/clover.xml new file mode 100644 index 0000000..1b46a3f --- /dev/null +++ b/coverage/clover.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/coverage/coverage-final.json @@ -0,0 +1 @@ +{} diff --git a/coverage/favicon.png b/coverage/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ Unknown% + Statements + 0/0 +
+ + +
+ Unknown% + Branches + 0/0 +
+ + +
+ Unknown% + Functions + 0/0 +
+ + +
+ Unknown% + Lines + 0/0 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/prettify.css b/coverage/prettify.css new file mode 100644 index 0000000..b317a7c --- /dev/null +++ b/coverage/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/prettify.js b/coverage/prettify.js new file mode 100644 index 0000000..b322523 --- /dev/null +++ b/coverage/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/sort-arrow-sprite.png b/coverage/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/coverage/sorter.js b/coverage/sorter.js new file mode 100644 index 0000000..4ed70ae --- /dev/null +++ b/coverage/sorter.js @@ -0,0 +1,210 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + + // Try to create a RegExp from the searchValue. If it fails (invalid regex), + // it will be treated as a plain text search + let searchRegex; + try { + searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive + } catch (error) { + searchRegex = null; + } + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + let isMatch = false; + + if (searchRegex) { + // If a valid regex was created, use it for matching + isMatch = searchRegex.test(row.textContent); + } else { + // Otherwise, fall back to the original plain text search + isMatch = row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()); + } + + row.style.display = isMatch ? '' : 'none'; + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/eslint.config.mjs b/eslint.config.mjs index 5d6013c..fe1d9e1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -67,7 +67,7 @@ export default tseslint.config( 'error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }, ], - 'sonarjs/cognitive-complexity': 'off', + 'sonarjs/cognitive-complexity': ['error', 79], 'sonarjs/different-types-comparison': 'off', 'sonarjs/function-return-type': 'off', 'sonarjs/no-duplicated-branches': 'off', diff --git a/package-lock.json b/package-lock.json index c2f29b0..9560bea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "@types/marked": "^5.0.2", "@types/marked-terminal": "^6.1.1", "@types/node": "^20.11.20", + "@vitest/coverage-v8": "^4.1.8", "@vitest/eslint-plugin": "^1.6.17", "eslint": "^10.3.0", "eslint-config-prettier": "^10.1.8", @@ -69,6 +70,16 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", @@ -78,6 +89,46 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@clack/core": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.4.2.tgz", @@ -728,6 +779,16 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -735,6 +796,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", @@ -1472,6 +1544,37 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz", + "integrity": "sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.8", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.8", + "vitest": "4.1.8" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, "node_modules/@vitest/eslint-plugin": { "version": "1.6.17", "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.17.tgz", @@ -1748,6 +1851,25 @@ "node": ">=12" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.3.tgz", + "integrity": "sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -2935,6 +3057,13 @@ "node": ">=8" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -3137,6 +3266,58 @@ "dev": true, "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jose": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", @@ -3748,6 +3929,34 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/marked": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", @@ -5228,11 +5437,42 @@ "picocolors": "^1.1.1" } }, + "@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true + }, "@babel/helper-validator-identifier": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==" }, + "@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "requires": { + "@babel/types": "^7.29.7" + } + }, + "@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + } + }, + "@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true + }, "@clack/core": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.4.2.tgz", @@ -5562,12 +5802,28 @@ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, "@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true }, + "@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "@napi-rs/wasm-runtime": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", @@ -5988,6 +6244,24 @@ } } }, + "@vitest/coverage-v8": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz", + "integrity": "sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.8", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + } + }, "@vitest/eslint-plugin": { "version": "1.6.17", "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.17.tgz", @@ -6146,6 +6420,25 @@ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true }, + "ast-v8-to-istanbul": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.3.tgz", + "integrity": "sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true + } + } + }, "balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -6867,6 +7160,12 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -6974,6 +7273,44 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true + }, + "istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, "jose": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", @@ -7298,6 +7635,26 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "dev": true, + "requires": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + }, "marked": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", diff --git a/package.json b/package.json index 84f6e15..4f2c21a 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@types/marked": "^5.0.2", "@types/marked-terminal": "^6.1.1", "@types/node": "^20.11.20", + "@vitest/coverage-v8": "^4.1.8", "@vitest/eslint-plugin": "^1.6.17", "eslint": "^10.3.0", "eslint-config-prettier": "^10.1.8", diff --git a/src/services/api-key-service.ts b/src/services/api-key-service.ts index 041c9f8..13dc6a0 100644 --- a/src/services/api-key-service.ts +++ b/src/services/api-key-service.ts @@ -55,72 +55,14 @@ export class ApiKeyService { */ public async create(options: CreateApiKeyOptions): Promise { try { - // Validate input before sending request - if (!options.name || options.name.trim().length === 0) { - throw new Error('API key name is required and cannot be empty'); - } - - if (options.name.length > 100) { - throw new Error('API key name must be 100 characters or less'); - } - - if (options.description && options.description.length > 500) { - throw new Error('API key description must be 500 characters or less'); - } + this.validateCreateOptions(options); const { data, error } = await this.client.POST('/v1/api-keys', { body: options, }); if (error) { - // Enhanced error handling with specific troubleshooting - - // Handle specific error cases - if (typeof error === 'object' && error !== null) { - const errorObject = error as any; - - if (errorObject.error?.code === 'API_KEY_CREATION_FAILED') { - let detailedMessage = 'Failed to create API key. This could be due to:\n'; - detailedMessage += '• Account limits or quota restrictions\n'; - detailedMessage += '• Insufficient permissions for API key creation\n'; - detailedMessage += '• Temporary server issues\n'; - detailedMessage += '• Billing or subscription issues\n\n'; - detailedMessage += 'Troubleshooting steps:\n'; - detailedMessage += '1. Check if you have reached your API key limit\n'; - detailedMessage += '2. Verify your account has API key creation permissions\n'; - detailedMessage += '3. Check your billing status and subscription\n'; - detailedMessage += '4. Try again in a few minutes if this is a temporary issue\n'; - detailedMessage += '5. Contact support if the problem persists'; - - throw new Error(detailedMessage); - } - - if (errorObject.error?.code === 'USER_NOT_FOUND') { - throw new Error( - 'Before you can create API keys, you need to finish setting up your account.\n\nCheck your inbox for a verification email from Berget AI and complete the account setup.', - ); - } - - if (errorObject.error?.code === 'QUOTA_EXCEEDED') { - throw new Error( - 'You have reached your API key limit. Please delete existing keys or contact support to increase your quota.', - ); - } - - if (errorObject.error?.code === 'INSUFFICIENT_PERMISSIONS') { - throw new Error( - 'Your account does not have permission to create API keys. Please contact your administrator.', - ); - } - - if (errorObject.error?.code === 'BILLING_REQUIRED') { - throw new Error( - 'A valid billing method is required to create API keys. Please add a payment method.', - ); - } - } - - throw new Error(JSON.stringify(error)); + throw this.mapCreateError(error); } if (!data) { @@ -129,28 +71,7 @@ export class ApiKeyService { return data; } catch (error) { - // Add additional context for common issues - if (error instanceof Error) { - if (error.message.includes('ECONNREFUSED')) { - throw new Error('Cannot connect to Berget API. Please check your internet connection.'); - } - - if (error.message.includes('ENOTFOUND')) { - throw new Error('Cannot resolve Berget API hostname. Please check your DNS settings.'); - } - - if (error.message.includes('401') || error.message.includes('Unauthorized')) { - throw new Error('Authentication failed. Please run `berget auth login` to log in again.'); - } - - if (error.message.includes('403')) { - throw new Error( - 'Access forbidden. Your account may not have permission to create API keys.', - ); - } - } - - throw error; + throw this.enhanceNetworkError(error); } } @@ -219,4 +140,100 @@ export class ApiKeyService { throw error; } } + + private buildCreationFailedMessage(): string { + return ( + 'Failed to create API key. This could be due to:\n' + + '• Account limits or quota restrictions\n' + + '• Insufficient permissions for API key creation\n' + + '• Temporary server issues\n' + + '• Billing or subscription issues\n\n' + + 'Troubleshooting steps:\n' + + '1. Check if you have reached your API key limit\n' + + '2. Verify your account has API key creation permissions\n' + + '3. Check your billing status and subscription\n' + + '4. Try again in a few minutes if this is a temporary issue\n' + + '5. Contact support if the problem persists' + ); + } + + private enhanceNetworkError(error: unknown): Error { + if (!(error instanceof Error)) { + throw error; + } + + const message = error.message; + + if (message.includes('ECONNREFUSED')) { + return new Error('Cannot connect to Berget API. Please check your internet connection.'); + } + + if (message.includes('ENOTFOUND')) { + return new Error('Cannot resolve Berget API hostname. Please check your DNS settings.'); + } + + if (message.includes('401') || message.includes('Unauthorized')) { + return new Error('Authentication failed. Please run `berget auth login` to log in again.'); + } + + if (message.includes('403')) { + return new Error( + 'Access forbidden. Your account may not have permission to create API keys.', + ); + } + + throw error; + } + + private mapCreateError(error: unknown): Error { + if (typeof error !== 'object' || error === null) { + return new Error(JSON.stringify(error)); + } + + const errorObject = error as any; + const code = errorObject.error?.code; + + switch (code) { + case 'API_KEY_CREATION_FAILED': { + return new Error(this.buildCreationFailedMessage()); + } + case 'BILLING_REQUIRED': { + return new Error( + 'A valid billing method is required to create API keys. Please add a payment method.', + ); + } + case 'INSUFFICIENT_PERMISSIONS': { + return new Error( + 'Your account does not have permission to create API keys. Please contact your administrator.', + ); + } + case 'QUOTA_EXCEEDED': { + return new Error( + 'You have reached your API key limit. Please delete existing keys or contact support to increase your quota.', + ); + } + case 'USER_NOT_FOUND': { + return new Error( + 'Before you can create API keys, you need to finish setting up your account.\n\nCheck your inbox for a verification email from Berget AI and complete the account setup.', + ); + } + default: { + return new Error(JSON.stringify(error)); + } + } + } + + private validateCreateOptions(options: CreateApiKeyOptions): void { + if (!options.name || options.name.trim().length === 0) { + throw new Error('API key name is required and cannot be empty'); + } + + if (options.name.length > 100) { + throw new Error('API key name must be 100 characters or less'); + } + + if (options.description && options.description.length > 500) { + throw new Error('API key description must be 500 characters or less'); + } + } } diff --git a/tests/services/api-key-service.test.ts b/tests/services/api-key-service.test.ts new file mode 100644 index 0000000..979dc48 --- /dev/null +++ b/tests/services/api-key-service.test.ts @@ -0,0 +1,256 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { ApiKeyService } from '../../src/services/api-key-service.js'; + +const mockPost = vi.fn(); + +vi.mock('../../src/client.js', () => ({ + createAuthenticatedClient: vi.fn(() => ({ + POST: mockPost, + })), +})); + +describe('ApiKeyService', () => { + let service: ApiKeyService; + + beforeEach(() => { + // Reset the singleton instance so each test gets a fresh instance + (ApiKeyService as any).instance = undefined; + service = ApiKeyService.getInstance(); + mockPost.mockReset(); + }); + + describe('create', () => { + it('creates an API key successfully', async () => { + const mockResponse = { + created: '2024-01-01', + description: null, + id: 1, + key: 'test-key', + name: 'Test Key', + }; + mockPost.mockResolvedValue({ data: mockResponse, error: null }); + + const result = await service.create({ name: 'Test Key' }); + + expect(result).toEqual(mockResponse); + expect(mockPost).toHaveBeenCalledWith('/v1/api-keys', { + body: { name: 'Test Key' }, + }); + }); + + it('creates an API key with description', async () => { + const mockResponse = { + created: '2024-01-01', + description: 'A test key', + id: 1, + key: 'test-key', + name: 'Test Key', + }; + mockPost.mockResolvedValue({ data: mockResponse, error: null }); + + const result = await service.create({ description: 'A test key', name: 'Test Key' }); + + expect(result).toEqual(mockResponse); + expect(mockPost).toHaveBeenCalledWith('/v1/api-keys', { + body: { description: 'A test key', name: 'Test Key' }, + }); + }); + + it('throws when name is empty', async () => { + await expect(service.create({ name: '' })).rejects.toThrow( + 'API key name is required and cannot be empty', + ); + expect(mockPost).not.toHaveBeenCalled(); + }); + + it('throws when name is whitespace only', async () => { + await expect(service.create({ name: ' ' })).rejects.toThrow( + 'API key name is required and cannot be empty', + ); + expect(mockPost).not.toHaveBeenCalled(); + }); + + it('throws when name exceeds 100 characters', async () => { + const longName = 'a'.repeat(101); + await expect(service.create({ name: longName })).rejects.toThrow( + 'API key name must be 100 characters or less', + ); + expect(mockPost).not.toHaveBeenCalled(); + }); + + it('allows name exactly 100 characters', async () => { + const mockResponse = { + created: '2024-01-01', + description: null, + id: 1, + key: 'test-key', + name: 'a'.repeat(100), + }; + mockPost.mockResolvedValue({ data: mockResponse, error: null }); + + const result = await service.create({ name: 'a'.repeat(100) }); + + expect(result.name).toBe('a'.repeat(100)); + }); + + it('throws when description exceeds 500 characters', async () => { + const longDescription = 'a'.repeat(501); + await expect(service.create({ description: longDescription, name: 'Test' })).rejects.toThrow( + 'API key description must be 500 characters or less', + ); + expect(mockPost).not.toHaveBeenCalled(); + }); + + it('allows description exactly 500 characters', async () => { + const mockResponse = { + created: '2024-01-01', + description: 'a'.repeat(500), + id: 1, + key: 'test-key', + name: 'Test', + }; + mockPost.mockResolvedValue({ data: mockResponse, error: null }); + + const result = await service.create({ description: 'a'.repeat(500), name: 'Test' }); + + expect(result.description).toBe('a'.repeat(500)); + }); + + it('throws when data is null', async () => { + mockPost.mockResolvedValue({ data: null, error: null }); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'No data received from server', + ); + }); + + describe('error code handling', () => { + it('throws detailed message for API_KEY_CREATION_FAILED', async () => { + mockPost.mockResolvedValue({ + data: null, + error: { error: { code: 'API_KEY_CREATION_FAILED' } }, + }); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'Failed to create API key. This could be due to:', + ); + }); + + it('throws account setup message for USER_NOT_FOUND', async () => { + mockPost.mockResolvedValue({ + data: null, + error: { error: { code: 'USER_NOT_FOUND' } }, + }); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'Before you can create API keys', + ); + }); + + it('throws quota message for QUOTA_EXCEEDED', async () => { + mockPost.mockResolvedValue({ + data: null, + error: { error: { code: 'QUOTA_EXCEEDED' } }, + }); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'You have reached your API key limit', + ); + }); + + it('throws permission message for INSUFFICIENT_PERMISSIONS', async () => { + mockPost.mockResolvedValue({ + data: null, + error: { error: { code: 'INSUFFICIENT_PERMISSIONS' } }, + }); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'Your account does not have permission to create API keys', + ); + }); + + it('throws billing message for BILLING_REQUIRED', async () => { + mockPost.mockResolvedValue({ + data: null, + error: { error: { code: 'BILLING_REQUIRED' } }, + }); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'A valid billing method is required', + ); + }); + + it('throws stringified error for unknown error object', async () => { + mockPost.mockResolvedValue({ + data: null, + error: { error: { code: 'UNKNOWN_ERROR' } }, + }); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + JSON.stringify({ error: { code: 'UNKNOWN_ERROR' } }), + ); + }); + + it('throws stringified error for non-object error', async () => { + mockPost.mockResolvedValue({ data: null, error: 'network error' }); + + await expect(service.create({ name: 'Test' })).rejects.toThrow('"network error"'); + }); + }); + + describe('network error handling', () => { + it('throws connection error for ECONNREFUSED', async () => { + mockPost.mockRejectedValue(new Error('ECONNREFUSED')); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'Cannot connect to Berget API', + ); + }); + + it('throws DNS error for ENOTFOUND', async () => { + mockPost.mockRejectedValue(new Error('ENOTFOUND')); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'Cannot resolve Berget API hostname', + ); + }); + + it('throws auth error for 401', async () => { + mockPost.mockRejectedValue(new Error('HTTP 401 Unauthorized')); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'Authentication failed. Please run `berget auth login`', + ); + }); + + it('throws auth error for Unauthorized', async () => { + mockPost.mockRejectedValue(new Error('Request failed: Unauthorized')); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'Authentication failed. Please run `berget auth login`', + ); + }); + + it('throws permission error for 403', async () => { + mockPost.mockRejectedValue(new Error('HTTP 403 Forbidden')); + + await expect(service.create({ name: 'Test' })).rejects.toThrow( + 'Access forbidden. Your account may not have permission to create API keys', + ); + }); + + it('re-throws unknown errors', async () => { + mockPost.mockRejectedValue(new Error('Something unexpected')); + + await expect(service.create({ name: 'Test' })).rejects.toThrow('Something unexpected'); + }); + + it('re-throws non-Error values', async () => { + mockPost.mockRejectedValue('plain string error'); + + await expect(service.create({ name: 'Test' })).rejects.toBe('plain string error'); + }); + }); + }); +}); From 87b20ee723ac32f1be47f6ce03a257b1e68337ba Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Wed, 3 Jun 2026 03:14:14 +0200 Subject: [PATCH 2/8] refactor(chat-service): reduce cognitive complexity from 76 to 25 - Extract handleStreamingResponse into focused helper methods: - logStreamingRequest, makeStreamingRequest - readStream, processLines - hasBalancedBraces, tryParseAndProcess - accumulateContent, logParseError, buildStreamResult - Introduce StreamState interface to pass state between methods - Add node:stream/web import for ReadableStreamDefaultReader type - Add 16 tests covering streaming, non-streaming, and error paths --- src/services/chat-service.ts | 374 ++++++++++++++++------------ tests/services/chat-service.test.ts | 306 +++++++++++++++++++++++ 2 files changed, 520 insertions(+), 160 deletions(-) create mode 100644 tests/services/chat-service.test.ts diff --git a/src/services/chat-service.ts b/src/services/chat-service.ts index 49f9c9c..5855e18 100644 --- a/src/services/chat-service.ts +++ b/src/services/chat-service.ts @@ -1,3 +1,5 @@ +import { ReadableStreamDefaultReader } from 'node:stream/web'; + import { createAuthenticatedClient } from '../client.js'; import { logger } from '../utils/logger.js'; @@ -17,6 +19,12 @@ export interface ChatMessage { role: 'assistant' | 'system' | 'user'; } +interface StreamState { + buffer: string; + fullContent: string; + fullResponse: any; +} + /** * Service for interacting with the chat API * Command group: chat @@ -161,6 +169,33 @@ export class ChatService { } } + private accumulateContent(parsedData: any, state: StreamState): void { + if ( + parsedData.choices && + parsedData.choices[0] && + parsedData.choices[0].delta && + parsedData.choices[0].delta.content + ) { + state.fullContent += parsedData.choices[0].delta.content; + } + } + + private buildStreamResult(state: StreamState): any { + if (state.fullResponse) { + if (state.fullContent) { + state.fullResponse.choices[0].message = { + content: state.fullContent, + role: 'assistant', + }; + } + return state.fullResponse; + } + + return { + choices: [{ message: { content: state.fullContent, role: 'assistant' } }], + }; + } + /** * Execute the completion request with the provided options * @param options The completion options @@ -247,183 +282,202 @@ export class ChatService { options: any, headers: Record, ): Promise { - // Use the same base URL as the client const baseUrl = process.env.API_BASE_URL || 'https://api.berget.ai'; const url = new URL(`${baseUrl}/v1/chat/completions`); try { - logger.debug(`Making streaming request to: ${url.toString()}`); - logger.debug(`Headers:`, JSON.stringify(headers, null, 2)); - logger.debug(`Body:`, JSON.stringify(options, null, 2)); - - // Make fetch request directly to handle streaming - const response = await fetch(url.toString(), { - body: JSON.stringify(options), - headers: { - Accept: 'text/event-stream', - 'Content-Type': 'application/json', - ...headers, - }, - method: 'POST', - }); - - logger.debug(`Response status: ${response.status}`); - logger.debug( - `Response headers:`, - JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2), + this.logStreamingRequest(url, headers, options); + const response = await this.makeStreamingRequest(url, options, headers); + const state: StreamState = { buffer: '', fullContent: '', fullResponse: null }; + await this.readStream(response.body!.getReader(), options, state); + return this.buildStreamResult(state); + } catch (error) { + logger.error(`Streaming error: ${error instanceof Error ? error.message : String(error)}`); + throw error; + } + } + + private hasBalancedBraces(jsonData: string): boolean { + let braceCount = 0; + let inString = false; + let escaped = false; + + for (const char of jsonData) { + if (escaped) { + escaped = false; + continue; + } + if (char === '\\') { + escaped = true; + continue; + } + if (char === '"') { + inString = !inString; + continue; + } + if (!inString && char === '{') { + braceCount++; + } else if (!inString && char === '}') { + braceCount--; + } + } + + return braceCount === 0; + } + + private logParseError(error: unknown, jsonData: string): void { + logger.error(`Error parsing chunk: ${error}`); + const errorMsg = (error as any).message || ''; + const errorPos = Number.parseInt(errorMsg.match(/position (\d+)/)?.[1] || '0'); + if (errorPos > 0) { + const start = Math.max(0, errorPos - 20); + const end = Math.min(jsonData.length, errorPos + 20); + logger.error(`Context around error position ${errorPos}:`); + logger.error(`"${jsonData.substring(start, end)}"`); + logger.error( + `Character codes: ${[...jsonData.substring(start, end)].map((c) => c.charCodeAt(0)).join(' ')}`, ); + } + } + + private logStreamingRequest(url: URL, headers: Record, options: any): void { + logger.debug(`Making streaming request to: ${url.toString()}`); + logger.debug(`Headers:`, JSON.stringify(headers, null, 2)); + logger.debug(`Body:`, JSON.stringify(options, null, 2)); + } + + private async makeStreamingRequest( + url: URL, + options: any, + headers: Record, + ): Promise { + const response = await fetch(url.toString(), { + body: JSON.stringify(options), + headers: { + Accept: 'text/event-stream', + 'Content-Type': 'application/json', + ...headers, + }, + method: 'POST', + }); + + logger.debug(`Response status: ${response.status}`); + logger.debug( + `Response headers:`, + JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2), + ); + + if (!response.ok) { + const errorText = await response.text(); + logger.error(`Stream request failed: ${response.status} ${response.statusText}`); + logger.error(`Error response: ${errorText}`); + throw new Error( + `Stream request failed: ${response.status} ${response.statusText} - ${errorText}`, + ); + } + + if (!response.body) { + throw new Error('No response body received'); + } + + return response; + } + + private processLines(lines: string[], options: any, state: StreamState): number { + let processedLines = 0; + + for (const [index, line] of lines.entries()) { + logger.debug(`Line ${index}: "${line}"`); + + if (!line.startsWith('data:')) { + continue; + } + + const jsonData = line.slice(5).trim(); + logger.debug(`Extracted JSON data: "${jsonData}"`); + + if (jsonData === '' || jsonData === '[DONE]') { + logger.debug(`Skipping empty data or [DONE] marker`); + processedLines = index + 1; + continue; + } - if (!response.ok) { - const errorText = await response.text(); - logger.error(`Stream request failed: ${response.status} ${response.statusText}`); - logger.error(`Error response: ${errorText}`); - throw new Error( - `Stream request failed: ${response.status} ${response.statusText} - ${errorText}`, + if (!jsonData.startsWith('{')) { + logger.warn( + `JSON data doesn't start with '{', might be partial: "${jsonData.slice(0, 50)}..."`, ); + break; } - if (!response.body) { - throw new Error('No response body received'); + if (!this.hasBalancedBraces(jsonData)) { + logger.warn( + `JSON braces don't balance, treating as partial: "${jsonData.slice(0, 50)}..."`, + ); + break; } - // Process the stream - const reader = response.body.getReader(); - const decoder = new TextDecoder(); - let fullContent = ''; - let fullResponse: any = null; - let buffer = ''; - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - - const chunk = decoder.decode(value, { stream: true }); - logger.debug(`Received chunk: ${chunk.length} bytes`); - - buffer += chunk; - logger.debug(`Added chunk to buffer. Buffer length: ${buffer.length}`); - - const lines = buffer.split('\n'); - logger.debug(`Processing ${lines.length} lines from buffer`); - - let processedLines = 0; - - for (const [index, line] of lines.entries()) { - logger.debug(`Line ${index}: "${line}"`); - - if (line.startsWith('data:')) { - const jsonData = line.slice(5).trim(); - logger.debug(`Extracted JSON data: "${jsonData}"`); - - if (jsonData === '' || jsonData === '[DONE]') { - logger.debug(`Skipping empty data or [DONE] marker`); - processedLines = index + 1; - continue; - } - - if (!jsonData.startsWith('{')) { - logger.warn( - `JSON data doesn't start with '{', might be partial: "${jsonData.slice(0, 50)}..."`, - ); - break; - } - - let braceCount = 0; - let inString = false; - let escaped = false; - - for (const char of jsonData) { - if (escaped) { - escaped = false; - continue; - } - if (char === '\\') { - escaped = true; - continue; - } - if (char === '"') { - inString = !inString; - continue; - } - if (!inString && char === '{') { - braceCount++; - } else if (!inString && char === '}') { - braceCount--; - } - } - - if (braceCount !== 0) { - logger.warn( - `JSON braces don't balance (${braceCount}), treating as partial: "${jsonData.slice(0, 50)}..."`, - ); - break; - } - - try { - logger.debug(`Attempting to parse JSON of length: ${jsonData.length}`); - const parsedData = JSON.parse(jsonData); - logger.debug(`Successfully parsed JSON: ${JSON.stringify(parsedData, null, 2)}`); - processedLines = index + 1; - - if (options.onChunk) { - options.onChunk(parsedData); - } - - if (!fullResponse) { - fullResponse = parsedData; - } else if ( - parsedData.choices && - parsedData.choices[0] && - parsedData.choices[0].delta && - parsedData.choices[0].delta.content - ) { - fullContent += parsedData.choices[0].delta.content; - } - } catch (error) { - logger.error(`Error parsing chunk: ${error}`); - const errorMsg = (error as any).message || ''; - const errorPos = Number.parseInt(errorMsg.match(/position (\d+)/)?.[1] || '0'); - if (errorPos > 0) { - const start = Math.max(0, errorPos - 20); - const end = Math.min(jsonData.length, errorPos + 20); - logger.error(`Context around error position ${errorPos}:`); - logger.error(`"${jsonData.substring(start, end)}"`); - logger.error( - `Character codes: ${[...jsonData.substring(start, end)] - .map((c) => c.charCodeAt(0)) - .join(' ')}`, - ); - } - } - } - } + if (this.tryParseAndProcess(jsonData, options, state)) { + processedLines = index + 1; + } else { + break; + } + } - if (processedLines > 0) { - const remainingLines = lines.slice(processedLines); - buffer = remainingLines.join('\n'); - logger.debug( - `Updated buffer. Remaining lines: ${remainingLines.length}, Buffer length: ${buffer.length}`, - ); - } + return processedLines; + } + + private async readStream( + reader: ReadableStreamDefaultReader, + options: any, + state: StreamState, + ): Promise { + const decoder = new TextDecoder(); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value, { stream: true }); + logger.debug(`Received chunk: ${chunk.length} bytes`); + + state.buffer += chunk; + logger.debug(`Added chunk to buffer. Buffer length: ${state.buffer.length}`); + + const lines = state.buffer.split('\n'); + logger.debug(`Processing ${lines.length} lines from buffer`); + + const processedLines = this.processLines(lines, options, state); + + if (processedLines > 0) { + const remainingLines = lines.slice(processedLines); + state.buffer = remainingLines.join('\n'); + logger.debug( + `Updated buffer. Remaining lines: ${remainingLines.length}, Buffer length: ${state.buffer.length}`, + ); } + } + } - // Construct the final response object similar to non-streaming response - if (fullResponse) { - if (fullContent) { - fullResponse.choices[0].message = { - content: fullContent, - role: 'assistant', - }; - } - return fullResponse; + private tryParseAndProcess(jsonData: string, options: any, state: StreamState): boolean { + try { + logger.debug(`Attempting to parse JSON of length: ${jsonData.length}`); + const parsedData = JSON.parse(jsonData); + logger.debug(`Successfully parsed JSON: ${JSON.stringify(parsedData, null, 2)}`); + + if (options.onChunk) { + options.onChunk(parsedData); } - return { - choices: [{ message: { content: fullContent, role: 'assistant' } }], - }; + if (state.fullResponse) { + this.accumulateContent(parsedData, state); + } else { + state.fullResponse = parsedData; + } + + return true; } catch (error) { - logger.error(`Streaming error: ${error instanceof Error ? error.message : String(error)}`); - throw error; + this.logParseError(error, jsonData); + return false; } } } diff --git a/tests/services/chat-service.test.ts b/tests/services/chat-service.test.ts new file mode 100644 index 0000000..f3cc9f1 --- /dev/null +++ b/tests/services/chat-service.test.ts @@ -0,0 +1,306 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { ChatService } from '../../src/services/chat-service.js'; + +const mockPost = vi.fn(); +const mockGet = vi.fn(); + +let fetchMock: any; + +vi.mock('../../src/client.js', () => ({ + createAuthenticatedClient: vi.fn(() => ({ + GET: mockGet, + POST: mockPost, + })), +})); + +vi.mock('../../src/utils/logger.js', () => ({ + logger: { + debug: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + }, +})); + +describe('ChatService', () => { + let service: ChatService; + + beforeEach(() => { + (ChatService as any).instance = undefined; + service = ChatService.getInstance(); + mockPost.mockReset(); + mockGet.mockReset(); + fetchMock = vi.fn(); + globalThis.fetch = fetchMock; + }); + + describe('createCompletion', () => { + it('returns data for non-streaming request', async () => { + const mockResponse = { + choices: [{ message: { content: 'Hello', role: 'assistant' } }], + }; + mockPost.mockResolvedValue({ data: mockResponse, error: null }); + + const result = await service.createCompletion({ + messages: [{ content: 'Hi', role: 'user' }], + stream: false, + }); + + expect(result).toEqual(mockResponse); + }); + + it('sets default model when not provided', async () => { + mockPost.mockResolvedValue({ + data: { choices: [{ message: { content: 'Hi', role: 'assistant' } }] }, + error: null, + }); + + await service.createCompletion({ messages: [{ content: 'Hi', role: 'user' }] }); + + expect(mockPost).toHaveBeenCalledWith( + '/v1/chat/completions', + expect.objectContaining({ + body: expect.objectContaining({ model: 'google/gemma-3-27b-it' }), + }), + ); + }); + + it('uses provided model', async () => { + mockPost.mockResolvedValue({ + data: { choices: [{ message: { content: 'Hi', role: 'assistant' } }] }, + error: null, + }); + + await service.createCompletion({ + messages: [{ content: 'Hi', role: 'user' }], + model: 'custom-model', + }); + + expect(mockPost).toHaveBeenCalledWith( + '/v1/chat/completions', + expect.objectContaining({ + body: expect.objectContaining({ model: 'custom-model' }), + }), + ); + }); + + it('adds apiKey to headers', async () => { + mockPost.mockResolvedValue({ + data: { choices: [{ message: { content: 'Hi', role: 'assistant' } }] }, + error: null, + }); + + await service.createCompletion({ + apiKey: 'test-key', + messages: [{ content: 'Hi', role: 'user' }], + }); + + expect(mockPost).toHaveBeenCalledWith( + '/v1/chat/completions', + expect.objectContaining({ + headers: { Authorization: 'test-key' }, + }), + ); + }); + + it('throws on API error response', async () => { + mockPost.mockResolvedValue({ data: null, error: { message: 'Bad request' } }); + + await expect( + service.createCompletion({ messages: [{ content: 'Hi', role: 'user' }] }), + ).rejects.toThrow('Bad request'); + }); + + it('initializes empty messages array when missing', async () => { + mockPost.mockResolvedValue({ + data: { choices: [{ message: { content: 'Hi', role: 'assistant' } }] }, + error: null, + }); + + await service.createCompletion({ messages: [] as any }); + + expect(mockPost).toHaveBeenCalled(); + }); + + it('propagates unexpected errors from executeCompletion', async () => { + mockPost.mockRejectedValue(new Error('Unexpected failure')); + + await expect( + service.createCompletion({ messages: [{ content: 'Hi', role: 'user' }] }), + ).rejects.toThrow('Unexpected failure'); + }); + }); + + describe('listModels', () => { + it('returns models without apiKey', async () => { + const mockData = { data: [{ id: 'model-1' }] }; + mockGet.mockResolvedValue({ data: mockData, error: null }); + + const result = await service.listModels(); + + expect(result).toEqual(mockData); + expect(mockGet).toHaveBeenCalledWith('/v1/models'); + }); + + it('returns models with apiKey', async () => { + const mockData = { data: [{ id: 'model-1' }] }; + mockGet.mockResolvedValue({ data: mockData, error: null }); + + const result = await service.listModels('test-key'); + + expect(result).toEqual(mockData); + expect(mockGet).toHaveBeenCalledWith('/v1/models', { + headers: { Authorization: 'test-key' }, + }); + }); + + it('throws on API error', async () => { + mockGet.mockResolvedValue({ data: null, error: 'service unavailable' }); + + await expect(service.listModels()).rejects.toThrow('Failed to list models'); + }); + }); + + describe('handleStreamingResponse', () => { + function createMockStream(chunks: string[]) { + let index = 0; + return { + getReader: () => ({ + read: () => { + if (index >= chunks.length) { + return Promise.resolve({ done: true, value: undefined }); + } + const chunk = new TextEncoder().encode(chunks[index++]); + return Promise.resolve({ done: false, value: chunk }); + }, + }), + }; + } + + it('streams chunks and returns full response', async () => { + const chunks: string[] = [ + 'data: {"id":"1","choices":[{"delta":{"content":"Hello"}}]}\n\n', + 'data: {"id":"1","choices":[{"delta":{"content":" world"}}]}\n\n', + 'data: [DONE]\n\n', + ]; + + fetchMock.mockResolvedValue({ + body: createMockStream(chunks), + headers: new Headers(), + ok: true, + status: 200, + statusText: 'OK', + }); + + const receivedChunks: any[] = []; + + const result = await service.createCompletion({ + messages: [{ content: 'Hi', role: 'user' }], + onChunk: (chunk: any) => receivedChunks.push(chunk), + stream: true, + }); + + expect(receivedChunks).toHaveLength(2); + expect(result.choices[0].message.content).toBe(' world'); + }); + + it('handles first chunk as full response with no content', async () => { + const chunks: string[] = ['data: {"id":"1","choices":[{"delta":{"content":"Test"}}]}\n\n']; + + fetchMock.mockResolvedValue({ + body: createMockStream(chunks), + headers: new Headers(), + ok: true, + status: 200, + statusText: 'OK', + }); + + const result = await service.createCompletion({ + messages: [{ content: 'Hi', role: 'user' }], + onChunk: vi.fn(), + stream: true, + }); + + // First chunk sets fullResponse, but no content accumulated + expect(result.id).toBe('1'); + }); + + it('handles empty stream', async () => { + fetchMock.mockResolvedValue({ + body: createMockStream([]), + headers: new Headers(), + ok: true, + status: 200, + statusText: 'OK', + }); + + const result = await service.createCompletion({ + messages: [{ content: 'Hi', role: 'user' }], + onChunk: vi.fn(), + stream: true, + }); + + expect(result.choices[0].message.content).toBe(''); + }); + + it('throws on non-ok response', async () => { + fetchMock.mockResolvedValue({ + headers: new Headers(), + ok: false, + status: 401, + statusText: 'Unauthorized', + text: () => Promise.resolve('Invalid API key'), + }); + + await expect( + service.createCompletion({ + messages: [{ content: 'Hi', role: 'user' }], + onChunk: vi.fn(), + stream: true, + }), + ).rejects.toThrow('Stream request failed: 401 Unauthorized'); + }); + + it('throws when response body is missing', async () => { + fetchMock.mockResolvedValue({ + body: null, + headers: new Headers(), + ok: true, + status: 200, + statusText: 'OK', + }); + + await expect( + service.createCompletion({ + messages: [{ content: 'Hi', role: 'user' }], + onChunk: vi.fn(), + stream: true, + }), + ).rejects.toThrow('No response body received'); + }); + + it('handles partial JSON across chunks', async () => { + const fullJson = '{"id":"1","choices":[{"delta":{"content":"Hello"}}]}'; + const chunks: string[] = [ + `data: ${fullJson.slice(0, 20)}\n\n`, + `data: ${fullJson.slice(20)}\n\n`, + ]; + + fetchMock.mockResolvedValue({ + body: createMockStream(chunks), + headers: new Headers(), + ok: true, + status: 200, + statusText: 'OK', + }); + + const result = await service.createCompletion({ + messages: [{ content: 'Hi', role: 'user' }], + onChunk: vi.fn(), + stream: true, + }); + + expect(result).toBeDefined(); + }); + }); +}); From 1119004b8b910482c96e4cb9a8007959ec615701 Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Wed, 3 Jun 2026 03:18:06 +0200 Subject: [PATCH 3/8] refactor(code/init): reduce cognitive complexity from 58 to 25 - Extract resolveToolConfigured() for tool installation retry logic - Extract buildScopeOptions() for scope selection options - Extract configureTool() for tool-specific configuration - Extract buildNextSteps() for next steps message generation - Reorder functions to satisfy perfectionist/sort-modules - All 45 existing tests pass --- coverage/clover.xml | 1217 ++++++++++++++++- coverage/coverage-final.json | 39 +- coverage/index.html | 202 ++- coverage/src/agents/app.ts.html | 166 +++ coverage/src/agents/backend.ts.html | 157 +++ coverage/src/agents/devops.ts.html | 184 +++ coverage/src/agents/frontend.ts.html | 157 +++ coverage/src/agents/fullstack.ts.html | 157 +++ coverage/src/agents/index.html | 221 +++ coverage/src/agents/index.ts.html | 304 ++++ coverage/src/agents/quality.ts.html | 292 ++++ coverage/src/agents/security.ts.html | 163 +++ coverage/src/auth/config.ts.html | 217 +++ coverage/src/auth/index.html | 146 ++ coverage/src/auth/issuer.ts.html | 187 +++ coverage/src/auth/jwt.ts.html | 274 ++++ .../auth/middleware/auth-middleware.ts.html | 202 +++ coverage/src/auth/middleware/index.html | 116 ++ .../src/auth/oauth/callback-pages.ts.html | 472 +++++++ coverage/src/auth/oauth/index.html | 146 ++ coverage/src/auth/oauth/pkce-flow.ts.html | 826 +++++++++++ coverage/src/auth/oauth/token-refresh.ts.html | 463 +++++++ coverage/src/auth/storage/index.html | 116 ++ coverage/src/auth/storage/token-store.ts.html | 328 +++++ coverage/src/client.ts.html | 208 +++ .../__tests__/fake-api-key-service.ts.html | 145 ++ .../code/__tests__/fake-auth-service.ts.html | 241 ++++ .../__tests__/fake-command-runner.ts.html | 235 ++++ .../code/__tests__/fake-file-store.ts.html | 217 +++ .../code/__tests__/fake-prompter.ts.html | 502 +++++++ .../src/commands/code/__tests__/index.html | 176 +++ .../code/adapters/clack-prompter.ts.html | 316 +++++ .../code/adapters/fs-file-store.ts.html | 199 +++ .../src/commands/code/adapters/index.html | 146 ++ .../adapters/spawn-command-runner.ts.html | 220 +++ coverage/src/commands/code/auth-sync.ts.html | 1066 +++++++++++++++ coverage/src/commands/code/errors.ts.html | 175 +++ coverage/src/commands/code/index.html | 206 +++ coverage/src/commands/code/init.ts.html | 748 ++++++++++ coverage/src/commands/code/opencode.ts.html | 931 +++++++++++++ coverage/src/commands/code/pi.ts.html | 628 +++++++++ coverage/src/commands/code/tool-check.ts.html | 319 +++++ coverage/src/commands/code/utils.ts.html | 172 +++ .../src/constants/command-structure.ts.html | 715 ++++++++++ coverage/src/constants/index.html | 116 ++ coverage/src/index.html | 116 ++ coverage/src/services/api-key-service.ts.html | 802 +++++++++++ coverage/src/services/auth-service.ts.html | 445 ++++++ coverage/src/services/index.html | 131 ++ coverage/src/utils/error-handler.ts.html | 538 ++++++++ coverage/src/utils/index.html | 131 ++ coverage/src/utils/logger.ts.html | 670 +++++++++ src/commands/code/init.ts | 217 +-- 53 files changed, 17379 insertions(+), 104 deletions(-) create mode 100644 coverage/src/agents/app.ts.html create mode 100644 coverage/src/agents/backend.ts.html create mode 100644 coverage/src/agents/devops.ts.html create mode 100644 coverage/src/agents/frontend.ts.html create mode 100644 coverage/src/agents/fullstack.ts.html create mode 100644 coverage/src/agents/index.html create mode 100644 coverage/src/agents/index.ts.html create mode 100644 coverage/src/agents/quality.ts.html create mode 100644 coverage/src/agents/security.ts.html create mode 100644 coverage/src/auth/config.ts.html create mode 100644 coverage/src/auth/index.html create mode 100644 coverage/src/auth/issuer.ts.html create mode 100644 coverage/src/auth/jwt.ts.html create mode 100644 coverage/src/auth/middleware/auth-middleware.ts.html create mode 100644 coverage/src/auth/middleware/index.html create mode 100644 coverage/src/auth/oauth/callback-pages.ts.html create mode 100644 coverage/src/auth/oauth/index.html create mode 100644 coverage/src/auth/oauth/pkce-flow.ts.html create mode 100644 coverage/src/auth/oauth/token-refresh.ts.html create mode 100644 coverage/src/auth/storage/index.html create mode 100644 coverage/src/auth/storage/token-store.ts.html create mode 100644 coverage/src/client.ts.html create mode 100644 coverage/src/commands/code/__tests__/fake-api-key-service.ts.html create mode 100644 coverage/src/commands/code/__tests__/fake-auth-service.ts.html create mode 100644 coverage/src/commands/code/__tests__/fake-command-runner.ts.html create mode 100644 coverage/src/commands/code/__tests__/fake-file-store.ts.html create mode 100644 coverage/src/commands/code/__tests__/fake-prompter.ts.html create mode 100644 coverage/src/commands/code/__tests__/index.html create mode 100644 coverage/src/commands/code/adapters/clack-prompter.ts.html create mode 100644 coverage/src/commands/code/adapters/fs-file-store.ts.html create mode 100644 coverage/src/commands/code/adapters/index.html create mode 100644 coverage/src/commands/code/adapters/spawn-command-runner.ts.html create mode 100644 coverage/src/commands/code/auth-sync.ts.html create mode 100644 coverage/src/commands/code/errors.ts.html create mode 100644 coverage/src/commands/code/index.html create mode 100644 coverage/src/commands/code/init.ts.html create mode 100644 coverage/src/commands/code/opencode.ts.html create mode 100644 coverage/src/commands/code/pi.ts.html create mode 100644 coverage/src/commands/code/tool-check.ts.html create mode 100644 coverage/src/commands/code/utils.ts.html create mode 100644 coverage/src/constants/command-structure.ts.html create mode 100644 coverage/src/constants/index.html create mode 100644 coverage/src/index.html create mode 100644 coverage/src/services/api-key-service.ts.html create mode 100644 coverage/src/services/auth-service.ts.html create mode 100644 coverage/src/services/index.html create mode 100644 coverage/src/utils/error-handler.ts.html create mode 100644 coverage/src/utils/index.html create mode 100644 coverage/src/utils/logger.ts.html diff --git a/coverage/clover.xml b/coverage/clover.xml index 1b46a3f..85eb52a 100644 --- a/coverage/clover.xml +++ b/coverage/clover.xml @@ -1,6 +1,1217 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json index 0967ef4..2c79f10 100644 --- a/coverage/coverage-final.json +++ b/coverage/coverage-final.json @@ -1 +1,38 @@ -{} +{"/Users/marcus/berget-monorepo/cli/src/client.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/client.ts","statementMap":{"0":{"start":{"line":12,"column":8},"end":{"line":12,"column":null}},"1":{"start":{"line":13,"column":8},"end":{"line":19,"column":null}},"2":{"start":{"line":21,"column":21},"end":{"line":21,"column":null}},"3":{"start":{"line":23,"column":2},"end":{"line":38,"column":null}},"4":{"start":{"line":26,"column":21},"end":{"line":26,"column":null}},"5":{"start":{"line":27,"column":8},"end":{"line":27,"column":null}},"6":{"start":{"line":30,"column":8},"end":{"line":35,"column":null}},"7":{"start":{"line":31,"column":32},"end":{"line":31,"column":null}},"8":{"start":{"line":32,"column":10},"end":{"line":32,"column":null}},"9":{"start":{"line":34,"column":10},"end":{"line":34,"column":null}},"10":{"start":{"line":40,"column":2},"end":{"line":40,"column":null}}},"fnMap":{"0":{"name":"createAuthenticatedClient","decl":{"start":{"line":11,"column":16},"end":{"line":11,"column":42}},"loc":{"start":{"line":11,"column":90},"end":{"line":41,"column":null}},"line":11},"1":{"name":"(anonymous_1)","decl":{"start":{"line":25,"column":16},"end":{"line":25,"column":28}},"loc":{"start":{"line":25,"column":28},"end":{"line":28,"column":null}},"line":25},"2":{"name":"(anonymous_2)","decl":{"start":{"line":29,"column":15},"end":{"line":29,"column":27}},"loc":{"start":{"line":29,"column":27},"end":{"line":36,"column":null}},"line":29}},"branchMap":{"0":{"loc":{"start":{"line":27,"column":15},"end":{"line":27,"column":null}},"type":"binary-expr","locations":[{"start":{"line":27,"column":15},"end":{"line":27,"column":37}},{"start":{"line":27,"column":37},"end":{"line":27,"column":null}}],"line":27}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0]},"meta":{"lastBranch":1,"lastFunction":3,"lastStatement":11,"seen":{"f:11:16:11:42":0,"s:12:8:12:Infinity":0,"s:13:8:19:Infinity":1,"s:21:21:21:Infinity":2,"s:23:2:38:Infinity":3,"f:25:16:25:28":1,"s:26:21:26:Infinity":4,"s:27:8:27:Infinity":5,"b:27:15:27:37:27:37:27:Infinity":0,"f:29:15:29:27":2,"s:30:8:35:Infinity":6,"s:31:32:31:Infinity":7,"s:32:10:32:Infinity":8,"s:34:10:34:Infinity":9,"s:40:2:40:Infinity":10}}} +,"/Users/marcus/berget-monorepo/cli/src/agents/app.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/app.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":27,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:27:Infinity":0}}} +,"/Users/marcus/berget-monorepo/cli/src/agents/backend.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/backend.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":24,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:24:Infinity":0}}} +,"/Users/marcus/berget-monorepo/cli/src/agents/devops.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/devops.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":33,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:33:Infinity":0}}} +,"/Users/marcus/berget-monorepo/cli/src/agents/frontend.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/frontend.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":24,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:24:Infinity":0}}} +,"/Users/marcus/berget-monorepo/cli/src/agents/fullstack.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/fullstack.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":24,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:24:Infinity":0}}} +,"/Users/marcus/berget-monorepo/cli/src/agents/index.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/index.ts","statementMap":{"0":{"start":{"line":11,"column":38},"end":{"line":19,"column":null}},"1":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"2":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"3":{"start":{"line":36,"column":2},"end":{"line":40,"column":null}},"4":{"start":{"line":44,"column":35},"end":{"line":44,"column":null}},"5":{"start":{"line":45,"column":20},"end":{"line":45,"column":null}},"6":{"start":{"line":47,"column":2},"end":{"line":49,"column":null}},"7":{"start":{"line":48,"column":4},"end":{"line":48,"column":null}},"8":{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},"9":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"10":{"start":{"line":55,"column":2},"end":{"line":57,"column":null}},"11":{"start":{"line":56,"column":4},"end":{"line":56,"column":null}},"12":{"start":{"line":59,"column":2},"end":{"line":64,"column":null}},"13":{"start":{"line":60,"column":4},"end":{"line":60,"column":null}},"14":{"start":{"line":61,"column":4},"end":{"line":63,"column":null}},"15":{"start":{"line":62,"column":6},"end":{"line":62,"column":null}},"16":{"start":{"line":66,"column":2},"end":{"line":66,"column":null}},"17":{"start":{"line":70,"column":2},"end":{"line":70,"column":null}}},"fnMap":{"0":{"name":"getAgent","decl":{"start":{"line":23,"column":16},"end":{"line":23,"column":25}},"loc":{"start":{"line":23,"column":58},"end":{"line":25,"column":null}},"line":23},"1":{"name":"getAllAgents","decl":{"start":{"line":27,"column":16},"end":{"line":27,"column":40}},"loc":{"start":{"line":27,"column":40},"end":{"line":29,"column":null}},"line":27},"2":{"name":"toAgentTemplate","decl":{"start":{"line":31,"column":16},"end":{"line":31,"column":32}},"loc":{"start":{"line":35,"column":2},"end":{"line":41,"column":null}},"line":35},"3":{"name":"toMarkdown","decl":{"start":{"line":43,"column":16},"end":{"line":43,"column":27}},"loc":{"start":{"line":43,"column":49},"end":{"line":67,"column":null}},"line":43},"4":{"name":"toPiPrompt","decl":{"start":{"line":69,"column":16},"end":{"line":69,"column":27}},"loc":{"start":{"line":69,"column":49},"end":{"line":71,"column":null}},"line":69}},"branchMap":{"0":{"loc":{"start":{"line":47,"column":2},"end":{"line":49,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":2},"end":{"line":49,"column":null}},{"start":{},"end":{}}],"line":47},"1":{"loc":{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},{"start":{},"end":{}}],"line":51},"2":{"loc":{"start":{"line":55,"column":2},"end":{"line":57,"column":null}},"type":"if","locations":[{"start":{"line":55,"column":2},"end":{"line":57,"column":null}},{"start":{},"end":{}}],"line":55},"3":{"loc":{"start":{"line":59,"column":2},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":59,"column":2},"end":{"line":64,"column":null}},{"start":{},"end":{}}],"line":59}},"s":{"0":1,"1":0,"2":28,"3":0,"4":7,"5":7,"6":7,"7":7,"8":7,"9":0,"10":7,"11":0,"12":7,"13":0,"14":0,"15":0,"16":7,"17":8},"f":{"0":0,"1":28,"2":0,"3":7,"4":8},"b":{"0":[7,0],"1":[0,7],"2":[0,7],"3":[0,7]},"meta":{"lastBranch":4,"lastFunction":5,"lastStatement":18,"seen":{"s:11:38:19:Infinity":0,"f:23:16:23:25":0,"s:24:2:24:Infinity":1,"f:27:16:27:40":1,"s:28:2:28:Infinity":2,"f:31:16:31:32":2,"s:36:2:40:Infinity":3,"f:43:16:43:27":3,"s:44:35:44:Infinity":4,"s:45:20:45:Infinity":5,"b:47:2:49:Infinity:undefined:undefined:undefined:undefined":0,"s:47:2:49:Infinity":6,"s:48:4:48:Infinity":7,"b:51:2:53:Infinity:undefined:undefined:undefined:undefined":1,"s:51:2:53:Infinity":8,"s:52:4:52:Infinity":9,"b:55:2:57:Infinity:undefined:undefined:undefined:undefined":2,"s:55:2:57:Infinity":10,"s:56:4:56:Infinity":11,"b:59:2:64:Infinity:undefined:undefined:undefined:undefined":3,"s:59:2:64:Infinity":12,"s:60:4:60:Infinity":13,"s:61:4:63:Infinity":14,"s:62:6:62:Infinity":15,"s:66:2:66:Infinity":16,"f:69:16:69:27":4,"s:70:2:70:Infinity":17}}} +,"/Users/marcus/berget-monorepo/cli/src/agents/quality.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/quality.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":69,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:69:Infinity":0}}} +,"/Users/marcus/berget-monorepo/cli/src/agents/security.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/security.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":26,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:26:Infinity":0}}} +,"/Users/marcus/berget-monorepo/cli/src/auth/config.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/config.ts","statementMap":{"0":{"start":{"line":5,"column":2},"end":{"line":13,"column":null}},"1":{"start":{"line":6,"column":23},"end":{"line":6,"column":null}},"2":{"start":{"line":7,"column":4},"end":{"line":12,"column":null}},"3":{"start":{"line":19,"column":2},"end":{"line":36,"column":null}},"4":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"5":{"start":{"line":22,"column":4},"end":{"line":26,"column":null}},"6":{"start":{"line":23,"column":6},"end":{"line":23,"column":null}},"7":{"start":{"line":25,"column":6},"end":{"line":25,"column":null}},"8":{"start":{"line":27,"column":9},"end":{"line":36,"column":null}},"9":{"start":{"line":28,"column":4},"end":{"line":28,"column":null}},"10":{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},"11":{"start":{"line":30,"column":9},"end":{"line":36,"column":null}},"12":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"13":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"14":{"start":{"line":34,"column":4},"end":{"line":34,"column":null}},"15":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"16":{"start":{"line":38,"column":2},"end":{"line":43,"column":null}}},"fnMap":{"0":{"name":"getAuthConfig","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":30}},"loc":{"start":{"line":3,"column":90},"end":{"line":44,"column":null}},"line":3}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":2},"end":{"line":13,"column":null}},"type":"if","locations":[{"start":{"line":5,"column":2},"end":{"line":13,"column":null}},{"start":{},"end":{}}],"line":5},"1":{"loc":{"start":{"line":6,"column":23},"end":{"line":6,"column":null}},"type":"binary-expr","locations":[{"start":{"line":6,"column":23},"end":{"line":6,"column":53}},{"start":{"line":6,"column":53},"end":{"line":6,"column":null}}],"line":6},"2":{"loc":{"start":{"line":19,"column":2},"end":{"line":36,"column":null}},"type":"if","locations":[{"start":{"line":19,"column":2},"end":{"line":36,"column":null}},{"start":{"line":27,"column":9},"end":{"line":36,"column":null}}],"line":19},"3":{"loc":{"start":{"line":22,"column":4},"end":{"line":26,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":4},"end":{"line":26,"column":null}},{"start":{"line":24,"column":11},"end":{"line":26,"column":null}}],"line":22},"4":{"loc":{"start":{"line":22,"column":8},"end":{"line":22,"column":75}},"type":"binary-expr","locations":[{"start":{"line":22,"column":8},"end":{"line":22,"column":44}},{"start":{"line":22,"column":44},"end":{"line":22,"column":75}}],"line":22},"5":{"loc":{"start":{"line":27,"column":9},"end":{"line":36,"column":null}},"type":"if","locations":[{"start":{"line":27,"column":9},"end":{"line":36,"column":null}},{"start":{"line":30,"column":9},"end":{"line":36,"column":null}}],"line":27},"6":{"loc":{"start":{"line":30,"column":9},"end":{"line":36,"column":null}},"type":"if","locations":[{"start":{"line":30,"column":9},"end":{"line":36,"column":null}},{"start":{"line":33,"column":9},"end":{"line":36,"column":null}}],"line":30}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0},"f":{"0":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0]},"meta":{"lastBranch":7,"lastFunction":1,"lastStatement":17,"seen":{"f:3:16:3:30":0,"b:5:2:13:Infinity:undefined:undefined:undefined:undefined":0,"s:5:2:13:Infinity":0,"s:6:23:6:Infinity":1,"b:6:23:6:53:6:53:6:Infinity":1,"s:7:4:12:Infinity":2,"b:19:2:36:Infinity:27:9:36:Infinity":2,"s:19:2:36:Infinity":3,"s:20:4:20:Infinity":4,"b:22:4:26:Infinity:24:11:26:Infinity":3,"s:22:4:26:Infinity":5,"b:22:8:22:44:22:44:22:75":4,"s:23:6:23:Infinity":6,"s:25:6:25:Infinity":7,"b:27:9:36:Infinity:30:9:36:Infinity":5,"s:27:9:36:Infinity":8,"s:28:4:28:Infinity":9,"s:29:4:29:Infinity":10,"b:30:9:36:Infinity:33:9:36:Infinity":6,"s:30:9:36:Infinity":11,"s:31:4:31:Infinity":12,"s:32:4:32:Infinity":13,"s:34:4:34:Infinity":14,"s:35:4:35:Infinity":15,"s:38:2:43:Infinity":16}}} +,"/Users/marcus/berget-monorepo/cli/src/auth/issuer.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/issuer.ts","statementMap":{"0":{"start":{"line":13,"column":14},"end":{"line":13,"column":null}},"1":{"start":{"line":16,"column":2},"end":{"line":16,"column":null}},"2":{"start":{"line":20,"column":20},"end":{"line":20,"column":null}},"3":{"start":{"line":22,"column":17},"end":{"line":22,"column":null}},"4":{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},"5":{"start":{"line":23,"column":14},"end":{"line":23,"column":null}},"6":{"start":{"line":25,"column":24},"end":{"line":30,"column":null}},"7":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"8":{"start":{"line":33,"column":2},"end":{"line":33,"column":null}}},"fnMap":{"0":{"name":"clearConfigurationCache","decl":{"start":{"line":15,"column":16},"end":{"line":15,"column":48}},"loc":{"start":{"line":15,"column":48},"end":{"line":17,"column":null}},"line":15},"1":{"name":"getConfiguration","decl":{"start":{"line":19,"column":22},"end":{"line":19,"column":39}},"loc":{"start":{"line":19,"column":83},"end":{"line":34,"column":null}},"line":19}},"branchMap":{"0":{"loc":{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},"type":"if","locations":[{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},{"start":{},"end":{}}],"line":23}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0},"f":{"0":0,"1":0},"b":{"0":[0,0]},"meta":{"lastBranch":1,"lastFunction":2,"lastStatement":9,"seen":{"s:13:14:13:Infinity":0,"f:15:16:15:48":0,"s:16:2:16:Infinity":1,"f:19:22:19:39":1,"s:20:20:20:Infinity":2,"s:22:17:22:Infinity":3,"b:23:2:23:Infinity:undefined:undefined:undefined:undefined":0,"s:23:2:23:Infinity":4,"s:23:14:23:Infinity":5,"s:25:24:30:Infinity":6,"s:32:2:32:Infinity":7,"s:33:2:33:Infinity":8}}} +,"/Users/marcus/berget-monorepo/cli/src/auth/jwt.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/jwt.ts","statementMap":{"0":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"1":{"start":{"line":16,"column":18},"end":{"line":16,"column":null}},"2":{"start":{"line":17,"column":2},"end":{"line":19,"column":null}},"3":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"4":{"start":{"line":20,"column":2},"end":{"line":20,"column":null}},"5":{"start":{"line":29,"column":18},"end":{"line":29,"column":null}},"6":{"start":{"line":30,"column":2},"end":{"line":30,"column":null}},"7":{"start":{"line":30,"column":16},"end":{"line":30,"column":null}},"8":{"start":{"line":31,"column":22},"end":{"line":31,"column":null}},"9":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"10":{"start":{"line":32,"column":20},"end":{"line":32,"column":null}},"11":{"start":{"line":33,"column":16},"end":{"line":33,"column":null}},"12":{"start":{"line":34,"column":2},"end":{"line":34,"column":null}},"13":{"start":{"line":34,"column":29},"end":{"line":34,"column":null}},"14":{"start":{"line":35,"column":2},"end":{"line":35,"column":null}},"15":{"start":{"line":45,"column":14},"end":{"line":45,"column":null}},"16":{"start":{"line":46,"column":26},"end":{"line":46,"column":null}},"17":{"start":{"line":47,"column":17},"end":{"line":47,"column":null}},"18":{"start":{"line":48,"column":2},"end":{"line":48,"column":null}},"19":{"start":{"line":55,"column":2},"end":{"line":62,"column":null}},"20":{"start":{"line":56,"column":18},"end":{"line":56,"column":null}},"21":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"22":{"start":{"line":57,"column":28},"end":{"line":57,"column":null}},"23":{"start":{"line":58,"column":20},"end":{"line":58,"column":null}},"24":{"start":{"line":59,"column":4},"end":{"line":59,"column":null}},"25":{"start":{"line":61,"column":4},"end":{"line":61,"column":null}}},"fnMap":{"0":{"name":"decodeJwtPayload","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":33}},"loc":{"start":{"line":6,"column":64},"end":{"line":8,"column":null}},"line":6},"1":{"name":"extractJwtExpiresAt","decl":{"start":{"line":15,"column":16},"end":{"line":15,"column":36}},"loc":{"start":{"line":15,"column":65},"end":{"line":21,"column":null}},"line":15},"2":{"name":"hasBergetCodeSeat","decl":{"start":{"line":28,"column":16},"end":{"line":28,"column":34}},"loc":{"start":{"line":28,"column":64},"end":{"line":36,"column":null}},"line":28},"3":{"name":"isTokenExpired","decl":{"start":{"line":44,"column":16},"end":{"line":44,"column":31}},"loc":{"start":{"line":44,"column":59},"end":{"line":49,"column":null}},"line":44},"4":{"name":"parseJwtBody","decl":{"start":{"line":54,"column":9},"end":{"line":54,"column":22}},"loc":{"start":{"line":54,"column":69},"end":{"line":63,"column":null}},"line":54}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":2},"end":{"line":19,"column":null}},"type":"if","locations":[{"start":{"line":17,"column":2},"end":{"line":19,"column":null}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":6},"end":{"line":17,"column":50}},"type":"binary-expr","locations":[{"start":{"line":17,"column":6},"end":{"line":17,"column":17}},{"start":{"line":17,"column":17},"end":{"line":17,"column":50}}],"line":17},"2":{"loc":{"start":{"line":30,"column":2},"end":{"line":30,"column":null}},"type":"if","locations":[{"start":{"line":30,"column":2},"end":{"line":30,"column":null}},{"start":{},"end":{}}],"line":30},"3":{"loc":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"type":"if","locations":[{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},{"start":{},"end":{}}],"line":32},"4":{"loc":{"start":{"line":34,"column":2},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":34,"column":2},"end":{"line":34,"column":null}},{"start":{},"end":{}}],"line":34},"5":{"loc":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"type":"if","locations":[{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},{"start":{},"end":{}}],"line":57}},"s":{"0":3,"1":5,"2":5,"3":5,"4":0,"5":3,"6":3,"7":0,"8":3,"9":3,"10":0,"11":3,"12":3,"13":0,"14":3,"15":2,"16":2,"17":2,"18":2,"19":11,"20":11,"21":11,"22":0,"23":11,"24":11,"25":0},"f":{"0":3,"1":5,"2":3,"3":2,"4":11},"b":{"0":[5,0],"1":[5,5],"2":[0,3],"3":[0,3],"4":[0,3],"5":[0,11]},"meta":{"lastBranch":6,"lastFunction":5,"lastStatement":26,"seen":{"f:6:16:6:33":0,"s:7:2:7:Infinity":0,"f:15:16:15:36":1,"s:16:18:16:Infinity":1,"b:17:2:19:Infinity:undefined:undefined:undefined:undefined":0,"s:17:2:19:Infinity":2,"b:17:6:17:17:17:17:17:50":1,"s:18:4:18:Infinity":3,"s:20:2:20:Infinity":4,"f:28:16:28:34":2,"s:29:18:29:Infinity":5,"b:30:2:30:Infinity:undefined:undefined:undefined:undefined":2,"s:30:2:30:Infinity":6,"s:30:16:30:Infinity":7,"s:31:22:31:Infinity":8,"b:32:2:32:Infinity:undefined:undefined:undefined:undefined":3,"s:32:2:32:Infinity":9,"s:32:20:32:Infinity":10,"s:33:16:33:Infinity":11,"b:34:2:34:Infinity:undefined:undefined:undefined:undefined":4,"s:34:2:34:Infinity":12,"s:34:29:34:Infinity":13,"s:35:2:35:Infinity":14,"f:44:16:44:31":3,"s:45:14:45:Infinity":15,"s:46:26:46:Infinity":16,"s:47:17:47:Infinity":17,"s:48:2:48:Infinity":18,"f:54:9:54:22":4,"s:55:2:62:Infinity":19,"s:56:18:56:Infinity":20,"b:57:4:57:Infinity:undefined:undefined:undefined:undefined":5,"s:57:4:57:Infinity":21,"s:57:28:57:Infinity":22,"s:58:20:58:Infinity":23,"s:59:4:59:Infinity":24,"s:61:4:61:Infinity":25}}} +,"/Users/marcus/berget-monorepo/cli/src/auth/middleware/auth-middleware.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/middleware/auth-middleware.ts","statementMap":{"0":{"start":{"line":10,"column":4},"end":{"line":15,"column":null}},"1":{"start":{"line":12,"column":20},"end":{"line":12,"column":null}},"2":{"start":{"line":13,"column":19},"end":{"line":13,"column":null}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":null}},"4":{"start":{"line":17,"column":2},"end":{"line":38,"column":null}},"5":{"start":{"line":19,"column":20},"end":{"line":19,"column":null}},"6":{"start":{"line":20,"column":6},"end":{"line":22,"column":null}},"7":{"start":{"line":21,"column":8},"end":{"line":21,"column":null}},"8":{"start":{"line":23,"column":6},"end":{"line":23,"column":null}},"9":{"start":{"line":26,"column":6},"end":{"line":35,"column":null}},"10":{"start":{"line":27,"column":19},"end":{"line":27,"column":null}},"11":{"start":{"line":28,"column":8},"end":{"line":34,"column":null}},"12":{"start":{"line":29,"column":27},"end":{"line":29,"column":null}},"13":{"start":{"line":30,"column":10},"end":{"line":33,"column":null}},"14":{"start":{"line":31,"column":12},"end":{"line":31,"column":null}},"15":{"start":{"line":32,"column":12},"end":{"line":32,"column":null}},"16":{"start":{"line":36,"column":6},"end":{"line":36,"column":null}}},"fnMap":{"0":{"name":"authMiddleware","decl":{"start":{"line":5,"column":16},"end":{"line":5,"column":31}},"loc":{"start":{"line":8,"column":15},"end":{"line":39,"column":null}},"line":8},"1":{"name":"(anonymous_1)","decl":{"start":{"line":11,"column":5},"end":{"line":11,"column":17}},"loc":{"start":{"line":11,"column":17},"end":{"line":15,"column":null}},"line":11},"2":{"name":"onRequest","decl":{"start":{"line":18,"column":10},"end":{"line":18,"column":20}},"loc":{"start":{"line":18,"column":25},"end":{"line":24,"column":null}},"line":18},"3":{"name":"onResponse","decl":{"start":{"line":25,"column":10},"end":{"line":25,"column":21}},"loc":{"start":{"line":25,"column":41},"end":{"line":37,"column":null}},"line":25}},"branchMap":{"0":{"loc":{"start":{"line":10,"column":4},"end":{"line":15,"column":null}},"type":"binary-expr","locations":[{"start":{"line":10,"column":4},"end":{"line":10,"column":null}},{"start":{"line":11,"column":5},"end":{"line":15,"column":null}}],"line":10},"1":{"loc":{"start":{"line":14,"column":13},"end":{"line":14,"column":null}},"type":"binary-expr","locations":[{"start":{"line":14,"column":13},"end":{"line":14,"column":35}},{"start":{"line":14,"column":35},"end":{"line":14,"column":null}}],"line":14},"2":{"loc":{"start":{"line":20,"column":6},"end":{"line":22,"column":null}},"type":"if","locations":[{"start":{"line":20,"column":6},"end":{"line":22,"column":null}},{"start":{},"end":{}}],"line":20},"3":{"loc":{"start":{"line":20,"column":10},"end":{"line":20,"column":54}},"type":"binary-expr","locations":[{"start":{"line":20,"column":10},"end":{"line":20,"column":19}},{"start":{"line":20,"column":19},"end":{"line":20,"column":54}}],"line":20},"4":{"loc":{"start":{"line":26,"column":6},"end":{"line":35,"column":null}},"type":"if","locations":[{"start":{"line":26,"column":6},"end":{"line":35,"column":null}},{"start":{},"end":{}}],"line":26},"5":{"loc":{"start":{"line":26,"column":10},"end":{"line":26,"column":49}},"type":"binary-expr","locations":[{"start":{"line":26,"column":10},"end":{"line":26,"column":32}},{"start":{"line":26,"column":32},"end":{"line":26,"column":49}}],"line":26},"6":{"loc":{"start":{"line":28,"column":8},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":8},"end":{"line":34,"column":null}},{"start":{},"end":{}}],"line":28},"7":{"loc":{"start":{"line":30,"column":10},"end":{"line":33,"column":null}},"type":"if","locations":[{"start":{"line":30,"column":10},"end":{"line":33,"column":null}},{"start":{},"end":{}}],"line":30}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0},"f":{"0":0,"1":0,"2":0,"3":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0]},"meta":{"lastBranch":8,"lastFunction":4,"lastStatement":17,"seen":{"f:5:16:5:31":0,"s:10:4:15:Infinity":0,"b:10:4:10:Infinity:11:5:15:Infinity":0,"f:11:5:11:17":1,"s:12:20:12:Infinity":1,"s:13:19:13:Infinity":2,"s:14:6:14:Infinity":3,"b:14:13:14:35:14:35:14:Infinity":1,"s:17:2:38:Infinity":4,"f:18:10:18:20":2,"s:19:20:19:Infinity":5,"b:20:6:22:Infinity:undefined:undefined:undefined:undefined":2,"s:20:6:22:Infinity":6,"b:20:10:20:19:20:19:20:54":3,"s:21:8:21:Infinity":7,"s:23:6:23:Infinity":8,"f:25:10:25:21":3,"b:26:6:35:Infinity:undefined:undefined:undefined:undefined":4,"s:26:6:35:Infinity":9,"b:26:10:26:32:26:32:26:49":5,"s:27:19:27:Infinity":10,"b:28:8:34:Infinity:undefined:undefined:undefined:undefined":6,"s:28:8:34:Infinity":11,"s:29:27:29:Infinity":12,"b:30:10:33:Infinity:undefined:undefined:undefined:undefined":7,"s:30:10:33:Infinity":13,"s:31:12:31:Infinity":14,"s:32:12:32:Infinity":15,"s:36:6:36:Infinity":16}}} +,"/Users/marcus/berget-monorepo/cli/src/auth/oauth/callback-pages.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/oauth/callback-pages.ts","statementMap":{"0":{"start":{"line":7,"column":20},"end":{"line":7,"column":null}},"1":{"start":{"line":8,"column":22},"end":{"line":8,"column":null}},"2":{"start":{"line":9,"column":2},"end":{"line":57,"column":null}},"3":{"start":{"line":65,"column":2},"end":{"line":65,"column":null}},"4":{"start":{"line":123,"column":2},"end":{"line":128,"column":null}}},"fnMap":{"0":{"name":"getErrorPage","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":29}},"loc":{"start":{"line":6,"column":69},"end":{"line":62,"column":null}},"line":6},"1":{"name":"getSuccessPage","decl":{"start":{"line":64,"column":16},"end":{"line":64,"column":41}},"loc":{"start":{"line":64,"column":41},"end":{"line":117,"column":null}},"line":64},"2":{"name":"escapeHtml","decl":{"start":{"line":122,"column":9},"end":{"line":122,"column":20}},"loc":{"start":{"line":122,"column":42},"end":{"line":129,"column":null}},"line":122}},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0},"f":{"0":0,"1":0,"2":0},"b":{},"meta":{"lastBranch":0,"lastFunction":3,"lastStatement":5,"seen":{"f:6:16:6:29":0,"s:7:20:7:Infinity":0,"s:8:22:8:Infinity":1,"s:9:2:57:Infinity":2,"f:64:16:64:41":1,"s:65:2:65:Infinity":3,"f:122:9:122:20":2,"s:123:2:128:Infinity":4}}} +,"/Users/marcus/berget-monorepo/cli/src/auth/oauth/pkce-flow.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/oauth/pkce-flow.ts","statementMap":{"0":{"start":{"line":18,"column":31},"end":{"line":18,"column":null}},"1":{"start":{"line":19,"column":24},"end":{"line":19,"column":null}},"2":{"start":{"line":37,"column":6},"end":{"line":37,"column":null}},"3":{"start":{"line":38,"column":16},"end":{"line":38,"column":null}},"4":{"start":{"line":40,"column":8},"end":{"line":40,"column":null}},"5":{"start":{"line":41,"column":24},"end":{"line":41,"column":null}},"6":{"start":{"line":42,"column":16},"end":{"line":42,"column":null}},"7":{"start":{"line":44,"column":2},"end":{"line":208,"column":null}},"8":{"start":{"line":45,"column":29},"end":{"line":45,"column":null}},"9":{"start":{"line":46,"column":24},"end":{"line":46,"column":null}},"10":{"start":{"line":48,"column":4},"end":{"line":50,"column":null}},"11":{"start":{"line":49,"column":6},"end":{"line":49,"column":null}},"12":{"start":{"line":53,"column":10},"end":{"line":59,"column":null}},"13":{"start":{"line":61,"column":4},"end":{"line":63,"column":null}},"14":{"start":{"line":62,"column":6},"end":{"line":62,"column":null}},"15":{"start":{"line":66,"column":23},"end":{"line":160,"column":null}},"16":{"start":{"line":72,"column":21},"end":{"line":72,"column":null}},"17":{"start":{"line":73,"column":22},"end":{"line":73,"column":null}},"18":{"start":{"line":75,"column":12},"end":{"line":90,"column":null}},"19":{"start":{"line":81,"column":8},"end":{"line":81,"column":null}},"20":{"start":{"line":81,"column":22},"end":{"line":81,"column":null}},"21":{"start":{"line":82,"column":8},"end":{"line":82,"column":null}},"22":{"start":{"line":83,"column":8},"end":{"line":83,"column":null}},"23":{"start":{"line":84,"column":8},"end":{"line":84,"column":null}},"24":{"start":{"line":85,"column":8},"end":{"line":87,"column":null}},"25":{"start":{"line":86,"column":10},"end":{"line":86,"column":null}},"26":{"start":{"line":88,"column":8},"end":{"line":88,"column":null}},"27":{"start":{"line":89,"column":8},"end":{"line":89,"column":null}},"28":{"start":{"line":92,"column":6},"end":{"line":138,"column":null}},"29":{"start":{"line":93,"column":27},"end":{"line":93,"column":null}},"30":{"start":{"line":95,"column":8},"end":{"line":99,"column":null}},"31":{"start":{"line":96,"column":10},"end":{"line":96,"column":null}},"32":{"start":{"line":97,"column":10},"end":{"line":97,"column":null}},"33":{"start":{"line":98,"column":10},"end":{"line":98,"column":null}},"34":{"start":{"line":101,"column":30},"end":{"line":101,"column":null}},"35":{"start":{"line":102,"column":21},"end":{"line":102,"column":null}},"36":{"start":{"line":103,"column":22},"end":{"line":103,"column":null}},"37":{"start":{"line":105,"column":8},"end":{"line":114,"column":null}},"38":{"start":{"line":106,"column":30},"end":{"line":106,"column":null}},"39":{"start":{"line":107,"column":10},"end":{"line":109,"column":null}},"40":{"start":{"line":108,"column":12},"end":{"line":108,"column":null}},"41":{"start":{"line":110,"column":10},"end":{"line":110,"column":null}},"42":{"start":{"line":111,"column":10},"end":{"line":111,"column":null}},"43":{"start":{"line":112,"column":10},"end":{"line":112,"column":null}},"44":{"start":{"line":113,"column":10},"end":{"line":113,"column":null}},"45":{"start":{"line":116,"column":8},"end":{"line":126,"column":null}},"46":{"start":{"line":117,"column":10},"end":{"line":119,"column":null}},"47":{"start":{"line":118,"column":12},"end":{"line":118,"column":null}},"48":{"start":{"line":120,"column":10},"end":{"line":120,"column":null}},"49":{"start":{"line":121,"column":10},"end":{"line":123,"column":null}},"50":{"start":{"line":124,"column":10},"end":{"line":124,"column":null}},"51":{"start":{"line":125,"column":10},"end":{"line":125,"column":null}},"52":{"start":{"line":128,"column":8},"end":{"line":133,"column":null}},"53":{"start":{"line":129,"column":10},"end":{"line":129,"column":null}},"54":{"start":{"line":130,"column":10},"end":{"line":130,"column":null}},"55":{"start":{"line":131,"column":10},"end":{"line":131,"column":null}},"56":{"start":{"line":132,"column":10},"end":{"line":132,"column":null}},"57":{"start":{"line":135,"column":8},"end":{"line":135,"column":null}},"58":{"start":{"line":136,"column":8},"end":{"line":136,"column":null}},"59":{"start":{"line":137,"column":8},"end":{"line":137,"column":null}},"60":{"start":{"line":140,"column":6},"end":{"line":143,"column":null}},"61":{"start":{"line":141,"column":8},"end":{"line":141,"column":null}},"62":{"start":{"line":142,"column":8},"end":{"line":142,"column":null}},"63":{"start":{"line":142,"column":33},"end":{"line":142,"column":55}},"64":{"start":{"line":145,"column":28},"end":{"line":148,"column":null}},"65":{"start":{"line":146,"column":14},"end":{"line":146,"column":null}},"66":{"start":{"line":151,"column":6},"end":{"line":159,"column":null}},"67":{"start":{"line":152,"column":8},"end":{"line":158,"column":null}},"68":{"start":{"line":153,"column":23},"end":{"line":153,"column":null}},"69":{"start":{"line":153,"column":65},"end":{"line":153,"column":null}},"70":{"start":{"line":154,"column":10},"end":{"line":154,"column":null}},"71":{"start":{"line":156,"column":10},"end":{"line":156,"column":null}},"72":{"start":{"line":157,"column":10},"end":{"line":157,"column":null}},"73":{"start":{"line":162,"column":4},"end":{"line":167,"column":null}},"74":{"start":{"line":163,"column":6},"end":{"line":166,"column":null}},"75":{"start":{"line":170,"column":24},"end":{"line":170,"column":null}},"76":{"start":{"line":172,"column":4},"end":{"line":175,"column":null}},"77":{"start":{"line":173,"column":6},"end":{"line":173,"column":null}},"78":{"start":{"line":174,"column":6},"end":{"line":174,"column":null}},"79":{"start":{"line":177,"column":4},"end":{"line":202,"column":null}},"80":{"start":{"line":178,"column":26},"end":{"line":181,"column":null}},"81":{"start":{"line":183,"column":6},"end":{"line":185,"column":null}},"82":{"start":{"line":184,"column":8},"end":{"line":184,"column":null}},"83":{"start":{"line":187,"column":6},"end":{"line":192,"column":null}},"84":{"start":{"line":194,"column":6},"end":{"line":200,"column":null}},"85":{"start":{"line":195,"column":8},"end":{"line":195,"column":null}},"86":{"start":{"line":196,"column":8},"end":{"line":199,"column":null}},"87":{"start":{"line":197,"column":10},"end":{"line":197,"column":null}},"88":{"start":{"line":198,"column":10},"end":{"line":198,"column":null}},"89":{"start":{"line":201,"column":6},"end":{"line":201,"column":null}},"90":{"start":{"line":204,"column":4},"end":{"line":207,"column":null}},"91":{"start":{"line":218,"column":2},"end":{"line":246,"column":null}},"92":{"start":{"line":222,"column":19},"end":{"line":222,"column":null}},"93":{"start":{"line":225,"column":6},"end":{"line":231,"column":null}},"94":{"start":{"line":226,"column":8},"end":{"line":230,"column":null}},"95":{"start":{"line":227,"column":10},"end":{"line":227,"column":null}},"96":{"start":{"line":227,"column":29},"end":{"line":227,"column":45}},"97":{"start":{"line":229,"column":10},"end":{"line":229,"column":null}},"98":{"start":{"line":233,"column":6},"end":{"line":240,"column":null}},"99":{"start":{"line":234,"column":24},"end":{"line":234,"column":null}},"100":{"start":{"line":235,"column":8},"end":{"line":239,"column":null}},"101":{"start":{"line":236,"column":10},"end":{"line":236,"column":null}},"102":{"start":{"line":238,"column":10},"end":{"line":238,"column":null}},"103":{"start":{"line":242,"column":6},"end":{"line":242,"column":null}},"104":{"start":{"line":245,"column":4},"end":{"line":245,"column":null}}},"fnMap":{"0":{"name":"startPkceFlow","decl":{"start":{"line":32,"column":22},"end":{"line":32,"column":36}},"loc":{"start":{"line":32,"column":90},"end":{"line":209,"column":null}},"line":32},"1":{"name":"(anonymous_1)","decl":{"start":{"line":66,"column":33},"end":{"line":66,"column":null}},"loc":{"start":{"line":71,"column":20},"end":{"line":160,"column":5}},"line":71},"2":{"name":"(anonymous_2)","decl":{"start":{"line":75,"column":12},"end":{"line":75,"column":27}},"loc":{"start":{"line":80,"column":12},"end":{"line":90,"column":null}},"line":80},"3":{"name":"(anonymous_3)","decl":{"start":{"line":92,"column":16},"end":{"line":92,"column":28}},"loc":{"start":{"line":92,"column":45},"end":{"line":138,"column":7}},"line":92},"4":{"name":"(anonymous_4)","decl":{"start":{"line":140,"column":16},"end":{"line":140,"column":31}},"loc":{"start":{"line":140,"column":54},"end":{"line":143,"column":7}},"line":140},"5":{"name":"(anonymous_5)","decl":{"start":{"line":142,"column":18},"end":{"line":142,"column":33}},"loc":{"start":{"line":142,"column":33},"end":{"line":142,"column":55}},"line":142},"6":{"name":"(anonymous_6)","decl":{"start":{"line":145,"column":28},"end":{"line":145,"column":null}},"loc":{"start":{"line":146,"column":14},"end":{"line":146,"column":null}},"line":146},"7":{"name":"(anonymous_7)","decl":{"start":{"line":151,"column":7},"end":{"line":151,"column":19}},"loc":{"start":{"line":151,"column":19},"end":{"line":159,"column":9}},"line":151},"8":{"name":"(anonymous_8)","decl":{"start":{"line":153,"column":65},"end":{"line":153,"column":null}},"loc":{"start":{"line":153,"column":65},"end":{"line":153,"column":null}},"line":153},"9":{"name":"startCallbackServer","decl":{"start":{"line":215,"column":9},"end":{"line":215,"column":null}},"loc":{"start":{"line":217,"column":50},"end":{"line":247,"column":null}},"line":217},"10":{"name":"(anonymous_10)","decl":{"start":{"line":218,"column":13},"end":{"line":218,"column":22}},"loc":{"start":{"line":218,"column":42},"end":{"line":246,"column":3}},"line":218},"11":{"name":"attemptListen","decl":{"start":{"line":224,"column":13},"end":{"line":224,"column":27}},"loc":{"start":{"line":224,"column":41},"end":{"line":243,"column":null}},"line":224},"12":{"name":"(anonymous_12)","decl":{"start":{"line":225,"column":18},"end":{"line":225,"column":28}},"loc":{"start":{"line":225,"column":61},"end":{"line":231,"column":7}},"line":225},"13":{"name":"(anonymous_13)","decl":{"start":{"line":227,"column":17},"end":{"line":227,"column":29}},"loc":{"start":{"line":227,"column":29},"end":{"line":227,"column":45}},"line":227},"14":{"name":"(anonymous_14)","decl":{"start":{"line":233,"column":18},"end":{"line":233,"column":37}},"loc":{"start":{"line":233,"column":37},"end":{"line":240,"column":7}},"line":233}},"branchMap":{"0":{"loc":{"start":{"line":35,"column":18},"end":{"line":35,"column":null}},"type":"default-arg","locations":[{"start":{"line":35,"column":40},"end":{"line":35,"column":null}}],"line":35},"1":{"loc":{"start":{"line":38,"column":16},"end":{"line":38,"column":null}},"type":"binary-expr","locations":[{"start":{"line":38,"column":16},"end":{"line":38,"column":31}},{"start":{"line":38,"column":31},"end":{"line":38,"column":null}}],"line":38},"2":{"loc":{"start":{"line":48,"column":4},"end":{"line":50,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":4},"end":{"line":50,"column":null}},{"start":{},"end":{}}],"line":48},"3":{"loc":{"start":{"line":61,"column":4},"end":{"line":63,"column":null}},"type":"if","locations":[{"start":{"line":61,"column":4},"end":{"line":63,"column":null}},{"start":{},"end":{}}],"line":61},"4":{"loc":{"start":{"line":81,"column":8},"end":{"line":81,"column":null}},"type":"if","locations":[{"start":{"line":81,"column":8},"end":{"line":81,"column":null}},{"start":{},"end":{}}],"line":81},"5":{"loc":{"start":{"line":93,"column":35},"end":{"line":93,"column":54}},"type":"binary-expr","locations":[{"start":{"line":93,"column":35},"end":{"line":93,"column":50}},{"start":{"line":93,"column":50},"end":{"line":93,"column":54}}],"line":93},"6":{"loc":{"start":{"line":95,"column":8},"end":{"line":99,"column":null}},"type":"if","locations":[{"start":{"line":95,"column":8},"end":{"line":99,"column":null}},{"start":{},"end":{}}],"line":95},"7":{"loc":{"start":{"line":101,"column":30},"end":{"line":101,"column":null}},"type":"binary-expr","locations":[{"start":{"line":101,"column":30},"end":{"line":101,"column":70}},{"start":{"line":101,"column":70},"end":{"line":101,"column":null}}],"line":101},"8":{"loc":{"start":{"line":102,"column":21},"end":{"line":102,"column":null}},"type":"binary-expr","locations":[{"start":{"line":102,"column":21},"end":{"line":102,"column":60}},{"start":{"line":102,"column":60},"end":{"line":102,"column":null}}],"line":102},"9":{"loc":{"start":{"line":103,"column":22},"end":{"line":103,"column":null}},"type":"binary-expr","locations":[{"start":{"line":103,"column":22},"end":{"line":103,"column":62}},{"start":{"line":103,"column":62},"end":{"line":103,"column":null}}],"line":103},"10":{"loc":{"start":{"line":105,"column":8},"end":{"line":114,"column":null}},"type":"if","locations":[{"start":{"line":105,"column":8},"end":{"line":114,"column":null}},{"start":{},"end":{}}],"line":105},"11":{"loc":{"start":{"line":106,"column":30},"end":{"line":106,"column":null}},"type":"binary-expr","locations":[{"start":{"line":106,"column":30},"end":{"line":106,"column":82}},{"start":{"line":106,"column":82},"end":{"line":106,"column":null}}],"line":106},"12":{"loc":{"start":{"line":107,"column":10},"end":{"line":109,"column":null}},"type":"if","locations":[{"start":{"line":107,"column":10},"end":{"line":109,"column":null}},{"start":{},"end":{}}],"line":107},"13":{"loc":{"start":{"line":116,"column":8},"end":{"line":126,"column":null}},"type":"if","locations":[{"start":{"line":116,"column":8},"end":{"line":126,"column":null}},{"start":{},"end":{}}],"line":116},"14":{"loc":{"start":{"line":117,"column":10},"end":{"line":119,"column":null}},"type":"if","locations":[{"start":{"line":117,"column":10},"end":{"line":119,"column":null}},{"start":{},"end":{}}],"line":117},"15":{"loc":{"start":{"line":128,"column":8},"end":{"line":133,"column":null}},"type":"if","locations":[{"start":{"line":128,"column":8},"end":{"line":133,"column":null}},{"start":{},"end":{}}],"line":128},"16":{"loc":{"start":{"line":162,"column":4},"end":{"line":167,"column":null}},"type":"if","locations":[{"start":{"line":162,"column":4},"end":{"line":167,"column":null}},{"start":{},"end":{}}],"line":162},"17":{"loc":{"start":{"line":162,"column":8},"end":{"line":162,"column":76}},"type":"binary-expr","locations":[{"start":{"line":162,"column":8},"end":{"line":162,"column":31}},{"start":{"line":162,"column":31},"end":{"line":162,"column":51}},{"start":{"line":162,"column":51},"end":{"line":162,"column":76}}],"line":162},"18":{"loc":{"start":{"line":164,"column":15},"end":{"line":164,"column":null}},"type":"binary-expr","locations":[{"start":{"line":164,"column":15},"end":{"line":164,"column":35}},{"start":{"line":164,"column":35},"end":{"line":164,"column":null}}],"line":164},"19":{"loc":{"start":{"line":172,"column":4},"end":{"line":175,"column":null}},"type":"if","locations":[{"start":{"line":172,"column":4},"end":{"line":175,"column":null}},{"start":{},"end":{}}],"line":172},"20":{"loc":{"start":{"line":183,"column":6},"end":{"line":185,"column":null}},"type":"if","locations":[{"start":{"line":183,"column":6},"end":{"line":185,"column":null}},{"start":{},"end":{}}],"line":183},"21":{"loc":{"start":{"line":194,"column":6},"end":{"line":200,"column":null}},"type":"if","locations":[{"start":{"line":194,"column":6},"end":{"line":200,"column":null}},{"start":{},"end":{}}],"line":194},"22":{"loc":{"start":{"line":196,"column":8},"end":{"line":199,"column":null}},"type":"if","locations":[{"start":{"line":196,"column":8},"end":{"line":199,"column":null}},{"start":{},"end":{}}],"line":196},"23":{"loc":{"start":{"line":205,"column":13},"end":{"line":205,"column":null}},"type":"cond-expr","locations":[{"start":{"line":205,"column":38},"end":{"line":205,"column":54}},{"start":{"line":205,"column":54},"end":{"line":205,"column":null}}],"line":205},"24":{"loc":{"start":{"line":226,"column":8},"end":{"line":230,"column":null}},"type":"if","locations":[{"start":{"line":226,"column":8},"end":{"line":230,"column":null}},{"start":{"line":228,"column":15},"end":{"line":230,"column":null}}],"line":226},"25":{"loc":{"start":{"line":226,"column":12},"end":{"line":226,"column":76}},"type":"binary-expr","locations":[{"start":{"line":226,"column":12},"end":{"line":226,"column":43}},{"start":{"line":226,"column":43},"end":{"line":226,"column":76}}],"line":226},"26":{"loc":{"start":{"line":235,"column":8},"end":{"line":239,"column":null}},"type":"if","locations":[{"start":{"line":235,"column":8},"end":{"line":239,"column":null}},{"start":{"line":237,"column":15},"end":{"line":239,"column":null}}],"line":235},"27":{"loc":{"start":{"line":235,"column":12},"end":{"line":235,"column":52}},"type":"binary-expr","locations":[{"start":{"line":235,"column":12},"end":{"line":235,"column":23}},{"start":{"line":235,"column":23},"end":{"line":235,"column":52}}],"line":235}},"s":{"0":1,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0,"103":0,"104":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0},"b":{"0":[0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0,0],"18":[0,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0],"23":[0,0],"24":[0,0],"25":[0,0],"26":[0,0],"27":[0,0]},"meta":{"lastBranch":28,"lastFunction":15,"lastStatement":105,"seen":{"s:18:31:18:Infinity":0,"s:19:24:19:Infinity":1,"f:32:22:32:36":0,"s:37:6:37:Infinity":2,"b:35:40:35:Infinity":0,"s:38:16:38:Infinity":3,"b:38:16:38:31:38:31:38:Infinity":1,"s:40:8:40:Infinity":4,"s:41:24:41:Infinity":5,"s:42:16:42:Infinity":6,"s:44:2:208:Infinity":7,"s:45:29:45:Infinity":8,"s:46:24:46:Infinity":9,"b:48:4:50:Infinity:undefined:undefined:undefined:undefined":2,"s:48:4:50:Infinity":10,"s:49:6:49:Infinity":11,"s:53:10:59:Infinity":12,"b:61:4:63:Infinity:undefined:undefined:undefined:undefined":3,"s:61:4:63:Infinity":13,"s:62:6:62:Infinity":14,"s:66:23:160:Infinity":15,"f:66:33:66:Infinity":1,"s:72:21:72:Infinity":16,"s:73:22:73:Infinity":17,"s:75:12:90:Infinity":18,"f:75:12:75:27":2,"b:81:8:81:Infinity:undefined:undefined:undefined:undefined":4,"s:81:8:81:Infinity":19,"s:81:22:81:Infinity":20,"s:82:8:82:Infinity":21,"s:83:8:83:Infinity":22,"s:84:8:84:Infinity":23,"s:85:8:87:Infinity":24,"s:86:10:86:Infinity":25,"s:88:8:88:Infinity":26,"s:89:8:89:Infinity":27,"s:92:6:138:Infinity":28,"f:92:16:92:28":3,"s:93:27:93:Infinity":29,"b:93:35:93:50:93:50:93:54":5,"b:95:8:99:Infinity:undefined:undefined:undefined:undefined":6,"s:95:8:99:Infinity":30,"s:96:10:96:Infinity":31,"s:97:10:97:Infinity":32,"s:98:10:98:Infinity":33,"s:101:30:101:Infinity":34,"b:101:30:101:70:101:70:101:Infinity":7,"s:102:21:102:Infinity":35,"b:102:21:102:60:102:60:102:Infinity":8,"s:103:22:103:Infinity":36,"b:103:22:103:62:103:62:103:Infinity":9,"b:105:8:114:Infinity:undefined:undefined:undefined:undefined":10,"s:105:8:114:Infinity":37,"s:106:30:106:Infinity":38,"b:106:30:106:82:106:82:106:Infinity":11,"b:107:10:109:Infinity:undefined:undefined:undefined:undefined":12,"s:107:10:109:Infinity":39,"s:108:12:108:Infinity":40,"s:110:10:110:Infinity":41,"s:111:10:111:Infinity":42,"s:112:10:112:Infinity":43,"s:113:10:113:Infinity":44,"b:116:8:126:Infinity:undefined:undefined:undefined:undefined":13,"s:116:8:126:Infinity":45,"b:117:10:119:Infinity:undefined:undefined:undefined:undefined":14,"s:117:10:119:Infinity":46,"s:118:12:118:Infinity":47,"s:120:10:120:Infinity":48,"s:121:10:123:Infinity":49,"s:124:10:124:Infinity":50,"s:125:10:125:Infinity":51,"b:128:8:133:Infinity:undefined:undefined:undefined:undefined":15,"s:128:8:133:Infinity":52,"s:129:10:129:Infinity":53,"s:130:10:130:Infinity":54,"s:131:10:131:Infinity":55,"s:132:10:132:Infinity":56,"s:135:8:135:Infinity":57,"s:136:8:136:Infinity":58,"s:137:8:137:Infinity":59,"s:140:6:143:Infinity":60,"f:140:16:140:31":4,"s:141:8:141:Infinity":61,"s:142:8:142:Infinity":62,"f:142:18:142:33":5,"s:142:33:142:55":63,"s:145:28:148:Infinity":64,"f:145:28:145:Infinity":6,"s:146:14:146:Infinity":65,"s:151:6:159:Infinity":66,"f:151:7:151:19":7,"s:152:8:158:Infinity":67,"s:153:23:153:Infinity":68,"f:153:65:153:Infinity":8,"s:153:65:153:Infinity":69,"s:154:10:154:Infinity":70,"s:156:10:156:Infinity":71,"s:157:10:157:Infinity":72,"b:162:4:167:Infinity:undefined:undefined:undefined:undefined":16,"s:162:4:167:Infinity":73,"b:162:8:162:31:162:31:162:51:162:51:162:76":17,"s:163:6:166:Infinity":74,"b:164:15:164:35:164:35:164:Infinity":18,"s:170:24:170:Infinity":75,"b:172:4:175:Infinity:undefined:undefined:undefined:undefined":19,"s:172:4:175:Infinity":76,"s:173:6:173:Infinity":77,"s:174:6:174:Infinity":78,"s:177:4:202:Infinity":79,"s:178:26:181:Infinity":80,"b:183:6:185:Infinity:undefined:undefined:undefined:undefined":20,"s:183:6:185:Infinity":81,"s:184:8:184:Infinity":82,"s:187:6:192:Infinity":83,"b:194:6:200:Infinity:undefined:undefined:undefined:undefined":21,"s:194:6:200:Infinity":84,"s:195:8:195:Infinity":85,"b:196:8:199:Infinity:undefined:undefined:undefined:undefined":22,"s:196:8:199:Infinity":86,"s:197:10:197:Infinity":87,"s:198:10:198:Infinity":88,"s:201:6:201:Infinity":89,"s:204:4:207:Infinity":90,"b:205:38:205:54:205:54:205:Infinity":23,"f:215:9:215:Infinity":9,"s:218:2:246:Infinity":91,"f:218:13:218:22":10,"s:222:19:222:Infinity":92,"f:224:13:224:27":11,"s:225:6:231:Infinity":93,"f:225:18:225:28":12,"b:226:8:230:Infinity:228:15:230:Infinity":24,"s:226:8:230:Infinity":94,"b:226:12:226:43:226:43:226:76":25,"s:227:10:227:Infinity":95,"f:227:17:227:29":13,"s:227:29:227:45":96,"s:229:10:229:Infinity":97,"s:233:6:240:Infinity":98,"f:233:18:233:37":14,"s:234:24:234:Infinity":99,"b:235:8:239:Infinity:237:15:239:Infinity":26,"s:235:8:239:Infinity":100,"b:235:12:235:23:235:23:235:52":27,"s:236:10:236:Infinity":101,"s:238:10:238:Infinity":102,"s:242:6:242:Infinity":103,"s:245:4:245:Infinity":104}}} +,"/Users/marcus/berget-monorepo/cli/src/auth/oauth/token-refresh.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/oauth/token-refresh.ts","statementMap":{"0":{"start":{"line":13,"column":30},"end":{"line":20,"column":null}},"1":{"start":{"line":22,"column":20},"end":{"line":22,"column":null}},"2":{"start":{"line":23,"column":27},"end":{"line":23,"column":null}},"3":{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},"4":{"start":{"line":26,"column":33},"end":{"line":26,"column":null}},"5":{"start":{"line":27,"column":16},"end":{"line":27,"column":null}},"6":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"7":{"start":{"line":28,"column":47},"end":{"line":28,"column":null}},"8":{"start":{"line":29,"column":2},"end":{"line":29,"column":null}},"9":{"start":{"line":35,"column":25},"end":{"line":35,"column":null}},"10":{"start":{"line":41,"column":17},"end":{"line":41,"column":null}},"11":{"start":{"line":42,"column":2},"end":{"line":45,"column":null}},"12":{"start":{"line":43,"column":4},"end":{"line":43,"column":null}},"13":{"start":{"line":44,"column":4},"end":{"line":44,"column":null}},"14":{"start":{"line":47,"column":19},"end":{"line":47,"column":null}},"15":{"start":{"line":48,"column":2},"end":{"line":50,"column":null}},"16":{"start":{"line":49,"column":4},"end":{"line":49,"column":null}},"17":{"start":{"line":52,"column":18},"end":{"line":54,"column":null}},"18":{"start":{"line":53,"column":4},"end":{"line":53,"column":null}},"19":{"start":{"line":56,"column":2},"end":{"line":56,"column":null}},"20":{"start":{"line":57,"column":2},"end":{"line":57,"column":null}},"21":{"start":{"line":66,"column":20},"end":{"line":66,"column":null}},"22":{"start":{"line":67,"column":2},"end":{"line":67,"column":null}},"23":{"start":{"line":67,"column":33},"end":{"line":67,"column":null}},"24":{"start":{"line":69,"column":16},"end":{"line":69,"column":null}},"25":{"start":{"line":71,"column":2},"end":{"line":121,"column":null}},"26":{"start":{"line":72,"column":4},"end":{"line":120,"column":null}},"27":{"start":{"line":73,"column":21},"end":{"line":73,"column":null}},"28":{"start":{"line":76,"column":26},"end":{"line":76,"column":null}},"29":{"start":{"line":77,"column":27},"end":{"line":77,"column":null}},"30":{"start":{"line":78,"column":24},"end":{"line":78,"column":null}},"31":{"start":{"line":81,"column":12},"end":{"line":81,"column":null}},"32":{"start":{"line":82,"column":24},"end":{"line":82,"column":null}},"33":{"start":{"line":84,"column":38},"end":{"line":88,"column":null}},"34":{"start":{"line":90,"column":6},"end":{"line":90,"column":null}},"35":{"start":{"line":91,"column":6},"end":{"line":91,"column":null}},"36":{"start":{"line":95,"column":6},"end":{"line":100,"column":null}},"37":{"start":{"line":96,"column":8},"end":{"line":98,"column":null}},"38":{"start":{"line":97,"column":10},"end":{"line":97,"column":null}},"39":{"start":{"line":99,"column":8},"end":{"line":99,"column":null}},"40":{"start":{"line":102,"column":6},"end":{"line":111,"column":null}},"41":{"start":{"line":109,"column":8},"end":{"line":109,"column":null}},"42":{"start":{"line":110,"column":8},"end":{"line":110,"column":null}},"43":{"start":{"line":113,"column":6},"end":{"line":117,"column":null}},"44":{"start":{"line":114,"column":8},"end":{"line":114,"column":null}},"45":{"start":{"line":115,"column":8},"end":{"line":115,"column":null}},"46":{"start":{"line":116,"column":8},"end":{"line":116,"column":null}},"47":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"48":{"start":{"line":125,"column":2},"end":{"line":125,"column":null}},"49":{"start":{"line":125,"column":34},"end":{"line":125,"column":57}}},"fnMap":{"0":{"name":"isTransientError","decl":{"start":{"line":25,"column":9},"end":{"line":25,"column":26}},"loc":{"start":{"line":25,"column":51},"end":{"line":30,"column":null}},"line":25},"1":{"name":"refreshAccessToken","decl":{"start":{"line":37,"column":22},"end":{"line":37,"column":null}},"loc":{"start":{"line":40,"column":20},"end":{"line":58,"column":null}},"line":40},"2":{"name":"(anonymous_2)","decl":{"start":{"line":52,"column":48},"end":{"line":52,"column":62}},"loc":{"start":{"line":52,"column":62},"end":{"line":54,"column":3}},"line":52},"3":{"name":"doRefresh","decl":{"start":{"line":65,"column":15},"end":{"line":65,"column":25}},"loc":{"start":{"line":65,"column":90},"end":{"line":122,"column":null}},"line":65},"4":{"name":"sleep","decl":{"start":{"line":124,"column":9},"end":{"line":124,"column":15}},"loc":{"start":{"line":124,"column":42},"end":{"line":126,"column":null}},"line":124},"5":{"name":"(anonymous_5)","decl":{"start":{"line":125,"column":13},"end":{"line":125,"column":22}},"loc":{"start":{"line":125,"column":34},"end":{"line":125,"column":57}},"line":125}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},"type":"if","locations":[{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},{"start":{},"end":{}}],"line":28},"2":{"loc":{"start":{"line":28,"column":6},"end":{"line":28,"column":47}},"type":"binary-expr","locations":[{"start":{"line":28,"column":6},"end":{"line":28,"column":14}},{"start":{"line":28,"column":14},"end":{"line":28,"column":47}}],"line":28},"3":{"loc":{"start":{"line":42,"column":2},"end":{"line":45,"column":null}},"type":"if","locations":[{"start":{"line":42,"column":2},"end":{"line":45,"column":null}},{"start":{},"end":{}}],"line":42},"4":{"loc":{"start":{"line":48,"column":2},"end":{"line":50,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":2},"end":{"line":50,"column":null}},{"start":{},"end":{}}],"line":48},"5":{"loc":{"start":{"line":67,"column":2},"end":{"line":67,"column":null}},"type":"if","locations":[{"start":{"line":67,"column":2},"end":{"line":67,"column":null}},{"start":{},"end":{}}],"line":67},"6":{"loc":{"start":{"line":77,"column":27},"end":{"line":77,"column":null}},"type":"binary-expr","locations":[{"start":{"line":77,"column":27},"end":{"line":77,"column":51}},{"start":{"line":77,"column":51},"end":{"line":77,"column":null}}],"line":77},"7":{"loc":{"start":{"line":78,"column":24},"end":{"line":78,"column":null}},"type":"binary-expr","locations":[{"start":{"line":78,"column":24},"end":{"line":78,"column":45}},{"start":{"line":78,"column":45},"end":{"line":78,"column":null}}],"line":78},"8":{"loc":{"start":{"line":82,"column":24},"end":{"line":82,"column":null}},"type":"cond-expr","locations":[{"start":{"line":82,"column":43},"end":{"line":82,"column":58}},{"start":{"line":82,"column":58},"end":{"line":82,"column":null}}],"line":82},"9":{"loc":{"start":{"line":95,"column":6},"end":{"line":100,"column":null}},"type":"if","locations":[{"start":{"line":95,"column":6},"end":{"line":100,"column":null}},{"start":{},"end":{}}],"line":95},"10":{"loc":{"start":{"line":96,"column":8},"end":{"line":98,"column":null}},"type":"if","locations":[{"start":{"line":96,"column":8},"end":{"line":98,"column":null}},{"start":{},"end":{}}],"line":96},"11":{"loc":{"start":{"line":96,"column":12},"end":{"line":96,"column":93}},"type":"binary-expr","locations":[{"start":{"line":96,"column":12},"end":{"line":96,"column":47}},{"start":{"line":96,"column":47},"end":{"line":96,"column":71}},{"start":{"line":96,"column":71},"end":{"line":96,"column":93}}],"line":96},"12":{"loc":{"start":{"line":102,"column":6},"end":{"line":111,"column":null}},"type":"if","locations":[{"start":{"line":102,"column":6},"end":{"line":111,"column":null}},{"start":{},"end":{}}],"line":102},"13":{"loc":{"start":{"line":103,"column":8},"end":{"line":106,"column":null}},"type":"binary-expr","locations":[{"start":{"line":103,"column":8},"end":{"line":103,"column":null}},{"start":{"line":104,"column":9},"end":{"line":104,"column":null}},{"start":{"line":105,"column":10},"end":{"line":105,"column":null}},{"start":{"line":106,"column":10},"end":{"line":106,"column":null}}],"line":103},"14":{"loc":{"start":{"line":113,"column":6},"end":{"line":117,"column":null}},"type":"if","locations":[{"start":{"line":113,"column":6},"end":{"line":117,"column":null}},{"start":{},"end":{}}],"line":113},"15":{"loc":{"start":{"line":113,"column":10},"end":{"line":113,"column":64}},"type":"binary-expr","locations":[{"start":{"line":113,"column":10},"end":{"line":113,"column":37}},{"start":{"line":113,"column":37},"end":{"line":113,"column":64}}],"line":113}},"s":{"0":1,"1":1,"2":1,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":1,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0,0],"12":[0,0],"13":[0,0,0,0],"14":[0,0],"15":[0,0]},"meta":{"lastBranch":16,"lastFunction":6,"lastStatement":50,"seen":{"s:13:30:20:Infinity":0,"s:22:20:22:Infinity":1,"s:23:27:23:Infinity":2,"f:25:9:25:26":0,"b:26:2:26:Infinity:undefined:undefined:undefined:undefined":0,"s:26:2:26:Infinity":3,"s:26:33:26:Infinity":4,"s:27:16:27:Infinity":5,"b:28:2:28:Infinity:undefined:undefined:undefined:undefined":1,"s:28:2:28:Infinity":6,"b:28:6:28:14:28:14:28:47":2,"s:28:47:28:Infinity":7,"s:29:2:29:Infinity":8,"s:35:25:35:Infinity":9,"f:37:22:37:Infinity":1,"s:41:17:41:Infinity":10,"b:42:2:45:Infinity:undefined:undefined:undefined:undefined":3,"s:42:2:45:Infinity":11,"s:43:4:43:Infinity":12,"s:44:4:44:Infinity":13,"s:47:19:47:Infinity":14,"b:48:2:50:Infinity:undefined:undefined:undefined:undefined":4,"s:48:2:50:Infinity":15,"s:49:4:49:Infinity":16,"s:52:18:54:Infinity":17,"f:52:48:52:62":2,"s:53:4:53:Infinity":18,"s:56:2:56:Infinity":19,"s:57:2:57:Infinity":20,"f:65:15:65:25":3,"s:66:20:66:Infinity":21,"b:67:2:67:Infinity:undefined:undefined:undefined:undefined":5,"s:67:2:67:Infinity":22,"s:67:33:67:Infinity":23,"s:69:16:69:Infinity":24,"s:71:2:121:Infinity":25,"s:72:4:120:Infinity":26,"s:73:21:73:Infinity":27,"s:76:26:76:Infinity":28,"s:77:27:77:Infinity":29,"b:77:27:77:51:77:51:77:Infinity":6,"s:78:24:78:Infinity":30,"b:78:24:78:45:78:45:78:Infinity":7,"s:81:12:81:Infinity":31,"s:82:24:82:Infinity":32,"b:82:43:82:58:82:58:82:Infinity":8,"s:84:38:88:Infinity":33,"s:90:6:90:Infinity":34,"s:91:6:91:Infinity":35,"b:95:6:100:Infinity:undefined:undefined:undefined:undefined":9,"s:95:6:100:Infinity":36,"b:96:8:98:Infinity:undefined:undefined:undefined:undefined":10,"s:96:8:98:Infinity":37,"b:96:12:96:47:96:47:96:71:96:71:96:93":11,"s:97:10:97:Infinity":38,"s:99:8:99:Infinity":39,"b:102:6:111:Infinity:undefined:undefined:undefined:undefined":12,"s:102:6:111:Infinity":40,"b:103:8:103:Infinity:104:9:104:Infinity:105:10:105:Infinity:106:10:106:Infinity":13,"s:109:8:109:Infinity":41,"s:110:8:110:Infinity":42,"b:113:6:117:Infinity:undefined:undefined:undefined:undefined":14,"s:113:6:117:Infinity":43,"b:113:10:113:37:113:37:113:64":15,"s:114:8:114:Infinity":44,"s:115:8:115:Infinity":45,"s:116:8:116:Infinity":46,"s:119:6:119:Infinity":47,"f:124:9:124:15":4,"s:125:2:125:Infinity":48,"f:125:13:125:22":5,"s:125:34:125:57":49}}} +,"/Users/marcus/berget-monorepo/cli/src/auth/storage/token-store.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/storage/token-store.ts","statementMap":{"0":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"1":{"start":{"line":23,"column":4},"end":{"line":27,"column":null}},"2":{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},"3":{"start":{"line":32,"column":4},"end":{"line":44,"column":null}},"4":{"start":{"line":33,"column":6},"end":{"line":33,"column":null}},"5":{"start":{"line":35,"column":20},"end":{"line":35,"column":null}},"6":{"start":{"line":36,"column":6},"end":{"line":38,"column":null}},"7":{"start":{"line":37,"column":8},"end":{"line":37,"column":null}},"8":{"start":{"line":39,"column":6},"end":{"line":42,"column":null}},"9":{"start":{"line":43,"column":6},"end":{"line":43,"column":null}},"10":{"start":{"line":46,"column":4},"end":{"line":63,"column":null}},"11":{"start":{"line":47,"column":21},"end":{"line":47,"column":null}},"12":{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},"13":{"start":{"line":54,"column":8},"end":{"line":54,"column":null}},"14":{"start":{"line":56,"column":6},"end":{"line":56,"column":null}},"15":{"start":{"line":58,"column":6},"end":{"line":61,"column":null}},"16":{"start":{"line":62,"column":6},"end":{"line":62,"column":null}},"17":{"start":{"line":67,"column":22},"end":{"line":67,"column":null}},"18":{"start":{"line":68,"column":4},"end":{"line":72,"column":null}},"19":{"start":{"line":69,"column":6},"end":{"line":69,"column":null}},"20":{"start":{"line":73,"column":4},"end":{"line":73,"column":null}},"21":{"start":{"line":74,"column":4},"end":{"line":74,"column":null}},"22":{"start":{"line":79,"column":20},"end":{"line":79,"column":null}},"23":{"start":{"line":80,"column":2},"end":{"line":80,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":18,"column":2},"end":{"line":18,"column":14}},"loc":{"start":{"line":18,"column":33},"end":{"line":20,"column":null}},"line":18},"1":{"name":"clear","decl":{"start":{"line":22,"column":8},"end":{"line":22,"column":31}},"loc":{"start":{"line":22,"column":31},"end":{"line":28,"column":null}},"line":22},"2":{"name":"get","decl":{"start":{"line":30,"column":8},"end":{"line":30,"column":41}},"loc":{"start":{"line":30,"column":41},"end":{"line":64,"column":null}},"line":30},"3":{"name":"set","decl":{"start":{"line":66,"column":8},"end":{"line":66,"column":12}},"loc":{"start":{"line":66,"column":44},"end":{"line":75,"column":null}},"line":66},"4":{"name":"getDefaultTokenFilePath","decl":{"start":{"line":78,"column":9},"end":{"line":78,"column":43}},"loc":{"start":{"line":78,"column":43},"end":{"line":81,"column":null}},"line":78}},"branchMap":{"0":{"loc":{"start":{"line":19,"column":25},"end":{"line":19,"column":null}},"type":"binary-expr","locations":[{"start":{"line":19,"column":25},"end":{"line":19,"column":37}},{"start":{"line":19,"column":37},"end":{"line":19,"column":null}}],"line":19},"1":{"loc":{"start":{"line":36,"column":6},"end":{"line":38,"column":null}},"type":"if","locations":[{"start":{"line":36,"column":6},"end":{"line":38,"column":null}},{"start":{},"end":{}}],"line":36},"2":{"loc":{"start":{"line":40,"column":37},"end":{"line":40,"column":61}},"type":"binary-expr","locations":[{"start":{"line":40,"column":37},"end":{"line":40,"column":45}},{"start":{"line":40,"column":45},"end":{"line":40,"column":61}}],"line":40},"3":{"loc":{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},"type":"if","locations":[{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},{"start":{},"end":{}}],"line":49},"4":{"loc":{"start":{"line":50,"column":8},"end":{"line":52,"column":null}},"type":"binary-expr","locations":[{"start":{"line":50,"column":8},"end":{"line":50,"column":null}},{"start":{"line":51,"column":8},"end":{"line":51,"column":null}},{"start":{"line":52,"column":8},"end":{"line":52,"column":null}}],"line":50}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0,0]},"meta":{"lastBranch":5,"lastFunction":5,"lastStatement":24,"seen":{"f:18:2:18:14":0,"s:19:4:19:Infinity":0,"b:19:25:19:37:19:37:19:Infinity":0,"f:22:8:22:31":1,"s:23:4:27:Infinity":1,"s:24:6:24:Infinity":2,"f:30:8:30:41":2,"s:32:4:44:Infinity":3,"s:33:6:33:Infinity":4,"s:35:20:35:Infinity":5,"b:36:6:38:Infinity:undefined:undefined:undefined:undefined":1,"s:36:6:38:Infinity":6,"s:37:8:37:Infinity":7,"s:39:6:42:Infinity":8,"b:40:37:40:45:40:45:40:61":2,"s:43:6:43:Infinity":9,"s:46:4:63:Infinity":10,"s:47:21:47:Infinity":11,"b:49:6:55:Infinity:undefined:undefined:undefined:undefined":3,"s:49:6:55:Infinity":12,"b:50:8:50:Infinity:51:8:51:Infinity:52:8:52:Infinity":4,"s:54:8:54:Infinity":13,"s:56:6:56:Infinity":14,"s:58:6:61:Infinity":15,"s:62:6:62:Infinity":16,"f:66:8:66:12":3,"s:67:22:67:Infinity":17,"s:68:4:72:Infinity":18,"s:69:6:69:Infinity":19,"s:73:4:73:Infinity":20,"s:74:4:74:Infinity":21,"f:78:9:78:43":4,"s:79:20:79:Infinity":22,"s:80:2:80:Infinity":23}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/auth-sync.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/auth-sync.ts","statementMap":{"0":{"start":{"line":32,"column":6},"end":{"line":32,"column":null}},"1":{"start":{"line":32,"column":43},"end":{"line":32,"column":null}},"2":{"start":{"line":34,"column":24},"end":{"line":37,"column":null}},"3":{"start":{"line":35,"column":33},"end":{"line":35,"column":null}},"4":{"start":{"line":36,"column":27},"end":{"line":36,"column":null}},"5":{"start":{"line":39,"column":62},"end":{"line":42,"column":null}},"6":{"start":{"line":49,"column":54},"end":{"line":49,"column":null}},"7":{"start":{"line":51,"column":22},"end":{"line":51,"column":null}},"8":{"start":{"line":53,"column":2},"end":{"line":68,"column":null}},"9":{"start":{"line":54,"column":19},"end":{"line":60,"column":null}},"10":{"start":{"line":62,"column":4},"end":{"line":64,"column":null}},"11":{"start":{"line":63,"column":6},"end":{"line":63,"column":null}},"12":{"start":{"line":66,"column":9},"end":{"line":68,"column":null}},"13":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"14":{"start":{"line":70,"column":2},"end":{"line":72,"column":null}},"15":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"16":{"start":{"line":75,"column":8},"end":{"line":75,"column":null}},"17":{"start":{"line":79,"column":2},"end":{"line":94,"column":null}},"18":{"start":{"line":80,"column":14},"end":{"line":80,"column":null}},"19":{"start":{"line":81,"column":4},"end":{"line":81,"column":null}},"20":{"start":{"line":82,"column":4},"end":{"line":88,"column":null}},"21":{"start":{"line":83,"column":6},"end":{"line":83,"column":null}},"22":{"start":{"line":84,"column":6},"end":{"line":84,"column":null}},"23":{"start":{"line":86,"column":6},"end":{"line":86,"column":null}},"24":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"25":{"start":{"line":89,"column":4},"end":{"line":92,"column":null}},"26":{"start":{"line":93,"column":4},"end":{"line":93,"column":null}},"27":{"start":{"line":97,"column":8},"end":{"line":97,"column":null}},"28":{"start":{"line":99,"column":2},"end":{"line":140,"column":null}},"29":{"start":{"line":101,"column":19},"end":{"line":107,"column":null}},"30":{"start":{"line":109,"column":4},"end":{"line":120,"column":null}},"31":{"start":{"line":110,"column":16},"end":{"line":110,"column":null}},"32":{"start":{"line":111,"column":6},"end":{"line":111,"column":null}},"33":{"start":{"line":112,"column":6},"end":{"line":118,"column":null}},"34":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"35":{"start":{"line":114,"column":8},"end":{"line":114,"column":null}},"36":{"start":{"line":116,"column":8},"end":{"line":116,"column":null}},"37":{"start":{"line":117,"column":8},"end":{"line":117,"column":null}},"38":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"39":{"start":{"line":123,"column":14},"end":{"line":123,"column":null}},"40":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"41":{"start":{"line":125,"column":4},"end":{"line":139,"column":null}},"42":{"start":{"line":126,"column":22},"end":{"line":129,"column":null}},"43":{"start":{"line":130,"column":6},"end":{"line":130,"column":null}},"44":{"start":{"line":131,"column":6},"end":{"line":131,"column":null}},"45":{"start":{"line":132,"column":6},"end":{"line":132,"column":null}},"46":{"start":{"line":134,"column":6},"end":{"line":134,"column":null}},"47":{"start":{"line":135,"column":6},"end":{"line":138,"column":null}},"48":{"start":{"line":143,"column":23},"end":{"line":146,"column":null}},"49":{"start":{"line":148,"column":2},"end":{"line":166,"column":null}},"50":{"start":{"line":149,"column":14},"end":{"line":149,"column":null}},"51":{"start":{"line":150,"column":4},"end":{"line":150,"column":null}},"52":{"start":{"line":151,"column":4},"end":{"line":165,"column":null}},"53":{"start":{"line":152,"column":22},"end":{"line":155,"column":null}},"54":{"start":{"line":156,"column":6},"end":{"line":156,"column":null}},"55":{"start":{"line":157,"column":6},"end":{"line":157,"column":null}},"56":{"start":{"line":158,"column":6},"end":{"line":158,"column":null}},"57":{"start":{"line":160,"column":6},"end":{"line":160,"column":null}},"58":{"start":{"line":161,"column":6},"end":{"line":164,"column":null}},"59":{"start":{"line":169,"column":2},"end":{"line":172,"column":null}},"60":{"start":{"line":173,"column":2},"end":{"line":173,"column":null}},"61":{"start":{"line":179,"column":52},"end":{"line":179,"column":null}},"62":{"start":{"line":181,"column":34},"end":{"line":181,"column":null}},"63":{"start":{"line":183,"column":2},"end":{"line":185,"column":null}},"64":{"start":{"line":184,"column":4},"end":{"line":184,"column":null}},"65":{"start":{"line":187,"column":2},"end":{"line":187,"column":null}},"66":{"start":{"line":189,"column":12},"end":{"line":189,"column":null}},"67":{"start":{"line":190,"column":2},"end":{"line":190,"column":null}},"68":{"start":{"line":192,"column":22},"end":{"line":194,"column":null}},"69":{"start":{"line":195,"column":2},"end":{"line":202,"column":null}},"70":{"start":{"line":196,"column":4},"end":{"line":196,"column":null}},"71":{"start":{"line":197,"column":4},"end":{"line":200,"column":null}},"72":{"start":{"line":201,"column":4},"end":{"line":201,"column":null}},"73":{"start":{"line":204,"column":2},"end":{"line":204,"column":null}},"74":{"start":{"line":206,"column":8},"end":{"line":206,"column":null}},"75":{"start":{"line":207,"column":2},"end":{"line":211,"column":null}},"76":{"start":{"line":208,"column":4},"end":{"line":208,"column":null}},"77":{"start":{"line":209,"column":4},"end":{"line":209,"column":null}},"78":{"start":{"line":210,"column":4},"end":{"line":210,"column":null}},"79":{"start":{"line":213,"column":2},"end":{"line":217,"column":null}},"80":{"start":{"line":225,"column":18},"end":{"line":225,"column":null}},"81":{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},"82":{"start":{"line":226,"column":16},"end":{"line":226,"column":null}},"83":{"start":{"line":227,"column":2},"end":{"line":232,"column":null}},"84":{"start":{"line":228,"column":19},"end":{"line":228,"column":null}},"85":{"start":{"line":229,"column":4},"end":{"line":229,"column":null}},"86":{"start":{"line":231,"column":4},"end":{"line":231,"column":null}},"87":{"start":{"line":236,"column":18},"end":{"line":236,"column":null}},"88":{"start":{"line":237,"column":2},"end":{"line":237,"column":null}},"89":{"start":{"line":237,"column":16},"end":{"line":237,"column":null}},"90":{"start":{"line":239,"column":2},"end":{"line":247,"column":null}},"91":{"start":{"line":240,"column":4},"end":{"line":240,"column":null}},"92":{"start":{"line":242,"column":4},"end":{"line":245,"column":null}},"93":{"start":{"line":246,"column":4},"end":{"line":246,"column":null}},"94":{"start":{"line":248,"column":2},"end":{"line":260,"column":null}},"95":{"start":{"line":250,"column":10},"end":{"line":250,"column":null}},"96":{"start":{"line":251,"column":4},"end":{"line":254,"column":null}},"97":{"start":{"line":253,"column":6},"end":{"line":253,"column":null}},"98":{"start":{"line":255,"column":4},"end":{"line":259,"column":null}},"99":{"start":{"line":261,"column":2},"end":{"line":261,"column":null}},"100":{"start":{"line":270,"column":19},"end":{"line":270,"column":null}},"101":{"start":{"line":271,"column":42},"end":{"line":271,"column":null}},"102":{"start":{"line":273,"column":18},"end":{"line":273,"column":null}},"103":{"start":{"line":274,"column":2},"end":{"line":280,"column":null}},"104":{"start":{"line":275,"column":4},"end":{"line":279,"column":null}},"105":{"start":{"line":276,"column":6},"end":{"line":276,"column":null}},"106":{"start":{"line":278,"column":6},"end":{"line":278,"column":null}},"107":{"start":{"line":282,"column":18},"end":{"line":288,"column":null}},"108":{"start":{"line":290,"column":2},"end":{"line":290,"column":null}},"109":{"start":{"line":291,"column":2},"end":{"line":291,"column":null}},"110":{"start":{"line":300,"column":19},"end":{"line":300,"column":null}},"111":{"start":{"line":301,"column":42},"end":{"line":301,"column":null}},"112":{"start":{"line":303,"column":18},"end":{"line":303,"column":null}},"113":{"start":{"line":304,"column":2},"end":{"line":310,"column":null}},"114":{"start":{"line":305,"column":4},"end":{"line":309,"column":null}},"115":{"start":{"line":306,"column":6},"end":{"line":306,"column":null}},"116":{"start":{"line":308,"column":6},"end":{"line":308,"column":null}},"117":{"start":{"line":313,"column":8},"end":{"line":313,"column":null}},"118":{"start":{"line":315,"column":18},"end":{"line":323,"column":null}},"119":{"start":{"line":325,"column":2},"end":{"line":325,"column":null}},"120":{"start":{"line":326,"column":2},"end":{"line":326,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":32,"column":6},"end":{"line":32,"column":23}},"loc":{"start":{"line":32,"column":43},"end":{"line":32,"column":null}},"line":32},"1":{"name":"(anonymous_1)","decl":{"start":{"line":35,"column":2},"end":{"line":35,"column":13}},"loc":{"start":{"line":35,"column":33},"end":{"line":35,"column":null}},"line":35},"2":{"name":"(anonymous_2)","decl":{"start":{"line":36,"column":2},"end":{"line":36,"column":7}},"loc":{"start":{"line":36,"column":27},"end":{"line":36,"column":null}},"line":36},"3":{"name":"configureAuth","decl":{"start":{"line":44,"column":22},"end":{"line":44,"column":null}},"loc":{"start":{"line":48,"column":23},"end":{"line":174,"column":null}},"line":48},"4":{"name":"ensureCliAuth","decl":{"start":{"line":176,"column":22},"end":{"line":176,"column":null}},"loc":{"start":{"line":178,"column":27},"end":{"line":218,"column":null}},"line":178},"5":{"name":"isToolAuthenticated","decl":{"start":{"line":220,"column":22},"end":{"line":220,"column":null}},"loc":{"start":{"line":224,"column":20},"end":{"line":233,"column":null}},"line":224},"6":{"name":"readCliAuth","decl":{"start":{"line":235,"column":22},"end":{"line":235,"column":34}},"loc":{"start":{"line":235,"column":94},"end":{"line":262,"column":null}},"line":235},"7":{"name":"syncApiKeyToTool","decl":{"start":{"line":264,"column":22},"end":{"line":264,"column":null}},"loc":{"start":{"line":269,"column":17},"end":{"line":292,"column":null}},"line":269},"8":{"name":"syncOAuthToTool","decl":{"start":{"line":294,"column":22},"end":{"line":294,"column":null}},"loc":{"start":{"line":299,"column":17},"end":{"line":327,"column":null}},"line":299}},"branchMap":{"0":{"loc":{"start":{"line":53,"column":2},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":2},"end":{"line":68,"column":null}},{"start":{"line":66,"column":9},"end":{"line":68,"column":null}}],"line":53},"1":{"loc":{"start":{"line":55,"column":61},"end":{"line":55,"column":101}},"type":"cond-expr","locations":[{"start":{"line":55,"column":83},"end":{"line":55,"column":96}},{"start":{"line":55,"column":96},"end":{"line":55,"column":101}}],"line":55},"2":{"loc":{"start":{"line":62,"column":4},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":62,"column":4},"end":{"line":64,"column":null}},{"start":{},"end":{}}],"line":62},"3":{"loc":{"start":{"line":66,"column":9},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":66,"column":9},"end":{"line":68,"column":null}},{"start":{},"end":{}}],"line":66},"4":{"loc":{"start":{"line":70,"column":2},"end":{"line":72,"column":null}},"type":"if","locations":[{"start":{"line":70,"column":2},"end":{"line":72,"column":null}},{"start":{},"end":{}}],"line":70},"5":{"loc":{"start":{"line":79,"column":2},"end":{"line":94,"column":null}},"type":"if","locations":[{"start":{"line":79,"column":2},"end":{"line":94,"column":null}},{"start":{},"end":{}}],"line":79},"6":{"loc":{"start":{"line":99,"column":2},"end":{"line":140,"column":null}},"type":"if","locations":[{"start":{"line":99,"column":2},"end":{"line":140,"column":null}},{"start":{},"end":{}}],"line":99},"7":{"loc":{"start":{"line":109,"column":4},"end":{"line":120,"column":null}},"type":"if","locations":[{"start":{"line":109,"column":4},"end":{"line":120,"column":null}},{"start":{},"end":{}}],"line":109},"8":{"loc":{"start":{"line":128,"column":17},"end":{"line":128,"column":57}},"type":"cond-expr","locations":[{"start":{"line":128,"column":39},"end":{"line":128,"column":52}},{"start":{"line":128,"column":52},"end":{"line":128,"column":57}}],"line":128},"9":{"loc":{"start":{"line":136,"column":8},"end":{"line":137,"column":null}},"type":"binary-expr","locations":[{"start":{"line":136,"column":8},"end":{"line":136,"column":null}},{"start":{"line":137,"column":10},"end":{"line":137,"column":null}}],"line":136},"10":{"loc":{"start":{"line":148,"column":2},"end":{"line":166,"column":null}},"type":"if","locations":[{"start":{"line":148,"column":2},"end":{"line":166,"column":null}},{"start":{},"end":{}}],"line":148},"11":{"loc":{"start":{"line":154,"column":17},"end":{"line":154,"column":57}},"type":"cond-expr","locations":[{"start":{"line":154,"column":39},"end":{"line":154,"column":52}},{"start":{"line":154,"column":52},"end":{"line":154,"column":57}}],"line":154},"12":{"loc":{"start":{"line":162,"column":8},"end":{"line":163,"column":null}},"type":"binary-expr","locations":[{"start":{"line":162,"column":8},"end":{"line":162,"column":null}},{"start":{"line":163,"column":10},"end":{"line":163,"column":null}}],"line":162},"13":{"loc":{"start":{"line":183,"column":2},"end":{"line":185,"column":null}},"type":"if","locations":[{"start":{"line":183,"column":2},"end":{"line":185,"column":null}},{"start":{},"end":{}}],"line":183},"14":{"loc":{"start":{"line":183,"column":6},"end":{"line":183,"column":54}},"type":"binary-expr","locations":[{"start":{"line":183,"column":6},"end":{"line":183,"column":17}},{"start":{"line":183,"column":17},"end":{"line":183,"column":54}}],"line":183},"15":{"loc":{"start":{"line":195,"column":2},"end":{"line":202,"column":null}},"type":"if","locations":[{"start":{"line":195,"column":2},"end":{"line":202,"column":null}},{"start":{},"end":{}}],"line":195},"16":{"loc":{"start":{"line":198,"column":9},"end":{"line":198,"column":66}},"type":"binary-expr","locations":[{"start":{"line":198,"column":9},"end":{"line":198,"column":30}},{"start":{"line":198,"column":30},"end":{"line":198,"column":66}}],"line":198},"17":{"loc":{"start":{"line":207,"column":2},"end":{"line":211,"column":null}},"type":"if","locations":[{"start":{"line":207,"column":2},"end":{"line":211,"column":null}},{"start":{},"end":{}}],"line":207},"18":{"loc":{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},"type":"if","locations":[{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},{"start":{},"end":{}}],"line":226},"19":{"loc":{"start":{"line":229,"column":11},"end":{"line":229,"column":null}},"type":"binary-expr","locations":[{"start":{"line":229,"column":11},"end":{"line":229,"column":48}},{"start":{"line":229,"column":48},"end":{"line":229,"column":null}}],"line":229},"20":{"loc":{"start":{"line":237,"column":2},"end":{"line":237,"column":null}},"type":"if","locations":[{"start":{"line":237,"column":2},"end":{"line":237,"column":null}},{"start":{},"end":{}}],"line":237},"21":{"loc":{"start":{"line":248,"column":2},"end":{"line":260,"column":null}},"type":"if","locations":[{"start":{"line":248,"column":2},"end":{"line":260,"column":null}},{"start":{},"end":{}}],"line":248},"22":{"loc":{"start":{"line":248,"column":6},"end":{"line":248,"column":51}},"type":"binary-expr","locations":[{"start":{"line":248,"column":6},"end":{"line":248,"column":29}},{"start":{"line":248,"column":29},"end":{"line":248,"column":51}}],"line":248},"23":{"loc":{"start":{"line":251,"column":4},"end":{"line":254,"column":null}},"type":"if","locations":[{"start":{"line":251,"column":4},"end":{"line":254,"column":null}},{"start":{},"end":{}}],"line":251},"24":{"loc":{"start":{"line":274,"column":2},"end":{"line":280,"column":null}},"type":"if","locations":[{"start":{"line":274,"column":2},"end":{"line":280,"column":null}},{"start":{},"end":{}}],"line":274},"25":{"loc":{"start":{"line":304,"column":2},"end":{"line":310,"column":null}},"type":"if","locations":[{"start":{"line":304,"column":2},"end":{"line":310,"column":null}},{"start":{},"end":{}}],"line":304}},"s":{"0":1,"1":46,"2":1,"3":24,"4":15,"5":1,"6":36,"7":36,"8":36,"9":1,"10":1,"11":1,"12":35,"13":3,"14":35,"15":32,"16":3,"17":3,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":3,"28":3,"29":2,"30":2,"31":2,"32":2,"33":2,"34":2,"35":2,"36":0,"37":0,"38":2,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":1,"49":1,"50":1,"51":1,"52":1,"53":1,"54":1,"55":1,"56":1,"57":0,"58":0,"59":0,"60":0,"61":46,"62":46,"63":46,"64":2,"65":44,"66":44,"67":44,"68":44,"69":44,"70":43,"71":43,"72":43,"73":1,"74":1,"75":1,"76":0,"77":0,"78":0,"79":1,"80":36,"81":36,"82":35,"83":1,"84":1,"85":1,"86":0,"87":46,"88":46,"89":44,"90":2,"91":2,"92":0,"93":0,"94":2,"95":2,"96":2,"97":0,"98":2,"99":0,"100":1,"101":1,"102":1,"103":1,"104":0,"105":0,"106":0,"107":1,"108":1,"109":1,"110":2,"111":2,"112":2,"113":2,"114":0,"115":0,"116":0,"117":2,"118":2,"119":2,"120":2},"f":{"0":46,"1":24,"2":15,"3":36,"4":46,"5":36,"6":46,"7":1,"8":2},"b":{"0":[1,35],"1":[1,0],"2":[1,0],"3":[3,32],"4":[32,3],"5":[0,3],"6":[2,1],"7":[2,0],"8":[0,0],"9":[0,0],"10":[1,0],"11":[0,1],"12":[0,0],"13":[2,44],"14":[46,2],"15":[43,1],"16":[43,0],"17":[0,1],"18":[35,1],"19":[1,1],"20":[44,2],"21":[2,0],"22":[2,2],"23":[0,2],"24":[0,1],"25":[0,2]},"meta":{"lastBranch":26,"lastFunction":9,"lastStatement":121,"seen":{"s:32:6:32:Infinity":0,"f:32:6:32:23":0,"s:32:43:32:Infinity":1,"s:34:24:37:Infinity":2,"f:35:2:35:13":1,"s:35:33:35:Infinity":3,"f:36:2:36:7":2,"s:36:27:36:Infinity":4,"s:39:62:42:Infinity":5,"f:44:22:44:Infinity":3,"s:49:54:49:Infinity":6,"s:51:22:51:Infinity":7,"b:53:2:68:Infinity:66:9:68:Infinity":0,"s:53:2:68:Infinity":8,"s:54:19:60:Infinity":9,"b:55:83:55:96:55:96:55:101":1,"b:62:4:64:Infinity:undefined:undefined:undefined:undefined":2,"s:62:4:64:Infinity":10,"s:63:6:63:Infinity":11,"b:66:9:68:Infinity:undefined:undefined:undefined:undefined":3,"s:66:9:68:Infinity":12,"s:67:4:67:Infinity":13,"b:70:2:72:Infinity:undefined:undefined:undefined:undefined":4,"s:70:2:72:Infinity":14,"s:71:4:71:Infinity":15,"s:75:8:75:Infinity":16,"b:79:2:94:Infinity:undefined:undefined:undefined:undefined":5,"s:79:2:94:Infinity":17,"s:80:14:80:Infinity":18,"s:81:4:81:Infinity":19,"s:82:4:88:Infinity":20,"s:83:6:83:Infinity":21,"s:84:6:84:Infinity":22,"s:86:6:86:Infinity":23,"s:87:6:87:Infinity":24,"s:89:4:92:Infinity":25,"s:93:4:93:Infinity":26,"s:97:8:97:Infinity":27,"b:99:2:140:Infinity:undefined:undefined:undefined:undefined":6,"s:99:2:140:Infinity":28,"s:101:19:107:Infinity":29,"b:109:4:120:Infinity:undefined:undefined:undefined:undefined":7,"s:109:4:120:Infinity":30,"s:110:16:110:Infinity":31,"s:111:6:111:Infinity":32,"s:112:6:118:Infinity":33,"s:113:8:113:Infinity":34,"s:114:8:114:Infinity":35,"s:116:8:116:Infinity":36,"s:117:8:117:Infinity":37,"s:119:6:119:Infinity":38,"s:123:14:123:Infinity":39,"s:124:4:124:Infinity":40,"s:125:4:139:Infinity":41,"s:126:22:129:Infinity":42,"b:128:39:128:52:128:52:128:57":8,"s:130:6:130:Infinity":43,"s:131:6:131:Infinity":44,"s:132:6:132:Infinity":45,"s:134:6:134:Infinity":46,"s:135:6:138:Infinity":47,"b:136:8:136:Infinity:137:10:137:Infinity":9,"s:143:23:146:Infinity":48,"b:148:2:166:Infinity:undefined:undefined:undefined:undefined":10,"s:148:2:166:Infinity":49,"s:149:14:149:Infinity":50,"s:150:4:150:Infinity":51,"s:151:4:165:Infinity":52,"s:152:22:155:Infinity":53,"b:154:39:154:52:154:52:154:57":11,"s:156:6:156:Infinity":54,"s:157:6:157:Infinity":55,"s:158:6:158:Infinity":56,"s:160:6:160:Infinity":57,"s:161:6:164:Infinity":58,"b:162:8:162:Infinity:163:10:163:Infinity":12,"s:169:2:172:Infinity":59,"s:173:2:173:Infinity":60,"f:176:22:176:Infinity":4,"s:179:52:179:Infinity":61,"s:181:34:181:Infinity":62,"b:183:2:185:Infinity:undefined:undefined:undefined:undefined":13,"s:183:2:185:Infinity":63,"b:183:6:183:17:183:17:183:54":14,"s:184:4:184:Infinity":64,"s:187:2:187:Infinity":65,"s:189:12:189:Infinity":66,"s:190:2:190:Infinity":67,"s:192:22:194:Infinity":68,"b:195:2:202:Infinity:undefined:undefined:undefined:undefined":15,"s:195:2:202:Infinity":69,"s:196:4:196:Infinity":70,"s:197:4:200:Infinity":71,"b:198:9:198:30:198:30:198:66":16,"s:201:4:201:Infinity":72,"s:204:2:204:Infinity":73,"s:206:8:206:Infinity":74,"b:207:2:211:Infinity:undefined:undefined:undefined:undefined":17,"s:207:2:211:Infinity":75,"s:208:4:208:Infinity":76,"s:209:4:209:Infinity":77,"s:210:4:210:Infinity":78,"s:213:2:217:Infinity":79,"f:220:22:220:Infinity":5,"s:225:18:225:Infinity":80,"b:226:2:226:Infinity:undefined:undefined:undefined:undefined":18,"s:226:2:226:Infinity":81,"s:226:16:226:Infinity":82,"s:227:2:232:Infinity":83,"s:228:19:228:Infinity":84,"s:229:4:229:Infinity":85,"b:229:11:229:48:229:48:229:Infinity":19,"s:231:4:231:Infinity":86,"f:235:22:235:34":6,"s:236:18:236:Infinity":87,"b:237:2:237:Infinity:undefined:undefined:undefined:undefined":20,"s:237:2:237:Infinity":88,"s:237:16:237:Infinity":89,"s:239:2:247:Infinity":90,"s:240:4:240:Infinity":91,"s:242:4:245:Infinity":92,"s:246:4:246:Infinity":93,"b:248:2:260:Infinity:undefined:undefined:undefined:undefined":21,"s:248:2:260:Infinity":94,"b:248:6:248:29:248:29:248:51":22,"s:250:10:250:Infinity":95,"b:251:4:254:Infinity:undefined:undefined:undefined:undefined":23,"s:251:4:254:Infinity":96,"s:253:6:253:Infinity":97,"s:255:4:259:Infinity":98,"s:261:2:261:Infinity":99,"f:264:22:264:Infinity":7,"s:270:19:270:Infinity":100,"s:271:42:271:Infinity":101,"s:273:18:273:Infinity":102,"b:274:2:280:Infinity:undefined:undefined:undefined:undefined":24,"s:274:2:280:Infinity":103,"s:275:4:279:Infinity":104,"s:276:6:276:Infinity":105,"s:278:6:278:Infinity":106,"s:282:18:288:Infinity":107,"s:290:2:290:Infinity":108,"s:291:2:291:Infinity":109,"f:294:22:294:Infinity":8,"s:300:19:300:Infinity":110,"s:301:42:301:Infinity":111,"s:303:18:303:Infinity":112,"b:304:2:310:Infinity:undefined:undefined:undefined:undefined":25,"s:304:2:310:Infinity":113,"s:305:4:309:Infinity":114,"s:306:6:306:Infinity":115,"s:308:6:308:Infinity":116,"s:313:8:313:Infinity":117,"s:315:18:323:Infinity":118,"s:325:2:325:Infinity":119,"s:326:2:326:Infinity":120}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/errors.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/errors.ts","statementMap":{"0":{"start":{"line":3,"column":4},"end":{"line":3,"column":null}},"1":{"start":{"line":4,"column":4},"end":{"line":4,"column":null}},"2":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"3":{"start":{"line":10,"column":20},"end":{"line":10,"column":null}},"4":{"start":{"line":11,"column":20},"end":{"line":11,"column":null}},"5":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"6":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"7":{"start":{"line":21,"column":4},"end":{"line":21,"column":null}},"8":{"start":{"line":27,"column":4},"end":{"line":27,"column":null}},"9":{"start":{"line":26,"column":30},"end":{"line":26,"column":46}},"10":{"start":{"line":28,"column":4},"end":{"line":28,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":2,"column":2},"end":{"line":2,"column":16}},"loc":{"start":{"line":2,"column":16},"end":{"line":5,"column":null}},"line":2},"1":{"name":"constructor","decl":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"loc":{"start":{"line":12,"column":4},"end":{"line":15,"column":null}},"line":12},"2":{"name":"constructor","decl":{"start":{"line":19,"column":2},"end":{"line":19,"column":14}},"loc":{"start":{"line":19,"column":31},"end":{"line":22,"column":null}},"line":19},"3":{"name":"constructor","decl":{"start":{"line":26,"column":2},"end":{"line":26,"column":14}},"loc":{"start":{"line":26,"column":46},"end":{"line":29,"column":null}},"line":26}},"branchMap":{},"s":{"0":6,"1":6,"2":2,"3":2,"4":2,"5":2,"6":5,"7":5,"8":1,"9":1,"10":1},"f":{"0":6,"1":2,"2":5,"3":1},"b":{},"meta":{"lastBranch":0,"lastFunction":4,"lastStatement":11,"seen":{"f:2:2:2:16":0,"s:3:4:3:Infinity":0,"s:4:4:4:Infinity":1,"f:9:2:9:Infinity":1,"s:13:4:13:Infinity":2,"s:10:20:10:Infinity":3,"s:11:20:11:Infinity":4,"s:14:4:14:Infinity":5,"f:19:2:19:14":2,"s:20:4:20:Infinity":6,"s:21:4:21:Infinity":7,"f:26:2:26:14":3,"s:27:4:27:Infinity":8,"s:26:30:26:46":9,"s:28:4:28:Infinity":10}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/init.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/init.ts","statementMap":{"0":{"start":{"line":42,"column":2},"end":{"line":52,"column":null}},"1":{"start":{"line":43,"column":4},"end":{"line":43,"column":null}},"2":{"start":{"line":44,"column":4},"end":{"line":44,"column":null}},"3":{"start":{"line":46,"column":4},"end":{"line":46,"column":null}},"4":{"start":{"line":46,"column":41},"end":{"line":46,"column":null}},"5":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"6":{"start":{"line":47,"column":37},"end":{"line":47,"column":null}},"7":{"start":{"line":48,"column":4},"end":{"line":49,"column":null}},"8":{"start":{"line":49,"column":6},"end":{"line":49,"column":null}},"9":{"start":{"line":50,"column":4},"end":{"line":50,"column":null}},"10":{"start":{"line":50,"column":45},"end":{"line":50,"column":null}},"11":{"start":{"line":51,"column":4},"end":{"line":51,"column":null}},"12":{"start":{"line":56,"column":89},"end":{"line":56,"column":null}},"13":{"start":{"line":58,"column":2},"end":{"line":58,"column":null}},"14":{"start":{"line":59,"column":2},"end":{"line":62,"column":null}},"15":{"start":{"line":64,"column":18},"end":{"line":64,"column":null}},"16":{"start":{"line":66,"column":18},"end":{"line":66,"column":null}},"17":{"start":{"line":67,"column":18},"end":{"line":67,"column":null}},"18":{"start":{"line":69,"column":15},"end":{"line":84,"column":null}},"19":{"start":{"line":87,"column":20},"end":{"line":87,"column":null}},"20":{"start":{"line":88,"column":23},"end":{"line":88,"column":null}},"21":{"start":{"line":90,"column":2},"end":{"line":125,"column":null}},"22":{"start":{"line":93,"column":4},"end":{"line":97,"column":null}},"23":{"start":{"line":94,"column":6},"end":{"line":96,"column":null}},"24":{"start":{"line":99,"column":19},"end":{"line":99,"column":null}},"25":{"start":{"line":101,"column":4},"end":{"line":103,"column":null}},"26":{"start":{"line":102,"column":6},"end":{"line":102,"column":null}},"27":{"start":{"line":105,"column":4},"end":{"line":120,"column":null}},"28":{"start":{"line":107,"column":22},"end":{"line":107,"column":null}},"29":{"start":{"line":108,"column":6},"end":{"line":119,"column":null}},"30":{"start":{"line":109,"column":8},"end":{"line":109,"column":null}},"31":{"start":{"line":111,"column":29},"end":{"line":111,"column":null}},"32":{"start":{"line":112,"column":8},"end":{"line":112,"column":null}},"33":{"start":{"line":112,"column":37},"end":{"line":112,"column":null}},"34":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"35":{"start":{"line":113,"column":41},"end":{"line":113,"column":null}},"36":{"start":{"line":114,"column":8},"end":{"line":118,"column":null}},"37":{"start":{"line":116,"column":29},"end":{"line":116,"column":null}},"38":{"start":{"line":117,"column":10},"end":{"line":117,"column":null}},"39":{"start":{"line":122,"column":4},"end":{"line":124,"column":null}},"40":{"start":{"line":123,"column":6},"end":{"line":123,"column":null}},"41":{"start":{"line":127,"column":16},"end":{"line":156,"column":null}},"42":{"start":{"line":158,"column":2},"end":{"line":158,"column":null}},"43":{"start":{"line":160,"column":21},"end":{"line":164,"column":null}},"44":{"start":{"line":167,"column":2},"end":{"line":175,"column":null}},"45":{"start":{"line":168,"column":4},"end":{"line":174,"column":null}},"46":{"start":{"line":169,"column":6},"end":{"line":169,"column":null}},"47":{"start":{"line":170,"column":6},"end":{"line":170,"column":null}},"48":{"start":{"line":172,"column":6},"end":{"line":172,"column":null}},"49":{"start":{"line":173,"column":6},"end":{"line":173,"column":null}},"50":{"start":{"line":177,"column":20},"end":{"line":191,"column":null}},"51":{"start":{"line":193,"column":19},"end":{"line":193,"column":null}},"52":{"start":{"line":195,"column":4},"end":{"line":197,"column":null}},"53":{"start":{"line":199,"column":2},"end":{"line":202,"column":null}},"54":{"start":{"line":204,"column":2},"end":{"line":204,"column":null}},"55":{"start":{"line":208,"column":17},"end":{"line":217,"column":null}},"56":{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},"57":{"start":{"line":219,"column":21},"end":{"line":219,"column":null}},"58":{"start":{"line":220,"column":2},"end":{"line":220,"column":null}}},"fnMap":{"0":{"name":"executeInitCommand","decl":{"start":{"line":41,"column":22},"end":{"line":41,"column":41}},"loc":{"start":{"line":41,"column":87},"end":{"line":53,"column":null}},"line":41},"1":{"name":"runInit","decl":{"start":{"line":55,"column":22},"end":{"line":55,"column":30}},"loc":{"start":{"line":55,"column":63},"end":{"line":205,"column":null}},"line":55},"2":{"name":"runInitCommand","decl":{"start":{"line":207,"column":22},"end":{"line":207,"column":54}},"loc":{"start":{"line":207,"column":54},"end":{"line":221,"column":null}},"line":207}},"branchMap":{"0":{"loc":{"start":{"line":46,"column":4},"end":{"line":46,"column":null}},"type":"if","locations":[{"start":{"line":46,"column":4},"end":{"line":46,"column":null}},{"start":{},"end":{}}],"line":46},"1":{"loc":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},{"start":{},"end":{}}],"line":47},"2":{"loc":{"start":{"line":48,"column":4},"end":{"line":49,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":4},"end":{"line":49,"column":null}},{"start":{},"end":{}}],"line":48},"3":{"loc":{"start":{"line":50,"column":4},"end":{"line":50,"column":null}},"type":"if","locations":[{"start":{"line":50,"column":4},"end":{"line":50,"column":null}},{"start":{},"end":{}}],"line":50},"4":{"loc":{"start":{"line":90,"column":2},"end":{"line":125,"column":null}},"type":"if","locations":[{"start":{"line":90,"column":2},"end":{"line":125,"column":null}},{"start":{},"end":{}}],"line":90},"5":{"loc":{"start":{"line":93,"column":4},"end":{"line":97,"column":null}},"type":"if","locations":[{"start":{"line":93,"column":4},"end":{"line":97,"column":null}},{"start":{},"end":{}}],"line":93},"6":{"loc":{"start":{"line":101,"column":4},"end":{"line":103,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":4},"end":{"line":103,"column":null}},{"start":{},"end":{}}],"line":101},"7":{"loc":{"start":{"line":105,"column":4},"end":{"line":120,"column":null}},"type":"if","locations":[{"start":{"line":105,"column":4},"end":{"line":120,"column":null}},{"start":{},"end":{}}],"line":105},"8":{"loc":{"start":{"line":108,"column":6},"end":{"line":119,"column":null}},"type":"if","locations":[{"start":{"line":108,"column":6},"end":{"line":119,"column":null}},{"start":{"line":110,"column":13},"end":{"line":119,"column":null}}],"line":108},"9":{"loc":{"start":{"line":112,"column":8},"end":{"line":112,"column":null}},"type":"if","locations":[{"start":{"line":112,"column":8},"end":{"line":112,"column":null}},{"start":{},"end":{}}],"line":112},"10":{"loc":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"type":"if","locations":[{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},{"start":{},"end":{}}],"line":113},"11":{"loc":{"start":{"line":114,"column":8},"end":{"line":118,"column":null}},"type":"if","locations":[{"start":{"line":114,"column":8},"end":{"line":118,"column":null}},{"start":{},"end":{}}],"line":114},"12":{"loc":{"start":{"line":122,"column":4},"end":{"line":124,"column":null}},"type":"if","locations":[{"start":{"line":122,"column":4},"end":{"line":124,"column":null}},{"start":{},"end":{}}],"line":122},"13":{"loc":{"start":{"line":133,"column":10},"end":{"line":139,"column":null}},"type":"cond-expr","locations":[{"start":{"line":134,"column":14},"end":{"line":136,"column":null}},{"start":{"line":137,"column":14},"end":{"line":139,"column":null}}],"line":133},"14":{"loc":{"start":{"line":134,"column":14},"end":{"line":136,"column":null}},"type":"cond-expr","locations":[{"start":{"line":135,"column":16},"end":{"line":135,"column":null}},{"start":{"line":136,"column":16},"end":{"line":136,"column":null}}],"line":134},"15":{"loc":{"start":{"line":137,"column":14},"end":{"line":139,"column":null}},"type":"cond-expr","locations":[{"start":{"line":138,"column":16},"end":{"line":138,"column":null}},{"start":{"line":139,"column":16},"end":{"line":139,"column":null}}],"line":137},"16":{"loc":{"start":{"line":145,"column":10},"end":{"line":151,"column":null}},"type":"cond-expr","locations":[{"start":{"line":146,"column":14},"end":{"line":148,"column":null}},{"start":{"line":149,"column":14},"end":{"line":151,"column":null}}],"line":145},"17":{"loc":{"start":{"line":146,"column":14},"end":{"line":148,"column":null}},"type":"cond-expr","locations":[{"start":{"line":147,"column":16},"end":{"line":147,"column":null}},{"start":{"line":148,"column":16},"end":{"line":148,"column":null}}],"line":146},"18":{"loc":{"start":{"line":149,"column":14},"end":{"line":151,"column":null}},"type":"cond-expr","locations":[{"start":{"line":150,"column":16},"end":{"line":150,"column":null}},{"start":{"line":151,"column":16},"end":{"line":151,"column":null}}],"line":149},"19":{"loc":{"start":{"line":167,"column":2},"end":{"line":175,"column":null}},"type":"if","locations":[{"start":{"line":167,"column":2},"end":{"line":175,"column":null}},{"start":{},"end":{}}],"line":167},"20":{"loc":{"start":{"line":168,"column":4},"end":{"line":174,"column":null}},"type":"if","locations":[{"start":{"line":168,"column":4},"end":{"line":174,"column":null}},{"start":{"line":171,"column":11},"end":{"line":174,"column":null}}],"line":168},"21":{"loc":{"start":{"line":177,"column":20},"end":{"line":191,"column":null}},"type":"cond-expr","locations":[{"start":{"line":178,"column":6},"end":{"line":184,"column":null}},{"start":{"line":185,"column":6},"end":{"line":191,"column":null}}],"line":177},"22":{"loc":{"start":{"line":178,"column":6},"end":{"line":184,"column":null}},"type":"cond-expr","locations":[{"start":{"line":179,"column":8},"end":{"line":181,"column":null}},{"start":{"line":182,"column":8},"end":{"line":184,"column":null}}],"line":178},"23":{"loc":{"start":{"line":179,"column":8},"end":{"line":181,"column":null}},"type":"cond-expr","locations":[{"start":{"line":180,"column":10},"end":{"line":180,"column":null}},{"start":{"line":181,"column":10},"end":{"line":181,"column":null}}],"line":179},"24":{"loc":{"start":{"line":182,"column":8},"end":{"line":184,"column":null}},"type":"cond-expr","locations":[{"start":{"line":183,"column":10},"end":{"line":183,"column":null}},{"start":{"line":184,"column":10},"end":{"line":184,"column":null}}],"line":182},"25":{"loc":{"start":{"line":185,"column":6},"end":{"line":191,"column":null}},"type":"cond-expr","locations":[{"start":{"line":186,"column":8},"end":{"line":188,"column":null}},{"start":{"line":189,"column":8},"end":{"line":191,"column":null}}],"line":185},"26":{"loc":{"start":{"line":186,"column":8},"end":{"line":188,"column":null}},"type":"cond-expr","locations":[{"start":{"line":187,"column":10},"end":{"line":187,"column":null}},{"start":{"line":188,"column":10},"end":{"line":188,"column":null}}],"line":186},"27":{"loc":{"start":{"line":189,"column":8},"end":{"line":191,"column":null}},"type":"cond-expr","locations":[{"start":{"line":190,"column":10},"end":{"line":190,"column":null}},{"start":{"line":191,"column":10},"end":{"line":191,"column":null}}],"line":189},"28":{"loc":{"start":{"line":193,"column":19},"end":{"line":193,"column":null}},"type":"cond-expr","locations":[{"start":{"line":193,"column":41},"end":{"line":193,"column":54}},{"start":{"line":193,"column":54},"end":{"line":193,"column":null}}],"line":193},"29":{"loc":{"start":{"line":195,"column":4},"end":{"line":197,"column":null}},"type":"cond-expr","locations":[{"start":{"line":196,"column":8},"end":{"line":196,"column":null}},{"start":{"line":197,"column":8},"end":{"line":197,"column":null}}],"line":195},"30":{"loc":{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},"type":"if","locations":[{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},{"start":{},"end":{}}],"line":219}},"s":{"0":8,"1":8,"2":1,"3":7,"4":1,"5":6,"6":6,"7":3,"8":1,"9":2,"10":2,"11":1,"12":46,"13":46,"14":46,"15":46,"16":46,"17":46,"18":46,"19":44,"20":42,"21":42,"22":13,"23":5,"24":8,"25":8,"26":1,"27":7,"28":4,"29":4,"30":1,"31":3,"32":3,"33":0,"34":3,"35":1,"36":3,"37":2,"38":2,"39":7,"40":3,"41":36,"42":36,"43":36,"44":36,"45":31,"46":19,"47":18,"48":12,"49":10,"50":31,"51":46,"52":46,"53":46,"54":46,"55":0,"56":0,"57":0,"58":0},"f":{"0":8,"1":46,"2":0},"b":{"0":[1,6],"1":[3,3],"2":[1,2],"3":[1,1],"4":[13,29],"5":[5,8],"6":[1,7],"7":[4,3],"8":[1,3],"9":[0,3],"10":[1,2],"11":[2,1],"12":[3,4],"13":[23,13],"14":[2,21],"15":[0,13],"16":[23,13],"17":[0,23],"18":[0,13],"19":[31,5],"20":[19,12],"21":[26,5],"22":[3,23],"23":[2,1],"24":[15,8],"25":[1,4],"26":[0,1],"27":[4,0],"28":[21,10],"29":[21,10],"30":[0,0]},"meta":{"lastBranch":31,"lastFunction":3,"lastStatement":59,"seen":{"f:41:22:41:41":0,"s:42:2:52:Infinity":0,"s:43:4:43:Infinity":1,"s:44:4:44:Infinity":2,"b:46:4:46:Infinity:undefined:undefined:undefined:undefined":0,"s:46:4:46:Infinity":3,"s:46:41:46:Infinity":4,"b:47:4:47:Infinity:undefined:undefined:undefined:undefined":1,"s:47:4:47:Infinity":5,"s:47:37:47:Infinity":6,"b:48:4:49:Infinity:undefined:undefined:undefined:undefined":2,"s:48:4:49:Infinity":7,"s:49:6:49:Infinity":8,"b:50:4:50:Infinity:undefined:undefined:undefined:undefined":3,"s:50:4:50:Infinity":9,"s:50:45:50:Infinity":10,"s:51:4:51:Infinity":11,"f:55:22:55:30":1,"s:56:89:56:Infinity":12,"s:58:2:58:Infinity":13,"s:59:2:62:Infinity":14,"s:64:18:64:Infinity":15,"s:66:18:66:Infinity":16,"s:67:18:67:Infinity":17,"s:69:15:84:Infinity":18,"s:87:20:87:Infinity":19,"s:88:23:88:Infinity":20,"b:90:2:125:Infinity:undefined:undefined:undefined:undefined":4,"s:90:2:125:Infinity":21,"b:93:4:97:Infinity:undefined:undefined:undefined:undefined":5,"s:93:4:97:Infinity":22,"s:94:6:96:Infinity":23,"s:99:19:99:Infinity":24,"b:101:4:103:Infinity:undefined:undefined:undefined:undefined":6,"s:101:4:103:Infinity":25,"s:102:6:102:Infinity":26,"b:105:4:120:Infinity:undefined:undefined:undefined:undefined":7,"s:105:4:120:Infinity":27,"s:107:22:107:Infinity":28,"b:108:6:119:Infinity:110:13:119:Infinity":8,"s:108:6:119:Infinity":29,"s:109:8:109:Infinity":30,"s:111:29:111:Infinity":31,"b:112:8:112:Infinity:undefined:undefined:undefined:undefined":9,"s:112:8:112:Infinity":32,"s:112:37:112:Infinity":33,"b:113:8:113:Infinity:undefined:undefined:undefined:undefined":10,"s:113:8:113:Infinity":34,"s:113:41:113:Infinity":35,"b:114:8:118:Infinity:undefined:undefined:undefined:undefined":11,"s:114:8:118:Infinity":36,"s:116:29:116:Infinity":37,"s:117:10:117:Infinity":38,"b:122:4:124:Infinity:undefined:undefined:undefined:undefined":12,"s:122:4:124:Infinity":39,"s:123:6:123:Infinity":40,"s:127:16:156:Infinity":41,"b:134:14:136:Infinity:137:14:139:Infinity":13,"b:135:16:135:Infinity:136:16:136:Infinity":14,"b:138:16:138:Infinity:139:16:139:Infinity":15,"b:146:14:148:Infinity:149:14:151:Infinity":16,"b:147:16:147:Infinity:148:16:148:Infinity":17,"b:150:16:150:Infinity:151:16:151:Infinity":18,"s:158:2:158:Infinity":42,"s:160:21:164:Infinity":43,"b:167:2:175:Infinity:undefined:undefined:undefined:undefined":19,"s:167:2:175:Infinity":44,"b:168:4:174:Infinity:171:11:174:Infinity":20,"s:168:4:174:Infinity":45,"s:169:6:169:Infinity":46,"s:170:6:170:Infinity":47,"s:172:6:172:Infinity":48,"s:173:6:173:Infinity":49,"s:177:20:191:Infinity":50,"b:178:6:184:Infinity:185:6:191:Infinity":21,"b:179:8:181:Infinity:182:8:184:Infinity":22,"b:180:10:180:Infinity:181:10:181:Infinity":23,"b:183:10:183:Infinity:184:10:184:Infinity":24,"b:186:8:188:Infinity:189:8:191:Infinity":25,"b:187:10:187:Infinity:188:10:188:Infinity":26,"b:190:10:190:Infinity:191:10:191:Infinity":27,"s:193:19:193:Infinity":51,"b:193:41:193:54:193:54:193:Infinity":28,"s:195:4:197:Infinity":52,"b:196:8:196:Infinity:197:8:197:Infinity":29,"s:199:2:202:Infinity":53,"s:204:2:204:Infinity":54,"f:207:22:207:54":2,"s:208:17:217:Infinity":55,"b:219:2:219:Infinity:undefined:undefined:undefined:undefined":30,"s:219:2:219:Infinity":56,"s:219:21:219:Infinity":57,"s:220:2:220:Infinity":58}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/opencode.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/opencode.ts","statementMap":{"0":{"start":{"line":12,"column":24},"end":{"line":12,"column":null}},"1":{"start":{"line":13,"column":29},"end":{"line":13,"column":null}},"2":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"3":{"start":{"line":25,"column":37},"end":{"line":25,"column":null}},"4":{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},"5":{"start":{"line":34,"column":23},"end":{"line":34,"column":null}},"6":{"start":{"line":35,"column":22},"end":{"line":35,"column":null}},"7":{"start":{"line":36,"column":22},"end":{"line":39,"column":null}},"8":{"start":{"line":40,"column":21},"end":{"line":43,"column":null}},"9":{"start":{"line":45,"column":2},"end":{"line":48,"column":null}},"10":{"start":{"line":54,"column":72},"end":{"line":54,"column":null}},"11":{"start":{"line":56,"column":21},"end":{"line":56,"column":null}},"12":{"start":{"line":57,"column":26},"end":{"line":57,"column":null}},"13":{"start":{"line":58,"column":21},"end":{"line":58,"column":null}},"14":{"start":{"line":60,"column":2},"end":{"line":62,"column":null}},"15":{"start":{"line":61,"column":4},"end":{"line":61,"column":null}},"16":{"start":{"line":64,"column":2},"end":{"line":68,"column":null}},"17":{"start":{"line":65,"column":4},"end":{"line":65,"column":null}},"18":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"19":{"start":{"line":70,"column":22},"end":{"line":73,"column":null}},"20":{"start":{"line":74,"column":2},"end":{"line":74,"column":null}},"21":{"start":{"line":74,"column":20},"end":{"line":74,"column":null}},"22":{"start":{"line":76,"column":12},"end":{"line":76,"column":null}},"23":{"start":{"line":77,"column":2},"end":{"line":77,"column":null}},"24":{"start":{"line":78,"column":2},"end":{"line":84,"column":null}},"25":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"26":{"start":{"line":80,"column":4},"end":{"line":80,"column":null}},"27":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"28":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"29":{"start":{"line":94,"column":51},"end":{"line":94,"column":null}},"30":{"start":{"line":96,"column":8},"end":{"line":96,"column":null}},"31":{"start":{"line":96,"column":46},"end":{"line":96,"column":73}},"32":{"start":{"line":98,"column":2},"end":{"line":100,"column":null}},"33":{"start":{"line":99,"column":4},"end":{"line":99,"column":null}},"34":{"start":{"line":103,"column":4},"end":{"line":105,"column":null}},"35":{"start":{"line":107,"column":2},"end":{"line":107,"column":null}},"36":{"start":{"line":109,"column":23},"end":{"line":119,"column":null}},"37":{"start":{"line":111,"column":24},"end":{"line":111,"column":null}},"38":{"start":{"line":112,"column":21},"end":{"line":112,"column":null}},"39":{"start":{"line":113,"column":6},"end":{"line":117,"column":null}},"40":{"start":{"line":121,"column":25},"end":{"line":125,"column":null}},"41":{"start":{"line":127,"column":2},"end":{"line":129,"column":null}},"42":{"start":{"line":128,"column":4},"end":{"line":128,"column":null}},"43":{"start":{"line":131,"column":30},"end":{"line":131,"column":null}},"44":{"start":{"line":132,"column":35},"end":{"line":132,"column":null}},"45":{"start":{"line":133,"column":2},"end":{"line":139,"column":null}},"46":{"start":{"line":135,"column":24},"end":{"line":135,"column":null}},"47":{"start":{"line":136,"column":21},"end":{"line":136,"column":null}},"48":{"start":{"line":137,"column":6},"end":{"line":137,"column":null}},"49":{"start":{"line":141,"column":33},"end":{"line":141,"column":null}},"50":{"start":{"line":142,"column":2},"end":{"line":142,"column":null}},"51":{"start":{"line":142,"column":28},"end":{"line":142,"column":null}},"52":{"start":{"line":143,"column":2},"end":{"line":143,"column":null}},"53":{"start":{"line":143,"column":33},"end":{"line":143,"column":null}},"54":{"start":{"line":144,"column":2},"end":{"line":149,"column":null}},"55":{"start":{"line":145,"column":4},"end":{"line":148,"column":null}},"56":{"start":{"line":146,"column":60},"end":{"line":146,"column":71}},"57":{"start":{"line":151,"column":22},"end":{"line":154,"column":null}},"58":{"start":{"line":156,"column":2},"end":{"line":158,"column":null}},"59":{"start":{"line":157,"column":4},"end":{"line":157,"column":null}},"60":{"start":{"line":160,"column":2},"end":{"line":160,"column":null}},"61":{"start":{"line":162,"column":12},"end":{"line":162,"column":null}},"62":{"start":{"line":163,"column":2},"end":{"line":163,"column":null}},"63":{"start":{"line":164,"column":2},"end":{"line":177,"column":null}},"64":{"start":{"line":165,"column":4},"end":{"line":172,"column":null}},"65":{"start":{"line":166,"column":20},"end":{"line":166,"column":null}},"66":{"start":{"line":166,"column":39},"end":{"line":166,"column":66}},"67":{"start":{"line":167,"column":6},"end":{"line":167,"column":null}},"68":{"start":{"line":167,"column":18},"end":{"line":167,"column":null}},"69":{"start":{"line":169,"column":24},"end":{"line":169,"column":null}},"70":{"start":{"line":170,"column":12},"end":{"line":170,"column":null}},"71":{"start":{"line":171,"column":6},"end":{"line":171,"column":null}},"72":{"start":{"line":173,"column":4},"end":{"line":173,"column":null}},"73":{"start":{"line":175,"column":4},"end":{"line":175,"column":null}},"74":{"start":{"line":176,"column":4},"end":{"line":176,"column":null}},"75":{"start":{"line":178,"column":2},"end":{"line":178,"column":null}},"76":{"start":{"line":182,"column":2},"end":{"line":233,"column":null}},"77":{"start":{"line":183,"column":20},"end":{"line":183,"column":null}},"78":{"start":{"line":184,"column":31},"end":{"line":184,"column":null}},"79":{"start":{"line":185,"column":10},"end":{"line":188,"column":null}},"80":{"start":{"line":190,"column":44},"end":{"line":190,"column":null}},"81":{"start":{"line":192,"column":6},"end":{"line":195,"column":null}},"82":{"start":{"line":197,"column":4},"end":{"line":199,"column":null}},"83":{"start":{"line":198,"column":6},"end":{"line":198,"column":null}},"84":{"start":{"line":201,"column":23},"end":{"line":201,"column":null}},"85":{"start":{"line":202,"column":39},"end":{"line":202,"column":null}},"86":{"start":{"line":203,"column":21},"end":{"line":203,"column":null}},"87":{"start":{"line":203,"column":59},"end":{"line":203,"column":92}},"88":{"start":{"line":204,"column":4},"end":{"line":204,"column":null}},"89":{"start":{"line":206,"column":4},"end":{"line":226,"column":null}},"90":{"start":{"line":207,"column":28},"end":{"line":207,"column":null}},"91":{"start":{"line":208,"column":12},"end":{"line":210,"column":null}},"92":{"start":{"line":211,"column":6},"end":{"line":211,"column":null}},"93":{"start":{"line":213,"column":6},"end":{"line":223,"column":null}},"94":{"start":{"line":214,"column":14},"end":{"line":221,"column":null}},"95":{"start":{"line":222,"column":8},"end":{"line":222,"column":null}},"96":{"start":{"line":225,"column":6},"end":{"line":225,"column":null}},"97":{"start":{"line":228,"column":44},"end":{"line":231,"column":null}},"98":{"start":{"line":232,"column":4},"end":{"line":232,"column":null}},"99":{"start":{"line":235,"column":40},"end":{"line":235,"column":null}},"100":{"start":{"line":236,"column":2},"end":{"line":242,"column":null}},"101":{"start":{"line":237,"column":4},"end":{"line":241,"column":null}},"102":{"start":{"line":238,"column":6},"end":{"line":238,"column":null}},"103":{"start":{"line":244,"column":21},"end":{"line":244,"column":null}},"104":{"start":{"line":245,"column":37},"end":{"line":245,"column":null}},"105":{"start":{"line":246,"column":19},"end":{"line":246,"column":null}},"106":{"start":{"line":246,"column":57},"end":{"line":246,"column":90}},"107":{"start":{"line":247,"column":2},"end":{"line":247,"column":null}},"108":{"start":{"line":248,"column":2},"end":{"line":248,"column":null}},"109":{"start":{"line":249,"column":2},"end":{"line":249,"column":null}},"110":{"start":{"line":251,"column":2},"end":{"line":251,"column":null}},"111":{"start":{"line":255,"column":2},"end":{"line":255,"column":null}},"112":{"start":{"line":255,"column":45},"end":{"line":255,"column":null}},"113":{"start":{"line":257,"column":5},"end":{"line":257,"column":null}},"114":{"start":{"line":258,"column":2},"end":{"line":258,"column":null}},"115":{"start":{"line":258,"column":31},"end":{"line":258,"column":null}},"116":{"start":{"line":259,"column":2},"end":{"line":259,"column":null}},"117":{"start":{"line":259,"column":38},"end":{"line":259,"column":95}},"118":{"start":{"line":268,"column":2},"end":{"line":274,"column":null}},"119":{"start":{"line":269,"column":22},"end":{"line":269,"column":null}},"120":{"start":{"line":270,"column":21},"end":{"line":270,"column":null}},"121":{"start":{"line":271,"column":4},"end":{"line":271,"column":null}},"122":{"start":{"line":271,"column":39},"end":{"line":271,"column":null}},"123":{"start":{"line":272,"column":4},"end":{"line":272,"column":null}},"124":{"start":{"line":272,"column":38},"end":{"line":272,"column":null}},"125":{"start":{"line":273,"column":4},"end":{"line":273,"column":null}},"126":{"start":{"line":276,"column":20},"end":{"line":276,"column":null}},"127":{"start":{"line":277,"column":20},"end":{"line":277,"column":null}},"128":{"start":{"line":278,"column":19},"end":{"line":278,"column":null}},"129":{"start":{"line":279,"column":2},"end":{"line":279,"column":null}},"130":{"start":{"line":279,"column":37},"end":{"line":279,"column":null}},"131":{"start":{"line":280,"column":2},"end":{"line":280,"column":null}},"132":{"start":{"line":280,"column":36},"end":{"line":280,"column":null}},"133":{"start":{"line":281,"column":2},"end":{"line":281,"column":null}}},"fnMap":{"0":{"name":"getOpencodeLabel","decl":{"start":{"line":24,"column":16},"end":{"line":24,"column":33}},"loc":{"start":{"line":24,"column":87},"end":{"line":27,"column":null}},"line":24},"1":{"name":"getOpencodeState","decl":{"start":{"line":29,"column":22},"end":{"line":29,"column":null}},"loc":{"start":{"line":33,"column":50},"end":{"line":49,"column":null}},"line":33},"2":{"name":"initOpenCode","decl":{"start":{"line":53,"column":22},"end":{"line":53,"column":35}},"loc":{"start":{"line":53,"column":74},"end":{"line":85,"column":null}},"line":53},"3":{"name":"initOpenCodeAgents","decl":{"start":{"line":87,"column":22},"end":{"line":87,"column":41}},"loc":{"start":{"line":93,"column":21},"end":{"line":179,"column":null}},"line":93},"4":{"name":"(anonymous_4)","decl":{"start":{"line":96,"column":32},"end":{"line":96,"column":40}},"loc":{"start":{"line":96,"column":46},"end":{"line":96,"column":73}},"line":96},"5":{"name":"(anonymous_5)","decl":{"start":{"line":110,"column":15},"end":{"line":110,"column":22}},"loc":{"start":{"line":110,"column":32},"end":{"line":118,"column":5}},"line":110},"6":{"name":"(anonymous_6)","decl":{"start":{"line":134,"column":23},"end":{"line":134,"column":30}},"loc":{"start":{"line":134,"column":52},"end":{"line":138,"column":5}},"line":134},"7":{"name":"(anonymous_7)","decl":{"start":{"line":146,"column":46},"end":{"line":146,"column":51}},"loc":{"start":{"line":146,"column":60},"end":{"line":146,"column":71}},"line":146},"8":{"name":"(anonymous_8)","decl":{"start":{"line":166,"column":27},"end":{"line":166,"column":33}},"loc":{"start":{"line":166,"column":39},"end":{"line":166,"column":66}},"line":166},"9":{"name":"generateModifiedContent","decl":{"start":{"line":181,"column":9},"end":{"line":181,"column":33}},"loc":{"start":{"line":181,"column":93},"end":{"line":252,"column":null}},"line":181},"10":{"name":"(anonymous_10)","decl":{"start":{"line":203,"column":37},"end":{"line":203,"column":45}},"loc":{"start":{"line":203,"column":59},"end":{"line":203,"column":92}},"line":203},"11":{"name":"(anonymous_11)","decl":{"start":{"line":246,"column":35},"end":{"line":246,"column":43}},"loc":{"start":{"line":246,"column":57},"end":{"line":246,"column":90}},"line":246},"12":{"name":"hasPluginInConfig","decl":{"start":{"line":254,"column":9},"end":{"line":254,"column":27}},"loc":{"start":{"line":254,"column":53},"end":{"line":260,"column":null}},"line":254},"13":{"name":"(anonymous_13)","decl":{"start":{"line":259,"column":17},"end":{"line":259,"column":23}},"loc":{"start":{"line":259,"column":38},"end":{"line":259,"column":95}},"line":259},"14":{"name":"resolveOpencodeConfigPath","decl":{"start":{"line":262,"column":15},"end":{"line":262,"column":null}},"loc":{"start":{"line":267,"column":19},"end":{"line":282,"column":null}},"line":267}},"branchMap":{"0":{"loc":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},{"start":{},"end":{}}],"line":25},"1":{"loc":{"start":{"line":25,"column":6},"end":{"line":25,"column":37}},"type":"binary-expr","locations":[{"start":{"line":25,"column":6},"end":{"line":25,"column":23}},{"start":{"line":25,"column":23},"end":{"line":25,"column":37}}],"line":25},"2":{"loc":{"start":{"line":46,"column":12},"end":{"line":46,"column":null}},"type":"binary-expr","locations":[{"start":{"line":46,"column":12},"end":{"line":46,"column":46}},{"start":{"line":46,"column":46},"end":{"line":46,"column":null}}],"line":46},"3":{"loc":{"start":{"line":47,"column":13},"end":{"line":47,"column":null}},"type":"binary-expr","locations":[{"start":{"line":47,"column":13},"end":{"line":47,"column":48}},{"start":{"line":47,"column":48},"end":{"line":47,"column":null}}],"line":47},"4":{"loc":{"start":{"line":60,"column":2},"end":{"line":62,"column":null}},"type":"if","locations":[{"start":{"line":60,"column":2},"end":{"line":62,"column":null}},{"start":{},"end":{}}],"line":60},"5":{"loc":{"start":{"line":60,"column":6},"end":{"line":60,"column":57}},"type":"binary-expr","locations":[{"start":{"line":60,"column":6},"end":{"line":60,"column":25}},{"start":{"line":60,"column":25},"end":{"line":60,"column":57}}],"line":60},"6":{"loc":{"start":{"line":64,"column":2},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":2},"end":{"line":68,"column":null}},{"start":{"line":66,"column":9},"end":{"line":68,"column":null}}],"line":64},"7":{"loc":{"start":{"line":72,"column":13},"end":{"line":72,"column":null}},"type":"cond-expr","locations":[{"start":{"line":72,"column":31},"end":{"line":72,"column":73}},{"start":{"line":72,"column":73},"end":{"line":72,"column":null}}],"line":72},"8":{"loc":{"start":{"line":74,"column":2},"end":{"line":74,"column":null}},"type":"if","locations":[{"start":{"line":74,"column":2},"end":{"line":74,"column":null}},{"start":{},"end":{}}],"line":74},"9":{"loc":{"start":{"line":98,"column":2},"end":{"line":100,"column":null}},"type":"if","locations":[{"start":{"line":98,"column":2},"end":{"line":100,"column":null}},{"start":{},"end":{}}],"line":98},"10":{"loc":{"start":{"line":103,"column":4},"end":{"line":105,"column":null}},"type":"cond-expr","locations":[{"start":{"line":104,"column":8},"end":{"line":104,"column":null}},{"start":{"line":105,"column":8},"end":{"line":105,"column":null}}],"line":103},"11":{"loc":{"start":{"line":114,"column":14},"end":{"line":114,"column":null}},"type":"cond-expr","locations":[{"start":{"line":114,"column":23},"end":{"line":114,"column":46}},{"start":{"line":114,"column":46},"end":{"line":114,"column":null}}],"line":114},"12":{"loc":{"start":{"line":127,"column":2},"end":{"line":129,"column":null}},"type":"if","locations":[{"start":{"line":127,"column":2},"end":{"line":129,"column":null}},{"start":{},"end":{}}],"line":127},"13":{"loc":{"start":{"line":137,"column":7},"end":{"line":137,"column":44}},"type":"cond-expr","locations":[{"start":{"line":137,"column":16},"end":{"line":137,"column":33}},{"start":{"line":137,"column":33},"end":{"line":137,"column":44}}],"line":137},"14":{"loc":{"start":{"line":142,"column":2},"end":{"line":142,"column":null}},"type":"if","locations":[{"start":{"line":142,"column":2},"end":{"line":142,"column":null}},{"start":{},"end":{}}],"line":142},"15":{"loc":{"start":{"line":143,"column":2},"end":{"line":143,"column":null}},"type":"if","locations":[{"start":{"line":143,"column":2},"end":{"line":143,"column":null}},{"start":{},"end":{}}],"line":143},"16":{"loc":{"start":{"line":144,"column":2},"end":{"line":149,"column":null}},"type":"if","locations":[{"start":{"line":144,"column":2},"end":{"line":149,"column":null}},{"start":{},"end":{}}],"line":144},"17":{"loc":{"start":{"line":156,"column":2},"end":{"line":158,"column":null}},"type":"if","locations":[{"start":{"line":156,"column":2},"end":{"line":158,"column":null}},{"start":{},"end":{}}],"line":156},"18":{"loc":{"start":{"line":167,"column":6},"end":{"line":167,"column":null}},"type":"if","locations":[{"start":{"line":167,"column":6},"end":{"line":167,"column":null}},{"start":{},"end":{}}],"line":167},"19":{"loc":{"start":{"line":182,"column":2},"end":{"line":233,"column":null}},"type":"if","locations":[{"start":{"line":182,"column":2},"end":{"line":233,"column":null}},{"start":{},"end":{}}],"line":182},"20":{"loc":{"start":{"line":183,"column":20},"end":{"line":183,"column":null}},"type":"binary-expr","locations":[{"start":{"line":183,"column":20},"end":{"line":183,"column":39}},{"start":{"line":183,"column":39},"end":{"line":183,"column":null}}],"line":183},"21":{"loc":{"start":{"line":192,"column":6},"end":{"line":195,"column":null}},"type":"binary-expr","locations":[{"start":{"line":192,"column":6},"end":{"line":192,"column":null}},{"start":{"line":193,"column":6},"end":{"line":193,"column":null}},{"start":{"line":194,"column":6},"end":{"line":194,"column":null}},{"start":{"line":195,"column":6},"end":{"line":195,"column":null}}],"line":192},"22":{"loc":{"start":{"line":197,"column":4},"end":{"line":199,"column":null}},"type":"if","locations":[{"start":{"line":197,"column":4},"end":{"line":199,"column":null}},{"start":{},"end":{}}],"line":197},"23":{"loc":{"start":{"line":201,"column":23},"end":{"line":201,"column":null}},"type":"cond-expr","locations":[{"start":{"line":201,"column":56},"end":{"line":201,"column":67}},{"start":{"line":201,"column":67},"end":{"line":201,"column":null}}],"line":201},"24":{"loc":{"start":{"line":202,"column":39},"end":{"line":202,"column":null}},"type":"binary-expr","locations":[{"start":{"line":202,"column":39},"end":{"line":202,"column":76}},{"start":{"line":202,"column":76},"end":{"line":202,"column":null}}],"line":202},"25":{"loc":{"start":{"line":206,"column":4},"end":{"line":226,"column":null}},"type":"if","locations":[{"start":{"line":206,"column":4},"end":{"line":226,"column":null}},{"start":{},"end":{}}],"line":206},"26":{"loc":{"start":{"line":213,"column":6},"end":{"line":223,"column":null}},"type":"if","locations":[{"start":{"line":213,"column":6},"end":{"line":223,"column":null}},{"start":{},"end":{}}],"line":213},"27":{"loc":{"start":{"line":236,"column":2},"end":{"line":242,"column":null}},"type":"if","locations":[{"start":{"line":236,"column":2},"end":{"line":242,"column":null}},{"start":{},"end":{}}],"line":236},"28":{"loc":{"start":{"line":244,"column":21},"end":{"line":244,"column":null}},"type":"cond-expr","locations":[{"start":{"line":244,"column":52},"end":{"line":244,"column":63}},{"start":{"line":244,"column":63},"end":{"line":244,"column":null}}],"line":244},"29":{"loc":{"start":{"line":245,"column":37},"end":{"line":245,"column":null}},"type":"binary-expr","locations":[{"start":{"line":245,"column":37},"end":{"line":245,"column":72}},{"start":{"line":245,"column":72},"end":{"line":245,"column":null}}],"line":245},"30":{"loc":{"start":{"line":249,"column":19},"end":{"line":249,"column":null}},"type":"binary-expr","locations":[{"start":{"line":249,"column":19},"end":{"line":249,"column":37}},{"start":{"line":249,"column":37},"end":{"line":249,"column":null}}],"line":249},"31":{"loc":{"start":{"line":255,"column":2},"end":{"line":255,"column":null}},"type":"if","locations":[{"start":{"line":255,"column":2},"end":{"line":255,"column":null}},{"start":{},"end":{}}],"line":255},"32":{"loc":{"start":{"line":255,"column":6},"end":{"line":255,"column":45}},"type":"binary-expr","locations":[{"start":{"line":255,"column":6},"end":{"line":255,"column":17}},{"start":{"line":255,"column":17},"end":{"line":255,"column":45}}],"line":255},"33":{"loc":{"start":{"line":257,"column":5},"end":{"line":257,"column":null}},"type":"binary-expr","locations":[{"start":{"line":257,"column":5},"end":{"line":257,"column":51}},{"start":{"line":257,"column":51},"end":{"line":257,"column":null}}],"line":257},"34":{"loc":{"start":{"line":258,"column":2},"end":{"line":258,"column":null}},"type":"if","locations":[{"start":{"line":258,"column":2},"end":{"line":258,"column":null}},{"start":{},"end":{}}],"line":258},"35":{"loc":{"start":{"line":259,"column":38},"end":{"line":259,"column":95}},"type":"binary-expr","locations":[{"start":{"line":259,"column":38},"end":{"line":259,"column":63}},{"start":{"line":259,"column":63},"end":{"line":259,"column":95}}],"line":259},"36":{"loc":{"start":{"line":268,"column":2},"end":{"line":274,"column":null}},"type":"if","locations":[{"start":{"line":268,"column":2},"end":{"line":274,"column":null}},{"start":{},"end":{}}],"line":268},"37":{"loc":{"start":{"line":271,"column":4},"end":{"line":271,"column":null}},"type":"if","locations":[{"start":{"line":271,"column":4},"end":{"line":271,"column":null}},{"start":{},"end":{}}],"line":271},"38":{"loc":{"start":{"line":272,"column":4},"end":{"line":272,"column":null}},"type":"if","locations":[{"start":{"line":272,"column":4},"end":{"line":272,"column":null}},{"start":{},"end":{}}],"line":272},"39":{"loc":{"start":{"line":279,"column":2},"end":{"line":279,"column":null}},"type":"if","locations":[{"start":{"line":279,"column":2},"end":{"line":279,"column":null}},{"start":{},"end":{}}],"line":279},"40":{"loc":{"start":{"line":280,"column":2},"end":{"line":280,"column":null}},"type":"if","locations":[{"start":{"line":280,"column":2},"end":{"line":280,"column":null}},{"start":{},"end":{}}],"line":280}},"s":{"0":1,"1":1,"2":46,"3":2,"4":44,"5":46,"6":46,"7":46,"8":46,"9":46,"10":19,"11":19,"12":19,"13":19,"14":19,"15":2,"16":17,"17":2,"18":15,"19":17,"20":17,"21":17,"22":16,"23":16,"24":16,"25":16,"26":16,"27":0,"28":0,"29":18,"30":18,"31":126,"32":18,"33":0,"34":18,"35":18,"36":18,"37":90,"38":90,"39":90,"40":18,"41":18,"42":13,"43":5,"44":5,"45":5,"46":9,"47":9,"48":9,"49":5,"50":5,"51":4,"52":5,"53":5,"54":5,"55":5,"56":5,"57":5,"58":5,"59":1,"60":4,"61":4,"62":4,"63":4,"64":4,"65":7,"66":23,"67":7,"68":0,"69":7,"70":7,"71":7,"72":4,"73":0,"74":0,"75":4,"76":19,"77":1,"78":1,"79":1,"80":1,"81":1,"82":1,"83":1,"84":1,"85":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1,"97":0,"98":0,"99":18,"100":18,"101":3,"102":3,"103":18,"104":19,"105":19,"106":3,"107":19,"108":19,"109":19,"110":19,"111":184,"112":180,"113":4,"114":184,"115":0,"116":4,"117":4,"118":19,"119":16,"120":16,"121":16,"122":1,"123":15,"124":3,"125":12,"126":3,"127":3,"128":3,"129":3,"130":0,"131":3,"132":0,"133":3},"f":{"0":46,"1":46,"2":19,"3":18,"4":126,"5":90,"6":9,"7":5,"8":23,"9":19,"10":1,"11":3,"12":184,"13":4,"14":19},"b":{"0":[2,44],"1":[46,44],"2":[46,46],"3":[46,46],"4":[2,17],"5":[19,4],"6":[2,15],"7":[2,15],"8":[1,16],"9":[0,18],"10":[15,3],"11":[2,88],"12":[13,5],"13":[2,7],"14":[4,1],"15":[1,4],"16":[5,0],"17":[1,4],"18":[0,7],"19":[1,18],"20":[1,0],"21":[1,1,1,1],"22":[1,0],"23":[1,0],"24":[1,0],"25":[1,0],"26":[1,0],"27":[3,15],"28":[18,0],"29":[19,15],"30":[19,16],"31":[180,4],"32":[184,4],"33":[4,0],"34":[0,184],"35":[4,4],"36":[16,3],"37":[1,15],"38":[3,12],"39":[0,3],"40":[0,3]},"meta":{"lastBranch":41,"lastFunction":15,"lastStatement":134,"seen":{"s:12:24:12:Infinity":0,"s:13:29:13:Infinity":1,"f:24:16:24:33":0,"b:25:2:25:Infinity:undefined:undefined:undefined:undefined":0,"s:25:2:25:Infinity":2,"b:25:6:25:23:25:23:25:37":1,"s:25:37:25:Infinity":3,"s:26:2:26:Infinity":4,"f:29:22:29:Infinity":1,"s:34:23:34:Infinity":5,"s:35:22:35:Infinity":6,"s:36:22:39:Infinity":7,"s:40:21:43:Infinity":8,"s:45:2:48:Infinity":9,"b:46:12:46:46:46:46:46:Infinity":2,"b:47:13:47:48:47:48:47:Infinity":3,"f:53:22:53:35":2,"s:54:72:54:Infinity":10,"s:56:21:56:Infinity":11,"s:57:26:57:Infinity":12,"s:58:21:58:Infinity":13,"b:60:2:62:Infinity:undefined:undefined:undefined:undefined":4,"s:60:2:62:Infinity":14,"b:60:6:60:25:60:25:60:57":5,"s:61:4:61:Infinity":15,"b:64:2:68:Infinity:66:9:68:Infinity":6,"s:64:2:68:Infinity":16,"s:65:4:65:Infinity":17,"s:67:4:67:Infinity":18,"s:70:22:73:Infinity":19,"b:72:31:72:73:72:73:72:Infinity":7,"b:74:2:74:Infinity:undefined:undefined:undefined:undefined":8,"s:74:2:74:Infinity":20,"s:74:20:74:Infinity":21,"s:76:12:76:Infinity":22,"s:77:2:77:Infinity":23,"s:78:2:84:Infinity":24,"s:79:4:79:Infinity":25,"s:80:4:80:Infinity":26,"s:82:4:82:Infinity":27,"s:83:4:83:Infinity":28,"f:87:22:87:41":3,"s:94:51:94:Infinity":29,"s:96:8:96:Infinity":30,"f:96:32:96:40":4,"s:96:46:96:73":31,"b:98:2:100:Infinity:undefined:undefined:undefined:undefined":9,"s:98:2:100:Infinity":32,"s:99:4:99:Infinity":33,"s:103:4:105:Infinity":34,"b:104:8:104:Infinity:105:8:105:Infinity":10,"s:107:2:107:Infinity":35,"s:109:23:119:Infinity":36,"f:110:15:110:22":5,"s:111:24:111:Infinity":37,"s:112:21:112:Infinity":38,"s:113:6:117:Infinity":39,"b:114:23:114:46:114:46:114:Infinity":11,"s:121:25:125:Infinity":40,"b:127:2:129:Infinity:undefined:undefined:undefined:undefined":12,"s:127:2:129:Infinity":41,"s:128:4:128:Infinity":42,"s:131:30:131:Infinity":43,"s:132:35:132:Infinity":44,"s:133:2:139:Infinity":45,"f:134:23:134:30":6,"s:135:24:135:Infinity":46,"s:136:21:136:Infinity":47,"s:137:6:137:Infinity":48,"b:137:16:137:33:137:33:137:44":13,"s:141:33:141:Infinity":49,"b:142:2:142:Infinity:undefined:undefined:undefined:undefined":14,"s:142:2:142:Infinity":50,"s:142:28:142:Infinity":51,"b:143:2:143:Infinity:undefined:undefined:undefined:undefined":15,"s:143:2:143:Infinity":52,"s:143:33:143:Infinity":53,"b:144:2:149:Infinity:undefined:undefined:undefined:undefined":16,"s:144:2:149:Infinity":54,"s:145:4:148:Infinity":55,"f:146:46:146:51":7,"s:146:60:146:71":56,"s:151:22:154:Infinity":57,"b:156:2:158:Infinity:undefined:undefined:undefined:undefined":17,"s:156:2:158:Infinity":58,"s:157:4:157:Infinity":59,"s:160:2:160:Infinity":60,"s:162:12:162:Infinity":61,"s:163:2:163:Infinity":62,"s:164:2:177:Infinity":63,"s:165:4:172:Infinity":64,"s:166:20:166:Infinity":65,"f:166:27:166:33":8,"s:166:39:166:66":66,"b:167:6:167:Infinity:undefined:undefined:undefined:undefined":18,"s:167:6:167:Infinity":67,"s:167:18:167:Infinity":68,"s:169:24:169:Infinity":69,"s:170:12:170:Infinity":70,"s:171:6:171:Infinity":71,"s:173:4:173:Infinity":72,"s:175:4:175:Infinity":73,"s:176:4:176:Infinity":74,"s:178:2:178:Infinity":75,"f:181:9:181:33":9,"b:182:2:233:Infinity:undefined:undefined:undefined:undefined":19,"s:182:2:233:Infinity":76,"s:183:20:183:Infinity":77,"b:183:20:183:39:183:39:183:Infinity":20,"s:184:31:184:Infinity":78,"s:185:10:188:Infinity":79,"s:190:44:190:Infinity":80,"s:192:6:195:Infinity":81,"b:192:6:192:Infinity:193:6:193:Infinity:194:6:194:Infinity:195:6:195:Infinity":21,"b:197:4:199:Infinity:undefined:undefined:undefined:undefined":22,"s:197:4:199:Infinity":82,"s:198:6:198:Infinity":83,"s:201:23:201:Infinity":84,"b:201:56:201:67:201:67:201:Infinity":23,"s:202:39:202:Infinity":85,"b:202:39:202:76:202:76:202:Infinity":24,"s:203:21:203:Infinity":86,"f:203:37:203:45":10,"s:203:59:203:92":87,"s:204:4:204:Infinity":88,"b:206:4:226:Infinity:undefined:undefined:undefined:undefined":25,"s:206:4:226:Infinity":89,"s:207:28:207:Infinity":90,"s:208:12:210:Infinity":91,"s:211:6:211:Infinity":92,"b:213:6:223:Infinity:undefined:undefined:undefined:undefined":26,"s:213:6:223:Infinity":93,"s:214:14:221:Infinity":94,"s:222:8:222:Infinity":95,"s:225:6:225:Infinity":96,"s:228:44:231:Infinity":97,"s:232:4:232:Infinity":98,"s:235:40:235:Infinity":99,"b:236:2:242:Infinity:undefined:undefined:undefined:undefined":27,"s:236:2:242:Infinity":100,"s:237:4:241:Infinity":101,"s:238:6:238:Infinity":102,"s:244:21:244:Infinity":103,"b:244:52:244:63:244:63:244:Infinity":28,"s:245:37:245:Infinity":104,"b:245:37:245:72:245:72:245:Infinity":29,"s:246:19:246:Infinity":105,"f:246:35:246:43":11,"s:246:57:246:90":106,"s:247:2:247:Infinity":107,"s:248:2:248:Infinity":108,"s:249:2:249:Infinity":109,"b:249:19:249:37:249:37:249:Infinity":30,"s:251:2:251:Infinity":110,"f:254:9:254:27":12,"b:255:2:255:Infinity:undefined:undefined:undefined:undefined":31,"s:255:2:255:Infinity":111,"b:255:6:255:17:255:17:255:45":32,"s:255:45:255:Infinity":112,"s:257:5:257:Infinity":113,"b:257:5:257:51:257:51:257:Infinity":33,"b:258:2:258:Infinity:undefined:undefined:undefined:undefined":34,"s:258:2:258:Infinity":114,"s:258:31:258:Infinity":115,"s:259:2:259:Infinity":116,"f:259:17:259:23":13,"s:259:38:259:95":117,"b:259:38:259:63:259:63:259:95":35,"f:262:15:262:Infinity":14,"b:268:2:274:Infinity:undefined:undefined:undefined:undefined":36,"s:268:2:274:Infinity":118,"s:269:22:269:Infinity":119,"s:270:21:270:Infinity":120,"b:271:4:271:Infinity:undefined:undefined:undefined:undefined":37,"s:271:4:271:Infinity":121,"s:271:39:271:Infinity":122,"b:272:4:272:Infinity:undefined:undefined:undefined:undefined":38,"s:272:4:272:Infinity":123,"s:272:38:272:Infinity":124,"s:273:4:273:Infinity":125,"s:276:20:276:Infinity":126,"s:277:20:277:Infinity":127,"s:278:19:278:Infinity":128,"b:279:2:279:Infinity:undefined:undefined:undefined:undefined":39,"s:279:2:279:Infinity":129,"s:279:37:279:Infinity":130,"b:280:2:280:Infinity:undefined:undefined:undefined:undefined":40,"s:280:2:280:Infinity":131,"s:280:36:280:Infinity":132,"s:281:2:281:Infinity":133}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/pi.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/pi.ts","statementMap":{"0":{"start":{"line":11,"column":20},"end":{"line":11,"column":null}},"1":{"start":{"line":12,"column":25},"end":{"line":12,"column":null}},"2":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"3":{"start":{"line":24,"column":37},"end":{"line":24,"column":null}},"4":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"5":{"start":{"line":33,"column":26},"end":{"line":33,"column":null}},"6":{"start":{"line":34,"column":25},"end":{"line":37,"column":null}},"7":{"start":{"line":39,"column":2},"end":{"line":42,"column":null}},"8":{"start":{"line":48,"column":61},"end":{"line":48,"column":null}},"9":{"start":{"line":49,"column":12},"end":{"line":49,"column":null}},"10":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"11":{"start":{"line":54,"column":2},"end":{"line":54,"column":null}},"12":{"start":{"line":55,"column":2},"end":{"line":61,"column":null}},"13":{"start":{"line":56,"column":4},"end":{"line":56,"column":null}},"14":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"15":{"start":{"line":59,"column":4},"end":{"line":59,"column":null}},"16":{"start":{"line":60,"column":4},"end":{"line":60,"column":null}},"17":{"start":{"line":64,"column":4},"end":{"line":66,"column":null}},"18":{"start":{"line":68,"column":14},"end":{"line":68,"column":null}},"19":{"start":{"line":70,"column":4},"end":{"line":72,"column":null}},"20":{"start":{"line":74,"column":2},"end":{"line":80,"column":null}},"21":{"start":{"line":75,"column":4},"end":{"line":78,"column":null}},"22":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"23":{"start":{"line":82,"column":2},"end":{"line":96,"column":null}},"24":{"start":{"line":83,"column":24},"end":{"line":86,"column":null}},"25":{"start":{"line":87,"column":4},"end":{"line":91,"column":null}},"26":{"start":{"line":88,"column":6},"end":{"line":88,"column":null}},"27":{"start":{"line":89,"column":6},"end":{"line":89,"column":null}},"28":{"start":{"line":90,"column":6},"end":{"line":90,"column":null}},"29":{"start":{"line":93,"column":4},"end":{"line":93,"column":null}},"30":{"start":{"line":94,"column":4},"end":{"line":94,"column":null}},"31":{"start":{"line":95,"column":4},"end":{"line":95,"column":null}},"32":{"start":{"line":106,"column":51},"end":{"line":106,"column":null}},"33":{"start":{"line":108,"column":8},"end":{"line":108,"column":null}},"34":{"start":{"line":108,"column":46},"end":{"line":108,"column":73}},"35":{"start":{"line":110,"column":2},"end":{"line":112,"column":null}},"36":{"start":{"line":111,"column":4},"end":{"line":111,"column":null}},"37":{"start":{"line":115,"column":4},"end":{"line":117,"column":null}},"38":{"start":{"line":119,"column":2},"end":{"line":119,"column":null}},"39":{"start":{"line":121,"column":26},"end":{"line":124,"column":null}},"40":{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},"41":{"start":{"line":126,"column":24},"end":{"line":126,"column":null}},"42":{"start":{"line":128,"column":28},"end":{"line":135,"column":null}},"43":{"start":{"line":130,"column":36},"end":{"line":134,"column":6}},"44":{"start":{"line":137,"column":16},"end":{"line":137,"column":null}},"45":{"start":{"line":137,"column":35},"end":{"line":137,"column":70}},"46":{"start":{"line":138,"column":2},"end":{"line":138,"column":null}},"47":{"start":{"line":138,"column":14},"end":{"line":138,"column":null}},"48":{"start":{"line":140,"column":23},"end":{"line":140,"column":null}},"49":{"start":{"line":141,"column":21},"end":{"line":143,"column":null}},"50":{"start":{"line":145,"column":22},"end":{"line":148,"column":null}},"51":{"start":{"line":150,"column":2},"end":{"line":152,"column":null}},"52":{"start":{"line":151,"column":4},"end":{"line":151,"column":null}},"53":{"start":{"line":154,"column":12},"end":{"line":154,"column":null}},"54":{"start":{"line":155,"column":2},"end":{"line":155,"column":null}},"55":{"start":{"line":156,"column":2},"end":{"line":165,"column":null}},"56":{"start":{"line":158,"column":6},"end":{"line":158,"column":null}},"57":{"start":{"line":159,"column":4},"end":{"line":159,"column":null}},"58":{"start":{"line":160,"column":4},"end":{"line":160,"column":null}},"59":{"start":{"line":161,"column":4},"end":{"line":161,"column":null}},"60":{"start":{"line":163,"column":4},"end":{"line":163,"column":null}},"61":{"start":{"line":164,"column":4},"end":{"line":164,"column":null}},"62":{"start":{"line":166,"column":2},"end":{"line":166,"column":null}},"63":{"start":{"line":170,"column":2},"end":{"line":170,"column":null}},"64":{"start":{"line":170,"column":49},"end":{"line":170,"column":null}},"65":{"start":{"line":171,"column":20},"end":{"line":171,"column":null}},"66":{"start":{"line":172,"column":2},"end":{"line":172,"column":null}},"67":{"start":{"line":172,"column":32},"end":{"line":172,"column":null}},"68":{"start":{"line":173,"column":2},"end":{"line":180,"column":null}},"69":{"start":{"line":174,"column":4},"end":{"line":174,"column":null}},"70":{"start":{"line":174,"column":31},"end":{"line":174,"column":null}},"71":{"start":{"line":175,"column":4},"end":{"line":178,"column":null}},"72":{"start":{"line":176,"column":22},"end":{"line":176,"column":null}},"73":{"start":{"line":177,"column":6},"end":{"line":177,"column":null}},"74":{"start":{"line":179,"column":4},"end":{"line":179,"column":null}}},"fnMap":{"0":{"name":"getPiLabel","decl":{"start":{"line":23,"column":16},"end":{"line":23,"column":27}},"loc":{"start":{"line":23,"column":81},"end":{"line":26,"column":null}},"line":23},"1":{"name":"getPiState","decl":{"start":{"line":28,"column":22},"end":{"line":28,"column":null}},"loc":{"start":{"line":32,"column":50},"end":{"line":43,"column":null}},"line":32},"2":{"name":"initPi","decl":{"start":{"line":47,"column":22},"end":{"line":47,"column":29}},"loc":{"start":{"line":47,"column":62},"end":{"line":97,"column":null}},"line":47},"3":{"name":"initPiAgent","decl":{"start":{"line":99,"column":22},"end":{"line":99,"column":34}},"loc":{"start":{"line":105,"column":21},"end":{"line":167,"column":null}},"line":105},"4":{"name":"(anonymous_4)","decl":{"start":{"line":108,"column":32},"end":{"line":108,"column":40}},"loc":{"start":{"line":108,"column":46},"end":{"line":108,"column":73}},"line":108},"5":{"name":"(anonymous_5)","decl":{"start":{"line":130,"column":20},"end":{"line":130,"column":25}},"loc":{"start":{"line":130,"column":36},"end":{"line":134,"column":6}},"line":130},"6":{"name":"(anonymous_6)","decl":{"start":{"line":137,"column":23},"end":{"line":137,"column":29}},"loc":{"start":{"line":137,"column":35},"end":{"line":137,"column":70}},"line":137},"7":{"name":"hasPiProviderInSettings","decl":{"start":{"line":169,"column":9},"end":{"line":169,"column":33}},"loc":{"start":{"line":169,"column":61},"end":{"line":181,"column":null}},"line":169},"8":{"name":"(anonymous_8)","decl":{"start":{"line":173,"column":18},"end":{"line":173,"column":24}},"loc":{"start":{"line":173,"column":39},"end":{"line":180,"column":3}},"line":173}},"branchMap":{"0":{"loc":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":24},"1":{"loc":{"start":{"line":24,"column":6},"end":{"line":24,"column":37}},"type":"binary-expr","locations":[{"start":{"line":24,"column":6},"end":{"line":24,"column":23}},{"start":{"line":24,"column":23},"end":{"line":24,"column":37}}],"line":24},"2":{"loc":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"type":"cond-expr","locations":[{"start":{"line":52,"column":26},"end":{"line":52,"column":59}},{"start":{"line":52,"column":59},"end":{"line":52,"column":null}}],"line":52},"3":{"loc":{"start":{"line":64,"column":4},"end":{"line":66,"column":null}},"type":"cond-expr","locations":[{"start":{"line":65,"column":8},"end":{"line":65,"column":null}},{"start":{"line":66,"column":8},"end":{"line":66,"column":null}}],"line":64},"4":{"loc":{"start":{"line":70,"column":4},"end":{"line":72,"column":null}},"type":"cond-expr","locations":[{"start":{"line":71,"column":9},"end":{"line":71,"column":null}},{"start":{"line":72,"column":8},"end":{"line":72,"column":null}}],"line":70},"5":{"loc":{"start":{"line":70,"column":4},"end":{"line":70,"column":null}},"type":"binary-expr","locations":[{"start":{"line":70,"column":4},"end":{"line":70,"column":31}},{"start":{"line":70,"column":31},"end":{"line":70,"column":47}},{"start":{"line":70,"column":47},"end":{"line":70,"column":null}}],"line":70},"6":{"loc":{"start":{"line":74,"column":2},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":74,"column":2},"end":{"line":80,"column":null}},{"start":{},"end":{}}],"line":74},"7":{"loc":{"start":{"line":82,"column":2},"end":{"line":96,"column":null}},"type":"if","locations":[{"start":{"line":82,"column":2},"end":{"line":96,"column":null}},{"start":{"line":92,"column":9},"end":{"line":96,"column":null}}],"line":82},"8":{"loc":{"start":{"line":87,"column":4},"end":{"line":91,"column":null}},"type":"if","locations":[{"start":{"line":87,"column":4},"end":{"line":91,"column":null}},{"start":{},"end":{}}],"line":87},"9":{"loc":{"start":{"line":110,"column":2},"end":{"line":112,"column":null}},"type":"if","locations":[{"start":{"line":110,"column":2},"end":{"line":112,"column":null}},{"start":{},"end":{}}],"line":110},"10":{"loc":{"start":{"line":115,"column":4},"end":{"line":117,"column":null}},"type":"cond-expr","locations":[{"start":{"line":116,"column":8},"end":{"line":116,"column":null}},{"start":{"line":117,"column":8},"end":{"line":117,"column":null}}],"line":115},"11":{"loc":{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},"type":"if","locations":[{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},{"start":{},"end":{}}],"line":126},"12":{"loc":{"start":{"line":138,"column":2},"end":{"line":138,"column":null}},"type":"if","locations":[{"start":{"line":138,"column":2},"end":{"line":138,"column":null}},{"start":{},"end":{}}],"line":138},"13":{"loc":{"start":{"line":141,"column":21},"end":{"line":143,"column":null}},"type":"cond-expr","locations":[{"start":{"line":142,"column":6},"end":{"line":142,"column":null}},{"start":{"line":143,"column":6},"end":{"line":143,"column":null}}],"line":141},"14":{"loc":{"start":{"line":150,"column":2},"end":{"line":152,"column":null}},"type":"if","locations":[{"start":{"line":150,"column":2},"end":{"line":152,"column":null}},{"start":{},"end":{}}],"line":150},"15":{"loc":{"start":{"line":158,"column":6},"end":{"line":158,"column":null}},"type":"cond-expr","locations":[{"start":{"line":158,"column":28},"end":{"line":158,"column":52}},{"start":{"line":158,"column":52},"end":{"line":158,"column":null}}],"line":158},"16":{"loc":{"start":{"line":170,"column":2},"end":{"line":170,"column":null}},"type":"if","locations":[{"start":{"line":170,"column":2},"end":{"line":170,"column":null}},{"start":{},"end":{}}],"line":170},"17":{"loc":{"start":{"line":170,"column":6},"end":{"line":170,"column":49}},"type":"binary-expr","locations":[{"start":{"line":170,"column":6},"end":{"line":170,"column":19}},{"start":{"line":170,"column":19},"end":{"line":170,"column":49}}],"line":170},"18":{"loc":{"start":{"line":172,"column":2},"end":{"line":172,"column":null}},"type":"if","locations":[{"start":{"line":172,"column":2},"end":{"line":172,"column":null}},{"start":{},"end":{}}],"line":172},"19":{"loc":{"start":{"line":174,"column":4},"end":{"line":174,"column":null}},"type":"if","locations":[{"start":{"line":174,"column":4},"end":{"line":174,"column":null}},{"start":{},"end":{}}],"line":174},"20":{"loc":{"start":{"line":175,"column":4},"end":{"line":178,"column":null}},"type":"if","locations":[{"start":{"line":175,"column":4},"end":{"line":178,"column":null}},{"start":{},"end":{}}],"line":175},"21":{"loc":{"start":{"line":175,"column":8},"end":{"line":175,"column":45}},"type":"binary-expr","locations":[{"start":{"line":175,"column":8},"end":{"line":175,"column":33}},{"start":{"line":175,"column":33},"end":{"line":175,"column":45}}],"line":175},"22":{"loc":{"start":{"line":177,"column":13},"end":{"line":177,"column":null}},"type":"binary-expr","locations":[{"start":{"line":177,"column":13},"end":{"line":177,"column":43}},{"start":{"line":177,"column":43},"end":{"line":177,"column":null}}],"line":177}},"s":{"0":1,"1":1,"2":46,"3":0,"4":46,"5":46,"6":46,"7":46,"8":12,"9":12,"10":12,"11":12,"12":12,"13":12,"14":10,"15":2,"16":2,"17":10,"18":12,"19":10,"20":12,"21":0,"22":0,"23":10,"24":0,"25":0,"26":0,"27":0,"28":0,"29":10,"30":10,"31":10,"32":10,"33":10,"34":70,"35":10,"36":0,"37":10,"38":10,"39":10,"40":10,"41":1,"42":9,"43":45,"44":9,"45":42,"46":9,"47":0,"48":9,"49":9,"50":10,"51":9,"52":1,"53":8,"54":8,"55":8,"56":8,"57":10,"58":8,"59":8,"60":0,"61":0,"62":8,"63":92,"64":91,"65":1,"66":1,"67":1,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0},"f":{"0":46,"1":46,"2":12,"3":10,"4":70,"5":45,"6":42,"7":92,"8":0},"b":{"0":[0,46],"1":[46,46],"2":[11,1],"3":[9,1],"4":[1,9],"5":[10,10,1],"6":[0,12],"7":[0,10],"8":[0,0],"9":[0,10],"10":[9,1],"11":[1,9],"12":[0,9],"13":[1,8],"14":[1,8],"15":[7,1],"16":[91,1],"17":[92,1],"18":[1,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0]},"meta":{"lastBranch":23,"lastFunction":9,"lastStatement":75,"seen":{"s:11:20:11:Infinity":0,"s:12:25:12:Infinity":1,"f:23:16:23:27":0,"b:24:2:24:Infinity:undefined:undefined:undefined:undefined":0,"s:24:2:24:Infinity":2,"b:24:6:24:23:24:23:24:37":1,"s:24:37:24:Infinity":3,"s:25:2:25:Infinity":4,"f:28:22:28:Infinity":1,"s:33:26:33:Infinity":5,"s:34:25:37:Infinity":6,"s:39:2:42:Infinity":7,"f:47:22:47:29":2,"s:48:61:48:Infinity":8,"s:49:12:49:Infinity":9,"s:52:4:52:Infinity":10,"b:52:26:52:59:52:59:52:Infinity":2,"s:54:2:54:Infinity":11,"s:55:2:61:Infinity":12,"s:56:4:56:Infinity":13,"s:57:4:57:Infinity":14,"s:59:4:59:Infinity":15,"s:60:4:60:Infinity":16,"s:64:4:66:Infinity":17,"b:65:8:65:Infinity:66:8:66:Infinity":3,"s:68:14:68:Infinity":18,"s:70:4:72:Infinity":19,"b:71:9:71:Infinity:72:8:72:Infinity":4,"b:70:4:70:31:70:31:70:47:70:47:70:Infinity":5,"b:74:2:80:Infinity:undefined:undefined:undefined:undefined":6,"s:74:2:80:Infinity":20,"s:75:4:78:Infinity":21,"s:79:4:79:Infinity":22,"b:82:2:96:Infinity:92:9:96:Infinity":7,"s:82:2:96:Infinity":23,"s:83:24:86:Infinity":24,"b:87:4:91:Infinity:undefined:undefined:undefined:undefined":8,"s:87:4:91:Infinity":25,"s:88:6:88:Infinity":26,"s:89:6:89:Infinity":27,"s:90:6:90:Infinity":28,"s:93:4:93:Infinity":29,"s:94:4:94:Infinity":30,"s:95:4:95:Infinity":31,"f:99:22:99:34":3,"s:106:51:106:Infinity":32,"s:108:8:108:Infinity":33,"f:108:32:108:40":4,"s:108:46:108:73":34,"b:110:2:112:Infinity:undefined:undefined:undefined:undefined":9,"s:110:2:112:Infinity":35,"s:111:4:111:Infinity":36,"s:115:4:117:Infinity":37,"b:116:8:116:Infinity:117:8:117:Infinity":10,"s:119:2:119:Infinity":38,"s:121:26:124:Infinity":39,"b:126:2:126:Infinity:undefined:undefined:undefined:undefined":11,"s:126:2:126:Infinity":40,"s:126:24:126:Infinity":41,"s:128:28:135:Infinity":42,"f:130:20:130:25":5,"s:130:36:134:6":43,"s:137:16:137:Infinity":44,"f:137:23:137:29":6,"s:137:35:137:70":45,"b:138:2:138:Infinity:undefined:undefined:undefined:undefined":12,"s:138:2:138:Infinity":46,"s:138:14:138:Infinity":47,"s:140:23:140:Infinity":48,"s:141:21:143:Infinity":49,"b:142:6:142:Infinity:143:6:143:Infinity":13,"s:145:22:148:Infinity":50,"b:150:2:152:Infinity:undefined:undefined:undefined:undefined":14,"s:150:2:152:Infinity":51,"s:151:4:151:Infinity":52,"s:154:12:154:Infinity":53,"s:155:2:155:Infinity":54,"s:156:2:165:Infinity":55,"s:158:6:158:Infinity":56,"b:158:28:158:52:158:52:158:Infinity":15,"s:159:4:159:Infinity":57,"s:160:4:160:Infinity":58,"s:161:4:161:Infinity":59,"s:163:4:163:Infinity":60,"s:164:4:164:Infinity":61,"s:166:2:166:Infinity":62,"f:169:9:169:33":7,"b:170:2:170:Infinity:undefined:undefined:undefined:undefined":16,"s:170:2:170:Infinity":63,"b:170:6:170:19:170:19:170:49":17,"s:170:49:170:Infinity":64,"s:171:20:171:Infinity":65,"b:172:2:172:Infinity:undefined:undefined:undefined:undefined":18,"s:172:2:172:Infinity":66,"s:172:32:172:Infinity":67,"s:173:2:180:Infinity":68,"f:173:18:173:24":8,"b:174:4:174:Infinity:undefined:undefined:undefined:undefined":19,"s:174:4:174:Infinity":69,"s:174:31:174:Infinity":70,"b:175:4:178:Infinity:undefined:undefined:undefined:undefined":20,"s:175:4:178:Infinity":71,"b:175:8:175:33:175:33:175:45":21,"s:176:22:176:Infinity":72,"s:177:6:177:Infinity":73,"b:177:13:177:43:177:43:177:Infinity":22,"s:179:4:179:Infinity":74}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/tool-check.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/tool-check.ts","statementMap":{"0":{"start":{"line":19,"column":68},"end":{"line":32,"column":null}},"1":{"start":{"line":38,"column":20},"end":{"line":38,"column":null}},"2":{"start":{"line":39,"column":15},"end":{"line":39,"column":null}},"3":{"start":{"line":41,"column":2},"end":{"line":47,"column":null}},"4":{"start":{"line":54,"column":18},"end":{"line":54,"column":null}},"5":{"start":{"line":55,"column":2},"end":{"line":55,"column":null}},"6":{"start":{"line":57,"column":17},"end":{"line":64,"column":null}},"7":{"start":{"line":66,"column":2},"end":{"line":66,"column":null}},"8":{"start":{"line":70,"column":2},"end":{"line":74,"column":null}},"9":{"start":{"line":71,"column":4},"end":{"line":73,"column":null}},"10":{"start":{"line":75,"column":2},"end":{"line":77,"column":null}}},"fnMap":{"0":{"name":"checkTool","decl":{"start":{"line":34,"column":22},"end":{"line":34,"column":null}},"loc":{"start":{"line":37,"column":28},"end":{"line":48,"column":null}},"line":37},"1":{"name":"promptForMissingTool","decl":{"start":{"line":50,"column":22},"end":{"line":50,"column":null}},"loc":{"start":{"line":53,"column":42},"end":{"line":67,"column":null}},"line":53},"2":{"name":"getInstallCommand","decl":{"start":{"line":69,"column":9},"end":{"line":69,"column":27}},"loc":{"start":{"line":69,"column":78},"end":{"line":78,"column":null}},"line":69}},"branchMap":{"0":{"loc":{"start":{"line":70,"column":2},"end":{"line":74,"column":null}},"type":"if","locations":[{"start":{"line":70,"column":2},"end":{"line":74,"column":null}},{"start":{},"end":{}}],"line":70},"1":{"loc":{"start":{"line":71,"column":11},"end":{"line":73,"column":null}},"type":"cond-expr","locations":[{"start":{"line":72,"column":8},"end":{"line":72,"column":null}},{"start":{"line":73,"column":8},"end":{"line":73,"column":null}}],"line":71},"2":{"loc":{"start":{"line":75,"column":9},"end":{"line":77,"column":null}},"type":"cond-expr","locations":[{"start":{"line":76,"column":6},"end":{"line":76,"column":null}},{"start":{"line":77,"column":6},"end":{"line":77,"column":null}}],"line":75}},"s":{"0":1,"1":50,"2":48,"3":48,"4":11,"5":11,"6":11,"7":11,"8":48,"9":0,"10":48},"f":{"0":50,"1":11,"2":48},"b":{"0":[0,48],"1":[0,0],"2":[33,15]},"meta":{"lastBranch":3,"lastFunction":3,"lastStatement":11,"seen":{"s:19:68:32:Infinity":0,"f:34:22:34:Infinity":0,"s:38:20:38:Infinity":1,"s:39:15:39:Infinity":2,"s:41:2:47:Infinity":3,"f:50:22:50:Infinity":1,"s:54:18:54:Infinity":4,"s:55:2:55:Infinity":5,"s:57:17:64:Infinity":6,"s:66:2:66:Infinity":7,"f:69:9:69:27":2,"b:70:2:74:Infinity:undefined:undefined:undefined:undefined":0,"s:70:2:74:Infinity":8,"s:71:4:73:Infinity":9,"b:72:8:72:Infinity:73:8:73:Infinity":1,"s:75:2:77:Infinity":10,"b:76:6:76:Infinity:77:6:77:Infinity":2}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/utils.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/utils.ts","statementMap":{"0":{"start":{"line":4,"column":18},"end":{"line":4,"column":null}},"1":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"2":{"start":{"line":5,"column":16},"end":{"line":5,"column":null}},"3":{"start":{"line":6,"column":2},"end":{"line":14,"column":null}},"4":{"start":{"line":7,"column":4},"end":{"line":7,"column":null}},"5":{"start":{"line":9,"column":4},"end":{"line":13,"column":null}},"6":{"start":{"line":10,"column":6},"end":{"line":10,"column":null}},"7":{"start":{"line":12,"column":6},"end":{"line":12,"column":null}},"8":{"start":{"line":18,"column":2},"end":{"line":18,"column":null}},"9":{"start":{"line":19,"column":2},"end":{"line":19,"column":null}},"10":{"start":{"line":20,"column":2},"end":{"line":20,"column":null}},"11":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}}},"fnMap":{"0":{"name":"readJsonMaybe","decl":{"start":{"line":3,"column":22},"end":{"line":3,"column":36}},"loc":{"start":{"line":3,"column":97},"end":{"line":15,"column":null}},"line":3},"1":{"name":"stripJsoncComments","decl":{"start":{"line":17,"column":16},"end":{"line":17,"column":35}},"loc":{"start":{"line":17,"column":60},"end":{"line":21,"column":null}},"line":17},"2":{"name":"writeJsonFile","decl":{"start":{"line":23,"column":22},"end":{"line":23,"column":null}},"loc":{"start":{"line":27,"column":17},"end":{"line":29,"column":null}},"line":27}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"type":"if","locations":[{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},{"start":{},"end":{}}],"line":5}},"s":{"0":286,"1":286,"2":280,"3":6,"4":6,"5":1,"6":1,"7":0,"8":1,"9":1,"10":1,"11":10},"f":{"0":286,"1":1,"2":10},"b":{"0":[280,6]},"meta":{"lastBranch":1,"lastFunction":3,"lastStatement":12,"seen":{"f:3:22:3:36":0,"s:4:18:4:Infinity":0,"b:5:2:5:Infinity:undefined:undefined:undefined:undefined":0,"s:5:2:5:Infinity":1,"s:5:16:5:Infinity":2,"s:6:2:14:Infinity":3,"s:7:4:7:Infinity":4,"s:9:4:13:Infinity":5,"s:10:6:10:Infinity":6,"s:12:6:12:Infinity":7,"f:17:16:17:35":1,"s:18:2:18:Infinity":8,"s:19:2:19:Infinity":9,"s:20:2:20:Infinity":10,"f:23:22:23:Infinity":2,"s:28:2:28:Infinity":11}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-api-key-service.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-api-key-service.ts","statementMap":{"0":{"start":{"line":9,"column":4},"end":{"line":9,"column":null}},"1":{"start":{"line":10,"column":4},"end":{"line":10,"column":null}},"2":{"start":{"line":11,"column":4},"end":{"line":11,"column":null}},"3":{"start":{"line":15,"column":4},"end":{"line":17,"column":null}},"4":{"start":{"line":16,"column":6},"end":{"line":16,"column":null}},"5":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":8,"column":2},"end":{"line":8,"column":14}},"loc":{"start":{"line":8,"column":89},"end":{"line":12,"column":null}},"line":8},"1":{"name":"create","decl":{"start":{"line":14,"column":8},"end":{"line":14,"column":15}},"loc":{"start":{"line":14,"column":91},"end":{"line":19,"column":null}},"line":14}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":27},"end":{"line":8,"column":47}},"type":"default-arg","locations":[{"start":{"line":8,"column":40},"end":{"line":8,"column":47}}],"line":8},"1":{"loc":{"start":{"line":8,"column":47},"end":{"line":8,"column":89}},"type":"default-arg","locations":[{"start":{"line":8,"column":62},"end":{"line":8,"column":89}}],"line":8},"2":{"loc":{"start":{"line":15,"column":4},"end":{"line":17,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":17,"column":null}},{"start":{},"end":{}}],"line":15}},"s":{"0":46,"1":46,"2":46,"3":1,"4":0,"5":1},"f":{"0":46,"1":1},"b":{"0":[46],"1":[46],"2":[0,1]},"meta":{"lastBranch":3,"lastFunction":2,"lastStatement":6,"seen":{"f:8:2:8:14":0,"b:8:40:8:47":0,"b:8:62:8:89":1,"s:9:4:9:Infinity":0,"s:10:4:10:Infinity":1,"s:11:4:11:Infinity":2,"f:14:8:14:15":1,"b:15:4:17:Infinity:undefined:undefined:undefined:undefined":2,"s:15:4:17:Infinity":3,"s:16:6:16:Infinity":4,"s:18:4:18:Infinity":5}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-auth-service.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-auth-service.ts","statementMap":{"0":{"start":{"line":4,"column":19},"end":{"line":4,"column":null}},"1":{"start":{"line":5,"column":30},"end":{"line":5,"column":null}},"2":{"start":{"line":8,"column":21},"end":{"line":8,"column":null}},"3":{"start":{"line":9,"column":21},"end":{"line":9,"column":41}},"4":{"start":{"line":10,"column":21},"end":{"line":10,"column":44}},"5":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"6":{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},"7":{"start":{"line":21,"column":4},"end":{"line":21,"column":null}},"8":{"start":{"line":22,"column":4},"end":{"line":24,"column":null}},"9":{"start":{"line":23,"column":6},"end":{"line":23,"column":null}},"10":{"start":{"line":26,"column":22},"end":{"line":26,"column":null}},"11":{"start":{"line":28,"column":24},"end":{"line":33,"column":null}},"12":{"start":{"line":35,"column":4},"end":{"line":40,"column":null}},"13":{"start":{"line":45,"column":2},"end":{"line":45,"column":null}},"14":{"start":{"line":49,"column":17},"end":{"line":49,"column":null}},"15":{"start":{"line":50,"column":15},"end":{"line":50,"column":null}},"16":{"start":{"line":51,"column":2},"end":{"line":51,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"loc":{"start":{"line":11,"column":4},"end":{"line":11,"column":null}},"line":11},"1":{"name":"login","decl":{"start":{"line":13,"column":8},"end":{"line":13,"column":34}},"loc":{"start":{"line":13,"column":34},"end":{"line":16,"column":null}},"line":13},"2":{"name":"loginInteractive","decl":{"start":{"line":18,"column":2},"end":{"line":18,"column":19}},"loc":{"start":{"line":20,"column":54},"end":{"line":41,"column":null}},"line":20},"3":{"name":"base64urlEncode","decl":{"start":{"line":44,"column":9},"end":{"line":44,"column":25}},"loc":{"start":{"line":44,"column":47},"end":{"line":46,"column":null}},"line":44},"4":{"name":"makeJwt","decl":{"start":{"line":48,"column":9},"end":{"line":48,"column":17}},"loc":{"start":{"line":48,"column":59},"end":{"line":52,"column":null}},"line":48}},"branchMap":{"0":{"loc":{"start":{"line":9,"column":4},"end":{"line":9,"column":null}},"type":"default-arg","locations":[{"start":{"line":9,"column":41},"end":{"line":9,"column":null}}],"line":9},"1":{"loc":{"start":{"line":10,"column":4},"end":{"line":10,"column":null}},"type":"default-arg","locations":[{"start":{"line":10,"column":44},"end":{"line":10,"column":null}}],"line":10},"2":{"loc":{"start":{"line":22,"column":4},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":4},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":22},"3":{"loc":{"start":{"line":28,"column":24},"end":{"line":33,"column":null}},"type":"cond-expr","locations":[{"start":{"line":29,"column":8},"end":{"line":32,"column":null}},{"start":{"line":33,"column":8},"end":{"line":33,"column":null}}],"line":28},"4":{"loc":{"start":{"line":31,"column":33},"end":{"line":31,"column":97}},"type":"cond-expr","locations":[{"start":{"line":31,"column":49},"end":{"line":31,"column":72}},{"start":{"line":31,"column":72},"end":{"line":31,"column":97}}],"line":31}},"s":{"0":46,"1":46,"2":46,"3":46,"4":46,"5":0,"6":0,"7":44,"8":44,"9":43,"10":1,"11":1,"12":44,"13":2,"14":1,"15":1,"16":1},"f":{"0":46,"1":0,"2":44,"3":2,"4":1},"b":{"0":[46],"1":[46],"2":[43,1],"3":[1,0],"4":[0,1]},"meta":{"lastBranch":5,"lastFunction":5,"lastStatement":17,"seen":{"s:4:19:4:Infinity":0,"s:5:30:5:Infinity":1,"f:7:2:7:Infinity":0,"b:9:41:9:Infinity":0,"b:10:44:10:Infinity":1,"s:8:21:8:Infinity":2,"s:9:21:9:41":3,"s:10:21:10:44":4,"f:13:8:13:34":1,"s:14:4:14:Infinity":5,"s:15:4:15:Infinity":6,"f:18:2:18:19":2,"s:21:4:21:Infinity":7,"b:22:4:24:Infinity:undefined:undefined:undefined:undefined":2,"s:22:4:24:Infinity":8,"s:23:6:23:Infinity":9,"s:26:22:26:Infinity":10,"s:28:24:33:Infinity":11,"b:29:8:32:Infinity:33:8:33:Infinity":3,"b:31:49:31:72:31:72:31:97":4,"s:35:4:40:Infinity":12,"f:44:9:44:25":3,"s:45:2:45:Infinity":13,"f:48:9:48:17":4,"s:49:17:49:Infinity":14,"s:50:15:50:Infinity":15,"s:51:2:51:Infinity":16}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-command-runner.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-command-runner.ts","statementMap":{"0":{"start":{"line":12,"column":91},"end":{"line":12,"column":null}},"1":{"start":{"line":14,"column":32},"end":{"line":14,"column":null}},"2":{"start":{"line":10,"column":4},"end":{"line":10,"column":null}},"3":{"start":{"line":17,"column":4},"end":{"line":17,"column":null}},"4":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"5":{"start":{"line":18,"column":53},"end":{"line":18,"column":83}},"6":{"start":{"line":22,"column":4},"end":{"line":29,"column":null}},"7":{"start":{"line":24,"column":21},"end":{"line":24,"column":null}},"8":{"start":{"line":25,"column":8},"end":{"line":25,"column":null}},"9":{"start":{"line":25,"column":39},"end":{"line":25,"column":null}},"10":{"start":{"line":26,"column":8},"end":{"line":26,"column":null}},"11":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"12":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"13":{"start":{"line":39,"column":20},"end":{"line":39,"column":null}},"14":{"start":{"line":39,"column":46},"end":{"line":39,"column":74}},"15":{"start":{"line":40,"column":4},"end":{"line":40,"column":null}},"16":{"start":{"line":40,"column":18},"end":{"line":40,"column":null}},"17":{"start":{"line":43,"column":6},"end":{"line":45,"column":null}},"18":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"19":{"start":{"line":47,"column":33},"end":{"line":47,"column":null}},"20":{"start":{"line":48,"column":4},"end":{"line":48,"column":null}}},"fnMap":{"0":{"name":"calls","decl":{"start":{"line":9,"column":6},"end":{"line":9,"column":14}},"loc":{"start":{"line":9,"column":14},"end":{"line":11,"column":null}},"line":9},"1":{"name":"checkInstalled","decl":{"start":{"line":16,"column":2},"end":{"line":16,"column":17}},"loc":{"start":{"line":16,"column":51},"end":{"line":19,"column":null}},"line":16},"2":{"name":"(anonymous_2)","decl":{"start":{"line":18,"column":41},"end":{"line":18,"column":47}},"loc":{"start":{"line":18,"column":53},"end":{"line":18,"column":83}},"line":18},"3":{"name":"handle","decl":{"start":{"line":21,"column":2},"end":{"line":21,"column":9}},"loc":{"start":{"line":21,"column":65},"end":{"line":31,"column":null}},"line":21},"4":{"name":"(anonymous_4)","decl":{"start":{"line":23,"column":6},"end":{"line":23,"column":14}},"loc":{"start":{"line":23,"column":34},"end":{"line":27,"column":null}},"line":23},"5":{"name":"run","decl":{"start":{"line":33,"column":8},"end":{"line":33,"column":null}},"loc":{"start":{"line":37,"column":21},"end":{"line":49,"column":null}},"line":37},"6":{"name":"(anonymous_6)","decl":{"start":{"line":39,"column":34},"end":{"line":39,"column":40}},"loc":{"start":{"line":39,"column":46},"end":{"line":39,"column":74}},"line":39}},"branchMap":{"0":{"loc":{"start":{"line":18,"column":27},"end":{"line":18,"column":93}},"type":"binary-expr","locations":[{"start":{"line":18,"column":27},"end":{"line":18,"column":88}},{"start":{"line":18,"column":88},"end":{"line":18,"column":93}}],"line":18},"1":{"loc":{"start":{"line":25,"column":8},"end":{"line":25,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":8},"end":{"line":25,"column":null}},{"start":{},"end":{}}],"line":25},"2":{"loc":{"start":{"line":40,"column":4},"end":{"line":40,"column":null}},"type":"if","locations":[{"start":{"line":40,"column":4},"end":{"line":40,"column":null}},{"start":{},"end":{}}],"line":40},"3":{"loc":{"start":{"line":43,"column":6},"end":{"line":45,"column":null}},"type":"cond-expr","locations":[{"start":{"line":44,"column":10},"end":{"line":44,"column":null}},{"start":{"line":45,"column":10},"end":{"line":45,"column":null}}],"line":43},"4":{"loc":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},{"start":{},"end":{}}],"line":47}},"s":{"0":36,"1":36,"2":3,"3":34,"4":34,"5":29,"6":61,"7":53,"8":53,"9":53,"10":0,"11":61,"12":12,"13":12,"14":24,"15":12,"16":0,"17":12,"18":12,"19":2,"20":10},"f":{"0":3,"1":34,"2":29,"3":61,"4":53,"5":12,"6":24},"b":{"0":[34,5],"1":[53,0],"2":[0,12],"3":[0,12],"4":[2,10]},"meta":{"lastBranch":5,"lastFunction":7,"lastStatement":21,"seen":{"s:12:91:12:Infinity":0,"s:14:32:14:Infinity":1,"f:9:6:9:14":0,"s:10:4:10:Infinity":2,"f:16:2:16:17":1,"s:17:4:17:Infinity":3,"s:18:4:18:Infinity":4,"b:18:27:18:88:18:88:18:93":0,"f:18:41:18:47":2,"s:18:53:18:83":5,"f:21:2:21:9":3,"s:22:4:29:Infinity":6,"f:23:6:23:14":4,"s:24:21:24:Infinity":7,"b:25:8:25:Infinity:undefined:undefined:undefined:undefined":1,"s:25:8:25:Infinity":8,"s:25:39:25:Infinity":9,"s:26:8:26:Infinity":10,"s:30:4:30:Infinity":11,"f:33:8:33:Infinity":5,"s:38:4:38:Infinity":12,"s:39:20:39:Infinity":13,"f:39:34:39:40":6,"s:39:46:39:74":14,"b:40:4:40:Infinity:undefined:undefined:undefined:undefined":2,"s:40:4:40:Infinity":15,"s:40:18:40:Infinity":16,"s:43:6:45:Infinity":17,"b:44:10:44:Infinity:45:10:45:Infinity":3,"b:47:4:47:Infinity:undefined:undefined:undefined:undefined":4,"s:47:4:47:Infinity":18,"s:47:33:47:Infinity":19,"s:48:4:48:Infinity":20}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-file-store.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-file-store.ts","statementMap":{"0":{"start":{"line":9,"column":63},"end":{"line":9,"column":null}},"1":{"start":{"line":10,"column":30},"end":{"line":10,"column":null}},"2":{"start":{"line":11,"column":39},"end":{"line":11,"column":null}},"3":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"4":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"5":{"start":{"line":22,"column":4},"end":{"line":22,"column":null}},"6":{"start":{"line":26,"column":4},"end":{"line":26,"column":null}},"7":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"8":{"start":{"line":34,"column":4},"end":{"line":34,"column":null}},"9":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"10":{"start":{"line":42,"column":4},"end":{"line":42,"column":null}}},"fnMap":{"0":{"name":"chmod","decl":{"start":{"line":13,"column":8},"end":{"line":13,"column":14}},"loc":{"start":{"line":13,"column":57},"end":{"line":15,"column":null}},"line":13},"1":{"name":"exists","decl":{"start":{"line":17,"column":8},"end":{"line":17,"column":15}},"loc":{"start":{"line":17,"column":47},"end":{"line":19,"column":null}},"line":17},"2":{"name":"getChmodCalls","decl":{"start":{"line":21,"column":2},"end":{"line":21,"column":57}},"loc":{"start":{"line":21,"column":57},"end":{"line":23,"column":null}},"line":21},"3":{"name":"getWrittenFiles","decl":{"start":{"line":25,"column":2},"end":{"line":25,"column":41}},"loc":{"start":{"line":25,"column":41},"end":{"line":27,"column":null}},"line":25},"4":{"name":"mkdir","decl":{"start":{"line":29,"column":8},"end":{"line":29,"column":14}},"loc":{"start":{"line":29,"column":43},"end":{"line":31,"column":null}},"line":29},"5":{"name":"readFile","decl":{"start":{"line":33,"column":8},"end":{"line":33,"column":17}},"loc":{"start":{"line":33,"column":55},"end":{"line":35,"column":null}},"line":33},"6":{"name":"seed","decl":{"start":{"line":37,"column":2},"end":{"line":37,"column":7}},"loc":{"start":{"line":37,"column":44},"end":{"line":39,"column":null}},"line":37},"7":{"name":"writeFile","decl":{"start":{"line":41,"column":8},"end":{"line":41,"column":18}},"loc":{"start":{"line":41,"column":64},"end":{"line":43,"column":null}},"line":41}},"branchMap":{"0":{"loc":{"start":{"line":18,"column":11},"end":{"line":18,"column":null}},"type":"binary-expr","locations":[{"start":{"line":18,"column":11},"end":{"line":18,"column":35}},{"start":{"line":18,"column":35},"end":{"line":18,"column":null}}],"line":18},"1":{"loc":{"start":{"line":34,"column":11},"end":{"line":34,"column":null}},"type":"binary-expr","locations":[{"start":{"line":34,"column":11},"end":{"line":34,"column":35}},{"start":{"line":34,"column":35},"end":{"line":34,"column":null}}],"line":34}},"s":{"0":45,"1":45,"2":45,"3":3,"4":145,"5":0,"6":24,"7":12,"8":390,"9":8,"10":44},"f":{"0":3,"1":145,"2":0,"3":24,"4":12,"5":390,"6":8,"7":44},"b":{"0":[145,136],"1":[390,377]},"meta":{"lastBranch":2,"lastFunction":8,"lastStatement":11,"seen":{"s:9:63:9:Infinity":0,"s:10:30:10:Infinity":1,"s:11:39:11:Infinity":2,"f:13:8:13:14":0,"s:14:4:14:Infinity":3,"f:17:8:17:15":1,"s:18:4:18:Infinity":4,"b:18:11:18:35:18:35:18:Infinity":0,"f:21:2:21:57":2,"s:22:4:22:Infinity":5,"f:25:2:25:41":3,"s:26:4:26:Infinity":6,"f:29:8:29:14":4,"s:30:4:30:Infinity":7,"f:33:8:33:17":5,"s:34:4:34:Infinity":8,"b:34:11:34:35:34:35:34:Infinity":1,"f:37:2:37:7":6,"s:38:4:38:Infinity":9,"f:41:8:41:18":7,"s:42:4:42:Infinity":10}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-prompter.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-prompter.ts","statementMap":{"0":{"start":{"line":5,"column":22},"end":{"line":5,"column":null}},"1":{"start":{"line":13,"column":13},"end":{"line":17,"column":null}},"2":{"start":{"line":13,"column":87},"end":{"line":17,"column":null}},"3":{"start":{"line":19,"column":13},"end":{"line":23,"column":null}},"4":{"start":{"line":19,"column":87},"end":{"line":23,"column":null}},"5":{"start":{"line":25,"column":13},"end":{"line":29,"column":null}},"6":{"start":{"line":25,"column":91},"end":{"line":29,"column":null}},"7":{"start":{"line":31,"column":13},"end":{"line":35,"column":null}},"8":{"start":{"line":31,"column":95},"end":{"line":35,"column":null}},"9":{"start":{"line":41,"column":61},"end":{"line":41,"column":null}},"10":{"start":{"line":43,"column":20},"end":{"line":43,"column":null}},"11":{"start":{"line":39,"column":4},"end":{"line":39,"column":null}},"12":{"start":{"line":45,"column":31},"end":{"line":45,"column":55}},"13":{"start":{"line":47,"column":4},"end":{"line":49,"column":null}},"14":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"15":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"16":{"start":{"line":55,"column":4},"end":{"line":55,"column":null}},"17":{"start":{"line":56,"column":18},"end":{"line":56,"column":null}},"18":{"start":{"line":57,"column":4},"end":{"line":58,"column":null}},"19":{"start":{"line":58,"column":6},"end":{"line":58,"column":null}},"20":{"start":{"line":59,"column":4},"end":{"line":60,"column":null}},"21":{"start":{"line":60,"column":6},"end":{"line":60,"column":null}},"22":{"start":{"line":61,"column":4},"end":{"line":62,"column":null}},"23":{"start":{"line":62,"column":6},"end":{"line":62,"column":null}},"24":{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},"25":{"start":{"line":63,"column":35},"end":{"line":63,"column":null}},"26":{"start":{"line":64,"column":4},"end":{"line":64,"column":null}},"27":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"28":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"29":{"start":{"line":75,"column":4},"end":{"line":75,"column":null}},"30":{"start":{"line":76,"column":18},"end":{"line":76,"column":null}},"31":{"start":{"line":77,"column":4},"end":{"line":78,"column":null}},"32":{"start":{"line":78,"column":6},"end":{"line":78,"column":null}},"33":{"start":{"line":79,"column":4},"end":{"line":80,"column":null}},"34":{"start":{"line":80,"column":6},"end":{"line":80,"column":null}},"35":{"start":{"line":81,"column":4},"end":{"line":82,"column":null}},"36":{"start":{"line":82,"column":6},"end":{"line":82,"column":null}},"37":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"38":{"start":{"line":83,"column":41},"end":{"line":83,"column":null}},"39":{"start":{"line":84,"column":4},"end":{"line":84,"column":null}},"40":{"start":{"line":88,"column":4},"end":{"line":88,"column":null}},"41":{"start":{"line":92,"column":4},"end":{"line":92,"column":null}},"42":{"start":{"line":96,"column":4},"end":{"line":96,"column":null}},"43":{"start":{"line":97,"column":18},"end":{"line":97,"column":null}},"44":{"start":{"line":98,"column":4},"end":{"line":98,"column":null}},"45":{"start":{"line":98,"column":16},"end":{"line":98,"column":null}},"46":{"start":{"line":99,"column":4},"end":{"line":100,"column":null}},"47":{"start":{"line":100,"column":6},"end":{"line":100,"column":null}},"48":{"start":{"line":101,"column":4},"end":{"line":102,"column":null}},"49":{"start":{"line":102,"column":6},"end":{"line":102,"column":null}},"50":{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},"51":{"start":{"line":103,"column":35},"end":{"line":103,"column":null}},"52":{"start":{"line":104,"column":4},"end":{"line":104,"column":null}},"53":{"start":{"line":108,"column":4},"end":{"line":115,"column":null}},"54":{"start":{"line":110,"column":8},"end":{"line":110,"column":null}},"55":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"56":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"57":{"start":{"line":119,"column":55},"end":{"line":119,"column":62}},"58":{"start":{"line":120,"column":4},"end":{"line":125,"column":null}},"59":{"start":{"line":121,"column":12},"end":{"line":123,"column":null}},"60":{"start":{"line":124,"column":6},"end":{"line":124,"column":null}},"61":{"start":{"line":129,"column":4},"end":{"line":129,"column":null}},"62":{"start":{"line":130,"column":18},"end":{"line":130,"column":null}},"63":{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},"64":{"start":{"line":131,"column":16},"end":{"line":131,"column":null}},"65":{"start":{"line":132,"column":4},"end":{"line":133,"column":null}},"66":{"start":{"line":133,"column":6},"end":{"line":133,"column":null}},"67":{"start":{"line":134,"column":4},"end":{"line":135,"column":null}},"68":{"start":{"line":135,"column":6},"end":{"line":135,"column":null}},"69":{"start":{"line":136,"column":4},"end":{"line":136,"column":null}},"70":{"start":{"line":136,"column":35},"end":{"line":136,"column":null}},"71":{"start":{"line":137,"column":4},"end":{"line":137,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":13,"column":13},"end":{"line":13,"column":26}},"loc":{"start":{"line":13,"column":87},"end":{"line":17,"column":null}},"line":13},"1":{"name":"(anonymous_1)","decl":{"start":{"line":19,"column":13},"end":{"line":19,"column":21}},"loc":{"start":{"line":19,"column":87},"end":{"line":23,"column":null}},"line":19},"2":{"name":"(anonymous_2)","decl":{"start":{"line":25,"column":13},"end":{"line":25,"column":24}},"loc":{"start":{"line":25,"column":91},"end":{"line":29,"column":null}},"line":25},"3":{"name":"(anonymous_3)","decl":{"start":{"line":31,"column":13},"end":{"line":31,"column":31}},"loc":{"start":{"line":31,"column":95},"end":{"line":35,"column":null}},"line":31},"4":{"name":"calls","decl":{"start":{"line":38,"column":6},"end":{"line":38,"column":14}},"loc":{"start":{"line":38,"column":14},"end":{"line":40,"column":null}},"line":38},"5":{"name":"constructor","decl":{"start":{"line":45,"column":2},"end":{"line":45,"column":14}},"loc":{"start":{"line":45,"column":55},"end":{"line":45,"column":null}},"line":45},"6":{"name":"assertExhausted","decl":{"start":{"line":46,"column":2},"end":{"line":46,"column":20}},"loc":{"start":{"line":46,"column":20},"end":{"line":50,"column":null}},"line":46},"7":{"name":"cancel","decl":{"start":{"line":51,"column":2},"end":{"line":51,"column":9}},"loc":{"start":{"line":51,"column":32},"end":{"line":53,"column":null}},"line":51},"8":{"name":"confirm","decl":{"start":{"line":54,"column":8},"end":{"line":54,"column":16}},"loc":{"start":{"line":54,"column":64},"end":{"line":65,"column":null}},"line":54},"9":{"name":"intro","decl":{"start":{"line":66,"column":2},"end":{"line":66,"column":8}},"loc":{"start":{"line":66,"column":31},"end":{"line":68,"column":null}},"line":66},"10":{"name":"log","decl":{"start":{"line":70,"column":2},"end":{"line":70,"column":6}},"loc":{"start":{"line":70,"column":43},"end":{"line":72,"column":null}},"line":70},"11":{"name":"multiselect","decl":{"start":{"line":74,"column":8},"end":{"line":74,"column":23}},"loc":{"start":{"line":74,"column":67},"end":{"line":85,"column":null}},"line":74},"12":{"name":"note","decl":{"start":{"line":87,"column":2},"end":{"line":87,"column":7}},"loc":{"start":{"line":87,"column":46},"end":{"line":89,"column":null}},"line":87},"13":{"name":"outro","decl":{"start":{"line":91,"column":2},"end":{"line":91,"column":8}},"loc":{"start":{"line":91,"column":31},"end":{"line":93,"column":null}},"line":91},"14":{"name":"select","decl":{"start":{"line":95,"column":8},"end":{"line":95,"column":18}},"loc":{"start":{"line":95,"column":78},"end":{"line":105,"column":null}},"line":95},"15":{"name":"spinner","decl":{"start":{"line":107,"column":2},"end":{"line":107,"column":21}},"loc":{"start":{"line":107,"column":21},"end":{"line":116,"column":null}},"line":107},"16":{"name":"(anonymous_16)","decl":{"start":{"line":109,"column":6},"end":{"line":109,"column":14}},"loc":{"start":{"line":109,"column":34},"end":{"line":111,"column":null}},"line":109},"17":{"name":"(anonymous_17)","decl":{"start":{"line":112,"column":6},"end":{"line":112,"column":13}},"loc":{"start":{"line":112,"column":33},"end":{"line":114,"column":null}},"line":112},"18":{"name":"tasks","decl":{"start":{"line":118,"column":8},"end":{"line":118,"column":14}},"loc":{"start":{"line":118,"column":61},"end":{"line":126,"column":null}},"line":118},"19":{"name":"(anonymous_19)","decl":{"start":{"line":119,"column":44},"end":{"line":119,"column":49}},"loc":{"start":{"line":119,"column":55},"end":{"line":119,"column":62}},"line":119},"20":{"name":"(anonymous_20)","decl":{"start":{"line":121,"column":12},"end":{"line":121,"column":20}},"loc":{"start":{"line":121,"column":37},"end":{"line":123,"column":null}},"line":121},"21":{"name":"text","decl":{"start":{"line":128,"column":8},"end":{"line":128,"column":13}},"loc":{"start":{"line":128,"column":60},"end":{"line":138,"column":null}},"line":128}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":9},"end":{"line":15,"column":null}},"type":"cond-expr","locations":[{"start":{"line":15,"column":37},"end":{"line":15,"column":57}},{"start":{"line":15,"column":57},"end":{"line":15,"column":null}}],"line":15},"1":{"loc":{"start":{"line":16,"column":12},"end":{"line":16,"column":null}},"type":"cond-expr","locations":[{"start":{"line":16,"column":40},"end":{"line":16,"column":48}},{"start":{"line":16,"column":48},"end":{"line":16,"column":null}}],"line":16},"2":{"loc":{"start":{"line":21,"column":9},"end":{"line":21,"column":null}},"type":"cond-expr","locations":[{"start":{"line":21,"column":37},"end":{"line":21,"column":57}},{"start":{"line":21,"column":57},"end":{"line":21,"column":null}}],"line":21},"3":{"loc":{"start":{"line":27,"column":9},"end":{"line":27,"column":null}},"type":"cond-expr","locations":[{"start":{"line":27,"column":37},"end":{"line":27,"column":57}},{"start":{"line":27,"column":57},"end":{"line":27,"column":null}}],"line":27},"4":{"loc":{"start":{"line":33,"column":9},"end":{"line":33,"column":null}},"type":"cond-expr","locations":[{"start":{"line":33,"column":37},"end":{"line":33,"column":57}},{"start":{"line":33,"column":57},"end":{"line":33,"column":null}}],"line":33},"5":{"loc":{"start":{"line":34,"column":12},"end":{"line":34,"column":null}},"type":"cond-expr","locations":[{"start":{"line":34,"column":32},"end":{"line":34,"column":45}},{"start":{"line":34,"column":45},"end":{"line":34,"column":null}}],"line":34},"6":{"loc":{"start":{"line":47,"column":4},"end":{"line":49,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":4},"end":{"line":49,"column":null}},{"start":{},"end":{}}],"line":47},"7":{"loc":{"start":{"line":57,"column":4},"end":{"line":58,"column":null}},"type":"if","locations":[{"start":{"line":57,"column":4},"end":{"line":58,"column":null}},{"start":{},"end":{}}],"line":57},"8":{"loc":{"start":{"line":59,"column":4},"end":{"line":60,"column":null}},"type":"if","locations":[{"start":{"line":59,"column":4},"end":{"line":60,"column":null}},{"start":{},"end":{}}],"line":59},"9":{"loc":{"start":{"line":61,"column":4},"end":{"line":62,"column":null}},"type":"if","locations":[{"start":{"line":61,"column":4},"end":{"line":62,"column":null}},{"start":{},"end":{}}],"line":61},"10":{"loc":{"start":{"line":61,"column":8},"end":{"line":61,"column":null}},"type":"binary-expr","locations":[{"start":{"line":61,"column":8},"end":{"line":61,"column":23}},{"start":{"line":61,"column":23},"end":{"line":61,"column":null}}],"line":61},"11":{"loc":{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},"type":"if","locations":[{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},{"start":{},"end":{}}],"line":63},"12":{"loc":{"start":{"line":77,"column":4},"end":{"line":78,"column":null}},"type":"if","locations":[{"start":{"line":77,"column":4},"end":{"line":78,"column":null}},{"start":{},"end":{}}],"line":77},"13":{"loc":{"start":{"line":79,"column":4},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":79,"column":4},"end":{"line":80,"column":null}},{"start":{},"end":{}}],"line":79},"14":{"loc":{"start":{"line":81,"column":4},"end":{"line":82,"column":null}},"type":"if","locations":[{"start":{"line":81,"column":4},"end":{"line":82,"column":null}},{"start":{},"end":{}}],"line":81},"15":{"loc":{"start":{"line":81,"column":8},"end":{"line":81,"column":null}},"type":"binary-expr","locations":[{"start":{"line":81,"column":8},"end":{"line":81,"column":23}},{"start":{"line":81,"column":23},"end":{"line":81,"column":null}}],"line":81},"16":{"loc":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"type":"if","locations":[{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},{"start":{},"end":{}}],"line":83},"17":{"loc":{"start":{"line":98,"column":4},"end":{"line":98,"column":null}},"type":"if","locations":[{"start":{"line":98,"column":4},"end":{"line":98,"column":null}},{"start":{},"end":{}}],"line":98},"18":{"loc":{"start":{"line":99,"column":4},"end":{"line":100,"column":null}},"type":"if","locations":[{"start":{"line":99,"column":4},"end":{"line":100,"column":null}},{"start":{},"end":{}}],"line":99},"19":{"loc":{"start":{"line":101,"column":4},"end":{"line":102,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":4},"end":{"line":102,"column":null}},{"start":{},"end":{}}],"line":101},"20":{"loc":{"start":{"line":101,"column":8},"end":{"line":101,"column":null}},"type":"binary-expr","locations":[{"start":{"line":101,"column":8},"end":{"line":101,"column":23}},{"start":{"line":101,"column":23},"end":{"line":101,"column":null}}],"line":101},"21":{"loc":{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},"type":"if","locations":[{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},{"start":{},"end":{}}],"line":103},"22":{"loc":{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},"type":"if","locations":[{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},{"start":{},"end":{}}],"line":131},"23":{"loc":{"start":{"line":132,"column":4},"end":{"line":133,"column":null}},"type":"if","locations":[{"start":{"line":132,"column":4},"end":{"line":133,"column":null}},{"start":{},"end":{}}],"line":132},"24":{"loc":{"start":{"line":134,"column":4},"end":{"line":135,"column":null}},"type":"if","locations":[{"start":{"line":134,"column":4},"end":{"line":135,"column":null}},{"start":{},"end":{}}],"line":134},"25":{"loc":{"start":{"line":134,"column":8},"end":{"line":134,"column":null}},"type":"binary-expr","locations":[{"start":{"line":134,"column":8},"end":{"line":134,"column":23}},{"start":{"line":134,"column":23},"end":{"line":134,"column":null}}],"line":134},"26":{"loc":{"start":{"line":136,"column":4},"end":{"line":136,"column":null}},"type":"if","locations":[{"start":{"line":136,"column":4},"end":{"line":136,"column":null}},{"start":{},"end":{}}],"line":136}},"s":{"0":1,"1":1,"2":105,"3":1,"4":0,"5":1,"6":42,"7":1,"8":18,"9":46,"10":46,"11":5,"12":46,"13":0,"14":0,"15":0,"16":42,"17":42,"18":42,"19":0,"20":42,"21":0,"22":42,"23":0,"24":42,"25":0,"26":42,"27":46,"28":36,"29":18,"30":18,"31":18,"32":0,"33":18,"34":0,"35":18,"36":0,"37":18,"38":0,"39":18,"40":238,"41":31,"42":105,"43":105,"44":105,"45":0,"46":105,"47":0,"48":105,"49":0,"50":105,"51":2,"52":103,"53":87,"54":87,"55":87,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0},"f":{"0":105,"1":0,"2":42,"3":18,"4":5,"5":46,"6":0,"7":0,"8":42,"9":46,"10":36,"11":18,"12":238,"13":31,"14":105,"15":87,"16":87,"17":87,"18":0,"19":0,"20":0,"21":0},"b":{"0":[0,105],"1":[2,103],"2":[0,0],"3":[40,2],"4":[0,18],"5":[0,18],"6":[0,0],"7":[0,42],"8":[0,42],"9":[0,42],"10":[42,41],"11":[0,42],"12":[0,18],"13":[0,18],"14":[0,18],"15":[18,0],"16":[0,18],"17":[0,105],"18":[0,105],"19":[0,105],"20":[105,0],"21":[2,103],"22":[0,0],"23":[0,0],"24":[0,0],"25":[0,0],"26":[0,0]},"meta":{"lastBranch":27,"lastFunction":22,"lastStatement":72,"seen":{"s:5:22:5:Infinity":0,"s:13:13:17:Infinity":1,"f:13:13:13:26":0,"s:13:87:17:Infinity":2,"b:15:37:15:57:15:57:15:Infinity":0,"b:16:40:16:48:16:48:16:Infinity":1,"s:19:13:23:Infinity":3,"f:19:13:19:21":1,"s:19:87:23:Infinity":4,"b:21:37:21:57:21:57:21:Infinity":2,"s:25:13:29:Infinity":5,"f:25:13:25:24":2,"s:25:91:29:Infinity":6,"b:27:37:27:57:27:57:27:Infinity":3,"s:31:13:35:Infinity":7,"f:31:13:31:31":3,"s:31:95:35:Infinity":8,"b:33:37:33:57:33:57:33:Infinity":4,"b:34:32:34:45:34:45:34:Infinity":5,"s:41:61:41:Infinity":9,"s:43:20:43:Infinity":10,"f:38:6:38:14":4,"s:39:4:39:Infinity":11,"f:45:2:45:14":5,"s:45:31:45:55":12,"f:46:2:46:20":6,"b:47:4:49:Infinity:undefined:undefined:undefined:undefined":6,"s:47:4:49:Infinity":13,"s:48:6:48:Infinity":14,"f:51:2:51:9":7,"s:52:4:52:Infinity":15,"f:54:8:54:16":8,"s:55:4:55:Infinity":16,"s:56:18:56:Infinity":17,"b:57:4:58:Infinity:undefined:undefined:undefined:undefined":7,"s:57:4:58:Infinity":18,"s:58:6:58:Infinity":19,"b:59:4:60:Infinity:undefined:undefined:undefined:undefined":8,"s:59:4:60:Infinity":20,"s:60:6:60:Infinity":21,"b:61:4:62:Infinity:undefined:undefined:undefined:undefined":9,"s:61:4:62:Infinity":22,"b:61:8:61:23:61:23:61:Infinity":10,"s:62:6:62:Infinity":23,"b:63:4:63:Infinity:undefined:undefined:undefined:undefined":11,"s:63:4:63:Infinity":24,"s:63:35:63:Infinity":25,"s:64:4:64:Infinity":26,"f:66:2:66:8":9,"s:67:4:67:Infinity":27,"f:70:2:70:6":10,"s:71:4:71:Infinity":28,"f:74:8:74:23":11,"s:75:4:75:Infinity":29,"s:76:18:76:Infinity":30,"b:77:4:78:Infinity:undefined:undefined:undefined:undefined":12,"s:77:4:78:Infinity":31,"s:78:6:78:Infinity":32,"b:79:4:80:Infinity:undefined:undefined:undefined:undefined":13,"s:79:4:80:Infinity":33,"s:80:6:80:Infinity":34,"b:81:4:82:Infinity:undefined:undefined:undefined:undefined":14,"s:81:4:82:Infinity":35,"b:81:8:81:23:81:23:81:Infinity":15,"s:82:6:82:Infinity":36,"b:83:4:83:Infinity:undefined:undefined:undefined:undefined":16,"s:83:4:83:Infinity":37,"s:83:41:83:Infinity":38,"s:84:4:84:Infinity":39,"f:87:2:87:7":12,"s:88:4:88:Infinity":40,"f:91:2:91:8":13,"s:92:4:92:Infinity":41,"f:95:8:95:18":14,"s:96:4:96:Infinity":42,"s:97:18:97:Infinity":43,"b:98:4:98:Infinity:undefined:undefined:undefined:undefined":17,"s:98:4:98:Infinity":44,"s:98:16:98:Infinity":45,"b:99:4:100:Infinity:undefined:undefined:undefined:undefined":18,"s:99:4:100:Infinity":46,"s:100:6:100:Infinity":47,"b:101:4:102:Infinity:undefined:undefined:undefined:undefined":19,"s:101:4:102:Infinity":48,"b:101:8:101:23:101:23:101:Infinity":20,"s:102:6:102:Infinity":49,"b:103:4:103:Infinity:undefined:undefined:undefined:undefined":21,"s:103:4:103:Infinity":50,"s:103:35:103:Infinity":51,"s:104:4:104:Infinity":52,"f:107:2:107:21":15,"s:108:4:115:Infinity":53,"f:109:6:109:14":16,"s:110:8:110:Infinity":54,"f:112:6:112:13":17,"s:113:8:113:Infinity":55,"f:118:8:118:14":18,"s:119:4:119:Infinity":56,"f:119:44:119:49":19,"s:119:55:119:62":57,"s:120:4:125:Infinity":58,"s:121:12:123:Infinity":59,"f:121:12:121:20":20,"s:124:6:124:Infinity":60,"f:128:8:128:13":21,"s:129:4:129:Infinity":61,"s:130:18:130:Infinity":62,"b:131:4:131:Infinity:undefined:undefined:undefined:undefined":22,"s:131:4:131:Infinity":63,"s:131:16:131:Infinity":64,"b:132:4:133:Infinity:undefined:undefined:undefined:undefined":23,"s:132:4:133:Infinity":65,"s:133:6:133:Infinity":66,"b:134:4:135:Infinity:undefined:undefined:undefined:undefined":24,"s:134:4:135:Infinity":67,"b:134:8:134:23:134:23:134:Infinity":25,"s:135:6:135:Infinity":68,"b:136:4:136:Infinity:undefined:undefined:undefined:undefined":26,"s:136:4:136:Infinity":69,"s:136:35:136:Infinity":70,"s:137:4:137:Infinity":71}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/clack-prompter.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/clack-prompter.ts","statementMap":{"0":{"start":{"line":7,"column":6},"end":{"line":10,"column":null}},"1":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"2":{"start":{"line":8,"column":21},"end":{"line":8,"column":null}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"4":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"5":{"start":{"line":17,"column":4},"end":{"line":17,"column":null}},"6":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"7":{"start":{"line":23,"column":4},"end":{"line":23,"column":null}},"8":{"start":{"line":33,"column":4},"end":{"line":33,"column":null}},"9":{"start":{"line":36,"column":4},"end":{"line":36,"column":null}},"10":{"start":{"line":39,"column":4},"end":{"line":39,"column":null}},"11":{"start":{"line":51,"column":4},"end":{"line":51,"column":null}},"12":{"start":{"line":55,"column":14},"end":{"line":55,"column":null}},"13":{"start":{"line":56,"column":4},"end":{"line":59,"column":null}},"14":{"start":{"line":57,"column":34},"end":{"line":57,"column":null}},"15":{"start":{"line":58,"column":33},"end":{"line":58,"column":null}},"16":{"start":{"line":63,"column":4},"end":{"line":71,"column":null}},"17":{"start":{"line":64,"column":27},"end":{"line":70,"column":8}},"18":{"start":{"line":66,"column":25},"end":{"line":66,"column":null}},"19":{"start":{"line":67,"column":10},"end":{"line":67,"column":null}},"20":{"start":{"line":75,"column":4},"end":{"line":75,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":6},"end":{"line":7,"column":19}},"loc":{"start":{"line":7,"column":40},"end":{"line":10,"column":null}},"line":7},"1":{"name":"cancel","decl":{"start":{"line":13,"column":2},"end":{"line":13,"column":9}},"loc":{"start":{"line":13,"column":32},"end":{"line":15,"column":null}},"line":13},"2":{"name":"confirm","decl":{"start":{"line":16,"column":8},"end":{"line":16,"column":16}},"loc":{"start":{"line":16,"column":88},"end":{"line":18,"column":null}},"line":16},"3":{"name":"intro","decl":{"start":{"line":19,"column":2},"end":{"line":19,"column":8}},"loc":{"start":{"line":19,"column":31},"end":{"line":21,"column":null}},"line":19},"4":{"name":"log","decl":{"start":{"line":22,"column":2},"end":{"line":22,"column":6}},"loc":{"start":{"line":22,"column":95},"end":{"line":24,"column":null}},"line":22},"5":{"name":"multiselect","decl":{"start":{"line":25,"column":8},"end":{"line":25,"column":23}},"loc":{"start":{"line":32,"column":19},"end":{"line":34,"column":null}},"line":32},"6":{"name":"note","decl":{"start":{"line":35,"column":2},"end":{"line":35,"column":7}},"loc":{"start":{"line":35,"column":46},"end":{"line":37,"column":null}},"line":35},"7":{"name":"outro","decl":{"start":{"line":38,"column":2},"end":{"line":38,"column":8}},"loc":{"start":{"line":38,"column":31},"end":{"line":40,"column":null}},"line":38},"8":{"name":"select","decl":{"start":{"line":42,"column":8},"end":{"line":42,"column":18}},"loc":{"start":{"line":50,"column":17},"end":{"line":52,"column":null}},"line":50},"9":{"name":"spinner","decl":{"start":{"line":54,"column":2},"end":{"line":54,"column":21}},"loc":{"start":{"line":54,"column":21},"end":{"line":60,"column":null}},"line":54},"10":{"name":"(anonymous_10)","decl":{"start":{"line":57,"column":6},"end":{"line":57,"column":14}},"loc":{"start":{"line":57,"column":34},"end":{"line":57,"column":null}},"line":57},"11":{"name":"(anonymous_11)","decl":{"start":{"line":58,"column":6},"end":{"line":58,"column":13}},"loc":{"start":{"line":58,"column":33},"end":{"line":58,"column":null}},"line":58},"12":{"name":"tasks","decl":{"start":{"line":62,"column":8},"end":{"line":62,"column":14}},"loc":{"start":{"line":62,"column":61},"end":{"line":72,"column":null}},"line":62},"13":{"name":"(anonymous_13)","decl":{"start":{"line":64,"column":12},"end":{"line":64,"column":17}},"loc":{"start":{"line":64,"column":27},"end":{"line":70,"column":8}},"line":64},"14":{"name":"(anonymous_14)","decl":{"start":{"line":65,"column":14},"end":{"line":65,"column":21}},"loc":{"start":{"line":65,"column":56},"end":{"line":68,"column":null}},"line":65},"15":{"name":"text","decl":{"start":{"line":74,"column":8},"end":{"line":74,"column":13}},"loc":{"start":{"line":74,"column":82},"end":{"line":76,"column":null}},"line":74}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},{"start":{},"end":{}}],"line":8},"1":{"loc":{"start":{"line":67,"column":17},"end":{"line":67,"column":null}},"type":"binary-expr","locations":[{"start":{"line":67,"column":17},"end":{"line":67,"column":27}},{"start":{"line":67,"column":27},"end":{"line":67,"column":null}}],"line":67}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0},"b":{"0":[0,0],"1":[0,0]},"meta":{"lastBranch":2,"lastFunction":16,"lastStatement":21,"seen":{"s:7:6:10:Infinity":0,"f:7:6:7:19":0,"b:8:2:8:Infinity:undefined:undefined:undefined:undefined":0,"s:8:2:8:Infinity":1,"s:8:21:8:Infinity":2,"s:9:2:9:Infinity":3,"f:13:2:13:9":1,"s:14:4:14:Infinity":4,"f:16:8:16:16":2,"s:17:4:17:Infinity":5,"f:19:2:19:8":3,"s:20:4:20:Infinity":6,"f:22:2:22:6":4,"s:23:4:23:Infinity":7,"f:25:8:25:23":5,"s:33:4:33:Infinity":8,"f:35:2:35:7":6,"s:36:4:36:Infinity":9,"f:38:2:38:8":7,"s:39:4:39:Infinity":10,"f:42:8:42:18":8,"s:51:4:51:Infinity":11,"f:54:2:54:21":9,"s:55:14:55:Infinity":12,"s:56:4:59:Infinity":13,"f:57:6:57:14":10,"s:57:34:57:Infinity":14,"f:58:6:58:13":11,"s:58:33:58:Infinity":15,"f:62:8:62:14":12,"s:63:4:71:Infinity":16,"f:64:12:64:17":13,"s:64:27:70:8":17,"f:65:14:65:21":14,"s:66:25:66:Infinity":18,"s:67:10:67:Infinity":19,"b:67:17:67:27:67:27:67:Infinity":1,"f:74:8:74:13":15,"s:75:4:75:Infinity":20}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/fs-file-store.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/fs-file-store.ts","statementMap":{"0":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"1":{"start":{"line":12,"column":4},"end":{"line":17,"column":null}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":null}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":null}},"4":{"start":{"line":16,"column":6},"end":{"line":16,"column":null}},"5":{"start":{"line":21,"column":4},"end":{"line":21,"column":null}},"6":{"start":{"line":25,"column":4},"end":{"line":30,"column":null}},"7":{"start":{"line":26,"column":6},"end":{"line":26,"column":null}},"8":{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},"9":{"start":{"line":28,"column":35},"end":{"line":28,"column":null}},"10":{"start":{"line":29,"column":6},"end":{"line":29,"column":null}},"11":{"start":{"line":34,"column":16},"end":{"line":34,"column":null}},"12":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"13":{"start":{"line":36,"column":4},"end":{"line":36,"column":null}}},"fnMap":{"0":{"name":"chmod","decl":{"start":{"line":7,"column":8},"end":{"line":7,"column":14}},"loc":{"start":{"line":7,"column":61},"end":{"line":9,"column":null}},"line":7},"1":{"name":"exists","decl":{"start":{"line":11,"column":8},"end":{"line":11,"column":15}},"loc":{"start":{"line":11,"column":51},"end":{"line":18,"column":null}},"line":11},"2":{"name":"mkdir","decl":{"start":{"line":20,"column":8},"end":{"line":20,"column":14}},"loc":{"start":{"line":20,"column":42},"end":{"line":22,"column":null}},"line":20},"3":{"name":"readFile","decl":{"start":{"line":24,"column":8},"end":{"line":24,"column":17}},"loc":{"start":{"line":24,"column":59},"end":{"line":31,"column":null}},"line":24},"4":{"name":"writeFile","decl":{"start":{"line":33,"column":8},"end":{"line":33,"column":18}},"loc":{"start":{"line":33,"column":68},"end":{"line":37,"column":null}},"line":33}},"branchMap":{"0":{"loc":{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},{"start":{},"end":{}}],"line":28}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0]},"meta":{"lastBranch":1,"lastFunction":5,"lastStatement":14,"seen":{"f:7:8:7:14":0,"s:8:4:8:Infinity":0,"f:11:8:11:15":1,"s:12:4:17:Infinity":1,"s:13:6:13:Infinity":2,"s:14:6:14:Infinity":3,"s:16:6:16:Infinity":4,"f:20:8:20:14":2,"s:21:4:21:Infinity":5,"f:24:8:24:17":3,"s:25:4:30:Infinity":6,"s:26:6:26:Infinity":7,"b:28:6:28:Infinity:undefined:undefined:undefined:undefined":0,"s:28:6:28:Infinity":8,"s:28:35:28:Infinity":9,"s:29:6:29:Infinity":10,"f:33:8:33:18":4,"s:34:16:34:Infinity":11,"s:35:4:35:Infinity":12,"s:36:4:36:Infinity":13}}} +,"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/spawn-command-runner.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/spawn-command-runner.ts","statementMap":{"0":{"start":{"line":7,"column":4},"end":{"line":11,"column":null}},"1":{"start":{"line":8,"column":12},"end":{"line":8,"column":null}},"2":{"start":{"line":9,"column":6},"end":{"line":9,"column":null}},"3":{"start":{"line":9,"column":34},"end":{"line":9,"column":53}},"4":{"start":{"line":10,"column":6},"end":{"line":10,"column":null}},"5":{"start":{"line":10,"column":30},"end":{"line":10,"column":44}},"6":{"start":{"line":19,"column":4},"end":{"line":43,"column":null}},"7":{"start":{"line":20,"column":12},"end":{"line":23,"column":null}},"8":{"start":{"line":25,"column":19},"end":{"line":25,"column":null}},"9":{"start":{"line":26,"column":19},"end":{"line":26,"column":null}},"10":{"start":{"line":28,"column":6},"end":{"line":30,"column":null}},"11":{"start":{"line":29,"column":8},"end":{"line":29,"column":null}},"12":{"start":{"line":31,"column":6},"end":{"line":33,"column":null}},"13":{"start":{"line":32,"column":8},"end":{"line":32,"column":null}},"14":{"start":{"line":35,"column":6},"end":{"line":41,"column":null}},"15":{"start":{"line":36,"column":8},"end":{"line":40,"column":null}},"16":{"start":{"line":37,"column":10},"end":{"line":37,"column":null}},"17":{"start":{"line":39,"column":10},"end":{"line":39,"column":null}},"18":{"start":{"line":42,"column":6},"end":{"line":42,"column":null}},"19":{"start":{"line":42,"column":35},"end":{"line":42,"column":48}}},"fnMap":{"0":{"name":"checkInstalled","decl":{"start":{"line":6,"column":8},"end":{"line":6,"column":23}},"loc":{"start":{"line":6,"column":57},"end":{"line":12,"column":null}},"line":6},"1":{"name":"(anonymous_1)","decl":{"start":{"line":7,"column":15},"end":{"line":7,"column":24}},"loc":{"start":{"line":7,"column":36},"end":{"line":11,"column":5}},"line":7},"2":{"name":"(anonymous_2)","decl":{"start":{"line":9,"column":15},"end":{"line":9,"column":25}},"loc":{"start":{"line":9,"column":34},"end":{"line":9,"column":53}},"line":9},"3":{"name":"(anonymous_3)","decl":{"start":{"line":10,"column":15},"end":{"line":10,"column":30}},"loc":{"start":{"line":10,"column":30},"end":{"line":10,"column":44}},"line":10},"4":{"name":"run","decl":{"start":{"line":14,"column":8},"end":{"line":14,"column":null}},"loc":{"start":{"line":18,"column":21},"end":{"line":44,"column":null}},"line":18},"5":{"name":"(anonymous_5)","decl":{"start":{"line":19,"column":15},"end":{"line":19,"column":32}},"loc":{"start":{"line":19,"column":52},"end":{"line":43,"column":5}},"line":19},"6":{"name":"(anonymous_6)","decl":{"start":{"line":28,"column":23},"end":{"line":28,"column":32}},"loc":{"start":{"line":28,"column":38},"end":{"line":30,"column":7}},"line":28},"7":{"name":"(anonymous_7)","decl":{"start":{"line":31,"column":23},"end":{"line":31,"column":32}},"loc":{"start":{"line":31,"column":38},"end":{"line":33,"column":7}},"line":31},"8":{"name":"(anonymous_8)","decl":{"start":{"line":35,"column":15},"end":{"line":35,"column":25}},"loc":{"start":{"line":35,"column":34},"end":{"line":41,"column":7}},"line":35},"9":{"name":"(anonymous_9)","decl":{"start":{"line":42,"column":15},"end":{"line":42,"column":25}},"loc":{"start":{"line":42,"column":35},"end":{"line":42,"column":48}},"line":42}},"branchMap":{"0":{"loc":{"start":{"line":21,"column":13},"end":{"line":21,"column":null}},"type":"binary-expr","locations":[{"start":{"line":21,"column":13},"end":{"line":21,"column":29}},{"start":{"line":21,"column":29},"end":{"line":21,"column":null}}],"line":21},"1":{"loc":{"start":{"line":36,"column":8},"end":{"line":40,"column":null}},"type":"if","locations":[{"start":{"line":36,"column":8},"end":{"line":40,"column":null}},{"start":{"line":38,"column":15},"end":{"line":40,"column":null}}],"line":36},"2":{"loc":{"start":{"line":39,"column":27},"end":{"line":39,"column":83}},"type":"binary-expr","locations":[{"start":{"line":39,"column":27},"end":{"line":39,"column":44}},{"start":{"line":39,"column":44},"end":{"line":39,"column":83}}],"line":39}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0]},"meta":{"lastBranch":3,"lastFunction":10,"lastStatement":20,"seen":{"f:6:8:6:23":0,"s:7:4:11:Infinity":0,"f:7:15:7:24":1,"s:8:12:8:Infinity":1,"s:9:6:9:Infinity":2,"f:9:15:9:25":2,"s:9:34:9:53":3,"s:10:6:10:Infinity":4,"f:10:15:10:30":3,"s:10:30:10:44":5,"f:14:8:14:Infinity":4,"s:19:4:43:Infinity":6,"f:19:15:19:32":5,"s:20:12:23:Infinity":7,"b:21:13:21:29:21:29:21:Infinity":0,"s:25:19:25:Infinity":8,"s:26:19:26:Infinity":9,"s:28:6:30:Infinity":10,"f:28:23:28:32":6,"s:29:8:29:Infinity":11,"s:31:6:33:Infinity":12,"f:31:23:31:32":7,"s:32:8:32:Infinity":13,"s:35:6:41:Infinity":14,"f:35:15:35:25":8,"b:36:8:40:Infinity:38:15:40:Infinity":1,"s:36:8:40:Infinity":15,"s:37:10:37:Infinity":16,"s:39:10:39:Infinity":17,"b:39:27:39:44:39:44:39:83":2,"s:42:6:42:Infinity":18,"f:42:15:42:25":9,"s:42:35:42:48":19}}} +,"/Users/marcus/berget-monorepo/cli/src/constants/command-structure.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/constants/command-structure.ts","statementMap":{"0":{"start":{"line":7,"column":30},"end":{"line":20,"column":null}},"1":{"start":{"line":23,"column":27},"end":{"line":113,"column":null}},"2":{"start":{"line":116,"column":36},"end":{"line":210,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":3,"seen":{"s:7:30:20:Infinity":0,"s:23:27:113:Infinity":1,"s:116:36:210:Infinity":2}}} +,"/Users/marcus/berget-monorepo/cli/src/services/api-key-service.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/services/api-key-service.ts","statementMap":{"0":{"start":{"line":35,"column":41},"end":{"line":35,"column":null}},"1":{"start":{"line":37,"column":36},"end":{"line":37,"column":null}},"2":{"start":{"line":41,"column":10},"end":{"line":41,"column":null}},"3":{"start":{"line":46,"column":4},"end":{"line":48,"column":null}},"4":{"start":{"line":47,"column":6},"end":{"line":47,"column":null}},"5":{"start":{"line":49,"column":4},"end":{"line":49,"column":null}},"6":{"start":{"line":57,"column":4},"end":{"line":75,"column":null}},"7":{"start":{"line":58,"column":6},"end":{"line":58,"column":null}},"8":{"start":{"line":60,"column":30},"end":{"line":62,"column":null}},"9":{"start":{"line":64,"column":6},"end":{"line":66,"column":null}},"10":{"start":{"line":65,"column":8},"end":{"line":65,"column":null}},"11":{"start":{"line":68,"column":6},"end":{"line":70,"column":null}},"12":{"start":{"line":69,"column":8},"end":{"line":69,"column":null}},"13":{"start":{"line":72,"column":6},"end":{"line":72,"column":null}},"14":{"start":{"line":74,"column":6},"end":{"line":74,"column":null}},"15":{"start":{"line":83,"column":4},"end":{"line":92,"column":null}},"16":{"start":{"line":84,"column":24},"end":{"line":86,"column":null}},"17":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"18":{"start":{"line":87,"column":17},"end":{"line":87,"column":null}},"19":{"start":{"line":88,"column":6},"end":{"line":88,"column":null}},"20":{"start":{"line":90,"column":6},"end":{"line":90,"column":null}},"21":{"start":{"line":91,"column":6},"end":{"line":91,"column":null}},"22":{"start":{"line":100,"column":4},"end":{"line":109,"column":null}},"23":{"start":{"line":101,"column":30},"end":{"line":103,"column":null}},"24":{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},"25":{"start":{"line":104,"column":17},"end":{"line":104,"column":null}},"26":{"start":{"line":105,"column":6},"end":{"line":105,"column":null}},"27":{"start":{"line":107,"column":6},"end":{"line":107,"column":null}},"28":{"start":{"line":108,"column":6},"end":{"line":108,"column":null}},"29":{"start":{"line":117,"column":4},"end":{"line":124,"column":null}},"30":{"start":{"line":118,"column":30},"end":{"line":118,"column":null}},"31":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"32":{"start":{"line":119,"column":17},"end":{"line":119,"column":null}},"33":{"start":{"line":120,"column":6},"end":{"line":120,"column":null}},"34":{"start":{"line":122,"column":6},"end":{"line":122,"column":null}},"35":{"start":{"line":123,"column":6},"end":{"line":123,"column":null}},"36":{"start":{"line":132,"column":4},"end":{"line":141,"column":null}},"37":{"start":{"line":133,"column":30},"end":{"line":135,"column":null}},"38":{"start":{"line":136,"column":6},"end":{"line":136,"column":null}},"39":{"start":{"line":136,"column":17},"end":{"line":136,"column":null}},"40":{"start":{"line":137,"column":6},"end":{"line":137,"column":null}},"41":{"start":{"line":139,"column":6},"end":{"line":139,"column":null}},"42":{"start":{"line":140,"column":6},"end":{"line":140,"column":null}},"43":{"start":{"line":145,"column":4},"end":{"line":156,"column":null}},"44":{"start":{"line":161,"column":4},"end":{"line":163,"column":null}},"45":{"start":{"line":162,"column":6},"end":{"line":162,"column":null}},"46":{"start":{"line":165,"column":20},"end":{"line":165,"column":null}},"47":{"start":{"line":167,"column":4},"end":{"line":169,"column":null}},"48":{"start":{"line":168,"column":6},"end":{"line":168,"column":null}},"49":{"start":{"line":171,"column":4},"end":{"line":173,"column":null}},"50":{"start":{"line":172,"column":6},"end":{"line":172,"column":null}},"51":{"start":{"line":175,"column":4},"end":{"line":177,"column":null}},"52":{"start":{"line":176,"column":6},"end":{"line":176,"column":null}},"53":{"start":{"line":179,"column":4},"end":{"line":183,"column":null}},"54":{"start":{"line":180,"column":6},"end":{"line":182,"column":null}},"55":{"start":{"line":185,"column":4},"end":{"line":185,"column":null}},"56":{"start":{"line":189,"column":4},"end":{"line":191,"column":null}},"57":{"start":{"line":190,"column":6},"end":{"line":190,"column":null}},"58":{"start":{"line":193,"column":24},"end":{"line":193,"column":null}},"59":{"start":{"line":194,"column":17},"end":{"line":194,"column":null}},"60":{"start":{"line":196,"column":4},"end":{"line":223,"column":null}},"61":{"start":{"line":198,"column":8},"end":{"line":198,"column":null}},"62":{"start":{"line":201,"column":8},"end":{"line":203,"column":null}},"63":{"start":{"line":206,"column":8},"end":{"line":208,"column":null}},"64":{"start":{"line":211,"column":8},"end":{"line":213,"column":null}},"65":{"start":{"line":216,"column":8},"end":{"line":218,"column":null}},"66":{"start":{"line":221,"column":8},"end":{"line":221,"column":null}},"67":{"start":{"line":227,"column":4},"end":{"line":229,"column":null}},"68":{"start":{"line":228,"column":6},"end":{"line":228,"column":null}},"69":{"start":{"line":231,"column":4},"end":{"line":233,"column":null}},"70":{"start":{"line":232,"column":6},"end":{"line":232,"column":null}},"71":{"start":{"line":235,"column":4},"end":{"line":237,"column":null}},"72":{"start":{"line":236,"column":6},"end":{"line":236,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":43,"column":2},"end":{"line":43,"column":10}},"loc":{"start":{"line":43,"column":24},"end":{"line":43,"column":null}},"line":43},"1":{"name":"getInstance","decl":{"start":{"line":45,"column":16},"end":{"line":45,"column":45}},"loc":{"start":{"line":45,"column":45},"end":{"line":50,"column":null}},"line":45},"2":{"name":"create","decl":{"start":{"line":56,"column":15},"end":{"line":56,"column":22}},"loc":{"start":{"line":56,"column":77},"end":{"line":76,"column":null}},"line":56},"3":{"name":"delete","decl":{"start":{"line":82,"column":15},"end":{"line":82,"column":22}},"loc":{"start":{"line":82,"column":52},"end":{"line":93,"column":null}},"line":82},"4":{"name":"describe","decl":{"start":{"line":99,"column":15},"end":{"line":99,"column":24}},"loc":{"start":{"line":99,"column":50},"end":{"line":110,"column":null}},"line":99},"5":{"name":"list","decl":{"start":{"line":116,"column":15},"end":{"line":116,"column":41}},"loc":{"start":{"line":116,"column":41},"end":{"line":125,"column":null}},"line":116},"6":{"name":"rotate","decl":{"start":{"line":131,"column":15},"end":{"line":131,"column":22}},"loc":{"start":{"line":131,"column":59},"end":{"line":142,"column":null}},"line":131},"7":{"name":"buildCreationFailedMessage","decl":{"start":{"line":144,"column":2},"end":{"line":144,"column":10}},"loc":{"start":{"line":144,"column":47},"end":{"line":158,"column":null}},"line":144},"8":{"name":"enhanceNetworkError","decl":{"start":{"line":160,"column":2},"end":{"line":160,"column":10}},"loc":{"start":{"line":160,"column":53},"end":{"line":186,"column":null}},"line":160},"9":{"name":"mapCreateError","decl":{"start":{"line":188,"column":2},"end":{"line":188,"column":10}},"loc":{"start":{"line":188,"column":48},"end":{"line":224,"column":null}},"line":188},"10":{"name":"validateCreateOptions","decl":{"start":{"line":226,"column":2},"end":{"line":226,"column":10}},"loc":{"start":{"line":226,"column":68},"end":{"line":238,"column":null}},"line":226}},"branchMap":{"0":{"loc":{"start":{"line":46,"column":4},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":46,"column":4},"end":{"line":48,"column":null}},{"start":{},"end":{}}],"line":46},"1":{"loc":{"start":{"line":64,"column":6},"end":{"line":66,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":6},"end":{"line":66,"column":null}},{"start":{},"end":{}}],"line":64},"2":{"loc":{"start":{"line":68,"column":6},"end":{"line":70,"column":null}},"type":"if","locations":[{"start":{"line":68,"column":6},"end":{"line":70,"column":null}},{"start":{},"end":{}}],"line":68},"3":{"loc":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"type":"if","locations":[{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},{"start":{},"end":{}}],"line":87},"4":{"loc":{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},"type":"if","locations":[{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},{"start":{},"end":{}}],"line":104},"5":{"loc":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"type":"if","locations":[{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},{"start":{},"end":{}}],"line":119},"6":{"loc":{"start":{"line":120,"column":13},"end":{"line":120,"column":null}},"type":"binary-expr","locations":[{"start":{"line":120,"column":13},"end":{"line":120,"column":21}},{"start":{"line":120,"column":21},"end":{"line":120,"column":null}}],"line":120},"7":{"loc":{"start":{"line":136,"column":6},"end":{"line":136,"column":null}},"type":"if","locations":[{"start":{"line":136,"column":6},"end":{"line":136,"column":null}},{"start":{},"end":{}}],"line":136},"8":{"loc":{"start":{"line":161,"column":4},"end":{"line":163,"column":null}},"type":"if","locations":[{"start":{"line":161,"column":4},"end":{"line":163,"column":null}},{"start":{},"end":{}}],"line":161},"9":{"loc":{"start":{"line":167,"column":4},"end":{"line":169,"column":null}},"type":"if","locations":[{"start":{"line":167,"column":4},"end":{"line":169,"column":null}},{"start":{},"end":{}}],"line":167},"10":{"loc":{"start":{"line":171,"column":4},"end":{"line":173,"column":null}},"type":"if","locations":[{"start":{"line":171,"column":4},"end":{"line":173,"column":null}},{"start":{},"end":{}}],"line":171},"11":{"loc":{"start":{"line":175,"column":4},"end":{"line":177,"column":null}},"type":"if","locations":[{"start":{"line":175,"column":4},"end":{"line":177,"column":null}},{"start":{},"end":{}}],"line":175},"12":{"loc":{"start":{"line":175,"column":8},"end":{"line":175,"column":69}},"type":"binary-expr","locations":[{"start":{"line":175,"column":8},"end":{"line":175,"column":35}},{"start":{"line":175,"column":35},"end":{"line":175,"column":69}}],"line":175},"13":{"loc":{"start":{"line":179,"column":4},"end":{"line":183,"column":null}},"type":"if","locations":[{"start":{"line":179,"column":4},"end":{"line":183,"column":null}},{"start":{},"end":{}}],"line":179},"14":{"loc":{"start":{"line":189,"column":4},"end":{"line":191,"column":null}},"type":"if","locations":[{"start":{"line":189,"column":4},"end":{"line":191,"column":null}},{"start":{},"end":{}}],"line":189},"15":{"loc":{"start":{"line":189,"column":8},"end":{"line":189,"column":53}},"type":"binary-expr","locations":[{"start":{"line":189,"column":8},"end":{"line":189,"column":37}},{"start":{"line":189,"column":37},"end":{"line":189,"column":53}}],"line":189},"16":{"loc":{"start":{"line":196,"column":4},"end":{"line":223,"column":null}},"type":"switch","locations":[{"start":{"line":197,"column":6},"end":{"line":199,"column":null}},{"start":{"line":200,"column":6},"end":{"line":204,"column":null}},{"start":{"line":205,"column":6},"end":{"line":209,"column":null}},{"start":{"line":210,"column":6},"end":{"line":214,"column":null}},{"start":{"line":215,"column":6},"end":{"line":219,"column":null}},{"start":{"line":220,"column":6},"end":{"line":222,"column":null}}],"line":196},"17":{"loc":{"start":{"line":227,"column":4},"end":{"line":229,"column":null}},"type":"if","locations":[{"start":{"line":227,"column":4},"end":{"line":229,"column":null}},{"start":{},"end":{}}],"line":227},"18":{"loc":{"start":{"line":227,"column":8},"end":{"line":227,"column":59}},"type":"binary-expr","locations":[{"start":{"line":227,"column":8},"end":{"line":227,"column":25}},{"start":{"line":227,"column":25},"end":{"line":227,"column":59}}],"line":227},"19":{"loc":{"start":{"line":231,"column":4},"end":{"line":233,"column":null}},"type":"if","locations":[{"start":{"line":231,"column":4},"end":{"line":233,"column":null}},{"start":{},"end":{}}],"line":231},"20":{"loc":{"start":{"line":235,"column":4},"end":{"line":237,"column":null}},"type":"if","locations":[{"start":{"line":235,"column":4},"end":{"line":237,"column":null}},{"start":{},"end":{}}],"line":235},"21":{"loc":{"start":{"line":235,"column":8},"end":{"line":235,"column":65}},"type":"binary-expr","locations":[{"start":{"line":235,"column":8},"end":{"line":235,"column":31}},{"start":{"line":235,"column":31},"end":{"line":235,"column":65}}],"line":235}},"s":{"0":1,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0},"f":{"0":0,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0,0,0,0,0],"17":[0,0],"18":[0,0],"19":[0,0],"20":[0,0],"21":[0,0]},"meta":{"lastBranch":22,"lastFunction":11,"lastStatement":73,"seen":{"s:35:41:35:Infinity":0,"s:37:36:37:Infinity":1,"s:41:10:41:Infinity":2,"f:43:2:43:10":0,"f:45:16:45:45":1,"b:46:4:48:Infinity:undefined:undefined:undefined:undefined":0,"s:46:4:48:Infinity":3,"s:47:6:47:Infinity":4,"s:49:4:49:Infinity":5,"f:56:15:56:22":2,"s:57:4:75:Infinity":6,"s:58:6:58:Infinity":7,"s:60:30:62:Infinity":8,"b:64:6:66:Infinity:undefined:undefined:undefined:undefined":1,"s:64:6:66:Infinity":9,"s:65:8:65:Infinity":10,"b:68:6:70:Infinity:undefined:undefined:undefined:undefined":2,"s:68:6:70:Infinity":11,"s:69:8:69:Infinity":12,"s:72:6:72:Infinity":13,"s:74:6:74:Infinity":14,"f:82:15:82:22":3,"s:83:4:92:Infinity":15,"s:84:24:86:Infinity":16,"b:87:6:87:Infinity:undefined:undefined:undefined:undefined":3,"s:87:6:87:Infinity":17,"s:87:17:87:Infinity":18,"s:88:6:88:Infinity":19,"s:90:6:90:Infinity":20,"s:91:6:91:Infinity":21,"f:99:15:99:24":4,"s:100:4:109:Infinity":22,"s:101:30:103:Infinity":23,"b:104:6:104:Infinity:undefined:undefined:undefined:undefined":4,"s:104:6:104:Infinity":24,"s:104:17:104:Infinity":25,"s:105:6:105:Infinity":26,"s:107:6:107:Infinity":27,"s:108:6:108:Infinity":28,"f:116:15:116:41":5,"s:117:4:124:Infinity":29,"s:118:30:118:Infinity":30,"b:119:6:119:Infinity:undefined:undefined:undefined:undefined":5,"s:119:6:119:Infinity":31,"s:119:17:119:Infinity":32,"s:120:6:120:Infinity":33,"b:120:13:120:21:120:21:120:Infinity":6,"s:122:6:122:Infinity":34,"s:123:6:123:Infinity":35,"f:131:15:131:22":6,"s:132:4:141:Infinity":36,"s:133:30:135:Infinity":37,"b:136:6:136:Infinity:undefined:undefined:undefined:undefined":7,"s:136:6:136:Infinity":38,"s:136:17:136:Infinity":39,"s:137:6:137:Infinity":40,"s:139:6:139:Infinity":41,"s:140:6:140:Infinity":42,"f:144:2:144:10":7,"s:145:4:156:Infinity":43,"f:160:2:160:10":8,"b:161:4:163:Infinity:undefined:undefined:undefined:undefined":8,"s:161:4:163:Infinity":44,"s:162:6:162:Infinity":45,"s:165:20:165:Infinity":46,"b:167:4:169:Infinity:undefined:undefined:undefined:undefined":9,"s:167:4:169:Infinity":47,"s:168:6:168:Infinity":48,"b:171:4:173:Infinity:undefined:undefined:undefined:undefined":10,"s:171:4:173:Infinity":49,"s:172:6:172:Infinity":50,"b:175:4:177:Infinity:undefined:undefined:undefined:undefined":11,"s:175:4:177:Infinity":51,"b:175:8:175:35:175:35:175:69":12,"s:176:6:176:Infinity":52,"b:179:4:183:Infinity:undefined:undefined:undefined:undefined":13,"s:179:4:183:Infinity":53,"s:180:6:182:Infinity":54,"s:185:4:185:Infinity":55,"f:188:2:188:10":9,"b:189:4:191:Infinity:undefined:undefined:undefined:undefined":14,"s:189:4:191:Infinity":56,"b:189:8:189:37:189:37:189:53":15,"s:190:6:190:Infinity":57,"s:193:24:193:Infinity":58,"s:194:17:194:Infinity":59,"b:197:6:199:Infinity:200:6:204:Infinity:205:6:209:Infinity:210:6:214:Infinity:215:6:219:Infinity:220:6:222:Infinity":16,"s:196:4:223:Infinity":60,"s:198:8:198:Infinity":61,"s:201:8:203:Infinity":62,"s:206:8:208:Infinity":63,"s:211:8:213:Infinity":64,"s:216:8:218:Infinity":65,"s:221:8:221:Infinity":66,"f:226:2:226:10":10,"b:227:4:229:Infinity:undefined:undefined:undefined:undefined":17,"s:227:4:229:Infinity":67,"b:227:8:227:25:227:25:227:59":18,"s:228:6:228:Infinity":68,"b:231:4:233:Infinity:undefined:undefined:undefined:undefined":19,"s:231:4:233:Infinity":69,"s:232:6:232:Infinity":70,"b:235:4:237:Infinity:undefined:undefined:undefined:undefined":20,"s:235:4:237:Infinity":71,"b:235:8:235:31:235:31:235:65":21,"s:236:6:236:Infinity":72}}} +,"/Users/marcus/berget-monorepo/cli/src/services/auth-service.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/services/auth-service.ts","statementMap":{"0":{"start":{"line":18,"column":41},"end":{"line":18,"column":null}},"1":{"start":{"line":21,"column":36},"end":{"line":21,"column":null}},"2":{"start":{"line":28,"column":4},"end":{"line":30,"column":null}},"3":{"start":{"line":29,"column":6},"end":{"line":29,"column":null}},"4":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"5":{"start":{"line":40,"column":4},"end":{"line":67,"column":null}},"6":{"start":{"line":41,"column":21},"end":{"line":41,"column":null}},"7":{"start":{"line":43,"column":6},"end":{"line":46,"column":null}},"8":{"start":{"line":44,"column":8},"end":{"line":44,"column":null}},"9":{"start":{"line":45,"column":8},"end":{"line":45,"column":null}},"10":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"11":{"start":{"line":50,"column":6},"end":{"line":57,"column":null}},"12":{"start":{"line":51,"column":24},"end":{"line":51,"column":null}},"13":{"start":{"line":52,"column":8},"end":{"line":54,"column":null}},"14":{"start":{"line":53,"column":10},"end":{"line":53,"column":null}},"15":{"start":{"line":59,"column":6},"end":{"line":59,"column":null}},"16":{"start":{"line":60,"column":6},"end":{"line":60,"column":null}},"17":{"start":{"line":61,"column":6},"end":{"line":61,"column":null}},"18":{"start":{"line":63,"column":6},"end":{"line":63,"column":null}},"19":{"start":{"line":65,"column":6},"end":{"line":65,"column":null}},"20":{"start":{"line":66,"column":6},"end":{"line":66,"column":null}},"21":{"start":{"line":82,"column":4},"end":{"line":105,"column":null}},"22":{"start":{"line":83,"column":12},"end":{"line":83,"column":null}},"23":{"start":{"line":84,"column":28},"end":{"line":84,"column":null}},"24":{"start":{"line":85,"column":21},"end":{"line":85,"column":null}},"25":{"start":{"line":87,"column":6},"end":{"line":97,"column":null}},"26":{"start":{"line":88,"column":27},"end":{"line":88,"column":null}},"27":{"start":{"line":89,"column":14},"end":{"line":89,"column":null}},"28":{"start":{"line":91,"column":10},"end":{"line":91,"column":null}},"29":{"start":{"line":92,"column":8},"end":{"line":96,"column":null}},"30":{"start":{"line":99,"column":6},"end":{"line":99,"column":null}},"31":{"start":{"line":101,"column":6},"end":{"line":104,"column":null}},"32":{"start":{"line":109,"column":4},"end":{"line":118,"column":null}},"33":{"start":{"line":110,"column":12},"end":{"line":110,"column":null}},"34":{"start":{"line":111,"column":39},"end":{"line":111,"column":null}},"35":{"start":{"line":112,"column":6},"end":{"line":114,"column":null}},"36":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"37":{"start":{"line":115,"column":6},"end":{"line":115,"column":null}},"38":{"start":{"line":117,"column":6},"end":{"line":117,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":25,"column":2},"end":{"line":25,"column":10}},"loc":{"start":{"line":25,"column":24},"end":{"line":25,"column":null}},"line":25},"1":{"name":"getInstance","decl":{"start":{"line":27,"column":16},"end":{"line":27,"column":43}},"loc":{"start":{"line":27,"column":43},"end":{"line":32,"column":null}},"line":27},"2":{"name":"login","decl":{"start":{"line":39,"column":15},"end":{"line":39,"column":21}},"loc":{"start":{"line":39,"column":87},"end":{"line":68,"column":null}},"line":39},"3":{"name":"loginInteractive","decl":{"start":{"line":75,"column":15},"end":{"line":75,"column":32}},"loc":{"start":{"line":81,"column":5},"end":{"line":106,"column":null}},"line":81},"4":{"name":"whoami","decl":{"start":{"line":108,"column":15},"end":{"line":108,"column":38}},"loc":{"start":{"line":108,"column":38},"end":{"line":119,"column":null}},"line":108}},"branchMap":{"0":{"loc":{"start":{"line":28,"column":4},"end":{"line":30,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":4},"end":{"line":30,"column":null}},{"start":{},"end":{}}],"line":28},"1":{"loc":{"start":{"line":43,"column":6},"end":{"line":46,"column":null}},"type":"if","locations":[{"start":{"line":43,"column":6},"end":{"line":46,"column":null}},{"start":{},"end":{}}],"line":43},"2":{"loc":{"start":{"line":44,"column":58},"end":{"line":44,"column":91}},"type":"binary-expr","locations":[{"start":{"line":44,"column":58},"end":{"line":44,"column":74}},{"start":{"line":44,"column":74},"end":{"line":44,"column":91}}],"line":44},"3":{"loc":{"start":{"line":52,"column":8},"end":{"line":54,"column":null}},"type":"if","locations":[{"start":{"line":52,"column":8},"end":{"line":54,"column":null}},{"start":{},"end":{}}],"line":52},"4":{"loc":{"start":{"line":53,"column":50},"end":{"line":53,"column":81}},"type":"binary-expr","locations":[{"start":{"line":53,"column":50},"end":{"line":53,"column":66}},{"start":{"line":53,"column":66},"end":{"line":53,"column":81}}],"line":53},"5":{"loc":{"start":{"line":87,"column":6},"end":{"line":97,"column":null}},"type":"if","locations":[{"start":{"line":87,"column":6},"end":{"line":97,"column":null}},{"start":{},"end":{}}],"line":87},"6":{"loc":{"start":{"line":87,"column":10},"end":{"line":87,"column":71}},"type":"binary-expr","locations":[{"start":{"line":87,"column":10},"end":{"line":87,"column":28}},{"start":{"line":87,"column":28},"end":{"line":87,"column":50}},{"start":{"line":87,"column":50},"end":{"line":87,"column":71}}],"line":87},"7":{"loc":{"start":{"line":91,"column":10},"end":{"line":91,"column":null}},"type":"cond-expr","locations":[{"start":{"line":91,"column":29},"end":{"line":91,"column":44}},{"start":{"line":91,"column":44},"end":{"line":91,"column":null}}],"line":91},"8":{"loc":{"start":{"line":91,"column":58},"end":{"line":91,"column":86}},"type":"binary-expr","locations":[{"start":{"line":91,"column":58},"end":{"line":91,"column":78}},{"start":{"line":91,"column":78},"end":{"line":91,"column":86}}],"line":91},"9":{"loc":{"start":{"line":102,"column":15},"end":{"line":102,"column":null}},"type":"cond-expr","locations":[{"start":{"line":102,"column":40},"end":{"line":102,"column":56}},{"start":{"line":102,"column":56},"end":{"line":102,"column":null}}],"line":102},"10":{"loc":{"start":{"line":112,"column":6},"end":{"line":114,"column":null}},"type":"if","locations":[{"start":{"line":112,"column":6},"end":{"line":114,"column":null}},{"start":{},"end":{}}],"line":112}},"s":{"0":1,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0},"f":{"0":0,"1":1,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0]},"meta":{"lastBranch":11,"lastFunction":5,"lastStatement":39,"seen":{"s:18:41:18:Infinity":0,"s:21:36:21:Infinity":1,"f:25:2:25:10":0,"f:27:16:27:43":1,"b:28:4:30:Infinity:undefined:undefined:undefined:undefined":0,"s:28:4:30:Infinity":2,"s:29:6:29:Infinity":3,"s:31:4:31:Infinity":4,"f:39:15:39:21":2,"s:40:4:67:Infinity":5,"s:41:21:41:Infinity":6,"b:43:6:46:Infinity:undefined:undefined:undefined:undefined":1,"s:43:6:46:Infinity":7,"s:44:8:44:Infinity":8,"b:44:58:44:74:44:74:44:91":2,"s:45:8:45:Infinity":9,"s:48:6:48:Infinity":10,"s:50:6:57:Infinity":11,"s:51:24:51:Infinity":12,"b:52:8:54:Infinity:undefined:undefined:undefined:undefined":3,"s:52:8:54:Infinity":13,"s:53:10:53:Infinity":14,"b:53:50:53:66:53:66:53:81":4,"s:59:6:59:Infinity":15,"s:60:6:60:Infinity":16,"s:61:6:61:Infinity":17,"s:63:6:63:Infinity":18,"s:65:6:65:Infinity":19,"s:66:6:66:Infinity":20,"f:75:15:75:32":3,"s:82:4:105:Infinity":21,"s:83:12:83:Infinity":22,"s:84:28:84:Infinity":23,"s:85:21:85:Infinity":24,"b:87:6:97:Infinity:undefined:undefined:undefined:undefined":5,"s:87:6:97:Infinity":25,"b:87:10:87:28:87:28:87:50:87:50:87:71":6,"s:88:27:88:Infinity":26,"s:89:14:89:Infinity":27,"s:91:10:91:Infinity":28,"b:91:29:91:44:91:44:91:Infinity":7,"b:91:58:91:78:91:78:91:86":8,"s:92:8:96:Infinity":29,"s:99:6:99:Infinity":30,"s:101:6:104:Infinity":31,"b:102:40:102:56:102:56:102:Infinity":9,"f:108:15:108:38":4,"s:109:4:118:Infinity":32,"s:110:12:110:Infinity":33,"s:111:39:111:Infinity":34,"b:112:6:114:Infinity:undefined:undefined:undefined:undefined":10,"s:112:6:114:Infinity":35,"s:113:8:113:Infinity":36,"s:115:6:115:Infinity":37,"s:117:6:117:Infinity":38}}} +,"/Users/marcus/berget-monorepo/cli/src/utils/error-handler.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/utils/error-handler.ts","statementMap":{"0":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"1":{"start":{"line":9,"column":21},"end":{"line":9,"column":null}},"2":{"start":{"line":10,"column":18},"end":{"line":10,"column":null}},"3":{"start":{"line":11,"column":18},"end":{"line":11,"column":null}},"4":{"start":{"line":14,"column":2},"end":{"line":34,"column":null}},"5":{"start":{"line":15,"column":4},"end":{"line":28,"column":null}},"6":{"start":{"line":17,"column":26},"end":{"line":17,"column":null}},"7":{"start":{"line":18,"column":6},"end":{"line":24,"column":null}},"8":{"start":{"line":19,"column":8},"end":{"line":19,"column":null}},"9":{"start":{"line":20,"column":8},"end":{"line":20,"column":null}},"10":{"start":{"line":21,"column":8},"end":{"line":21,"column":null}},"11":{"start":{"line":23,"column":8},"end":{"line":23,"column":null}},"12":{"start":{"line":27,"column":6},"end":{"line":27,"column":null}},"13":{"start":{"line":29,"column":9},"end":{"line":34,"column":null}},"14":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"15":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"16":{"start":{"line":33,"column":4},"end":{"line":33,"column":null}},"17":{"start":{"line":37,"column":2},"end":{"line":39,"column":null}},"18":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"19":{"start":{"line":40,"column":2},"end":{"line":42,"column":null}},"20":{"start":{"line":41,"column":4},"end":{"line":41,"column":null}},"21":{"start":{"line":45,"column":2},"end":{"line":45,"column":null}},"22":{"start":{"line":56,"column":2},"end":{"line":56,"column":null}},"23":{"start":{"line":59,"column":2},"end":{"line":69,"column":null}},"24":{"start":{"line":65,"column":4},"end":{"line":65,"column":null}},"25":{"start":{"line":66,"column":4},"end":{"line":66,"column":null}},"26":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"27":{"start":{"line":68,"column":4},"end":{"line":68,"column":null}},"28":{"start":{"line":72,"column":2},"end":{"line":83,"column":null}},"29":{"start":{"line":78,"column":4},"end":{"line":78,"column":null}},"30":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"31":{"start":{"line":80,"column":4},"end":{"line":80,"column":null}},"32":{"start":{"line":81,"column":4},"end":{"line":81,"column":null}},"33":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"34":{"start":{"line":86,"column":2},"end":{"line":98,"column":null}},"35":{"start":{"line":91,"column":4},"end":{"line":91,"column":null}},"36":{"start":{"line":92,"column":4},"end":{"line":92,"column":null}},"37":{"start":{"line":93,"column":4},"end":{"line":95,"column":null}},"38":{"start":{"line":96,"column":4},"end":{"line":96,"column":null}},"39":{"start":{"line":97,"column":4},"end":{"line":97,"column":null}},"40":{"start":{"line":101,"column":2},"end":{"line":110,"column":null}},"41":{"start":{"line":106,"column":4},"end":{"line":106,"column":null}},"42":{"start":{"line":107,"column":4},"end":{"line":107,"column":null}},"43":{"start":{"line":108,"column":4},"end":{"line":108,"column":null}},"44":{"start":{"line":109,"column":4},"end":{"line":109,"column":null}},"45":{"start":{"line":113,"column":2},"end":{"line":123,"column":null}},"46":{"start":{"line":118,"column":4},"end":{"line":118,"column":null}},"47":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"48":{"start":{"line":120,"column":4},"end":{"line":120,"column":null}},"49":{"start":{"line":121,"column":4},"end":{"line":121,"column":null}},"50":{"start":{"line":122,"column":4},"end":{"line":122,"column":null}},"51":{"start":{"line":126,"column":2},"end":{"line":131,"column":null}},"52":{"start":{"line":127,"column":4},"end":{"line":127,"column":null}},"53":{"start":{"line":128,"column":4},"end":{"line":128,"column":null}},"54":{"start":{"line":129,"column":4},"end":{"line":129,"column":null}},"55":{"start":{"line":130,"column":4},"end":{"line":130,"column":null}},"56":{"start":{"line":134,"column":2},"end":{"line":146,"column":null}},"57":{"start":{"line":142,"column":4},"end":{"line":142,"column":null}},"58":{"start":{"line":143,"column":4},"end":{"line":143,"column":null}},"59":{"start":{"line":144,"column":4},"end":{"line":144,"column":null}},"60":{"start":{"line":145,"column":4},"end":{"line":145,"column":null}},"61":{"start":{"line":148,"column":2},"end":{"line":150,"column":null}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":28}},"loc":{"start":{"line":6,"column":63},"end":{"line":46,"column":null}},"line":6},"1":{"name":"provideTroubleshootingTips","decl":{"start":{"line":51,"column":9},"end":{"line":51,"column":null}},"loc":{"start":{"line":55,"column":8},"end":{"line":151,"column":null}},"line":55}},"branchMap":{"0":{"loc":{"start":{"line":14,"column":2},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":14,"column":2},"end":{"line":34,"column":null}},{"start":{"line":29,"column":9},"end":{"line":34,"column":null}}],"line":14},"1":{"loc":{"start":{"line":18,"column":6},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":18,"column":6},"end":{"line":24,"column":null}},{"start":{"line":22,"column":13},"end":{"line":24,"column":null}}],"line":18},"2":{"loc":{"start":{"line":19,"column":23},"end":{"line":19,"column":null}},"type":"binary-expr","locations":[{"start":{"line":19,"column":23},"end":{"line":19,"column":52}},{"start":{"line":19,"column":52},"end":{"line":19,"column":null}}],"line":19},"3":{"loc":{"start":{"line":20,"column":20},"end":{"line":20,"column":null}},"type":"binary-expr","locations":[{"start":{"line":20,"column":20},"end":{"line":20,"column":46}},{"start":{"line":20,"column":46},"end":{"line":20,"column":null}}],"line":20},"4":{"loc":{"start":{"line":21,"column":20},"end":{"line":21,"column":null}},"type":"binary-expr","locations":[{"start":{"line":21,"column":20},"end":{"line":21,"column":46}},{"start":{"line":21,"column":46},"end":{"line":21,"column":null}}],"line":21},"5":{"loc":{"start":{"line":29,"column":9},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":29,"column":9},"end":{"line":34,"column":null}},{"start":{},"end":{}}],"line":29},"6":{"loc":{"start":{"line":29,"column":13},"end":{"line":29,"column":37}},"type":"binary-expr","locations":[{"start":{"line":29,"column":13},"end":{"line":29,"column":22}},{"start":{"line":29,"column":22},"end":{"line":29,"column":37}}],"line":29},"7":{"loc":{"start":{"line":37,"column":2},"end":{"line":39,"column":null}},"type":"if","locations":[{"start":{"line":37,"column":2},"end":{"line":39,"column":null}},{"start":{},"end":{}}],"line":37},"8":{"loc":{"start":{"line":40,"column":2},"end":{"line":42,"column":null}},"type":"if","locations":[{"start":{"line":40,"column":2},"end":{"line":42,"column":null}},{"start":{},"end":{}}],"line":40},"9":{"loc":{"start":{"line":59,"column":2},"end":{"line":69,"column":null}},"type":"if","locations":[{"start":{"line":59,"column":2},"end":{"line":69,"column":null}},{"start":{},"end":{}}],"line":59},"10":{"loc":{"start":{"line":60,"column":4},"end":{"line":63,"column":null}},"type":"binary-expr","locations":[{"start":{"line":60,"column":4},"end":{"line":60,"column":null}},{"start":{"line":61,"column":4},"end":{"line":61,"column":null}},{"start":{"line":62,"column":4},"end":{"line":62,"column":null}},{"start":{"line":63,"column":4},"end":{"line":63,"column":null}}],"line":60},"11":{"loc":{"start":{"line":72,"column":2},"end":{"line":83,"column":null}},"type":"if","locations":[{"start":{"line":72,"column":2},"end":{"line":83,"column":null}},{"start":{},"end":{}}],"line":72},"12":{"loc":{"start":{"line":73,"column":4},"end":{"line":76,"column":null}},"type":"binary-expr","locations":[{"start":{"line":73,"column":4},"end":{"line":73,"column":null}},{"start":{"line":74,"column":4},"end":{"line":74,"column":null}},{"start":{"line":75,"column":4},"end":{"line":75,"column":null}},{"start":{"line":76,"column":4},"end":{"line":76,"column":null}}],"line":73},"13":{"loc":{"start":{"line":86,"column":2},"end":{"line":98,"column":null}},"type":"if","locations":[{"start":{"line":86,"column":2},"end":{"line":98,"column":null}},{"start":{},"end":{}}],"line":86},"14":{"loc":{"start":{"line":87,"column":4},"end":{"line":89,"column":null}},"type":"binary-expr","locations":[{"start":{"line":87,"column":4},"end":{"line":87,"column":null}},{"start":{"line":88,"column":4},"end":{"line":88,"column":null}},{"start":{"line":89,"column":4},"end":{"line":89,"column":null}}],"line":87},"15":{"loc":{"start":{"line":101,"column":2},"end":{"line":110,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":2},"end":{"line":110,"column":null}},{"start":{},"end":{}}],"line":101},"16":{"loc":{"start":{"line":102,"column":4},"end":{"line":104,"column":null}},"type":"binary-expr","locations":[{"start":{"line":102,"column":4},"end":{"line":102,"column":null}},{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},{"start":{"line":104,"column":4},"end":{"line":104,"column":null}}],"line":102},"17":{"loc":{"start":{"line":113,"column":2},"end":{"line":123,"column":null}},"type":"if","locations":[{"start":{"line":113,"column":2},"end":{"line":123,"column":null}},{"start":{},"end":{}}],"line":113},"18":{"loc":{"start":{"line":114,"column":4},"end":{"line":116,"column":null}},"type":"binary-expr","locations":[{"start":{"line":114,"column":4},"end":{"line":114,"column":null}},{"start":{"line":115,"column":4},"end":{"line":115,"column":null}},{"start":{"line":116,"column":5},"end":{"line":116,"column":18}},{"start":{"line":116,"column":18},"end":{"line":116,"column":null}}],"line":114},"19":{"loc":{"start":{"line":126,"column":2},"end":{"line":131,"column":null}},"type":"if","locations":[{"start":{"line":126,"column":2},"end":{"line":131,"column":null}},{"start":{},"end":{}}],"line":126},"20":{"loc":{"start":{"line":126,"column":6},"end":{"line":126,"column":76}},"type":"binary-expr","locations":[{"start":{"line":126,"column":6},"end":{"line":126,"column":41}},{"start":{"line":126,"column":41},"end":{"line":126,"column":76}}],"line":126},"21":{"loc":{"start":{"line":134,"column":2},"end":{"line":146,"column":null}},"type":"if","locations":[{"start":{"line":134,"column":2},"end":{"line":146,"column":null}},{"start":{},"end":{}}],"line":134},"22":{"loc":{"start":{"line":135,"column":4},"end":{"line":140,"column":null}},"type":"binary-expr","locations":[{"start":{"line":135,"column":4},"end":{"line":135,"column":null}},{"start":{"line":136,"column":4},"end":{"line":136,"column":null}},{"start":{"line":137,"column":4},"end":{"line":137,"column":null}},{"start":{"line":138,"column":4},"end":{"line":138,"column":null}},{"start":{"line":139,"column":4},"end":{"line":139,"column":null}},{"start":{"line":140,"column":4},"end":{"line":140,"column":null}}],"line":135}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0},"f":{"0":0,"1":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0,0,0],"11":[0,0],"12":[0,0,0,0],"13":[0,0],"14":[0,0,0],"15":[0,0],"16":[0,0,0],"17":[0,0],"18":[0,0,0,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0,0,0,0,0]},"meta":{"lastBranch":23,"lastFunction":2,"lastStatement":62,"seen":{"f:6:16:6:28":0,"s:7:2:7:Infinity":0,"s:9:21:9:Infinity":1,"s:10:18:10:Infinity":2,"s:11:18:11:Infinity":3,"b:14:2:34:Infinity:29:9:34:Infinity":0,"s:14:2:34:Infinity":4,"s:15:4:28:Infinity":5,"s:17:26:17:Infinity":6,"b:18:6:24:Infinity:22:13:24:Infinity":1,"s:18:6:24:Infinity":7,"s:19:8:19:Infinity":8,"b:19:23:19:52:19:52:19:Infinity":2,"s:20:8:20:Infinity":9,"b:20:20:20:46:20:46:20:Infinity":3,"s:21:8:21:Infinity":10,"b:21:20:21:46:21:46:21:Infinity":4,"s:23:8:23:Infinity":11,"s:27:6:27:Infinity":12,"b:29:9:34:Infinity:undefined:undefined:undefined:undefined":5,"s:29:9:34:Infinity":13,"b:29:13:29:22:29:22:29:37":6,"s:31:4:31:Infinity":14,"s:32:4:32:Infinity":15,"s:33:4:33:Infinity":16,"b:37:2:39:Infinity:undefined:undefined:undefined:undefined":7,"s:37:2:39:Infinity":17,"s:38:4:38:Infinity":18,"b:40:2:42:Infinity:undefined:undefined:undefined:undefined":8,"s:40:2:42:Infinity":19,"s:41:4:41:Infinity":20,"s:45:2:45:Infinity":21,"f:51:9:51:Infinity":1,"s:56:2:56:Infinity":22,"b:59:2:69:Infinity:undefined:undefined:undefined:undefined":9,"s:59:2:69:Infinity":23,"b:60:4:60:Infinity:61:4:61:Infinity:62:4:62:Infinity:63:4:63:Infinity":10,"s:65:4:65:Infinity":24,"s:66:4:66:Infinity":25,"s:67:4:67:Infinity":26,"s:68:4:68:Infinity":27,"b:72:2:83:Infinity:undefined:undefined:undefined:undefined":11,"s:72:2:83:Infinity":28,"b:73:4:73:Infinity:74:4:74:Infinity:75:4:75:Infinity:76:4:76:Infinity":12,"s:78:4:78:Infinity":29,"s:79:4:79:Infinity":30,"s:80:4:80:Infinity":31,"s:81:4:81:Infinity":32,"s:82:4:82:Infinity":33,"b:86:2:98:Infinity:undefined:undefined:undefined:undefined":13,"s:86:2:98:Infinity":34,"b:87:4:87:Infinity:88:4:88:Infinity:89:4:89:Infinity":14,"s:91:4:91:Infinity":35,"s:92:4:92:Infinity":36,"s:93:4:95:Infinity":37,"s:96:4:96:Infinity":38,"s:97:4:97:Infinity":39,"b:101:2:110:Infinity:undefined:undefined:undefined:undefined":15,"s:101:2:110:Infinity":40,"b:102:4:102:Infinity:103:4:103:Infinity:104:4:104:Infinity":16,"s:106:4:106:Infinity":41,"s:107:4:107:Infinity":42,"s:108:4:108:Infinity":43,"s:109:4:109:Infinity":44,"b:113:2:123:Infinity:undefined:undefined:undefined:undefined":17,"s:113:2:123:Infinity":45,"b:114:4:114:Infinity:115:4:115:Infinity:116:5:116:18:116:18:116:Infinity":18,"s:118:4:118:Infinity":46,"s:119:4:119:Infinity":47,"s:120:4:120:Infinity":48,"s:121:4:121:Infinity":49,"s:122:4:122:Infinity":50,"b:126:2:131:Infinity:undefined:undefined:undefined:undefined":19,"s:126:2:131:Infinity":51,"b:126:6:126:41:126:41:126:76":20,"s:127:4:127:Infinity":52,"s:128:4:128:Infinity":53,"s:129:4:129:Infinity":54,"s:130:4:130:Infinity":55,"b:134:2:146:Infinity:undefined:undefined:undefined:undefined":21,"s:134:2:146:Infinity":56,"b:135:4:135:Infinity:136:4:136:Infinity:137:4:137:Infinity:138:4:138:Infinity:139:4:139:Infinity:140:4:140:Infinity":22,"s:142:4:142:Infinity":57,"s:143:4:143:Infinity":58,"s:144:4:144:Infinity":59,"s:145:4:145:Infinity":60,"s:148:2:150:Infinity":61}}} +,"/Users/marcus/berget-monorepo/cli/src/utils/logger.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/utils/logger.ts","statementMap":{"0":{"start":{"line":6,"column":7},"end":{"line":12,"column":null}},"1":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"2":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"4":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"5":{"start":{"line":11,"column":2},"end":{"line":11,"column":null}},"6":{"start":{"line":14,"column":18},"end":{"line":14,"column":null}},"7":{"start":{"line":21,"column":10},"end":{"line":21,"column":null}},"8":{"start":{"line":25,"column":4},"end":{"line":31,"column":null}},"9":{"start":{"line":26,"column":6},"end":{"line":26,"column":null}},"10":{"start":{"line":27,"column":11},"end":{"line":31,"column":null}},"11":{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},"12":{"start":{"line":29,"column":11},"end":{"line":31,"column":null}},"13":{"start":{"line":30,"column":6},"end":{"line":30,"column":null}},"14":{"start":{"line":35,"column":4},"end":{"line":37,"column":null}},"15":{"start":{"line":36,"column":6},"end":{"line":36,"column":null}},"16":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"17":{"start":{"line":46,"column":4},"end":{"line":56,"column":null}},"18":{"start":{"line":47,"column":30},"end":{"line":47,"column":null}},"19":{"start":{"line":48,"column":27},"end":{"line":50,"column":null}},"20":{"start":{"line":49,"column":8},"end":{"line":49,"column":null}},"21":{"start":{"line":51,"column":6},"end":{"line":55,"column":null}},"22":{"start":{"line":52,"column":8},"end":{"line":52,"column":null}},"23":{"start":{"line":54,"column":8},"end":{"line":54,"column":null}},"24":{"start":{"line":63,"column":4},"end":{"line":69,"column":null}},"25":{"start":{"line":64,"column":6},"end":{"line":68,"column":null}},"26":{"start":{"line":65,"column":8},"end":{"line":65,"column":null}},"27":{"start":{"line":67,"column":8},"end":{"line":67,"column":null}},"28":{"start":{"line":76,"column":4},"end":{"line":76,"column":null}},"29":{"start":{"line":83,"column":4},"end":{"line":89,"column":null}},"30":{"start":{"line":84,"column":6},"end":{"line":88,"column":null}},"31":{"start":{"line":85,"column":8},"end":{"line":85,"column":null}},"32":{"start":{"line":87,"column":8},"end":{"line":87,"column":null}},"33":{"start":{"line":96,"column":4},"end":{"line":102,"column":null}},"34":{"start":{"line":97,"column":6},"end":{"line":101,"column":null}},"35":{"start":{"line":98,"column":8},"end":{"line":98,"column":null}},"36":{"start":{"line":100,"column":8},"end":{"line":100,"column":null}},"37":{"start":{"line":109,"column":4},"end":{"line":109,"column":null}},"38":{"start":{"line":116,"column":4},"end":{"line":122,"column":null}},"39":{"start":{"line":117,"column":6},"end":{"line":121,"column":null}},"40":{"start":{"line":118,"column":8},"end":{"line":118,"column":null}},"41":{"start":{"line":120,"column":8},"end":{"line":120,"column":null}},"42":{"start":{"line":129,"column":4},"end":{"line":135,"column":null}},"43":{"start":{"line":130,"column":6},"end":{"line":134,"column":null}},"44":{"start":{"line":131,"column":8},"end":{"line":131,"column":null}},"45":{"start":{"line":133,"column":8},"end":{"line":133,"column":null}},"46":{"start":{"line":142,"column":4},"end":{"line":167,"column":null}},"47":{"start":{"line":144,"column":8},"end":{"line":144,"column":null}},"48":{"start":{"line":145,"column":8},"end":{"line":145,"column":null}},"49":{"start":{"line":148,"column":8},"end":{"line":148,"column":null}},"50":{"start":{"line":149,"column":8},"end":{"line":149,"column":null}},"51":{"start":{"line":152,"column":8},"end":{"line":152,"column":null}},"52":{"start":{"line":153,"column":8},"end":{"line":153,"column":null}},"53":{"start":{"line":156,"column":8},"end":{"line":156,"column":null}},"54":{"start":{"line":157,"column":8},"end":{"line":157,"column":null}},"55":{"start":{"line":160,"column":8},"end":{"line":160,"column":null}},"56":{"start":{"line":161,"column":8},"end":{"line":161,"column":null}},"57":{"start":{"line":165,"column":8},"end":{"line":165,"column":null}},"58":{"start":{"line":177,"column":15},"end":{"line":177,"column":null}},"59":{"start":{"line":180,"column":2},"end":{"line":180,"column":null}},"60":{"start":{"line":183,"column":2},"end":{"line":183,"column":null}},"61":{"start":{"line":186,"column":2},"end":{"line":186,"column":null}},"62":{"start":{"line":189,"column":2},"end":{"line":189,"column":null}},"63":{"start":{"line":191,"column":2},"end":{"line":191,"column":null}},"64":{"start":{"line":195,"column":22},"end":{"line":195,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":6,"column":7},"end":{"line":6,"column":12}},"loc":{"start":{"line":6,"column":7},"end":{"line":12,"column":null}},"line":6},"1":{"name":"constructor","decl":{"start":{"line":23,"column":2},"end":{"line":23,"column":10}},"loc":{"start":{"line":23,"column":24},"end":{"line":32,"column":null}},"line":23},"2":{"name":"getInstance","decl":{"start":{"line":34,"column":16},"end":{"line":34,"column":38}},"loc":{"start":{"line":34,"column":38},"end":{"line":39,"column":null}},"line":34},"3":{"name":"debug","decl":{"start":{"line":45,"column":2},"end":{"line":45,"column":9}},"loc":{"start":{"line":45,"column":60},"end":{"line":57,"column":null}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":48,"column":38},"end":{"line":48,"column":43}},"loc":{"start":{"line":49,"column":8},"end":{"line":49,"column":null}},"line":49},"5":{"name":"error","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":9}},"loc":{"start":{"line":62,"column":60},"end":{"line":70,"column":null}},"line":62},"6":{"name":"getLogLevel","decl":{"start":{"line":75,"column":2},"end":{"line":75,"column":9}},"loc":{"start":{"line":75,"column":33},"end":{"line":77,"column":null}},"line":75},"7":{"name":"info","decl":{"start":{"line":82,"column":2},"end":{"line":82,"column":9}},"loc":{"start":{"line":82,"column":59},"end":{"line":90,"column":null}},"line":82},"8":{"name":"log","decl":{"start":{"line":95,"column":2},"end":{"line":95,"column":9}},"loc":{"start":{"line":95,"column":58},"end":{"line":103,"column":null}},"line":95},"9":{"name":"setLogLevel","decl":{"start":{"line":108,"column":2},"end":{"line":108,"column":9}},"loc":{"start":{"line":108,"column":44},"end":{"line":110,"column":null}},"line":108},"10":{"name":"success","decl":{"start":{"line":115,"column":2},"end":{"line":115,"column":9}},"loc":{"start":{"line":115,"column":62},"end":{"line":123,"column":null}},"line":115},"11":{"name":"warn","decl":{"start":{"line":128,"column":2},"end":{"line":128,"column":9}},"loc":{"start":{"line":128,"column":59},"end":{"line":136,"column":null}},"line":128},"12":{"name":"setLogLevelFromString","decl":{"start":{"line":141,"column":2},"end":{"line":141,"column":10}},"loc":{"start":{"line":141,"column":53},"end":{"line":168,"column":null}},"line":141},"13":{"name":"redactSecrets","decl":{"start":{"line":176,"column":9},"end":{"line":176,"column":23}},"loc":{"start":{"line":176,"column":46},"end":{"line":192,"column":null}},"line":176}},"branchMap":{"0":{"loc":{"start":{"line":25,"column":4},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":4},"end":{"line":31,"column":null}},{"start":{"line":27,"column":11},"end":{"line":31,"column":null}}],"line":25},"1":{"loc":{"start":{"line":27,"column":11},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":27,"column":11},"end":{"line":31,"column":null}},{"start":{"line":29,"column":11},"end":{"line":31,"column":null}}],"line":27},"2":{"loc":{"start":{"line":29,"column":11},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":29,"column":11},"end":{"line":31,"column":null}},{"start":{},"end":{}}],"line":29},"3":{"loc":{"start":{"line":35,"column":4},"end":{"line":37,"column":null}},"type":"if","locations":[{"start":{"line":35,"column":4},"end":{"line":37,"column":null}},{"start":{},"end":{}}],"line":35},"4":{"loc":{"start":{"line":46,"column":4},"end":{"line":56,"column":null}},"type":"if","locations":[{"start":{"line":46,"column":4},"end":{"line":56,"column":null}},{"start":{},"end":{}}],"line":46},"5":{"loc":{"start":{"line":49,"column":8},"end":{"line":49,"column":null}},"type":"cond-expr","locations":[{"start":{"line":49,"column":34},"end":{"line":49,"column":55}},{"start":{"line":49,"column":55},"end":{"line":49,"column":null}}],"line":49},"6":{"loc":{"start":{"line":51,"column":6},"end":{"line":55,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":6},"end":{"line":55,"column":null}},{"start":{"line":53,"column":13},"end":{"line":55,"column":null}}],"line":51},"7":{"loc":{"start":{"line":63,"column":4},"end":{"line":69,"column":null}},"type":"if","locations":[{"start":{"line":63,"column":4},"end":{"line":69,"column":null}},{"start":{},"end":{}}],"line":63},"8":{"loc":{"start":{"line":64,"column":6},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":6},"end":{"line":68,"column":null}},{"start":{"line":66,"column":13},"end":{"line":68,"column":null}}],"line":64},"9":{"loc":{"start":{"line":83,"column":4},"end":{"line":89,"column":null}},"type":"if","locations":[{"start":{"line":83,"column":4},"end":{"line":89,"column":null}},{"start":{},"end":{}}],"line":83},"10":{"loc":{"start":{"line":84,"column":6},"end":{"line":88,"column":null}},"type":"if","locations":[{"start":{"line":84,"column":6},"end":{"line":88,"column":null}},{"start":{"line":86,"column":13},"end":{"line":88,"column":null}}],"line":84},"11":{"loc":{"start":{"line":96,"column":4},"end":{"line":102,"column":null}},"type":"if","locations":[{"start":{"line":96,"column":4},"end":{"line":102,"column":null}},{"start":{},"end":{}}],"line":96},"12":{"loc":{"start":{"line":97,"column":6},"end":{"line":101,"column":null}},"type":"if","locations":[{"start":{"line":97,"column":6},"end":{"line":101,"column":null}},{"start":{"line":99,"column":13},"end":{"line":101,"column":null}}],"line":97},"13":{"loc":{"start":{"line":116,"column":4},"end":{"line":122,"column":null}},"type":"if","locations":[{"start":{"line":116,"column":4},"end":{"line":122,"column":null}},{"start":{},"end":{}}],"line":116},"14":{"loc":{"start":{"line":117,"column":6},"end":{"line":121,"column":null}},"type":"if","locations":[{"start":{"line":117,"column":6},"end":{"line":121,"column":null}},{"start":{"line":119,"column":13},"end":{"line":121,"column":null}}],"line":117},"15":{"loc":{"start":{"line":129,"column":4},"end":{"line":135,"column":null}},"type":"if","locations":[{"start":{"line":129,"column":4},"end":{"line":135,"column":null}},{"start":{},"end":{}}],"line":129},"16":{"loc":{"start":{"line":130,"column":6},"end":{"line":134,"column":null}},"type":"if","locations":[{"start":{"line":130,"column":6},"end":{"line":134,"column":null}},{"start":{"line":132,"column":13},"end":{"line":134,"column":null}}],"line":130},"17":{"loc":{"start":{"line":142,"column":4},"end":{"line":167,"column":null}},"type":"switch","locations":[{"start":{"line":143,"column":6},"end":{"line":146,"column":null}},{"start":{"line":147,"column":6},"end":{"line":150,"column":null}},{"start":{"line":151,"column":6},"end":{"line":154,"column":null}},{"start":{"line":155,"column":6},"end":{"line":158,"column":null}},{"start":{"line":159,"column":6},"end":{"line":162,"column":null}},{"start":{"line":163,"column":6},"end":{"line":166,"column":null}}],"line":142}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":0,"10":1,"11":0,"12":1,"13":0,"14":1,"15":1,"16":1,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":1},"f":{"0":1,"1":1,"2":1,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0},"b":{"0":[0,1],"1":[0,1],"2":[0,1],"3":[1,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0,0,0,0,0]},"meta":{"lastBranch":18,"lastFunction":14,"lastStatement":65,"seen":{"s:6:7:12:Infinity":0,"f:6:7:6:12":0,"s:7:2:7:Infinity":1,"s:8:2:8:Infinity":2,"s:9:2:9:Infinity":3,"s:10:2:10:Infinity":4,"s:11:2:11:Infinity":5,"s:14:18:14:Infinity":6,"s:21:10:21:Infinity":7,"f:23:2:23:10":1,"b:25:4:31:Infinity:27:11:31:Infinity":0,"s:25:4:31:Infinity":8,"s:26:6:26:Infinity":9,"b:27:11:31:Infinity:29:11:31:Infinity":1,"s:27:11:31:Infinity":10,"s:28:6:28:Infinity":11,"b:29:11:31:Infinity:undefined:undefined:undefined:undefined":2,"s:29:11:31:Infinity":12,"s:30:6:30:Infinity":13,"f:34:16:34:38":2,"b:35:4:37:Infinity:undefined:undefined:undefined:undefined":3,"s:35:4:37:Infinity":14,"s:36:6:36:Infinity":15,"s:38:4:38:Infinity":16,"f:45:2:45:9":3,"b:46:4:56:Infinity:undefined:undefined:undefined:undefined":4,"s:46:4:56:Infinity":17,"s:47:30:47:Infinity":18,"s:48:27:50:Infinity":19,"f:48:38:48:43":4,"s:49:8:49:Infinity":20,"b:49:34:49:55:49:55:49:Infinity":5,"b:51:6:55:Infinity:53:13:55:Infinity":6,"s:51:6:55:Infinity":21,"s:52:8:52:Infinity":22,"s:54:8:54:Infinity":23,"f:62:2:62:9":5,"b:63:4:69:Infinity:undefined:undefined:undefined:undefined":7,"s:63:4:69:Infinity":24,"b:64:6:68:Infinity:66:13:68:Infinity":8,"s:64:6:68:Infinity":25,"s:65:8:65:Infinity":26,"s:67:8:67:Infinity":27,"f:75:2:75:9":6,"s:76:4:76:Infinity":28,"f:82:2:82:9":7,"b:83:4:89:Infinity:undefined:undefined:undefined:undefined":9,"s:83:4:89:Infinity":29,"b:84:6:88:Infinity:86:13:88:Infinity":10,"s:84:6:88:Infinity":30,"s:85:8:85:Infinity":31,"s:87:8:87:Infinity":32,"f:95:2:95:9":8,"b:96:4:102:Infinity:undefined:undefined:undefined:undefined":11,"s:96:4:102:Infinity":33,"b:97:6:101:Infinity:99:13:101:Infinity":12,"s:97:6:101:Infinity":34,"s:98:8:98:Infinity":35,"s:100:8:100:Infinity":36,"f:108:2:108:9":9,"s:109:4:109:Infinity":37,"f:115:2:115:9":10,"b:116:4:122:Infinity:undefined:undefined:undefined:undefined":13,"s:116:4:122:Infinity":38,"b:117:6:121:Infinity:119:13:121:Infinity":14,"s:117:6:121:Infinity":39,"s:118:8:118:Infinity":40,"s:120:8:120:Infinity":41,"f:128:2:128:9":11,"b:129:4:135:Infinity:undefined:undefined:undefined:undefined":15,"s:129:4:135:Infinity":42,"b:130:6:134:Infinity:132:13:134:Infinity":16,"s:130:6:134:Infinity":43,"s:131:8:131:Infinity":44,"s:133:8:133:Infinity":45,"f:141:2:141:10":12,"b:143:6:146:Infinity:147:6:150:Infinity:151:6:154:Infinity:155:6:158:Infinity:159:6:162:Infinity:163:6:166:Infinity":17,"s:142:4:167:Infinity":46,"s:144:8:144:Infinity":47,"s:145:8:145:Infinity":48,"s:148:8:148:Infinity":49,"s:149:8:149:Infinity":50,"s:152:8:152:Infinity":51,"s:153:8:153:Infinity":52,"s:156:8:156:Infinity":53,"s:157:8:157:Infinity":54,"s:160:8:160:Infinity":55,"s:161:8:161:Infinity":56,"s:165:8:165:Infinity":57,"f:176:9:176:23":13,"s:177:15:177:Infinity":58,"s:180:2:180:Infinity":59,"s:183:2:183:Infinity":60,"s:186:2:186:Infinity":61,"s:189:2:189:Infinity":62,"s:191:2:191:Infinity":63,"s:195:22:195:Infinity":64}}} +} diff --git a/coverage/index.html b/coverage/index.html index 7f2566f..503d920 100644 --- a/coverage/index.html +++ b/coverage/index.html @@ -23,30 +23,30 @@

All files

- Unknown% + 44.54% Statements - 0/0 + 506/1136
- Unknown% + 37.76% Branches - 0/0 + 253/670
- Unknown% + 45.54% Functions - 0/0 + 92/202
- Unknown% + 44.45% Lines - 0/0 + 473/1064
@@ -61,7 +61,7 @@

All files

-
+
@@ -78,7 +78,187 @@

All files

- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
src +
+
0%0/110%0/20%0/30%0/11
src/agents +
+
72%18/2550%4/860%3/572%18/25
src/auth +
+
40.38%21/5225%7/2862.5%5/844.68%21/47
src/auth/middleware +
+
0%0/170%0/160%0/40%0/17
src/auth/oauth +
+
3.75%6/1600%0/910%0/243.94%6/152
src/auth/storage +
+
0%0/240%0/110%0/50%0/24
src/commands/code +
+
82.26%348/42376.67%194/25395.65%44/4683.03%323/389
src/commands/code/__tests__ +
+
70.86%90/12755%44/8079.54%35/4473.87%82/111
src/commands/code/adapters +
+
1.81%1/550%0/120%0/312%1/50
src/constants +
+
100%3/3100%0/0100%0/0100%3/3
src/services +
+
3.57%4/1120%0/7112.5%2/163.7%4/108
src/utils +
+
11.81%15/1274.08%4/9818.75%3/1611.81%15/127
@@ -86,7 +266,7 @@

All files

+ + + + + + \ No newline at end of file diff --git a/coverage/src/agents/backend.ts.html b/coverage/src/agents/backend.ts.html new file mode 100644 index 0000000..6632f0f --- /dev/null +++ b/coverage/src/agents/backend.ts.html @@ -0,0 +1,157 @@ + + + + + + Code coverage report for src/agents/backend.ts + + + + + + + + + +
+
+

All files / src/agents backend.ts

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Agent } from './types.js';
+ 
+export const agent: Agent = {
+  config: {
+    description: 'Functional, modular Koa + TypeScript services',
+    mode: 'primary',
+    name: 'backend',
+  },
+  systemPrompt: `# Backend Agent
+ 
+Functional, modular Koa + TypeScript services with schema-first approach and code quality focus.
+ 
+**Use when:**
+ 
+- Working with Koa routers and services
+- Backend development in /services
+- API development and database work
+ 
+**Key features:**
+ 
+- Zod validation and OpenAPI generation
+- Code quality and refactoring principles
+- PR workflow integration`,
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/agents/devops.ts.html b/coverage/src/agents/devops.ts.html new file mode 100644 index 0000000..fe08861 --- /dev/null +++ b/coverage/src/agents/devops.ts.html @@ -0,0 +1,184 @@ + + + + + + Code coverage report for src/agents/devops.ts + + + + + + + + + +
+
+

All files / src/agents devops.ts

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Agent } from './types.js';
+ 
+export const agent: Agent = {
+  config: {
+    description: 'Declarative GitOps infra with FluxCD, Kustomize, Helm, operators.',
+    mode: 'primary',
+    name: 'devops',
+    permission: {
+      bash: 'allow',
+      edit: 'allow',
+      webfetch: 'allow',
+    },
+    temperature: 0.3,
+    top_p: 0.8,
+  },
+  systemPrompt: `You are Berget Code DevOps agent. Voice: Scandinavian calm—precise, concise, confident. Start simple: k8s/{deployment,service,ingress}. Add FluxCD sync to repo and image automation. Use Kustomize bases/overlays (staging, production). Add dependencies via Helm from upstream sources; prefer native operators when available (CloudNativePG, cert-manager, external-dns). SemVer with -rc tags keeps CI environments current. Observability with Prometheus/Grafana. No manual kubectl in production—Git is the source of truth.
+ 
+GIT WORKFLOW RULES (CRITICAL):
+- NEVER push directly to main branch - ALWAYS use pull requests
+- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
+- ALWAYS clean up test files, documentation files, and temporary artifacts before committing
+- ALWAYS ensure git history maintains production quality - no test commits, no debugging code
+- ALWAYS create descriptive commit messages following project conventions
+- ALWAYS run tests and build before creating PR
+ 
+Helm Values Configuration Process:
+1. Documentation First Approach: Always fetch official documentation from Artifact Hub/GitHub for the specific chart version before writing values. Search Artifact Hub for exact chart version documentation, check the chart's GitHub repository for official docs and examples, verify the exact version being used in the deployment.
+2. Validation Requirements: Check for available validation schemas before committing YAML files. Use Helm's built-in validation tools (helm lint, helm template). Validate against JSON schema if available for the chart. Ensure YAML syntax correctness with linters.
+3. Standard Workflow: Identify chart name and exact version. Fetch official documentation from Artifact Hub/GitHub. Check for available schemas and validation tools. Write values according to official documentation. Validate against schema (if available). Test with helm template or helm lint. Commit validated YAML files.
+4. Quality Assurance: Never commit unvalidated Helm values. Use helm dependency update when adding new charts. Test rendering with helm template --dry-run before deployment. Document any custom values with comments referencing official docs.
+ 
+CRITICAL: When all devops implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.`,
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/agents/frontend.ts.html b/coverage/src/agents/frontend.ts.html new file mode 100644 index 0000000..61f2e67 --- /dev/null +++ b/coverage/src/agents/frontend.ts.html @@ -0,0 +1,157 @@ + + + + + + Code coverage report for src/agents/frontend.ts + + + + + + + + + +
+
+

All files / src/agents frontend.ts

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Agent } from './types.js';
+ 
+export const agent: Agent = {
+  config: {
+    description: 'Scandinavian, type-safe UIs with React, Tailwind, and Shadcn',
+    mode: 'primary',
+    name: 'frontend',
+  },
+  systemPrompt: `# Frontend Agent
+ 
+Builds Scandinavian, type-safe UIs with React, Tailwind, and Shadcn.
+ 
+**Use when:**
+ 
+- Working with React components (.tsx files)
+- Frontend development in /apps/frontend
+- UI/UX implementation
+ 
+**Key features:**
+ 
+- Design system integration
+- Semantic tokens and accessibility
+- Props-first component architecture`,
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/agents/fullstack.ts.html b/coverage/src/agents/fullstack.ts.html new file mode 100644 index 0000000..472ca26 --- /dev/null +++ b/coverage/src/agents/fullstack.ts.html @@ -0,0 +1,157 @@ + + + + + + Code coverage report for src/agents/fullstack.ts + + + + + + + + + +
+
+

All files / src/agents fullstack.ts

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Agent } from './types.js';
+ 
+export const agent: Agent = {
+  config: {
+    description: 'Router/coordinator agent for full-stack development',
+    mode: 'primary',
+    name: 'fullstack',
+  },
+  systemPrompt: `# Fullstack Agent
+ 
+Router/coordinator agent for full-stack development with schema-driven architecture. Handles routing between different personas based on file paths and task requirements.
+ 
+**Use when:**
+ 
+- Working across multiple parts of a monorepo
+- Need to coordinate between frontend, backend, devops, and app
+- Starting new projects and need to determine tech stack
+ 
+**Key features:**
+ 
+- Schema-driven development (database → OpenAPI → types)
+- Automatic routing to appropriate persona
+- Tech stack discovery and recommendations`,
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/agents/index.html b/coverage/src/agents/index.html new file mode 100644 index 0000000..a7eeeb9 --- /dev/null +++ b/coverage/src/agents/index.html @@ -0,0 +1,221 @@ + + + + + + Code coverage report for src/agents + + + + + + + + + +
+
+

All files src/agents

+
+ +
+ 72% + Statements + 18/25 +
+ + +
+ 50% + Branches + 4/8 +
+ + +
+ 60% + Functions + 3/5 +
+ + +
+ 72% + Lines + 18/25 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
app.ts +
+
100%1/1100%0/0100%0/0100%1/1
backend.ts +
+
100%1/1100%0/0100%0/0100%1/1
devops.ts +
+
100%1/1100%0/0100%0/0100%1/1
frontend.ts +
+
100%1/1100%0/0100%0/0100%1/1
fullstack.ts +
+
100%1/1100%0/0100%0/0100%1/1
index.ts +
+
61.11%11/1850%4/860%3/561.11%11/18
quality.ts +
+
100%1/1100%0/0100%0/0100%1/1
security.ts +
+
100%1/1100%0/0100%0/0100%1/1
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/agents/index.ts.html b/coverage/src/agents/index.ts.html new file mode 100644 index 0000000..d5be0a4 --- /dev/null +++ b/coverage/src/agents/index.ts.html @@ -0,0 +1,304 @@ + + + + + + Code coverage report for src/agents/index.ts + + + + + + + + + +
+
+

All files / src/agents index.ts

+
+ +
+ 61.11% + Statements + 11/18 +
+ + +
+ 50% + Branches + 4/8 +
+ + +
+ 60% + Functions + 3/5 +
+ + +
+ 61.11% + Lines + 11/18 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +28x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +7x +7x +  +7x +7x +  +  +7x +  +  +  +7x +  +  +  +7x +  +  +  +  +  +  +7x +  +  +  +8x +  +  +  + 
import type { Agent } from './types.js';
+ 
+import { agent as app } from './app.js';
+import { agent as backend } from './backend.js';
+import { agent as devops } from './devops.js';
+import { agent as frontend } from './frontend.js';
+import { agent as fullstack } from './fullstack.js';
+import { agent as quality } from './quality.js';
+import { agent as security } from './security.js';
+ 
+const agents: Record<string, Agent> = {
+  app,
+  backend,
+  devops,
+  frontend,
+  fullstack,
+  quality,
+  security,
+};
+ 
+export { agents };
+ 
+export function getAgent(name: string): Agent | undefined {
+  return agents[name];
+}
+ 
+export function getAllAgents(): Agent[] {
+  return Object.values(agents);
+}
+ 
+export function toAgentTemplate(agent: Agent): {
+  content: string;
+  description: string;
+  name: string;
+} {
+  return {
+    content: agent.systemPrompt,
+    description: agent.config.description,
+    name: agent.config.name,
+  };
+}
+ 
+export function toMarkdown(agent: Agent): string {
+  const { config, systemPrompt } = agent;
+  let frontmatter = `---\nname: ${config.name}\ndescription: ${config.description}\n`;
+ 
+  Eif (config.mode) {
+    frontmatter += `mode: ${config.mode}\n`;
+  }
+ 
+  Iif (config.temperature) {
+    frontmatter += `temperature: ${config.temperature}\n`;
+  }
+ 
+  Iif (config.top_p) {
+    frontmatter += `top_p: ${config.top_p}\n`;
+  }
+ 
+  Iif (config.permission) {
+    frontmatter += `permission:\n`;
+    for (const [key, value] of Object.entries(config.permission)) {
+      frontmatter += `  ${key}: ${value}\n`;
+    }
+  }
+ 
+  return `${frontmatter}---\n\n${systemPrompt}`;
+}
+ 
+export function toPiPrompt(agent: Agent): string {
+  return agent.systemPrompt;
+}
+ 
+export { type Agent, type AgentConfig } from './types.js';
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/agents/quality.ts.html b/coverage/src/agents/quality.ts.html new file mode 100644 index 0000000..b964d1e --- /dev/null +++ b/coverage/src/agents/quality.ts.html @@ -0,0 +1,292 @@ + + + + + + Code coverage report for src/agents/quality.ts + + + + + + + + + +
+
+

All files / src/agents quality.ts

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Agent } from './types.js';
+ 
+export const agent: Agent = {
+  config: {
+    description: 'Quality assurance specialist for testing, building, and complete PR management.',
+    mode: 'subagent',
+    name: 'quality',
+    permission: {
+      bash: 'allow',
+      edit: 'allow',
+      webfetch: 'allow',
+    },
+    temperature: 0.1,
+    top_p: 0.9,
+  },
+  systemPrompt: `Voice: Scandinavian calm—precise, concise, confident. You are Berget Code Quality agent. Specialist in code quality assurance, testing, building, and pull request lifecycle management.
+ 
+Core responsibilities:
+  - Run comprehensive test suites (npm test, npm run test, jest, vitest)
+  - Execute build processes (npm run build, webpack, vite, tsc)
+  - Create and manage pull requests with proper descriptions
+  - Handle merge conflicts and keep main updated
+  - Monitor GitHub for reviewer comments and address them
+  - Ensure code quality standards are met
+  - Validate linting and formatting (npm run lint, prettier)
+  - Check test coverage and performance benchmarks
+  - Handle CI/CD pipeline validation
+ 
+Complete PR Workflow:
+   1. Ensure all tests pass: npm test
+   2. Build successfully: npm run build
+   3. Commit all changes with proper message
+   4. Push to feature branch
+   5. Update main branch and handle merge conflicts
+   6. Create or update PR with comprehensive description
+   7. Monitor for reviewer comments
+   8. Address feedback and push updates
+   9. Always provide PR URL for user review
+ 
+Essential CLI commands:
+   - npm test or npm run test (run test suite)
+   - npm run build (build project)
+   - npm run lint (run linting)
+   - npm run format (format code)
+   - npm run test:coverage (check coverage)
+   - git add <specific-files> && git commit -m "message" && git push (commit and push)
+   - git checkout main && git pull origin main (update main)
+   - git checkout feature-branch && git merge main (handle conflicts)
+   - gh pr create --title "title" --body "body" (create PR)
+   - gh pr view --comments (check PR comments)
+   - gh pr edit --title "title" --body "body" (update PR)
+ 
+PR Creation Process:
+   - Always include clear summary of changes
+   - List technical details and improvements
+   - Include testing and validation results
+   - Add any breaking changes or migration notes
+   - Provide PR URL immediately after creation
+ 
+GIT WORKFLOW RULES (CRITICAL - ENFORCE STRICTLY):
+   - NEVER push directly to main branch - ALWAYS use pull requests
+   - NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
+   - ALWAYS clean up test files, documentation files, and temporary artifacts before committing
+   - ALWAYS ensure git history maintains production quality - no test commits, no debugging code
+   - ALWAYS create descriptive commit messages following project conventions
+   - ALWAYS run tests and build before creating PR
+ 
+Always provide specific command examples and wait for processes to complete before proceeding.`,
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/agents/security.ts.html b/coverage/src/agents/security.ts.html new file mode 100644 index 0000000..4e9925e --- /dev/null +++ b/coverage/src/agents/security.ts.html @@ -0,0 +1,163 @@ + + + + + + Code coverage report for src/agents/security.ts + + + + + + + + + +
+
+

All files / src/agents security.ts

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Agent } from './types.js';
+ 
+export const agent: Agent = {
+  config: {
+    description:
+      'Security specialist for pentesting, OWASP compliance, and vulnerability assessments.',
+    mode: 'subagent',
+    name: 'security',
+    permission: {
+      bash: 'allow',
+      edit: 'deny',
+      webfetch: 'allow',
+    },
+    temperature: 0.2,
+    top_p: 0.8,
+  },
+  systemPrompt: `Voice: Scandinavian calm—precise, concise, confident. You are Berget Code Security agent. Expert in application security, penetration testing, and OWASP standards. Core responsibilities: Conduct security assessments and penetration tests, Validate OWASP Top 10 compliance, Review code for security vulnerabilities, Implement security headers and Content Security Policy (CSP), Audit API security, Check for sensitive data exposure, Validate input sanitization and output encoding, Assess dependency security and supply chain risks. Tools and techniques: OWASP ZAP, Burp Suite, security linters, dependency scanners, manual code review. Always provide specific, actionable security recommendations with priority levels.
+ 
+GIT WORKFLOW RULES (CRITICAL):
+- NEVER push directly to main branch - ALWAYS use pull requests
+- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
+- ALWAYS clean up test files, documentation files, and temporary artifacts before committing
+- ALWAYS ensure git history maintains production quality - no test commits, no debugging code
+- ALWAYS create descriptive commit messages following project conventions
+- ALWAYS run tests and build before creating PR`,
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/config.ts.html b/coverage/src/auth/config.ts.html new file mode 100644 index 0000000..d2c8a86 --- /dev/null +++ b/coverage/src/auth/config.ts.html @@ -0,0 +1,217 @@ + + + + + + Code coverage report for src/auth/config.ts + + + + + + + + + +
+
+

All files / src/auth config.ts

+
+ +
+ 0% + Statements + 0/17 +
+ + +
+ 0% + Branches + 0/14 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/17 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import type { AuthConfig } from './types.js';
+ 
+export function getAuthConfig(options?: { local?: boolean; stage?: boolean }): AuthConfig {
+  // Allow explicit override of Keycloak URL
+  if (process.env.BERGET_KEYCLOAK_URL) {
+    const apiBaseUrl = process.env.BERGET_API_URL || 'https://api.berget.ai';
+    return {
+      apiBaseUrl,
+      clientId: 'berget-code',
+      keycloakUrl: process.env.BERGET_KEYCLOAK_URL,
+      realm: 'berget',
+    };
+  }
+ 
+  let apiBaseUrl: string;
+  let keycloakUrl: string;
+ 
+  // Environment variable always takes precedence
+  if (process.env.BERGET_API_URL) {
+    apiBaseUrl = process.env.BERGET_API_URL;
+    // Infer keycloak from API URL for custom endpoints
+    if (apiBaseUrl.includes('localhost') || apiBaseUrl.includes('stage.')) {
+      keycloakUrl = 'https://keycloak.stage.berget.ai';
+    } else {
+      keycloakUrl = 'https://keycloak.berget.ai';
+    }
+  } else if (options?.local) {
+    apiBaseUrl = 'http://localhost:3000';
+    keycloakUrl = 'https://keycloak.stage.berget.ai';
+  } else if (options?.stage) {
+    apiBaseUrl = 'https://api.stage.berget.ai';
+    keycloakUrl = 'https://keycloak.stage.berget.ai';
+  } else {
+    apiBaseUrl = 'https://api.berget.ai';
+    keycloakUrl = 'https://keycloak.berget.ai';
+  }
+ 
+  return {
+    apiBaseUrl,
+    clientId: 'berget-code',
+    keycloakUrl,
+    realm: 'berget',
+  };
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/index.html b/coverage/src/auth/index.html new file mode 100644 index 0000000..8d78a30 --- /dev/null +++ b/coverage/src/auth/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for src/auth + + + + + + + + + +
+
+

All files src/auth

+
+ +
+ 40.38% + Statements + 21/52 +
+ + +
+ 25% + Branches + 7/28 +
+ + +
+ 62.5% + Functions + 5/8 +
+ + +
+ 44.68% + Lines + 21/47 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
config.ts +
+
0%0/170%0/140%0/10%0/17
issuer.ts +
+
11.11%1/90%0/20%0/212.5%1/8
jwt.ts +
+
76.92%20/2658.33%7/12100%5/590.9%20/22
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/issuer.ts.html b/coverage/src/auth/issuer.ts.html new file mode 100644 index 0000000..aecd27c --- /dev/null +++ b/coverage/src/auth/issuer.ts.html @@ -0,0 +1,187 @@ + + + + + + Code coverage report for src/auth/issuer.ts + + + + + + + + + +
+
+

All files / src/auth issuer.ts

+
+ +
+ 11.11% + Statements + 1/9 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 12.5% + Lines + 1/8 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
// openid-client@^6 API surface verified:
+// discovery(url: URL, clientId: string, clientMetadata?: object, clientAuth?: ClientAuth): Promise<Configuration>
+// randomPKCECodeVerifier(): string
+// calculatePKCECodeChallenge(codeVerifier: string): string
+// buildAuthorizationUrl(configuration: Configuration, parameters?: Record<string, string>): URL
+// authorizationCodeGrant(configuration: Configuration, url: URL, checkState?: boolean, options?: object): Promise<{ access_token: string, refresh_token?: string, expires_in?: number, ... }>
+// refreshTokenGrant(configuration: Configuration, refreshToken: string, options?: object): Promise<{ access_token: string, refresh_token?: string, expires_in?: number, ... }>
+ 
+import { type Configuration, discovery } from 'openid-client';
+ 
+import type { AuthConfig } from './types.js';
+ 
+const cache = new Map<string, Configuration>();
+ 
+export function clearConfigurationCache(): void {
+  cache.clear();
+}
+ 
+export async function getConfiguration(config: AuthConfig): Promise<Configuration> {
+  const issuerUrl = new URL(`${config.keycloakUrl}/realms/${config.realm}`).toString();
+ 
+  const cached = cache.get(issuerUrl);
+  if (cached) return cached;
+ 
+  const configuration = await discovery(
+    new URL(issuerUrl),
+    config.clientId,
+    {}, // no additional client metadata needed for public PKCE client
+    // 4th arg (clientAuth) omitted — public PKCE client has no auth
+  );
+ 
+  cache.set(issuerUrl, configuration);
+  return configuration;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/jwt.ts.html b/coverage/src/auth/jwt.ts.html new file mode 100644 index 0000000..434c6d3 --- /dev/null +++ b/coverage/src/auth/jwt.ts.html @@ -0,0 +1,274 @@ + + + + + + Code coverage report for src/auth/jwt.ts + + + + + + + + + +
+
+

All files / src/auth jwt.ts

+
+ +
+ 76.92% + Statements + 20/26 +
+ + +
+ 58.33% + Branches + 7/12 +
+ + +
+ 100% + Functions + 5/5 +
+ + +
+ 90.9% + Lines + 20/22 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64  +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +5x +5x +5x +  +  +  +  +  +  +  +  +  +  +3x +3x +3x +3x +3x +3x +3x +  +  +  +  +  +  +  +  +  +2x +2x +2x +2x +  +  +  +  +  +  +11x +11x +11x +11x +11x +  +  +  +  + 
/**
+ * Decode the payload of a JWT token without verification.
+ * @param token The JWT token string
+ * @returns The decoded payload, or null if the token is invalid
+ */
+export function decodeJwtPayload(token: string): null | unknown {
+  return parseJwtBody(token);
+}
+ 
+/**
+ * Extract the expiration timestamp (in milliseconds) from a JWT token.
+ * @param accessToken The JWT access token
+ * @returns The expiration timestamp in milliseconds, or 0 if invalid
+ */
+export function extractJwtExpiresAt(accessToken: string): number {
+  const decoded = parseJwtBody(accessToken);
+  Eif (decoded && typeof decoded.exp === 'number') {
+    return decoded.exp * 1000; // JWT exp is in seconds, convert to milliseconds
+  }
+  return 0;
+}
+ 
+/**
+ * Check if the JWT token has the `berget_code_seat` role.
+ * @param accessToken The JWT access token
+ * @returns true if the token has the `berget_code_seat` role, false otherwise
+ */
+export function hasBergetCodeSeat(accessToken: string): boolean {
+  const decoded = parseJwtBody(accessToken);
+  Iif (!decoded) return false;
+  const realmAccess = decoded.realm_access as Record<string, unknown> | undefined;
+  Iif (!realmAccess) return false;
+  const roles = realmAccess.roles as string[] | undefined;
+  Iif (!Array.isArray(roles)) return false;
+  return roles.includes('berget_code_seat');
+}
+ 
+/**
+ * Check if a token is expired with a configurable buffer.
+ * Uses 10% of remaining lifetime or 30 seconds, whichever is smaller.
+ * @param expiresAt The expiration timestamp in milliseconds
+ * @returns true if expired or about to expire, false otherwise
+ */
+export function isTokenExpired(expiresAt: number): boolean {
+  const now = Date.now();
+  const timeUntilExpiry = expiresAt - now;
+  const buffer = Math.min(30 * 1000, timeUntilExpiry * 0.1);
+  return now + buffer >= expiresAt;
+}
+ 
+/**
+ * Internal: split a JWT into its three parts and parse the payload JSON.
+ */
+function parseJwtBody(token: string): null | Record<string, unknown> {
+  try {
+    const parts = token.split('.');
+    Iif (parts.length !== 3) return null;
+    const payload = Buffer.from(parts[1], 'base64url').toString('utf8');
+    return JSON.parse(payload);
+  } catch {
+    return null;
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/middleware/auth-middleware.ts.html b/coverage/src/auth/middleware/auth-middleware.ts.html new file mode 100644 index 0000000..12ff78e --- /dev/null +++ b/coverage/src/auth/middleware/auth-middleware.ts.html @@ -0,0 +1,202 @@ + + + + + + Code coverage report for src/auth/middleware/auth-middleware.ts + + + + + + + + + +
+
+

All files / src/auth/middleware auth-middleware.ts

+
+ +
+ 0% + Statements + 0/17 +
+ + +
+ 0% + Branches + 0/16 +
+ + +
+ 0% + Functions + 0/4 +
+ + +
+ 0% + Lines + 0/17 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import type { Middleware } from 'openapi-fetch';
+ 
+import { FileTokenStore } from '../storage/token-store.js';
+ 
+export function authMiddleware(options: {
+  getToken?: () => Promise<null | string>;
+  refresh?: () => Promise<boolean>;
+}): Middleware {
+  const getToken =
+    options.getToken ||
+    (async () => {
+      const store = new FileTokenStore();
+      const data = await store.get();
+      return data?.access_token || null;
+    });
+ 
+  return {
+    async onRequest(req) {
+      const token = await getToken();
+      if (token && !req.headers.get('Authorization')) {
+        req.headers.set('Authorization', `Bearer ${token}`);
+      }
+      return req;
+    },
+    async onResponse(res, _options, req) {
+      if (res.status === 401 && options.refresh) {
+        const ok = await options.refresh();
+        if (ok) {
+          const newToken = await getToken();
+          if (newToken) {
+            req.headers.set('Authorization', `Bearer ${newToken}`);
+            return fetch(req);
+          }
+        }
+      }
+      return undefined; // no modification
+    },
+  };
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/middleware/index.html b/coverage/src/auth/middleware/index.html new file mode 100644 index 0000000..b69284a --- /dev/null +++ b/coverage/src/auth/middleware/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for src/auth/middleware + + + + + + + + + +
+
+

All files src/auth/middleware

+
+ +
+ 0% + Statements + 0/17 +
+ + +
+ 0% + Branches + 0/16 +
+ + +
+ 0% + Functions + 0/4 +
+ + +
+ 0% + Lines + 0/17 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
auth-middleware.ts +
+
0%0/170%0/160%0/40%0/17
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/oauth/callback-pages.ts.html b/coverage/src/auth/oauth/callback-pages.ts.html new file mode 100644 index 0000000..2e5fb22 --- /dev/null +++ b/coverage/src/auth/oauth/callback-pages.ts.html @@ -0,0 +1,472 @@ + + + + + + Code coverage report for src/auth/oauth/callback-pages.ts + + + + + + + + + +
+
+

All files / src/auth/oauth callback-pages.ts

+
+ +
+ 0% + Statements + 0/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 0% + Lines + 0/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
/**
+ * HTML callback pages for the OAuth PKCE browser flow.
+ * Kept separate from pkce-flow.ts to keep the flow logic focused.
+ */
+ 
+export function getErrorPage(title: string, message: string): string {
+  const safeTitle = escapeHtml(title);
+  const safeMessage = escapeHtml(message);
+  return `<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Berget - Authentication Failed</title>
+    <style>
+      * { margin: 0; padding: 0; box-sizing: border-box; }
+      body {
+        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        min-height: 100vh;
+        background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%);
+        color: #fff;
+      }
+      .container {
+        text-align: center;
+        padding: 3rem;
+        max-width: 400px;
+      }
+      .icon {
+        width: 80px;
+        height: 80px;
+        background: linear-gradient(135deg, #f87171 0%, #ef4444 100%);
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin: 0 auto 1.5rem;
+        box-shadow: 0 4px 20px rgba(248, 113, 113, 0.3);
+      }
+      .icon svg { width: 40px; height: 40px; stroke: #fff; stroke-width: 3; }
+      h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.75rem; color: #fff; }
+      p { color: #94a3b8; font-size: 0.95rem; line-height: 1.5; }
+      .brand { margin-top: 2rem; opacity: 0.5; font-size: 0.8rem; letter-spacing: 0.05em; }
+    </style>
+  </head>
+  <body>
+    <div class="container">
+      <div class="icon">
+        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <line x1="18" y1="6" x2="6" y2="18"></line>
+          <line x1="6" y1="6" x2="18" y2="18"></line>
+        </svg>
+      </div>
+      <h1>${safeTitle}</h1>
+      <p>${safeMessage}</p>
+      <div class="brand">BERGET</div>
+    </div>
+  </body>
+</html>`;
+}
+ 
+export function getSuccessPage(): string {
+  return `<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Berget - Authentication Successful</title>
+    <style>
+      * { margin: 0; padding: 0; box-sizing: border-box; }
+      body {
+        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        min-height: 100vh;
+        background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%);
+        color: #fff;
+      }
+      .container {
+        text-align: center;
+        padding: 3rem;
+        max-width: 400px;
+      }
+      .icon {
+        width: 80px;
+        height: 80px;
+        background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin: 0 auto 1.5rem;
+        box-shadow: 0 4px 20px rgba(74, 222, 128, 0.3);
+      }
+      .icon svg { width: 40px; height: 40px; stroke: #fff; stroke-width: 3; }
+      h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.75rem; color: #fff; }
+      p { color: #94a3b8; font-size: 0.95rem; line-height: 1.5; }
+      .brand { margin-top: 2rem; opacity: 0.5; font-size: 0.8rem; letter-spacing: 0.05em; }
+    </style>
+  </head>
+  <body>
+    <div class="container">
+      <div class="icon">
+        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <polyline points="20 6 9 17 4 12"></polyline>
+        </svg>
+      </div>
+      <h1>Authentication Successful</h1>
+      <p>You can close this window and return to your terminal.</p>
+      <div class="brand">BERGET</div>
+    </div>
+  </body>
+</html>`;
+}
+ 
+/**
+ * Escape HTML special characters to prevent XSS.
+ */
+function escapeHtml(text: string): string {
+  return text
+    .replace(/&/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/"/g, '&quot;')
+    .replace(/'/g, '&#x27;');
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/oauth/index.html b/coverage/src/auth/oauth/index.html new file mode 100644 index 0000000..fb8a7c9 --- /dev/null +++ b/coverage/src/auth/oauth/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for src/auth/oauth + + + + + + + + + +
+
+

All files src/auth/oauth

+
+ +
+ 3.75% + Statements + 6/160 +
+ + +
+ 0% + Branches + 0/91 +
+ + +
+ 0% + Functions + 0/24 +
+ + +
+ 3.94% + Lines + 6/152 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
callback-pages.ts +
+
0%0/5100%0/00%0/30%0/5
pkce-flow.ts +
+
1.9%2/1050%0/560%0/151.98%2/101
token-refresh.ts +
+
8%4/500%0/350%0/68.69%4/46
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/oauth/pkce-flow.ts.html b/coverage/src/auth/oauth/pkce-flow.ts.html new file mode 100644 index 0000000..453b805 --- /dev/null +++ b/coverage/src/auth/oauth/pkce-flow.ts.html @@ -0,0 +1,826 @@ + + + + + + Code coverage report for src/auth/oauth/pkce-flow.ts + + + + + + + + + +
+
+

All files / src/auth/oauth pkce-flow.ts

+
+ +
+ 1.9% + Statements + 2/105 +
+ + +
+ 0% + Branches + 0/56 +
+ + +
+ 0% + Functions + 0/15 +
+ + +
+ 1.98% + Lines + 2/101 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as crypto from 'node:crypto';
+import * as http from 'node:http';
+import * as net from 'node:net';
+import {
+  authorizationCodeGrant,
+  buildAuthorizationUrl,
+  calculatePKCECodeChallenge,
+  type Configuration,
+  randomPKCECodeVerifier,
+  ResponseBodyError,
+} from 'openid-client';
+ 
+import type { BrowserAuthResult } from '../types.js';
+ 
+import { logger, LogLevel } from '../../utils/logger.js';
+import { getErrorPage, getSuccessPage } from './callback-pages.js';
+ 
+const FALLBACK_CALLBACK_PORT = 8787;
+const AUTH_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
+ 
+export interface PkceFlowOptions {
+  config: Configuration;
+  /** Injected http.createServer for testability */
+  createServer?: typeof http.createServer;
+  debug?: boolean;
+}
+ 
+/**
+ * Start the PKCE browser flow: spin up a callback server, open the browser,
+ * and exchange the authorization code for tokens.
+ */
+export async function startPkceFlow(options: PkceFlowOptions): Promise<BrowserAuthResult> {
+  const {
+    config,
+    createServer: createServerFactory = http.createServer,
+    debug: debugOption,
+  } = options;
+  const debug = debugOption || logger.getLogLevel() >= LogLevel.DEBUG;
+ 
+  const codeVerifier = randomPKCECodeVerifier();
+  const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
+  const state = crypto.randomUUID();
+ 
+  try {
+    const { port, server } = await startCallbackServer(createServerFactory);
+    const redirectUri = `http://127.0.0.1:${port}/callback`;
+ 
+    if (debug) {
+      console.log(`Callback server listening on port ${port}`);
+    }
+ 
+    // Build authorization URL using openid-client
+    const authorizationUrl = buildAuthorizationUrl(config, {
+      code_challenge: codeChallenge,
+      code_challenge_method: 'S256',
+      redirect_uri: redirectUri,
+      scope: 'openid email profile offline_access',
+      state,
+    });
+ 
+    if (debug) {
+      logger.debug('Built authorization URL:', authorizationUrl.toString().split('?')[0] + '?...');
+    }
+ 
+    // Create the callback handler promise
+    const authResult = await new Promise<{
+      callbackUrl?: string;
+      code?: string;
+      error?: string;
+      success: boolean;
+    }>((resolve) => {
+      let resolved = false;
+      const sockets = new Set<net.Socket>();
+ 
+      const safeResolve = (result: {
+        callbackUrl?: string;
+        code?: string;
+        error?: string;
+        success: boolean;
+      }) => {
+        if (resolved) return;
+        resolved = true;
+        clearTimeout(timeoutHandle);
+        server.close();
+        for (const socket of sockets) {
+          socket.destroy();
+        }
+        sockets.clear();
+        resolve(result);
+      };
+ 
+      server.on('request', (request, res) => {
+        const requestUrl = new URL(request.url || '', `http://127.0.0.1:${port}`);
+ 
+        if (requestUrl.pathname !== '/callback') {
+          res.writeHead(404, { Connection: 'close' });
+          res.end();
+          return;
+        }
+ 
+        const receivedState = requestUrl.searchParams.get('state') || '';
+        const code = requestUrl.searchParams.get('code') || '';
+        const error = requestUrl.searchParams.get('error') || '';
+ 
+        if (error) {
+          const description = requestUrl.searchParams.get('error_description') || error;
+          if (debug) {
+            logger.debug(`Callback returned OAuth error: ${error} — ${description}`);
+          }
+          res.writeHead(400, { Connection: 'close', 'Content-Type': 'text/html; charset=utf-8' });
+          res.end(getErrorPage('Authentication Failed', description));
+          safeResolve({ error, success: false });
+          return;
+        }
+ 
+        if (receivedState !== state) {
+          if (debug) {
+            logger.debug(`State mismatch: expected ${state}, got ${receivedState}`);
+          }
+          res.writeHead(403, { Connection: 'close', 'Content-Type': 'text/html; charset=utf-8' });
+          res.end(
+            getErrorPage('Authentication Failed', 'Invalid state parameter. Please try again.'),
+          );
+          safeResolve({ error: 'Invalid state parameter', success: false });
+          return;
+        }
+ 
+        if (!code) {
+          res.writeHead(400, { Connection: 'close', 'Content-Type': 'text/html; charset=utf-8' });
+          res.end(getErrorPage('Authentication Failed', 'Missing authorization code.'));
+          safeResolve({ error: 'Missing authorization code', success: false });
+          return;
+        }
+ 
+        res.writeHead(200, { Connection: 'close', 'Content-Type': 'text/html; charset=utf-8' });
+        res.end(getSuccessPage());
+        safeResolve({ callbackUrl: requestUrl.toString(), code, success: true });
+      });
+ 
+      server.on('connection', (socket: net.Socket) => {
+        sockets.add(socket);
+        socket.on('close', () => sockets.delete(socket));
+      });
+ 
+      const timeoutHandle = setTimeout(
+        () => safeResolve({ error: 'Authentication timed out', success: false }),
+        AUTH_TIMEOUT_MS,
+      );
+ 
+      // Open browser
+      (async () => {
+        try {
+          const open = await import('open').then((m) => m.default);
+          await open(authorizationUrl.toString());
+        } catch (error) {
+          logger.debug('Failed to open browser:', error);
+          logger.info(`Please open this URL in your browser: ${authorizationUrl.toString()}`);
+        }
+      })();
+    });
+ 
+    if (!authResult.success || !authResult.code || !authResult.callbackUrl) {
+      return {
+        error: authResult.error || 'Unknown error',
+        success: false,
+      };
+    }
+ 
+    // Exchange code for tokens using the FULL callback URL (preserves iss, session_state, etc.)
+    const callbackUrl = new URL(authResult.callbackUrl);
+ 
+    if (debug) {
+      logger.debug('Exchanging code for tokens at token endpoint');
+      logger.debug('Callback URL used for exchange:', callbackUrl.toString());
+    }
+ 
+    try {
+      const tokenResult = await authorizationCodeGrant(config, callbackUrl, {
+        expectedState: state,
+        pkceCodeVerifier: codeVerifier,
+      });
+ 
+      if (debug) {
+        logger.debug('Token exchange succeeded. Expires in:', tokenResult.expires_in);
+      }
+ 
+      return {
+        accessToken: tokenResult.access_token,
+        expiresIn: tokenResult.expires_in,
+        refreshToken: tokenResult.refresh_token,
+        success: true,
+      };
+    } catch (tokenError) {
+      if (debug) {
+        logger.debug('Token exchange failed:', tokenError);
+        if (tokenError instanceof ResponseBodyError) {
+          logger.debug('ResponseBodyError details — status:', (tokenError as any).status);
+          logger.debug('ResponseBodyError details — response:', (tokenError as any).response);
+        }
+      }
+      throw tokenError;
+    }
+  } catch (error) {
+    return {
+      error: error instanceof Error ? error.message : String(error),
+      success: false,
+    };
+  }
+}
+ 
+/**
+ * Start a local HTTP callback server with port fallback.
+ * Returns the bound port.
+ */
+function startCallbackServer(
+  createServerFactory: typeof http.createServer,
+): Promise<{ port: number; server: http.Server }> {
+  return new Promise((resolve, reject) => {
+    // Do not pass a request handler here — the caller will attach it via
+    // server.on('request'). Passing a handler would cause double writes
+    // if the caller also uses server.on('request').
+    const server = createServerFactory();
+ 
+    function attemptListen(port: number) {
+      server.once('error', (error: NodeJS.ErrnoException) => {
+        if (error.code === 'EADDRINUSE' && port === FALLBACK_CALLBACK_PORT) {
+          server.close(() => attemptListen(0));
+        } else {
+          reject(error);
+        }
+      });
+ 
+      server.once('listening', () => {
+        const address = server.address();
+        if (address && typeof address === 'object') {
+          resolve({ port: address.port, server });
+        } else {
+          reject(new Error('Server address is not available'));
+        }
+      });
+ 
+      server.listen(port, '127.0.0.1');
+    }
+ 
+    attemptListen(FALLBACK_CALLBACK_PORT);
+  });
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/oauth/token-refresh.ts.html b/coverage/src/auth/oauth/token-refresh.ts.html new file mode 100644 index 0000000..3b15b51 --- /dev/null +++ b/coverage/src/auth/oauth/token-refresh.ts.html @@ -0,0 +1,463 @@ + + + + + + Code coverage report for src/auth/oauth/token-refresh.ts + + + + + + + + + +
+
+

All files / src/auth/oauth token-refresh.ts

+
+ +
+ 8% + Statements + 4/50 +
+ + +
+ 0% + Branches + 0/35 +
+ + +
+ 0% + Functions + 0/6 +
+ + +
+ 8.69% + Lines + 4/46 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import type { Configuration } from 'openid-client';
+ 
+import { refreshTokenGrant } from 'openid-client';
+import { ResponseBodyError } from 'openid-client';
+ 
+import type { TokenStore } from '../storage/token-store.js';
+import type { TokenData } from '../types.js';
+ 
+import { extractJwtExpiresAt } from '../jwt.js';
+ 
+// Well-known transient network error codes. Retrying these is safe and
+// common, e.g. brief DNS failure, port temporarily unavailable.
+const TRANSIENT_ERROR_CODES = new Set([
+  'EAI_AGAIN',
+  'ECONNREFUSED',
+  'ECONNRESET',
+  'ENETUNREACH',
+  'ENOTFOUND',
+  'ETIMEDOUT',
+]);
+ 
+const MAX_RETRIES = 3;
+const INITIAL_BACKOFF_MS = 200;
+ 
+function isTransientError(error: unknown): boolean {
+  if (!(error instanceof Error)) return false;
+  const code = (error as NodeJS.ErrnoException).code;
+  if (code && TRANSIENT_ERROR_CODES.has(code)) return true;
+  return false;
+}
+ 
+// In-flight refresh promises keyed by config, then by store.
+// This prevents two calls with the SAME config+store from duplicating,
+// while ensuring different stores don't share promises.
+const inFlightByConfig = new WeakMap<Configuration, Map<TokenStore, Promise<boolean>>>();
+ 
+export async function refreshAccessToken(
+  config: Configuration,
+  tokenStore: TokenStore,
+): Promise<boolean> {
+  let storeMap = inFlightByConfig.get(config);
+  if (!storeMap) {
+    storeMap = new Map<TokenStore, Promise<boolean>>();
+    inFlightByConfig.set(config, storeMap);
+  }
+ 
+  const existing = storeMap.get(tokenStore);
+  if (existing) {
+    return existing;
+  }
+ 
+  const promise = doRefresh(config, tokenStore).finally(() => {
+    storeMap!.delete(tokenStore);
+  });
+ 
+  storeMap.set(tokenStore, promise);
+  return promise;
+}
+ 
+/**
+ * Try to refresh the access token with exponential backoff on transient
+ * network failures. Permanent auth errors clear stored tokens; transient
+ * errors are retried up to MAX_RETRIES and never delete tokens.
+ */
+async function doRefresh(config: Configuration, tokenStore: TokenStore): Promise<boolean> {
+  const tokenData = await tokenStore.get();
+  if (!tokenData?.refresh_token) return false;
+ 
+  let attempt = 0;
+ 
+  while (true) {
+    try {
+      const result = await refreshTokenGrant(config, tokenData.refresh_token);
+ 
+      // Extract tokens from response
+      const accessToken = result.access_token;
+      const refreshToken = result.refresh_token || tokenData.refresh_token;
+      const expiresIn = result.expires_in || 3600;
+ 
+      // Calculate expiration from JWT or fallback
+      const jwtExpiresAt = extractJwtExpiresAt(accessToken);
+      const expiresAt = jwtExpiresAt > 0 ? jwtExpiresAt : Date.now() + expiresIn * 1000;
+ 
+      const newTokenData: TokenData = {
+        access_token: accessToken,
+        expires_at: expiresAt,
+        refresh_token: refreshToken,
+      };
+ 
+      await tokenStore.set(newTokenData);
+      return true;
+    } catch (error) {
+      // On invalid/expired refresh token (401/403 from Keycloak), clear tokens.
+      // ResponseBodyError from openid-client carries structured error info.
+      if (error instanceof ResponseBodyError) {
+        if (error.error === 'invalid_grant' || error.status === 401 || error.status === 403) {
+          await tokenStore.clear();
+        }
+        return false;
+      }
+ 
+      if (
+        error instanceof Error &&
+        (error.message.includes('401') ||
+          error.message.includes('403') ||
+          error.message.includes('invalid_grant'))
+      ) {
+        // Fallback for non-standard error shapes (e.g. network-level failures)
+        await tokenStore.clear();
+        return false;
+      }
+ 
+      if (isTransientError(error) && attempt < MAX_RETRIES - 1) {
+        await sleep(INITIAL_BACKOFF_MS * 2 ** attempt);
+        attempt++;
+        continue;
+      }
+ 
+      return false;
+    }
+  }
+}
+ 
+function sleep(ms: number): Promise<void> {
+  return new Promise((resolve) => setTimeout(resolve, ms));
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/storage/index.html b/coverage/src/auth/storage/index.html new file mode 100644 index 0000000..5085700 --- /dev/null +++ b/coverage/src/auth/storage/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for src/auth/storage + + + + + + + + + +
+
+

All files src/auth/storage

+
+ +
+ 0% + Statements + 0/24 +
+ + +
+ 0% + Branches + 0/11 +
+ + +
+ 0% + Functions + 0/5 +
+ + +
+ 0% + Lines + 0/24 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
token-store.ts +
+
0%0/240%0/110%0/50%0/24
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/auth/storage/token-store.ts.html b/coverage/src/auth/storage/token-store.ts.html new file mode 100644 index 0000000..4232d5b --- /dev/null +++ b/coverage/src/auth/storage/token-store.ts.html @@ -0,0 +1,328 @@ + + + + + + Code coverage report for src/auth/storage/token-store.ts + + + + + + + + + +
+
+

All files / src/auth/storage token-store.ts

+
+ +
+ 0% + Statements + 0/24 +
+ + +
+ 0% + Branches + 0/11 +
+ + +
+ 0% + Functions + 0/5 +
+ + +
+ 0% + Lines + 0/24 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as fs from 'node:fs/promises';
+import * as os from 'node:os';
+import * as path from 'node:path';
+ 
+import type { TokenData } from '../types.js';
+ 
+import { logger } from '../../utils/logger.js';
+ 
+export interface TokenStore {
+  clear(): Promise<void>;
+  get(): Promise<null | TokenData>;
+  set(data: TokenData): Promise<void>;
+}
+ 
+export class FileTokenStore implements TokenStore {
+  private tokenFilePath: string;
+ 
+  constructor(filePath?: string) {
+    this.tokenFilePath = filePath || getDefaultTokenFilePath();
+  }
+ 
+  async clear(): Promise<void> {
+    try {
+      await fs.unlink(this.tokenFilePath);
+    } catch {
+      // ignore if file doesn't exist
+    }
+  }
+ 
+  async get(): Promise<null | TokenData> {
+    let data: string | undefined;
+    try {
+      data = await fs.readFile(this.tokenFilePath, 'utf8');
+    } catch (error) {
+      const code = (error as NodeJS.ErrnoException).code;
+      if (code === 'ENOENT') {
+        return null; // Not logged in — expected
+      }
+      logger.warn(
+        `Could not read auth file (${code || 'unknown error'}). Run \`berget auth login\` to re-authenticate.`,
+        String(error),
+      );
+      return null;
+    }
+ 
+    try {
+      const parsed = JSON.parse(data) as TokenData;
+      // Validate shape
+      if (
+        typeof parsed.access_token === 'string' &&
+        typeof parsed.refresh_token === 'string' &&
+        typeof parsed.expires_at === 'number'
+      ) {
+        return parsed;
+      }
+      return null;
+    } catch (error) {
+      logger.warn(
+        `Auth file appears corrupted. Run \`berget auth login\` to re-authenticate.`,
+        String(error),
+      );
+      return null;
+    }
+  }
+ 
+  async set(data: TokenData): Promise<void> {
+    const bergetDir = path.dirname(this.tokenFilePath);
+    try {
+      await fs.mkdir(bergetDir, { recursive: true });
+    } catch {
+      // ignore
+    }
+    await fs.writeFile(this.tokenFilePath, JSON.stringify(data, null, 2));
+    await fs.chmod(this.tokenFilePath, 0o600);
+  }
+}
+ 
+function getDefaultTokenFilePath(): string {
+  const bergetDir = path.join(os.homedir(), '.berget');
+  return path.join(bergetDir, 'auth.json');
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/client.ts.html b/coverage/src/client.ts.html new file mode 100644 index 0000000..0b94f5d --- /dev/null +++ b/coverage/src/client.ts.html @@ -0,0 +1,208 @@ + + + + + + Code coverage report for src/client.ts + + + + + + + + + +
+
+

All files / src client.ts

+
+ +
+ 0% + Statements + 0/11 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 0% + Lines + 0/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import createClient from 'openapi-fetch';
+ 
+import type { paths } from './types/api.js';
+ 
+import { getAuthConfig } from './auth/config.js';
+import { getConfiguration } from './auth/issuer.js';
+import { authMiddleware } from './auth/middleware/auth-middleware.js';
+import { refreshAccessToken } from './auth/oauth/token-refresh.js';
+import { FileTokenStore } from './auth/storage/token-store.js';
+ 
+export function createAuthenticatedClient(options?: { local?: boolean; stage?: boolean }) {
+  const config = getAuthConfig(options);
+  const client = createClient<paths>({
+    baseUrl: config.apiBaseUrl,
+    headers: {
+      Accept: 'application/json',
+      'Content-Type': 'application/json',
+    },
+  });
+ 
+  const tokenStore = new FileTokenStore();
+ 
+  client.use(
+    authMiddleware({
+      getToken: async () => {
+        const data = await tokenStore.get();
+        return data?.access_token || null;
+      },
+      refresh: async () => {
+        try {
+          const configuration = await getConfiguration(config);
+          return await refreshAccessToken(configuration, tokenStore);
+        } catch {
+          return false;
+        }
+      },
+    }),
+  );
+ 
+  return client;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-api-key-service.ts.html b/coverage/src/commands/code/__tests__/fake-api-key-service.ts.html new file mode 100644 index 0000000..1b653f7 --- /dev/null +++ b/coverage/src/commands/code/__tests__/fake-api-key-service.ts.html @@ -0,0 +1,145 @@ + + + + + + Code coverage report for src/commands/code/__tests__/fake-api-key-service.ts + + + + + + + + + +
+
+

All files / src/commands/code/__tests__ fake-api-key-service.ts

+
+ +
+ 83.33% + Statements + 5/6 +
+ + +
+ 75% + Branches + 3/4 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 83.33% + Lines + 5/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21  +  +  +  +  +  +  +  +46x +46x +46x +  +  +  +1x +  +  +1x +  +  + 
import type { ApiKeyServicePort } from '../ports/auth-services.js';
+ 
+export class FakeApiKeyService implements ApiKeyServicePort {
+  private readonly _errorMessage: string;
+  private readonly _key: string;
+  private readonly _shouldFail: boolean;
+ 
+  constructor(key: string, shouldFail = false, errorMessage = 'API key creation failed') {
+    this._key = key;
+    this._shouldFail = shouldFail;
+    this._errorMessage = errorMessage;
+  }
+ 
+  async create(_options: { description?: string; name: string }): Promise<{ key: string }> {
+    Iif (this._shouldFail) {
+      throw new Error(this._errorMessage);
+    }
+    return { key: this._key };
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-auth-service.ts.html b/coverage/src/commands/code/__tests__/fake-auth-service.ts.html new file mode 100644 index 0000000..9cb1bee --- /dev/null +++ b/coverage/src/commands/code/__tests__/fake-auth-service.ts.html @@ -0,0 +1,241 @@ + + + + + + Code coverage report for src/commands/code/__tests__/fake-auth-service.ts + + + + + + + + + +
+
+

All files / src/commands/code/__tests__ fake-auth-service.ts

+
+ +
+ 88.23% + Statements + 15/17 +
+ + +
+ 75% + Branches + 6/8 +
+ + +
+ 80% + Functions + 4/5 +
+ + +
+ 88.23% + Lines + 15/17 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53  +  +  +46x +46x +  +  +46x +46x +46x +  +  +  +  +  +  +  +  +  +  +44x +44x +43x +  +  +1x +  +1x +  +  +  +  +  +  +44x +  +  +  +  +  +  +  +  +  +2x +  +  +  +1x +1x +1x +  + 
import type { AuthServicePort } from '../ports/auth-services.js';
+ 
+export class FakeAuthService implements AuthServicePort {
+  loginCallCount = 0;
+  loginInteractiveCallCount = 0;
+ 
+  constructor(
+    private readonly _shouldSucceed: boolean,
+    private readonly _hasSeat: boolean = true,
+    private readonly _validToken: boolean = true,
+  ) {}
+ 
+  async login(): Promise<boolean> {
+    this.loginCallCount++;
+    return this._shouldSucceed;
+  }
+ 
+  loginInteractive(_options?: {
+    debug?: boolean;
+  }): ReturnType<AuthServicePort['loginInteractive']> {
+    this.loginInteractiveCallCount++;
+    if (!this._shouldSucceed) {
+      return Promise.resolve({ error: 'Login failed', success: false });
+    }
+ 
+    const farFuture = Math.floor(Date.now() / 1000) + 3600 * 24 * 365; // 1 year from now in seconds
+ 
+    const accessToken = this._validToken
+      ? makeJwt({
+          exp: farFuture,
+          realm_access: { roles: this._hasSeat ? ['berget_code_seat'] : ['default-roles-berget'] },
+        })
+      : 'invalid.token.here';
+ 
+    return Promise.resolve({
+      accessToken,
+      expiresIn: 3600,
+      refreshToken: 'refresh',
+      success: true,
+    });
+  }
+}
+ 
+function base64urlEncode(data: string): string {
+  return Buffer.from(data).toString('base64url');
+}
+ 
+function makeJwt(payload: Record<string, unknown>): string {
+  const header = base64urlEncode(JSON.stringify({ alg: 'none', typ: 'JWT' }));
+  const body = base64urlEncode(JSON.stringify(payload));
+  return `${header}.${body}.signature`;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-command-runner.ts.html b/coverage/src/commands/code/__tests__/fake-command-runner.ts.html new file mode 100644 index 0000000..548d376 --- /dev/null +++ b/coverage/src/commands/code/__tests__/fake-command-runner.ts.html @@ -0,0 +1,235 @@ + + + + + + Code coverage report for src/commands/code/__tests__/fake-command-runner.ts + + + + + + + + + +
+
+

All files / src/commands/code/__tests__ fake-command-runner.ts

+
+ +
+ 90.47% + Statements + 19/21 +
+ + +
+ 70% + Branches + 7/10 +
+ + +
+ 100% + Functions + 7/7 +
+ + +
+ 93.75% + Lines + 15/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51  +  +  +  +  +  +  +  +  +3x +  +36x +  +36x +  +  +34x +34x +  +  +  +61x +  +53x +53x +  +  +  +  +61x +  +  +  +  +  +  +  +12x +24x +12x +  +  +12x +  +  +  +12x +10x +  +  + 
import type { CommandRunner } from '../ports/command-runner.js';
+ 
+type Handler = {
+  match: (command: string, arguments_: readonly string[]) => boolean;
+  response: ((command: string, arguments_: readonly string[]) => Error | string) | Error | string;
+};
+ 
+export class FakeCommandRunner implements CommandRunner {
+  get calls() {
+    return this._calls;
+  }
+  private _calls: Array<{ args: string[]; command: string; options?: { cwd?: string } }> = [];
+ 
+  private handlers: Handler[] = [];
+ 
+  checkInstalled(binary: string): Promise<boolean> {
+    this._calls.push({ args: [], command: `check:${binary}` });
+    return Promise.resolve(this.handlers.some((h) => h.match(binary, ['--version'])) || false);
+  }
+ 
+  handle(match: RegExp | string, response: Error | string): this {
+    this.handlers.push({
+      match: (cmd, arguments_) => {
+        const full = `${cmd} ${arguments_.join(' ')}`;
+        Eif (typeof match === 'string') return full.startsWith(match);
+        return match.test(full);
+      },
+      response,
+    });
+    return this;
+  }
+ 
+  async run(
+    command: string,
+    arguments_: readonly string[],
+    options?: { cwd?: string },
+  ): Promise<string> {
+    this._calls.push({ args: [...arguments_], command, options });
+    const handler = this.handlers.find((h) => h.match(command, arguments_));
+    Iif (!handler) throw new Error(`Unexpected command: ${command} ${arguments_.join(' ')}`);
+ 
+    const result =
+      typeof handler.response === 'function'
+        ? handler.response(command, arguments_)
+        : handler.response;
+ 
+    if (result instanceof Error) throw result;
+    return result;
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-file-store.ts.html b/coverage/src/commands/code/__tests__/fake-file-store.ts.html new file mode 100644 index 0000000..c3d925b --- /dev/null +++ b/coverage/src/commands/code/__tests__/fake-file-store.ts.html @@ -0,0 +1,217 @@ + + + + + + Code coverage report for src/commands/code/__tests__/fake-file-store.ts + + + + + + + + + +
+
+

All files / src/commands/code/__tests__ fake-file-store.ts

+
+ +
+ 90.9% + Statements + 10/11 +
+ + +
+ 100% + Branches + 4/4 +
+ + +
+ 87.5% + Functions + 7/8 +
+ + +
+ 90.9% + Lines + 10/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45  +  +  +  +  +  +  +  +45x +45x +45x +  +  +3x +  +  +  +145x +  +  +  +  +  +  +  +24x +  +  +  +12x +  +  +  +390x +  +  +  +8x +  +  +  +44x +  +  + 
import type { FileStore } from '../ports/file-store.js';
+ 
+export interface FileEntry {
+  content: string;
+  isDirectory?: boolean;
+}
+ 
+export class FakeFileStore implements FileStore {
+  private _chmodCalls: Array<{ mode: number; path: string }> = [];
+  private dirs: Set<string> = new Set();
+  private files: Map<string, string> = new Map();
+ 
+  async chmod(path: string, mode: number): Promise<void> {
+    this._chmodCalls.push({ mode, path });
+  }
+ 
+  async exists(path: string): Promise<boolean> {
+    return this.files.has(path) || this.dirs.has(path);
+  }
+ 
+  getChmodCalls(): Array<{ mode: number; path: string }> {
+    return this._chmodCalls;
+  }
+ 
+  getWrittenFiles(): Map<string, string> {
+    return new Map(this.files);
+  }
+ 
+  async mkdir(path: string): Promise<void> {
+    this.dirs.add(path);
+  }
+ 
+  async readFile(path: string): Promise<null | string> {
+    return this.files.get(path) ?? null;
+  }
+ 
+  seed(path: string, content: string): void {
+    this.files.set(path, content);
+  }
+ 
+  async writeFile(path: string, content: string): Promise<void> {
+    this.files.set(path, content);
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-prompter.ts.html b/coverage/src/commands/code/__tests__/fake-prompter.ts.html new file mode 100644 index 0000000..5323dfa --- /dev/null +++ b/coverage/src/commands/code/__tests__/fake-prompter.ts.html @@ -0,0 +1,502 @@ + + + + + + Code coverage report for src/commands/code/__tests__/fake-prompter.ts + + + + + + + + + +
+
+

All files / src/commands/code/__tests__ fake-prompter.ts

+
+ +
+ 56.94% + Statements + 41/72 +
+ + +
+ 44.44% + Branches + 24/54 +
+ + +
+ 68.18% + Functions + 15/22 +
+ + +
+ 60.65% + Lines + 37/61 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140  +  +  +  +1x +  +  +  +  +  +  +  +105x +  +  +  +  +  +1x +  +  +  +  +  +42x +  +  +  +  +  +18x +  +  +  +  +  +  +  +5x +  +46x +  +46x +  +46x +  +  +  +  +  +  +  +  +  +42x +42x +42x +  +42x +  +42x +  +42x +42x +  +  +46x +  +  +  +36x +  +  +  +18x +18x +18x +  +18x +  +18x +  +18x +18x +  +  +  +238x +  +  +  +31x +  +  +  +105x +105x +105x +105x +  +105x +  +105x +103x +  +  +  +87x +  +87x +  +  +87x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import type { Prompter, Spinner, TaskItem } from '../ports/prompter.js';
+ 
+import { CancelledError } from '../errors.js';
+ 
+export const CANCEL = Symbol('cancel');
+ 
+type PromptEntry =
+  | { kind: 'confirm'; match?: RegExp; response: boolean | symbol }
+  | { kind: 'multiselect'; match?: RegExp; response: (string | symbol)[] }
+  | { kind: 'select'; match?: RegExp; response: string | symbol }
+  | { kind: 'text'; match?: RegExp; response: string | symbol };
+ 
+export const select = <T>(value: symbol | T, match?: RegExp | string): PromptEntry => ({
+  kind: 'select',
+  match: typeof match === 'string' ? new RegExp(match) : match,
+  response: typeof value === 'symbol' ? value : String(value),
+});
+ 
+export const text = (value: string | symbol, match?: RegExp | string): PromptEntry => ({
+  kind: 'text',
+  match: typeof match === 'string' ? new RegExp(match) : match,
+  response: value,
+});
+ 
+export const confirm = (value: boolean | symbol, match?: RegExp | string): PromptEntry => ({
+  kind: 'confirm',
+  match: typeof match === 'string' ? new RegExp(match) : match,
+  response: value,
+});
+ 
+export const multiselect = <T>(values: symbol | T[], match?: RegExp | string): PromptEntry => ({
+  kind: 'multiselect',
+  match: typeof match === 'string' ? new RegExp(match) : match,
+  response: values === CANCEL ? [CANCEL] : ((values as T[]).map(String) as (string | symbol)[]),
+});
+ 
+export class FakePrompter implements Prompter {
+  get calls() {
+    return this._calls;
+  }
+  private _calls: Array<{ args: unknown; method: string }> = [];
+ 
+  private _cursor = 0;
+ 
+  constructor(private readonly _script: PromptEntry[]) {}
+  assertExhausted() {
+    if (this._cursor !== this._script.length) {
+      throw new Error(`Script not exhausted: ${this._script.length - this._cursor} entries left`);
+    }
+  }
+  cancel(message: string): void {
+    this._calls.push({ args: { message }, method: 'cancel' });
+  }
+  async confirm(options: { message: string }): Promise<boolean> {
+    this._calls.push({ args: options, method: 'confirm' });
+    const entry = this._script[this._cursor++];
+    Iif (!entry)
+      throw new Error(`No script entry for confirm #${this._cursor} (${options.message})`);
+    Iif (entry.kind !== 'confirm')
+      throw new Error(`Expected confirm, got ${entry.kind} for ${options.message}`);
+    Iif (entry.match && !entry.match.test(options.message))
+      throw new Error(`Message mismatch: got "${options.message}"`);
+    Iif (entry.response === CANCEL) throw new CancelledError();
+    return entry.response as boolean;
+  }
+  intro(message: string): void {
+    this._calls.push({ args: { message }, method: 'intro' });
+  }
+ 
+  log(type: string, message: string): void {
+    this._calls.push({ args: { message, type }, method: 'log' });
+  }
+ 
+  async multiselect<T>(options: { message: string }): Promise<T[]> {
+    this._calls.push({ args: options, method: 'multiselect' });
+    const entry = this._script[this._cursor++];
+    Iif (!entry)
+      throw new Error(`No script entry for multiselect #${this._cursor} (${options.message})`);
+    Iif (entry.kind !== 'multiselect')
+      throw new Error(`Expected multiselect, got ${entry.kind} for ${options.message}`);
+    Iif (entry.match && !entry.match.test(options.message))
+      throw new Error(`Message mismatch: got "${options.message}"`);
+    Iif (entry.response.includes(CANCEL)) throw new CancelledError();
+    return entry.response as T[];
+  }
+ 
+  note(message: string, title?: string): void {
+    this._calls.push({ args: { message, title }, method: 'note' });
+  }
+ 
+  outro(message: string): void {
+    this._calls.push({ args: { message }, method: 'outro' });
+  }
+ 
+  async select<T>(options: { initialValue?: T; message: string }): Promise<T> {
+    this._calls.push({ args: options, method: 'select' });
+    const entry = this._script[this._cursor++];
+    Iif (!entry) throw new Error(`No script entry for select #${this._cursor} (${options.message})`);
+    Iif (entry.kind !== 'select')
+      throw new Error(`Expected select, got ${entry.kind} for ${options.message}`);
+    Iif (entry.match && !entry.match.test(options.message))
+      throw new Error(`Message mismatch: got "${options.message}"`);
+    if (entry.response === CANCEL) throw new CancelledError();
+    return entry.response as T;
+  }
+ 
+  spinner(): Spinner {
+    return {
+      start: (message: string) => {
+        this._calls.push({ args: { message: message }, method: 'spinner.start' });
+      },
+      stop: (message: string) => {
+        this._calls.push({ args: { message: message }, method: 'spinner.stop' });
+      },
+    };
+  }
+ 
+  async tasks(items: ReadonlyArray<TaskItem>): Promise<void> {
+    this._calls.push({ args: { items: items.map((i) => i.title) }, method: 'tasks' });
+    for (const item of items) {
+      const noop = (_msg: string) => {
+        // no-op in tests
+      };
+      await item.task(noop);
+    }
+  }
+ 
+  async text(options: { message: string }): Promise<string> {
+    this._calls.push({ args: options, method: 'text' });
+    const entry = this._script[this._cursor++];
+    if (!entry) throw new Error(`No script entry for text #${this._cursor} (${options.message})`);
+    if (entry.kind !== 'text')
+      throw new Error(`Expected text, got ${entry.kind} for ${options.message}`);
+    if (entry.match && !entry.match.test(options.message))
+      throw new Error(`Message mismatch: got "${options.message}"`);
+    if (entry.response === CANCEL) throw new CancelledError();
+    return entry.response as string;
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/index.html b/coverage/src/commands/code/__tests__/index.html new file mode 100644 index 0000000..f655719 --- /dev/null +++ b/coverage/src/commands/code/__tests__/index.html @@ -0,0 +1,176 @@ + + + + + + Code coverage report for src/commands/code/__tests__ + + + + + + + + + +
+
+

All files src/commands/code/__tests__

+
+ +
+ 70.86% + Statements + 90/127 +
+ + +
+ 55% + Branches + 44/80 +
+ + +
+ 79.54% + Functions + 35/44 +
+ + +
+ 73.87% + Lines + 82/111 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
fake-api-key-service.ts +
+
83.33%5/675%3/4100%2/283.33%5/6
fake-auth-service.ts +
+
88.23%15/1775%6/880%4/588.23%15/17
fake-command-runner.ts +
+
90.47%19/2170%7/10100%7/793.75%15/16
fake-file-store.ts +
+
90.9%10/11100%4/487.5%7/890.9%10/11
fake-prompter.ts +
+
56.94%41/7244.44%24/5468.18%15/2260.65%37/61
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/adapters/clack-prompter.ts.html b/coverage/src/commands/code/adapters/clack-prompter.ts.html new file mode 100644 index 0000000..a5d97cd --- /dev/null +++ b/coverage/src/commands/code/adapters/clack-prompter.ts.html @@ -0,0 +1,316 @@ + + + + + + Code coverage report for src/commands/code/adapters/clack-prompter.ts + + + + + + + + + +
+
+

All files / src/commands/code/adapters clack-prompter.ts

+
+ +
+ 4.76% + Statements + 1/21 +
+ + +
+ 0% + Branches + 0/4 +
+ + +
+ 0% + Functions + 0/16 +
+ + +
+ 5% + Lines + 1/20 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as p from '@clack/prompts';
+ 
+import type { Prompter, Spinner, TaskItem } from '../ports/prompter.js';
+ 
+import { CancelledError } from '../errors.js';
+ 
+const unwrap = <T>(v: symbol | T): T => {
+  if (p.isCancel(v)) throw new CancelledError();
+  return v as T;
+};
+ 
+export class ClackPrompter implements Prompter {
+  cancel(message: string): void {
+    p.cancel(message);
+  }
+  async confirm(options: { initialValue?: boolean; message: string }): Promise<boolean> {
+    return unwrap(await p.confirm(options));
+  }
+  intro(message: string): void {
+    p.intro(message);
+  }
+  log(type: 'error' | 'info' | 'message' | 'step' | 'success' | 'warn', message: string): void {
+    p.log[type](message);
+  }
+  async multiselect<T>(options: {
+    message: string;
+    options: ReadonlyArray<{
+      hint?: string;
+      label: string;
+      value: T;
+    }>;
+  }): Promise<T[]> {
+    return unwrap(await p.multiselect(options as any));
+  }
+  note(message: string, title?: string): void {
+    p.note(message, title);
+  }
+  outro(message: string): void {
+    p.outro(message);
+  }
+ 
+  async select<T>(options: {
+    initialValue?: T;
+    message: string;
+    options: ReadonlyArray<{
+      hint?: string;
+      label: string;
+      value: T;
+    }>;
+  }): Promise<T> {
+    return unwrap(await p.select(options as any));
+  }
+ 
+  spinner(): Spinner {
+    const s = p.spinner();
+    return {
+      start: (message: string) => s.start(message),
+      stop: (message: string) => s.stop(message),
+    };
+  }
+ 
+  async tasks(items: ReadonlyArray<TaskItem>): Promise<void> {
+    await p.tasks(
+      items.map((item) => ({
+        task: async (message: (msg: string) => void) => {
+          const result = await item.task(message);
+          return result ?? item.title;
+        },
+        title: item.title,
+      })),
+    );
+  }
+ 
+  async text(options: { message: string; placeholder?: string }): Promise<string> {
+    return unwrap(await p.text(options));
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/adapters/fs-file-store.ts.html b/coverage/src/commands/code/adapters/fs-file-store.ts.html new file mode 100644 index 0000000..2b5eb30 --- /dev/null +++ b/coverage/src/commands/code/adapters/fs-file-store.ts.html @@ -0,0 +1,199 @@ + + + + + + Code coverage report for src/commands/code/adapters/fs-file-store.ts + + + + + + + + + +
+
+

All files / src/commands/code/adapters fs-file-store.ts

+
+ +
+ 0% + Statements + 0/14 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/5 +
+ + +
+ 0% + Lines + 0/13 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { promises as fs } from 'node:fs';
+import * as path from 'node:path';
+ 
+import type { FileStore } from '../ports/file-store.js';
+ 
+export class FsFileStore implements FileStore {
+  async chmod(filePath: string, mode: number): Promise<void> {
+    await fs.chmod(filePath, mode);
+  }
+ 
+  async exists(filePath: string): Promise<boolean> {
+    try {
+      await fs.access(filePath);
+      return true;
+    } catch {
+      return false;
+    }
+  }
+ 
+  async mkdir(dir: string): Promise<void> {
+    await fs.mkdir(dir, { recursive: true });
+  }
+ 
+  async readFile(filePath: string): Promise<null | string> {
+    try {
+      return await fs.readFile(filePath, 'utf8');
+    } catch (error: any) {
+      if (error.code === 'ENOENT') return null;
+      throw error;
+    }
+  }
+ 
+  async writeFile(filePath: string, content: string): Promise<void> {
+    const dir = path.dirname(filePath);
+    await fs.mkdir(dir, { recursive: true });
+    await fs.writeFile(filePath, content, 'utf8');
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/adapters/index.html b/coverage/src/commands/code/adapters/index.html new file mode 100644 index 0000000..04f712b --- /dev/null +++ b/coverage/src/commands/code/adapters/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for src/commands/code/adapters + + + + + + + + + +
+
+

All files src/commands/code/adapters

+
+ +
+ 1.81% + Statements + 1/55 +
+ + +
+ 0% + Branches + 0/12 +
+ + +
+ 0% + Functions + 0/31 +
+ + +
+ 2% + Lines + 1/50 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
clack-prompter.ts +
+
4.76%1/210%0/40%0/165%1/20
fs-file-store.ts +
+
0%0/140%0/20%0/50%0/13
spawn-command-runner.ts +
+
0%0/200%0/60%0/100%0/17
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/adapters/spawn-command-runner.ts.html b/coverage/src/commands/code/adapters/spawn-command-runner.ts.html new file mode 100644 index 0000000..d40d221 --- /dev/null +++ b/coverage/src/commands/code/adapters/spawn-command-runner.ts.html @@ -0,0 +1,220 @@ + + + + + + Code coverage report for src/commands/code/adapters/spawn-command-runner.ts + + + + + + + + + +
+
+

All files / src/commands/code/adapters spawn-command-runner.ts

+
+ +
+ 0% + Statements + 0/20 +
+ + +
+ 0% + Branches + 0/6 +
+ + +
+ 0% + Functions + 0/10 +
+ + +
+ 0% + Lines + 0/17 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { spawn } from 'node:child_process';
+ 
+import type { CommandRunner } from '../ports/command-runner.js';
+ 
+export class SpawnCommandRunner implements CommandRunner {
+  async checkInstalled(binary: string): Promise<boolean> {
+    return new Promise((resolve) => {
+      const child = spawn('which', [binary], { stdio: 'pipe' });
+      child.on('close', (code) => resolve(code === 0));
+      child.on('error', () => resolve(false));
+    });
+  }
+ 
+  async run(
+    command: string,
+    arguments_: readonly string[],
+    options?: { cwd?: string },
+  ): Promise<string> {
+    return new Promise<string>((resolve, reject) => {
+      const child = spawn(command, arguments_ as string[], {
+        cwd: options?.cwd || process.cwd(),
+        stdio: 'pipe',
+      });
+ 
+      let stdout = '';
+      let stderr = '';
+ 
+      child.stdout?.on('data', (d) => {
+        stdout += d.toString();
+      });
+      child.stderr?.on('data', (d) => {
+        stderr += d.toString();
+      });
+ 
+      child.on('close', (code) => {
+        if (code === 0) {
+          resolve(stdout);
+        } else {
+          reject(new Error(stderr.trim() || `Command failed with exit code ${code}`));
+        }
+      });
+      child.on('error', (error) => reject(error));
+    });
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/auth-sync.ts.html b/coverage/src/commands/code/auth-sync.ts.html new file mode 100644 index 0000000..0f9686a --- /dev/null +++ b/coverage/src/commands/code/auth-sync.ts.html @@ -0,0 +1,1066 @@ + + + + + + Code coverage report for src/commands/code/auth-sync.ts + + + + + + + + + +
+
+

All files / src/commands/code auth-sync.ts

+
+ +
+ 68.59% + Statements + 83/121 +
+ + +
+ 65.38% + Branches + 34/52 +
+ + +
+ 100% + Functions + 9/9 +
+ + +
+ 67.79% + Lines + 80/118 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +46x +  +1x +24x +15x +  +  +1x +  +  +  +  +  +  +  +  +  +36x +  +36x +  +36x +1x +  +  +  +  +  +  +  +1x +1x +  +  +35x +3x +  +  +35x +32x +  +  +  +3x +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +3x +  +2x +  +  +  +  +  +  +  +2x +2x +2x +2x +2x +2x +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +1x +1x +1x +1x +1x +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +46x +  +46x +  +46x +2x +  +  +44x +  +44x +44x +  +44x +  +  +44x +43x +43x +  +  +  +43x +  +  +1x +  +1x +1x +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +36x +36x +1x +1x +1x +  +  +  +  +  +  +46x +46x +  +2x +2x +  +  +  +  +  +  +  +2x +  +2x +2x +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +  +1x +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +2x +2x +  +2x +2x +  +  +  +  +  +  +  +  +2x +  +2x +  +  +  +  +  +  +  +  +  +2x +2x +  + 
import type { ApiKeyServicePort, AuthServicePort } from './ports/auth-services.js';
+import type { FileStore } from './ports/file-store.js';
+import type { Prompter } from './ports/prompter.js';
+ 
+import {
+  decodeJwtPayload,
+  extractJwtExpiresAt,
+  hasBergetCodeSeat,
+  isTokenExpired,
+} from '../../auth/jwt.js';
+import { logger } from '../../utils/logger.js';
+import { FatalError } from './errors.js';
+ 
+export interface AuthDeps {
+  apiKeyService: ApiKeyServicePort;
+  authService: AuthServicePort;
+  files: FileStore;
+  homeDir: string;
+  prompter: Prompter;
+}
+ 
+export interface AuthResult {
+  authenticated: boolean;
+}
+ 
+export interface CliAuth {
+  access_token: string;
+  expires_at: number;
+  refresh_token: string;
+}
+ 
+const CLI_AUTH_PATH = (homeDir: string) => homeDir + '/.berget/auth.json';
+ 
+const TOOL_AUTH_PATHS = {
+  opencode: (homeDir: string) => homeDir + '/.local/share/opencode/auth.json',
+  pi: (homeDir: string) => homeDir + '/.pi/agent/auth.json',
+} as const;
+ 
+const TOOL_API_KEY_TYPES: Record<'opencode' | 'pi', string> = {
+  opencode: 'api',
+  pi: 'api_key',
+};
+ 
+export async function configureAuth(
+  deps: Pick<AuthDeps, 'apiKeyService' | 'files' | 'homeDir' | 'prompter'>,
+  tool: 'opencode' | 'pi',
+  cliAuth: CliAuth | null,
+): Promise<AuthResult> {
+  const { apiKeyService, files, homeDir, prompter } = deps;
+ 
+  const alreadyAuth = await isToolAuthenticated(files, homeDir, tool);
+ 
+  if (alreadyAuth) {
+    const choice = await prompter.select<'keep' | 'reconfigure'>({
+      message: `Account is already connected to Berget AI (${tool === 'opencode' ? 'OpenCode' : 'Pi'}). How do you want to proceed?`,
+      options: [
+        { label: 'Keep existing authentication', value: 'keep' },
+        { label: 'Reconfigure — choose a different method', value: 'reconfigure' },
+      ],
+    });
+ 
+    Eif (choice === 'keep') {
+      return { authenticated: true };
+    }
+    // Fall through to reconfigure
+  } else if (cliAuth !== null) {
+    prompter.note('Authentication required to use Berget AI.', 'Connect your account');
+  }
+ 
+  if (cliAuth === null) {
+    return { authenticated: false };
+  }
+ 
+  // Check Berget Code seat
+  const jwtPayload = decodeJwtPayload(cliAuth.access_token);
+ 
+  // If we can't decode the JWT, sync OAuth anyway — the tokens are valid even if
+  // we can't verify the subscription role. Let the tool handle authorization.
+  Iif (!jwtPayload) {
+    const s = prompter.spinner();
+    s.start('Authenticating with Berget AI...');
+    try {
+      await syncOAuthToTool(files, homeDir, tool, cliAuth);
+      s.stop('Authenticated.');
+    } catch (error) {
+      s.stop('Authentication failed.');
+      throw error;
+    }
+    prompter.note(
+      'Warning: Could not verify Berget Code subscription status.\nIf you do not have a subscription, the tool may show an authorization error.',
+      'Authentication',
+    );
+    return { authenticated: true };
+  }
+ 
+  // JWT decoded successfully — check subscription seat
+  const hasSeat = hasBergetCodeSeat(cliAuth.access_token);
+ 
+  if (hasSeat) {
+    // Case B: Has seat — ask how to authenticate
+    const method = await prompter.select<'api_key' | 'subscription'>({
+      message: 'You have a Berget Code subscription. How do you want to authenticate?',
+      options: [
+        { label: 'Use my Berget Code subscription', value: 'subscription' },
+        { label: 'Use an API key instead', value: 'api_key' },
+      ],
+    });
+ 
+    Eif (method === 'subscription') {
+      const s = prompter.spinner();
+      s.start('Authenticating with Berget AI via subscription...');
+      try {
+        await syncOAuthToTool(files, homeDir, tool, cliAuth);
+        s.stop('Authenticated.');
+      } catch (error) {
+        s.stop('Authentication failed.');
+        throw error;
+      }
+      return { authenticated: true };
+    }
+ 
+    // Create API key instead
+    const s = prompter.spinner();
+    s.start('Creating API key...');
+    try {
+      const { key } = await apiKeyService.create({
+        description: 'Created by berget code init',
+        name: `${tool === 'opencode' ? 'OpenCode' : 'Pi'} (created by berget CLI)`,
+      });
+      await syncApiKeyToTool(files, homeDir, tool, key);
+      s.stop('API key created and saved.');
+      return { authenticated: true };
+    } catch (error: any) {
+      s.stop('API key creation failed.');
+      throw new FatalError(
+        error?.message ||
+          'Could not create API key. Please create one manually with `berget api-keys create`.',
+      );
+    }
+  }
+ 
+  // No Berget Code seat — prompt for API key creation
+  const shouldCreate = await prompter.confirm({
+    initialValue: true,
+    message: 'You do not have a Berget Code subscription. Would you like to create a new API key?',
+  });
+ 
+  Eif (shouldCreate) {
+    const s = prompter.spinner();
+    s.start('Creating API key...');
+    try {
+      const { key } = await apiKeyService.create({
+        description: 'Created by berget code init',
+        name: `${tool === 'opencode' ? 'OpenCode' : 'Pi'} (created by berget CLI)`,
+      });
+      await syncApiKeyToTool(files, homeDir, tool, key);
+      s.stop('API key created and saved.');
+      return { authenticated: true };
+    } catch (error: any) {
+      s.stop('API key creation failed.');
+      throw new FatalError(
+        error?.message ||
+          'Could not create API key. Please create one manually with `berget api-keys create`.',
+      );
+    }
+  }
+ 
+  // Case D: Declined
+  prompter.note(
+    'Authentication skipped. You\'ll need to set up authentication manually:\n1. Run: berget api-keys create --name "My Key"\n2. Set BERGET_API_KEY environment variable, or\n3. Run `berget auth login` and try again',
+    'Authentication',
+  );
+  return { authenticated: false };
+}
+ 
+export async function ensureCliAuth(
+  deps: Pick<AuthDeps, 'authService' | 'files' | 'homeDir' | 'prompter'>,
+): Promise<CliAuth | null> {
+  const { authService, files, homeDir, prompter } = deps;
+ 
+  const cliAuth: CliAuth | null = await readCliAuth(files, homeDir);
+ 
+  if (cliAuth && !isTokenExpired(cliAuth.expires_at)) {
+    return cliAuth;
+  }
+ 
+  prompter.note('Authentication required to use Berget AI.', 'Connect your account');
+ 
+  const s = prompter.spinner();
+  s.start('Waiting for browser login...');
+ 
+  const loginResult = await authService.loginInteractive({
+    debug: process.env.LOG_LEVEL === 'debug',
+  });
+  if (!loginResult.success) {
+    s.stop('Login failed.');
+    prompter.note(
+      `${loginResult.error || 'Login timed out or was cancelled.'}\n\nPlease run \`berget auth login\` manually, then run \`berget code init\` again.`,
+      'Authentication Failed',
+    );
+    return null;
+  }
+ 
+  s.stop('Successfully logged in to Berget.');
+ 
+  const jwtExpiresAt = extractJwtExpiresAt(loginResult.accessToken!);
+  Iif (jwtExpiresAt === 0) {
+    s.stop('Login succeeded but received invalid token.');
+    prompter.note('Please try logging in again or contact support.', 'Authentication Error');
+    return null;
+  }
+ 
+  return {
+    access_token: loginResult.accessToken!,
+    expires_at: jwtExpiresAt,
+    refresh_token: loginResult.refreshToken!,
+  };
+}
+ 
+export async function isToolAuthenticated(
+  files: FileStore,
+  homeDir: string,
+  tool: 'opencode' | 'pi',
+): Promise<boolean> {
+  const content = await files.readFile(TOOL_AUTH_PATHS[tool](homeDir));
+  if (!content) return false;
+  try {
+    const parsed = JSON.parse(content);
+    return typeof parsed.berget === 'object' && parsed.berget !== null;
+  } catch {
+    return false;
+  }
+}
+ 
+export async function readCliAuth(files: FileStore, homeDir: string): Promise<CliAuth | null> {
+  const content = await files.readFile(CLI_AUTH_PATH(homeDir));
+  if (!content) return null;
+  let parsed: any;
+  try {
+    parsed = JSON.parse(content);
+  } catch (error) {
+    logger.warn(
+      `CLI auth file appears corrupted. Run \`berget auth login\` to re-authenticate.`,
+      String(error),
+    );
+    return null;
+  }
+  Eif (parsed.access_token && parsed.refresh_token) {
+    // Extract the actual expiry time from the JWT token instead of using the stored expires_at
+    const jwtExpiresAt = extractJwtExpiresAt(parsed.access_token);
+    Iif (jwtExpiresAt === 0) {
+      // Invalid token, return null
+      return null;
+    }
+    return {
+      access_token: parsed.access_token,
+      expires_at: jwtExpiresAt,
+      refresh_token: parsed.refresh_token,
+    };
+  }
+  return null;
+}
+ 
+export async function syncApiKeyToTool(
+  files: FileStore,
+  homeDir: string,
+  tool: 'opencode' | 'pi',
+  apiKey: string,
+): Promise<void> {
+  const authPath = TOOL_AUTH_PATHS[tool](homeDir);
+  let existing: Record<string, unknown> = {};
+ 
+  const content = await files.readFile(authPath);
+  Iif (content) {
+    try {
+      existing = JSON.parse(content) as Record<string, unknown>;
+    } catch {
+      existing = {};
+    }
+  }
+ 
+  const updated = {
+    ...existing,
+    berget: {
+      key: apiKey,
+      type: TOOL_API_KEY_TYPES[tool],
+    },
+  };
+ 
+  await files.writeFile(authPath, JSON.stringify(updated, null, 2) + '\n');
+  await files.chmod(authPath, 0o600);
+}
+ 
+export async function syncOAuthToTool(
+  files: FileStore,
+  homeDir: string,
+  tool: 'opencode' | 'pi',
+  cliAuth: CliAuth,
+): Promise<void> {
+  const authPath = TOOL_AUTH_PATHS[tool](homeDir);
+  let existing: Record<string, unknown> = {};
+ 
+  const content = await files.readFile(authPath);
+  Iif (content) {
+    try {
+      existing = JSON.parse(content) as Record<string, unknown>;
+    } catch {
+      existing = {};
+    }
+  }
+ 
+  // Use the JWT's actual expiry time for consistency
+  const jwtExpiresAt = extractJwtExpiresAt(cliAuth.access_token);
+ 
+  const updated = {
+    ...existing,
+    berget: {
+      access: cliAuth.access_token,
+      expires: jwtExpiresAt,
+      refresh: cliAuth.refresh_token,
+      type: 'oauth',
+    },
+  };
+ 
+  await files.writeFile(authPath, JSON.stringify(updated, null, 2) + '\n');
+  await files.chmod(authPath, 0o600);
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/errors.ts.html b/coverage/src/commands/code/errors.ts.html new file mode 100644 index 0000000..7017a2e --- /dev/null +++ b/coverage/src/commands/code/errors.ts.html @@ -0,0 +1,175 @@ + + + + + + Code coverage report for src/commands/code/errors.ts + + + + + + + + + +
+
+

All files / src/commands/code errors.ts

+
+ +
+ 100% + Statements + 11/11 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 4/4 +
+ + +
+ 100% + Lines + 11/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31  +  +6x +6x +  +  +  +  +  +2x +2x +  +2x +2x +  +  +  +  +  +5x +5x +  +  +  +  +1x +1x +1x +  +  + 
export class CancelledError extends Error {
+  constructor() {
+    super('Wizard cancelled');
+    this.name = 'CancelledError';
+  }
+}
+ 
+export class CommandFailedError extends Error {
+  constructor(
+    public readonly command: string,
+    public readonly exitCode: number,
+  ) {
+    super(`Command "${command}" failed with exit code ${exitCode}`);
+    this.name = 'CommandFailedError';
+  }
+}
+ 
+export class FatalError extends Error {
+  constructor(message: string) {
+    super(message);
+    this.name = 'FatalError';
+  }
+}
+ 
+export class PrerequisiteError extends Error {
+  constructor(public readonly binary: string) {
+    super(`Required binary not found: ${binary}`);
+    this.name = 'PrerequisiteError';
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/index.html b/coverage/src/commands/code/index.html new file mode 100644 index 0000000..c66003a --- /dev/null +++ b/coverage/src/commands/code/index.html @@ -0,0 +1,206 @@ + + + + + + Code coverage report for src/commands/code + + + + + + + + + +
+
+

All files src/commands/code

+
+ +
+ 82.26% + Statements + 348/423 +
+ + +
+ 76.67% + Branches + 194/253 +
+ + +
+ 95.65% + Functions + 44/46 +
+ + +
+ 83.03% + Lines + 323/389 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
auth-sync.ts +
+
68.59%83/12165.38%34/52100%9/967.79%80/118
errors.ts +
+
100%11/11100%0/0100%4/4100%11/11
init.ts +
+
91.52%54/5987.09%54/6266.66%2/394.33%50/53
opencode.ts +
+
91.79%123/13483.33%70/84100%15/1594.06%111/118
pi.ts +
+
74.66%56/7565.95%31/4788.88%8/976.11%51/67
tool-check.ts +
+
90.9%10/1150%3/6100%3/390.9%10/11
utils.ts +
+
91.66%11/12100%2/2100%3/390.9%10/11
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/init.ts.html b/coverage/src/commands/code/init.ts.html new file mode 100644 index 0000000..0537cd6 --- /dev/null +++ b/coverage/src/commands/code/init.ts.html @@ -0,0 +1,748 @@ + + + + + + Code coverage report for src/commands/code/init.ts + + + + + + + + + +
+
+

All files / src/commands/code init.ts

+
+ +
+ 91.52% + Statements + 54/59 +
+ + +
+ 87.09% + Branches + 54/62 +
+ + +
+ 66.66% + Functions + 2/3 +
+ + +
+ 94.33% + Lines + 50/53 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +8x +8x +1x +  +7x +6x +3x +1x +2x +1x +  +  +  +  +46x +  +46x +46x +  +  +  +  +46x +  +46x +46x +  +46x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +44x +42x +  +42x +  +  +13x +5x +  +  +  +  +8x +  +8x +1x +  +  +7x +  +4x +4x +1x +  +3x +3x +3x +3x +  +2x +2x +  +  +  +  +7x +3x +  +  +  +36x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +36x +  +36x +  +  +  +  +  +  +36x +31x +19x +18x +  +12x +10x +  +  +  +31x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +46x +  +46x +  +  +  +46x +  +  +  +  +46x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import chalk from 'chalk';
+import * as os from 'node:os';
+ 
+import type { ApiKeyServicePort, AuthServicePort } from './ports/auth-services.js';
+import type { CommandRunner } from './ports/command-runner.js';
+import type { FileStore } from './ports/file-store.js';
+import type { Prompter } from './ports/prompter.js';
+ 
+import { ApiKeyService } from '../../services/api-key-service.js';
+import { AuthService } from '../../services/auth-service.js';
+import { ClackPrompter } from './adapters/clack-prompter.js';
+import { FsFileStore } from './adapters/fs-file-store.js';
+import { SpawnCommandRunner } from './adapters/spawn-command-runner.js';
+import { configureAuth, ensureCliAuth } from './auth-sync.js';
+import { CancelledError, CommandFailedError, FatalError, PrerequisiteError } from './errors.js';
+import {
+  getOpencodeLabel,
+  getOpencodeState,
+  initOpenCode,
+  initOpenCodeAgents,
+} from './opencode.js';
+import { getPiLabel, getPiState, initPi, initPiAgent } from './pi.js';
+import { checkTool, promptForMissingTool } from './tool-check.js';
+ 
+export interface InitCommandResult {
+  exitCode: number;
+  stderr?: string;
+}
+ 
+export interface WizardDeps {
+  apiKeyService: ApiKeyServicePort;
+  authService: AuthServicePort;
+  commands: CommandRunner;
+  cwd: string;
+  files: FileStore;
+  homeDir: string;
+  isTty?: boolean;
+  prompter: Prompter;
+}
+ 
+export async function executeInitCommand(deps: WizardDeps): Promise<InitCommandResult> {
+  try {
+    await runInit(deps);
+    return { exitCode: 0 };
+  } catch (error) {
+    if (error instanceof CancelledError) return { exitCode: 130 };
+    if (error instanceof FatalError) return { exitCode: 1, stderr: error.message };
+    if (error instanceof PrerequisiteError)
+      return { exitCode: 2, stderr: `Missing required binary: ${error.binary}` };
+    if (error instanceof CommandFailedError) return { exitCode: 5, stderr: error.message };
+    throw error;
+  }
+}
+ 
+export async function runInit(deps: WizardDeps): Promise<void> {
+  const { apiKeyService, authService, commands, cwd, files, homeDir, isTty, prompter } = deps;
+ 
+  prompter.intro(`${chalk.bgGreen.black(' berget code ')}`);
+  prompter.note(
+    `Ask questions and report bugs on our GitHub repository:\n\n${chalk.cyan.underline('https://github.com/berget-ai/cli')}`,
+    'Need help?',
+  );
+ 
+  const cliAuth = await ensureCliAuth({ authService, files, homeDir, prompter });
+ 
+  const ocState = await getOpencodeState(files, homeDir, cwd);
+  const piState = await getPiState(files, homeDir, cwd);
+ 
+  const tool = await prompter.select<'opencode' | 'pi'>({
+    initialValue: 'opencode',
+    message: 'How do you want to use Berget AI?',
+    options: [
+      {
+        hint: 'Open source AI coding agent',
+        label: `OpenCode${getOpencodeLabel(ocState)}`,
+        value: 'opencode',
+      },
+      {
+        hint: 'Minimal terminal coding harness',
+        label: `Pi${getPiLabel(piState)}`,
+        value: 'pi',
+      },
+    ],
+  });
+ 
+  // Check if the selected tool is installed
+  const toolCheck = await checkTool(commands, tool);
+  let toolConfigured = toolCheck.installed;
+ 
+  if (!toolCheck.installed) {
+    // Non-TTY guard: throw instead of exit so callers (including tests)
+    // can decide how to handle the failure.
+    if (isTty === false) {
+      throw new FatalError(
+        `${toolCheck.name} is not installed.\nInstall it first:\n  ${toolCheck.installCommand}\nDocs: ${toolCheck.docsUrl}`,
+      );
+    }
+ 
+    const action = await promptForMissingTool(prompter, toolCheck);
+ 
+    if (action === 'exit') {
+      throw new CancelledError();
+    }
+ 
+    if (action === 'retry') {
+      // Re-check once. If still missing, show prompt again.
+      const recheck = await checkTool(commands, tool);
+      if (recheck.installed) {
+        toolConfigured = true;
+      } else {
+        const secondAction = await promptForMissingTool(prompter, recheck);
+        Iif (secondAction === 'exit') throw new CancelledError();
+        if (secondAction === 'continue') toolConfigured = false;
+        if (secondAction === 'retry') {
+          // One more check, then give up and treat as "continue"
+          const finalCheck = await checkTool(commands, tool);
+          toolConfigured = finalCheck.installed;
+        }
+      }
+    }
+ 
+    if (action === 'continue') {
+      toolConfigured = false;
+    }
+  }
+ 
+  const scope = await prompter.select<'global' | 'project'>({
+    initialValue: 'project',
+    message: 'Where should the configuration apply?',
+    options: [
+      {
+        hint:
+          tool === 'opencode'
+            ? ocState.project
+              ? 'Already configured'
+              : 'opencode.json in current directory'
+            : piState.project
+              ? 'Already configured'
+              : '.pi/settings.json in current directory',
+        label: 'This project only',
+        value: 'project',
+      },
+      {
+        hint:
+          tool === 'opencode'
+            ? ocState.global
+              ? 'Already configured'
+              : '~/.config/opencode/opencode.json'
+            : piState.global
+              ? 'Already configured'
+              : '~/.pi/agent/settings.json',
+        label: 'Globally for all projects',
+        value: 'global',
+      },
+    ],
+  });
+ 
+  prompter.log('step', 'Configuring authentication...');
+ 
+  const authResult = await configureAuth(
+    { apiKeyService, files, homeDir, prompter },
+    tool,
+    cliAuth,
+  );
+ 
+  // Only configure the tool if it's installed (or user chose retry and it was found)
+  if (toolConfigured) {
+    if (tool === 'opencode') {
+      await initOpenCode({ commands, cwd, files, homeDir, prompter, scope });
+      await initOpenCodeAgents({ cwd, files, homeDir, prompter, scope });
+    } else {
+      await initPi({ commands, cwd, files, homeDir, prompter, scope });
+      await initPiAgent({ cwd, files, homeDir, prompter, scope });
+    }
+  }
+ 
+  const nextSteps = toolConfigured
+    ? authResult.authenticated
+      ? tool === 'opencode'
+        ? "You're all set!\n\n1. Run: opencode\n2. Select model: /models"
+        : "You're all set!\n\n1. Restart Pi or run /reload\n2. Select model: /model"
+      : tool === 'opencode'
+        ? 'Next steps:\n\n1. Run: opencode\n2. Type: /connect\n3. Choose your auth method:\n   • "Login with Berget" — Berget Code plan\n   • "Enter Berget API Key manually"\n   • (or set BERGET_API_KEY env var)\n4. Select model: /models'
+        : 'Next steps:\n\n1. Restart Pi or run /reload\n2. Type: /login\n3. Choose your auth method:\n   • "Use a subscription" → Berget AI\n   • (or set BERGET_API_KEY env var)\n4. Select model: /model'
+    : authResult.authenticated
+      ? tool === 'opencode'
+        ? `Auth is configured. Next steps:\n\n1. Install OpenCode:\n   ${toolCheck.installCommand}\n2. Run: opencode\n3. Select model: /models`
+        : `Auth is configured. Next steps:\n\n1. Install Pi:\n   ${toolCheck.installCommand}\n2. Run: pi\n3. Select model: /model`
+      : tool === 'opencode'
+        ? `Next steps:\n\n1. Install OpenCode:\n   ${toolCheck.installCommand}\n2. Run: opencode\n3. Authenticate with Berget AI`
+        : `Next steps:\n\n1. Install Pi:\n   ${toolCheck.installCommand}\n2. Run: pi\n3. Authenticate with Berget AI`;
+ 
+  const toolName = tool === 'opencode' ? 'OpenCode' : 'Pi';
+  const docsUrl =
+    tool === 'opencode'
+      ? 'https://github.com/berget-ai/opencode-berget-auth'
+      : 'https://github.com/berget-ai/pi-provider';
+ 
+  prompter.note(
+    `${nextSteps}\n\nFor more information, see official docs:\n\n${docsUrl}`,
+    `Successfully configured Berget AI for ${toolName}`,
+  );
+ 
+  prompter.outro('Initialization complete!');
+}
+ 
+export async function runInitCommand(): Promise<void> {
+  const result = await executeInitCommand({
+    apiKeyService: ApiKeyService.getInstance(),
+    authService: AuthService.getInstance(),
+    commands: new SpawnCommandRunner(),
+    cwd: process.cwd(),
+    files: new FsFileStore(),
+    homeDir: os.homedir(),
+    isTty: process.stdin.isTTY,
+    prompter: new ClackPrompter(),
+  });
+ 
+  if (result.stderr) console.error(result.stderr);
+  process.exitCode = result.exitCode;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/opencode.ts.html b/coverage/src/commands/code/opencode.ts.html new file mode 100644 index 0000000..ce5e7a6 --- /dev/null +++ b/coverage/src/commands/code/opencode.ts.html @@ -0,0 +1,931 @@ + + + + + + Code coverage report for src/commands/code/opencode.ts + + + + + + + + + +
+
+

All files / src/commands/code opencode.ts

+
+ +
+ 91.79% + Statements + 123/134 +
+ + +
+ 83.33% + Branches + 70/84 +
+ + +
+ 100% + Functions + 15/15 +
+ + +
+ 94.06% + Lines + 111/118 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283  +  +  +  +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +46x +44x +  +  +  +  +  +  +  +46x +46x +46x +  +  +  +46x +  +  +  +  +46x +  +  +  +  +  +  +  +  +19x +  +19x +19x +19x +  +19x +2x +  +  +17x +2x +  +15x +  +  +17x +  +  +  +17x +  +16x +16x +16x +16x +16x +  +  +  +  +  +  +  +  +  +  +  +  +  +18x +  +126x +  +18x +  +  +  +  +18x +  +  +  +18x +  +18x +  +90x +90x +90x +  +  +  +  +  +  +  +18x +  +  +  +  +  +18x +13x +  +  +5x +5x +5x +  +9x +9x +9x +  +  +  +5x +5x +5x +5x +5x +5x +  +  +  +  +5x +  +  +  +  +5x +1x +  +  +4x +  +4x +4x +4x +4x +23x +7x +  +7x +7x +7x +  +4x +  +  +  +  +4x +  +  +  +19x +1x +1x +1x +  +  +  +  +1x +  +1x +  +  +  +  +1x +1x +  +  +1x +1x +1x +1x +  +1x +1x +1x +  +  +1x +  +1x +1x +  +  +  +  +  +  +  +1x +  +  +1x +  +  +  +  +  +  +  +  +  +18x +18x +3x +3x +  +  +  +  +  +18x +19x +19x +19x +19x +19x +  +19x +  +  +  +184x +  +4x +184x +4x +  +  +  +  +  +  +  +  +19x +16x +16x +16x +15x +12x +  +  +3x +3x +3x +3x +3x +3x +  + 
import { applyEdits, modify, parse } from 'jsonc-parser';
+import path from 'node:path';
+ 
+import type { CommandRunner } from './ports/command-runner.js';
+import type { FileStore } from './ports/file-store.js';
+import type { Prompter } from './ports/prompter.js';
+ 
+import { getAllAgents, toMarkdown } from '../../agents/index.js';
+import { CancelledError } from './errors.js';
+import { readJsonMaybe } from './utils.js';
+ 
+const OPENCODE_PLUGIN = '@bergetai/opencode-auth@1.0.24';
+const OPENCODE_PLUGIN_NAME = '@bergetai/opencode-auth';
+ 
+export interface InitOpenCodeDeps {
+  commands: CommandRunner;
+  cwd: string;
+  files: FileStore;
+  homeDir: string;
+  prompter: Prompter;
+  scope: 'global' | 'project';
+}
+ 
+export function getOpencodeLabel(state: { global: boolean; project: boolean }): string {
+  if (state.project || state.global) return ' (already configured)';
+  return '';
+}
+ 
+export async function getOpencodeState(
+  files: FileStore,
+  homeDir: string,
+  cwd: string,
+): Promise<{ global: boolean; project: boolean }> {
+  const projectJsonc = await readJsonMaybe(files, path.join(cwd, 'opencode.jsonc'));
+  const projectJson = await readJsonMaybe(files, path.join(cwd, 'opencode.json'));
+  const globalJsonc = await readJsonMaybe(
+    files,
+    path.join(homeDir, '.config', 'opencode', 'opencode.jsonc'),
+  );
+  const globalJson = await readJsonMaybe(
+    files,
+    path.join(homeDir, '.config', 'opencode', 'opencode.json'),
+  );
+ 
+  return {
+    global: hasPluginInConfig(globalJsonc) || hasPluginInConfig(globalJson),
+    project: hasPluginInConfig(projectJsonc) || hasPluginInConfig(projectJson),
+  };
+}
+ 
+/* ─── State helpers ─────────────────────────────────────────────────────── */
+ 
+export async function initOpenCode(deps: InitOpenCodeDeps): Promise<void> {
+  const { commands: _commands, cwd, files, homeDir, prompter, scope } = deps;
+ 
+  const configPath = await resolveOpencodeConfigPath(files, homeDir, cwd, scope);
+  const existingContent = await files.readFile(configPath);
+  const newContent = generateModifiedContent(existingContent, configPath);
+ 
+  if (existingContent && existingContent === newContent) {
+    return;
+  }
+ 
+  if (existingContent) {
+    prompter.note(`OpenCode config will be updated at:\n  ${configPath}`, 'Config update');
+  } else {
+    prompter.note(`OpenCode config will be created at:\n  ${configPath}`, 'Config update');
+  }
+ 
+  const shouldWrite = await prompter.confirm({
+    initialValue: true,
+    message: existingContent ? `Write these changes to ${configPath}?` : `Create ${configPath}?`,
+  });
+  if (!shouldWrite) throw new CancelledError();
+ 
+  const s = prompter.spinner();
+  s.start('Writing OpenCode configuration...');
+  try {
+    await files.writeFile(configPath, newContent);
+    s.stop(`Wrote configuration to ${configPath}.`);
+  } catch (error) {
+    s.stop('Failed to write configuration.');
+    throw error;
+  }
+}
+ 
+export async function initOpenCodeAgents(deps: {
+  cwd: string;
+  files: FileStore;
+  homeDir: string;
+  prompter: Prompter;
+  scope: 'global' | 'project';
+}): Promise<boolean> {
+  const { cwd, files, homeDir, prompter, scope } = deps;
+ 
+  const agents = getAllAgents().filter((a) => a.config.mode === 'primary');
+ 
+  Iif (agents.length === 0) {
+    return false;
+  }
+ 
+  const agentsDir =
+    scope === 'project'
+      ? path.join(cwd, '.opencode', 'agents')
+      : path.join(homeDir, '.config', 'opencode', 'agents');
+ 
+  prompter.note('Space to toggle, Enter to confirm.', 'Agent Setup');
+ 
+  const agentOptions = await Promise.all(
+    agents.map(async (agent) => {
+      const agentPath = path.join(agentsDir, `${agent.config.name}.md`);
+      const exists = await files.exists(agentPath);
+      return {
+        hint: exists ? 'already configured' : agent.config.description,
+        label: agent.config.name,
+        value: agent.config.name,
+      };
+    }),
+  );
+ 
+  const selectedAgents = await prompter.multiselect({
+    message: 'Select agents to set up:',
+    options: agentOptions,
+    required: false,
+  });
+ 
+  if (selectedAgents.length === 0) {
+    return false;
+  }
+ 
+  const newAgents: string[] = [];
+  const existingAgents: string[] = [];
+  await Promise.all(
+    selectedAgents.map(async (agentName: string) => {
+      const agentPath = path.join(agentsDir, `${agentName}.md`);
+      const exists = await files.exists(agentPath);
+      (exists ? existingAgents : newAgents).push(agentName);
+    }),
+  );
+ 
+  const summaryParts: string[] = [];
+  if (newAgents.length > 0) summaryParts.push(`New: ${newAgents.join(', ')}`);
+  if (existingAgents.length > 0) summaryParts.push(`Replaced: ${existingAgents.join(', ')}`);
+  Eif (summaryParts.length > 0) {
+    prompter.note(
+      `  Agent Setup Summary:\n${summaryParts.map((part) => `  ${part}`).join('\n')}`,
+      'Agent Setup',
+    );
+  }
+ 
+  const shouldWrite = await prompter.confirm({
+    initialValue: true,
+    message: 'Write agent configuration files?',
+  });
+ 
+  if (!shouldWrite) {
+    throw new CancelledError();
+  }
+ 
+  await files.mkdir(agentsDir);
+ 
+  const s = prompter.spinner();
+  s.start('Writing agent configurations...');
+  try {
+    for (const agentName of selectedAgents) {
+      const agent = agents.find((a) => a.config.name === agentName);
+      Iif (!agent) continue;
+ 
+      const agentPath = path.join(agentsDir, `${agentName}.md`);
+      const content = toMarkdown(agent);
+      await files.writeFile(agentPath, content);
+    }
+    s.stop(`Wrote ${selectedAgents.length} agent(s) to ${agentsDir}`);
+  } catch (error) {
+    s.stop('Failed to write agent configurations.');
+    throw error;
+  }
+  return true;
+}
+ 
+function generateModifiedContent(existingContent: null | string, configPath: string): string {
+  if (configPath.endsWith('.jsonc')) {
+    const content = existingContent || '{}';
+    const parseErrors: any[] = [];
+    const parsed = parse(content, parseErrors, {
+      allowTrailingComma: true,
+      disallowComments: false,
+    });
+ 
+    let jsConfig: Record<string, unknown> = {};
+    const canModifyText =
+      parsed !== undefined &&
+      typeof parsed === 'object' &&
+      parsed !== null &&
+      !Array.isArray(parsed);
+ 
+    Eif (canModifyText) {
+      jsConfig = parsed as Record<string, unknown>;
+    }
+ 
+    const pluginsKey = jsConfig.plugins === undefined ? 'plugin' : 'plugins';
+    const existingPlugins: string[] = (jsConfig[pluginsKey] as string[]) || [];
+    const filtered = existingPlugins.filter((p: string) => !p.includes(OPENCODE_PLUGIN_NAME));
+    filtered.push(OPENCODE_PLUGIN);
+ 
+    Eif (canModifyText) {
+      let modifiedContent = content;
+      const pluginEdits = modify(modifiedContent, [pluginsKey], filtered, {
+        formattingOptions: { insertSpaces: true, tabSize: 2 },
+      });
+      modifiedContent = applyEdits(modifiedContent, pluginEdits);
+ 
+      Eif (!jsConfig.$schema) {
+        const schemaEdits = modify(
+          modifiedContent,
+          ['$schema'],
+          'https://opencode.ai/config.json',
+          {
+            formattingOptions: { insertSpaces: true, tabSize: 2 },
+          },
+        );
+        modifiedContent = applyEdits(modifiedContent, schemaEdits);
+      }
+ 
+      return modifiedContent;
+    }
+ 
+    const config: Record<string, unknown> = {
+      $schema: 'https://opencode.ai/config.json',
+      [pluginsKey]: filtered,
+    };
+    return JSON.stringify(config, null, 2) + '\n';
+  }
+ 
+  let config: Record<string, unknown> = {};
+  if (existingContent) {
+    try {
+      config = JSON.parse(existingContent);
+    } catch {
+      // ignore malformed, overwrite
+    }
+  }
+ 
+  const pluginsKey = config.plugins === undefined ? 'plugin' : 'plugins';
+  const existingPlugins: string[] = (config[pluginsKey] as string[]) || [];
+  const filtered = existingPlugins.filter((p: string) => !p.includes(OPENCODE_PLUGIN_NAME));
+  filtered.push(OPENCODE_PLUGIN);
+  config[pluginsKey] = filtered;
+  config.$schema = config.$schema || 'https://opencode.ai/config.json';
+ 
+  return JSON.stringify(config, null, 2) + '\n';
+}
+ 
+function hasPluginInConfig(config: unknown): boolean {
+  if (!config || typeof config !== 'object') return false;
+  const plugins =
+    (config as Record<string, unknown>).plugin || (config as Record<string, unknown>).plugins;
+  Iif (!Array.isArray(plugins)) return false;
+  return plugins.some((p: unknown) => typeof p === 'string' && p.includes(OPENCODE_PLUGIN_NAME));
+}
+ 
+async function resolveOpencodeConfigPath(
+  files: FileStore,
+  homeDir: string,
+  cwd: string,
+  scope: 'global' | 'project',
+): Promise<string> {
+  if (scope === 'project') {
+    const jsoncPath = path.join(cwd, 'opencode.jsonc');
+    const jsonPath = path.join(cwd, 'opencode.json');
+    if (await files.exists(jsoncPath)) return jsoncPath;
+    if (await files.exists(jsonPath)) return jsonPath;
+    return jsonPath;
+  }
+ 
+  const globalDir = path.join(homeDir, '.config', 'opencode');
+  const jsoncPath = path.join(globalDir, 'opencode.jsonc');
+  const jsonPath = path.join(globalDir, 'opencode.json');
+  Iif (await files.exists(jsoncPath)) return jsoncPath;
+  Iif (await files.exists(jsonPath)) return jsonPath;
+  return jsonPath;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/pi.ts.html b/coverage/src/commands/code/pi.ts.html new file mode 100644 index 0000000..9ab2045 --- /dev/null +++ b/coverage/src/commands/code/pi.ts.html @@ -0,0 +1,628 @@ + + + + + + Code coverage report for src/commands/code/pi.ts + + + + + + + + + +
+
+

All files / src/commands/code pi.ts

+
+ +
+ 74.66% + Statements + 56/75 +
+ + +
+ 65.95% + Branches + 31/47 +
+ + +
+ 88.88% + Functions + 8/9 +
+ + +
+ 76.11% + Lines + 51/67 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182  +  +  +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +46x +46x +  +  +  +  +  +  +  +46x +46x +  +  +  +  +46x +  +  +  +  +  +  +  +  +12x +12x +  +  +12x +  +12x +12x +12x +10x +  +2x +2x +  +  +  +10x +  +  +  +12x +  +10x +  +  +  +12x +  +  +  +  +  +  +  +10x +  +  +  +  +  +  +  +  +  +  +10x +10x +10x +  +  +  +  +  +  +  +  +  +  +10x +  +70x +  +10x +  +  +  +  +10x +  +  +  +10x +  +10x +  +  +  +  +10x +  +9x +  +45x +  +  +  +  +  +  +42x +9x +  +9x +9x +  +  +  +10x +  +  +  +  +9x +1x +  +  +8x +8x +8x +  +8x +10x +8x +8x +  +  +  +  +8x +  +  +  +92x +1x +1x +  +  +  +  +  +  +  +  +  + 
import path from 'node:path';
+ 
+import type { CommandRunner } from './ports/command-runner.js';
+import type { FileStore } from './ports/file-store.js';
+import type { Prompter } from './ports/prompter.js';
+ 
+import { getAllAgents, toPiPrompt } from '../../agents/index.js';
+import { CancelledError, CommandFailedError } from './errors.js';
+import { readJsonMaybe, writeJsonFile } from './utils.js';
+ 
+const PI_PROVIDER = 'npm:@bergetai/pi-provider';
+const PI_PROVIDER_NAME = '@bergetai/pi-provider';
+ 
+export interface InitPiDeps {
+  commands: CommandRunner;
+  cwd: string;
+  files: FileStore;
+  homeDir: string;
+  prompter: Prompter;
+  scope: 'global' | 'project';
+}
+ 
+export function getPiLabel(state: { global: boolean; project: boolean }): string {
+  Iif (state.project || state.global) return ' (already configured)';
+  return '';
+}
+ 
+export async function getPiState(
+  files: FileStore,
+  homeDir: string,
+  cwd: string,
+): Promise<{ global: boolean; project: boolean }> {
+  const projectSettings = await readJsonMaybe(files, path.join(cwd, '.pi', 'settings.json'));
+  const globalSettings = await readJsonMaybe(
+    files,
+    path.join(homeDir, '.pi', 'agent', 'settings.json'),
+  );
+ 
+  return {
+    global: hasPiProviderInSettings(globalSettings),
+    project: hasPiProviderInSettings(projectSettings),
+  };
+}
+ 
+/* ─── State helpers ─────────────────────────────────────────────────────── */
+ 
+export async function initPi(deps: InitPiDeps): Promise<void> {
+  const { commands, cwd, files, homeDir, prompter, scope } = deps;
+  const s = prompter.spinner();
+ 
+  const installArguments =
+    scope === 'project' ? ['install', '-l', PI_PROVIDER] : ['install', PI_PROVIDER];
+ 
+  s.start('Installing Berget AI provider for Pi...');
+  try {
+    await commands.run('pi', installArguments);
+    s.stop('Installed Pi provider.');
+  } catch {
+    s.stop('Pi provider installation failed. Please try again or install manually.');
+    throw new CommandFailedError(`pi ${installArguments.join(' ')}`, 1);
+  }
+ 
+  const settingsPath =
+    scope === 'project'
+      ? path.join(cwd, '.pi', 'settings.json')
+      : path.join(homeDir, '.pi', 'agent', 'settings.json');
+ 
+  const raw = await readJsonMaybe(files, settingsPath);
+  const settings: Record<string, unknown> =
+    typeof raw === 'object' && raw !== null && !Array.isArray(raw)
+      ? (raw as Record<string, unknown>)
+      : {};
+ 
+  Iif (settings.defaultProvider === 'berget') {
+    prompter.note(
+      'Berget AI is already set as your default provider.',
+      'Default provider already set',
+    );
+    return;
+  }
+ 
+  Iif (settings.defaultProvider) {
+    const makeDefault = await prompter.confirm({
+      initialValue: false,
+      message: `Your default provider is ${settings.defaultProvider}. Switch to Berget AI instead?`,
+    });
+    if (makeDefault) {
+      settings.defaultProvider = 'berget';
+      await writeJsonFile(files, settingsPath, settings);
+      prompter.note('Berget AI is now your default provider.', 'Updated default provider');
+    }
+  } else {
+    settings.defaultProvider = 'berget';
+    await writeJsonFile(files, settingsPath, settings);
+    prompter.note('Berget AI is now your default provider.', 'Updated default provider');
+  }
+}
+ 
+export async function initPiAgent(deps: {
+  cwd: string;
+  files: FileStore;
+  homeDir: string;
+  prompter: Prompter;
+  scope: 'global' | 'project';
+}): Promise<boolean> {
+  const { cwd, files, homeDir, prompter, scope } = deps;
+ 
+  const agents = getAllAgents().filter((a) => a.config.mode === 'primary');
+ 
+  Iif (agents.length === 0) {
+    return false;
+  }
+ 
+  const systemPath =
+    scope === 'project'
+      ? path.join(cwd, '.pi', 'SYSTEM.md')
+      : path.join(homeDir, '.pi', 'agent', 'SYSTEM.md');
+ 
+  prompter.note('Pi uses a single system prompt.', 'Agent Setup');
+ 
+  const shouldInitAgent = await prompter.confirm({
+    initialValue: false,
+    message: 'Set up an agent for Pi?',
+  });
+ 
+  if (!shouldInitAgent) return false;
+ 
+  const selectedAgentName = await prompter.select({
+    message: 'Choose an agent:',
+    options: agents.map((agent) => ({
+      hint: agent.config.description,
+      label: agent.config.name,
+      value: agent.config.name,
+    })),
+  });
+ 
+  const agent = agents.find((a) => a.config.name === selectedAgentName);
+  Iif (!agent) return false;
+ 
+  const systemExists = await files.exists(systemPath);
+  const confirmMsg = systemExists
+    ? `SYSTEM.md already exists. Replace with ${agent.config.name}?`
+    : 'Create agent configuration?';
+ 
+  const shouldWrite = await prompter.confirm({
+    initialValue: true,
+    message: confirmMsg,
+  });
+ 
+  if (!shouldWrite) {
+    throw new CancelledError();
+  }
+ 
+  const s = prompter.spinner();
+  s.start('Writing agent configuration...');
+  try {
+    const systemDir =
+      scope === 'project' ? path.join(cwd, '.pi') : path.join(homeDir, '.pi', 'agent');
+    await files.mkdir(systemDir);
+    await files.writeFile(systemPath, toPiPrompt(agent));
+    s.stop(`Wrote agent configuration to ${systemPath}`);
+  } catch (error) {
+    s.stop('Failed to write agent configuration.');
+    throw error;
+  }
+  return true;
+}
+ 
+function hasPiProviderInSettings(settings: unknown): boolean {
+  if (!settings || typeof settings !== 'object') return false;
+  const packages = (settings as Record<string, unknown>).packages;
+  Eif (!Array.isArray(packages)) return false;
+  return packages.some((p: unknown) => {
+    if (typeof p === 'string') return p.includes(PI_PROVIDER_NAME);
+    if (typeof p === 'object' && p !== null) {
+      const source = (p as Record<string, unknown>).source;
+      return typeof source === 'string' && source.includes(PI_PROVIDER_NAME);
+    }
+    return false;
+  });
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/tool-check.ts.html b/coverage/src/commands/code/tool-check.ts.html new file mode 100644 index 0000000..a71c4fb --- /dev/null +++ b/coverage/src/commands/code/tool-check.ts.html @@ -0,0 +1,319 @@ + + + + + + Code coverage report for src/commands/code/tool-check.ts + + + + + + + + + +
+
+

All files / src/commands/code tool-check.ts

+
+ +
+ 90.9% + Statements + 10/11 +
+ + +
+ 50% + Branches + 3/6 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 90.9% + Lines + 10/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +50x +48x +  +48x +  +  +  +  +  +  +  +  +  +  +  +  +11x +11x +  +11x +  +  +  +  +  +  +  +  +11x +  +  +  +48x +  +  +  +  +48x +  +  +  + 
import type { CommandRunner } from './ports/command-runner.js';
+import type { Prompter } from './ports/prompter.js';
+ 
+export interface ToolCheckResult {
+  description: string;
+  docsUrl: string;
+  installCommand: string;
+  installed: boolean;
+  name: string;
+}
+ 
+interface ToolInfo {
+  description: string;
+  docsUrl: string;
+  installCommand: string;
+  name: string;
+}
+ 
+const TOOL_INFO: Record<string, Omit<ToolInfo, 'installCommand'>> = {
+  opencode: {
+    description:
+      'OpenCode is an open source AI coding agent. Install it to start coding with AI in your terminal.',
+    docsUrl: 'https://opencode.ai/docs',
+    name: 'OpenCode',
+  },
+  pi: {
+    description:
+      'Pi is a minimal terminal coding harness. Install it to start coding with AI in your terminal.',
+    docsUrl: 'https://pi.dev/docs/latest',
+    name: 'Pi',
+  },
+};
+ 
+export async function checkTool(
+  commands: CommandRunner,
+  tool: 'opencode' | 'pi',
+): Promise<ToolCheckResult> {
+  const installed = await commands.checkInstalled(tool);
+  const info = TOOL_INFO[tool];
+ 
+  return {
+    description: info.description,
+    docsUrl: info.docsUrl,
+    installCommand: getInstallCommand(tool, process.platform),
+    installed,
+    name: info.name,
+  };
+}
+ 
+export async function promptForMissingTool(
+  prompter: Prompter,
+  tool: ToolCheckResult,
+): Promise<'continue' | 'exit' | 'retry'> {
+  const message = `${tool.description}\n\nInstall:\n  ${tool.installCommand}\n\nDocs: ${tool.docsUrl}`;
+  prompter.note(message, `${tool.name} not installed`);
+ 
+  const action = await prompter.select<'continue' | 'exit' | 'retry'>({
+    message: 'What would you like to do?',
+    options: [
+      { label: "I've installed it — check again", value: 'retry' },
+      { label: 'Continue without installing (auth only)', value: 'continue' },
+      { label: 'Exit', value: 'exit' },
+    ],
+  });
+ 
+  return action;
+}
+ 
+function getInstallCommand(tool: 'opencode' | 'pi', platform: string): string {
+  Iif (platform === 'win32') {
+    return tool === 'opencode'
+      ? 'npm install -g opencode-ai'
+      : 'npm install -g @earendil-works/pi-coding-agent';
+  }
+  return tool === 'opencode'
+    ? 'curl -fsSL https://opencode.ai/install | bash'
+    : 'curl -fsSL https://pi.dev/install.sh | sh';
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/commands/code/utils.ts.html b/coverage/src/commands/code/utils.ts.html new file mode 100644 index 0000000..79c3841 --- /dev/null +++ b/coverage/src/commands/code/utils.ts.html @@ -0,0 +1,172 @@ + + + + + + Code coverage report for src/commands/code/utils.ts + + + + + + + + + +
+
+

All files / src/commands/code utils.ts

+
+ +
+ 91.66% + Statements + 11/12 +
+ + +
+ 100% + Branches + 2/2 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 90.9% + Lines + 10/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30  +  +  +286x +286x +6x +6x +  +1x +1x +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +10x +  + 
import type { FileStore } from './ports/file-store.js';
+ 
+export async function readJsonMaybe(files: FileStore, filePath: string): Promise<null | unknown> {
+  const content = await files.readFile(filePath);
+  if (!content) return null;
+  try {
+    return JSON.parse(content);
+  } catch {
+    try {
+      return JSON.parse(stripJsoncComments(content));
+    } catch {
+      return null;
+    }
+  }
+}
+ 
+export function stripJsoncComments(content: string): string {
+  content = content.replaceAll(/\/\/.*$/gm, '');
+  content = content.replaceAll(/\/\*[\s\S]*?\*\//g, '');
+  return content;
+}
+ 
+export async function writeJsonFile(
+  files: FileStore,
+  filePath: string,
+  data: Record<string, unknown>,
+): Promise<void> {
+  await files.writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`);
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/constants/command-structure.ts.html b/coverage/src/constants/command-structure.ts.html new file mode 100644 index 0000000..476de2d --- /dev/null +++ b/coverage/src/constants/command-structure.ts.html @@ -0,0 +1,715 @@ + + + + + + Code coverage report for src/constants/command-structure.ts + + + + + + + + + +
+
+

All files / src/constants command-structure.ts

+
+ +
+ 100% + Statements + 3/3 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 3/3 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
/**
+ * Command structure constants for the CLI
+ * Following patterns from AWS CLI and Google Cloud CLI
+ */
+ 
+// Main command groups
+export const COMMAND_GROUPS = {
+  API_KEYS: 'api-keys',
+  APPS: 'apps',
+  AUTH: 'auth',
+  BILLING: 'billing',
+  CHAT: 'chat',
+  CLUSTERS: 'clusters',
+  CODE: 'code',
+  FLUX: 'flux',
+  HELM: 'helm',
+  KUBECTL: 'kubectl',
+  MODELS: 'models',
+  USERS: 'users',
+};
+ 
+// Subcommands for each group
+export const SUBCOMMANDS = {
+  // API Keys commands
+  API_KEYS: {
+    CREATE: 'create',
+    DELETE: 'delete',
+    DESCRIBE: 'describe',
+    GET_DEFAULT: 'get-default',
+    LIST: 'list',
+    ROTATE: 'rotate',
+    SET_DEFAULT: 'set-default',
+  },
+ 
+  // Apps commands
+  APPS: {
+    DESCRIBE_INSTALLATION: 'describe-installation',
+    DESCRIBE_TEMPLATE: 'describe-template',
+    INSTALL: 'install',
+    LIST_INSTALLATIONS: 'list-installations',
+    LIST_TEMPLATES: 'list-templates',
+    UNINSTALL: 'uninstall',
+  },
+ 
+  // Auth commands
+  AUTH: {
+    LOGIN: 'login',
+    LOGOUT: 'logout',
+    WHOAMI: 'whoami',
+  },
+ 
+  // Billing commands
+  BILLING: {
+    ADD_PAYMENT_METHOD: 'add-payment-method',
+    DESCRIBE_INVOICE: 'describe-invoice',
+    GET_USAGE: 'get-usage',
+    LIST_INVOICES: 'list-invoices',
+    LIST_PAYMENT_METHODS: 'list-payment-methods',
+    REMOVE_PAYMENT_METHOD: 'remove-payment-method',
+    UPDATE_SUBSCRIPTION: 'update-subscription',
+  },
+ 
+  // Chat commands
+  CHAT: {
+    LIST: 'list',
+    RUN: 'run',
+  },
+ 
+  // Clusters commands
+  CLUSTERS: {
+    DESCRIBE: 'describe',
+    GET_USAGE: 'get-usage',
+    LIST: 'list',
+  },
+ 
+  // Code commands
+  CODE: {
+    INIT: 'init',
+  },
+ 
+  // Flux commands
+  FLUX: {
+    BOOTSTRAP: 'bootstrap',
+    INSTALL: 'install',
+  },
+ 
+  // Helm commands
+  HELM: {
+    ADD_REPO: 'add-repo',
+    INSTALL: 'install',
+  },
+ 
+  // Kubectl commands
+  KUBECTL: {
+    APPLY: 'apply',
+    CREATE_NAMESPACE: 'create-namespace',
+    GET: 'get',
+  },
+ 
+  // Models commands
+  MODELS: {
+    DESCRIBE: 'describe',
+    LIST: 'list',
+  },
+ 
+  // Users commands
+  USERS: {
+    DESCRIBE: 'describe',
+    INVITE: 'invite',
+    LIST: 'list',
+    UPDATE: 'update',
+  },
+};
+ 
+// Command descriptions
+export const COMMAND_DESCRIPTIONS = {
+  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.CREATE}`]: 'Create a new API key',
+  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.DELETE}`]: 'Delete an API key',
+  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.DESCRIBE}`]:
+    'Get usage statistics for an API key',
+  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.GET_DEFAULT}`]:
+    'Show the current default API key',
+ 
+  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.LIST}`]: 'List all API keys',
+  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.ROTATE}`]: 'Rotate an API key',
+  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.SET_DEFAULT}`]:
+    'Set an API key as the default for chat commands',
+  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.DESCRIBE_INSTALLATION}`]:
+    'Get detailed information about an installed application',
+  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.DESCRIBE_TEMPLATE}`]:
+    'Get detailed information about an application template',
+  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.INSTALL}`]: 'Install an application',
+  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.LIST_INSTALLATIONS}`]: 'List installed applications',
+  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.LIST_TEMPLATES}`]:
+    'List available application templates',
+ 
+  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.UNINSTALL}`]: 'Uninstall an application',
+  [`${COMMAND_GROUPS.AUTH} ${SUBCOMMANDS.AUTH.LOGIN}`]: 'Log in to Berget AI',
+  [`${COMMAND_GROUPS.AUTH} ${SUBCOMMANDS.AUTH.LOGOUT}`]: 'Log out from Berget AI',
+  [`${COMMAND_GROUPS.AUTH} ${SUBCOMMANDS.AUTH.WHOAMI}`]: 'Display current user information',
+ 
+  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.ADD_PAYMENT_METHOD}`]:
+    'Add a new payment method',
+  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.DESCRIBE_INVOICE}`]:
+    'Get detailed information about an invoice',
+  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.GET_USAGE}`]: 'Get current usage metrics',
+  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.LIST_INVOICES}`]: 'List all invoices',
+  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.LIST_PAYMENT_METHODS}`]:
+    'List all payment methods',
+  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.REMOVE_PAYMENT_METHOD}`]:
+    'Remove a payment method',
+  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.UPDATE_SUBSCRIPTION}`]:
+    'Update subscription plan',
+ 
+  [`${COMMAND_GROUPS.CHAT} ${SUBCOMMANDS.CHAT.LIST}`]: 'List available chat models',
+  [`${COMMAND_GROUPS.CHAT} ${SUBCOMMANDS.CHAT.RUN}`]: 'Run a chat session with a specified model',
+  [`${COMMAND_GROUPS.CLUSTERS} ${SUBCOMMANDS.CLUSTERS.DESCRIBE}`]:
+    'Get detailed information about a cluster',
+ 
+  [`${COMMAND_GROUPS.CLUSTERS} ${SUBCOMMANDS.CLUSTERS.GET_USAGE}`]:
+    'Get resource usage for a cluster',
+  [`${COMMAND_GROUPS.CLUSTERS} ${SUBCOMMANDS.CLUSTERS.LIST}`]: 'List all clusters',
+  [`${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`]:
+    'Interactive setup for Berget AI coding tools',
+ 
+  [`${COMMAND_GROUPS.FLUX} ${SUBCOMMANDS.FLUX.BOOTSTRAP}`]: 'Bootstrap Flux CD',
+  [`${COMMAND_GROUPS.FLUX} ${SUBCOMMANDS.FLUX.INSTALL}`]: 'Install Flux CD',
+  [`${COMMAND_GROUPS.HELM} ${SUBCOMMANDS.HELM.ADD_REPO}`]: 'Add a Helm repository',
+ 
+  [`${COMMAND_GROUPS.HELM} ${SUBCOMMANDS.HELM.INSTALL}`]: 'Install a Helm chart',
+  [`${COMMAND_GROUPS.KUBECTL} ${SUBCOMMANDS.KUBECTL.APPLY}`]: 'Apply a Kubernetes configuration',
+  [`${COMMAND_GROUPS.KUBECTL} ${SUBCOMMANDS.KUBECTL.CREATE_NAMESPACE}`]:
+    'Create a Kubernetes namespace',
+  [`${COMMAND_GROUPS.KUBECTL} ${SUBCOMMANDS.KUBECTL.GET}`]: 'Get Kubernetes resources',
+  [`${COMMAND_GROUPS.MODELS} ${SUBCOMMANDS.MODELS.DESCRIBE}`]:
+    'Get detailed information about an AI model',
+ 
+  [`${COMMAND_GROUPS.MODELS} ${SUBCOMMANDS.MODELS.LIST}`]: 'List available AI models',
+  [`${COMMAND_GROUPS.USERS} ${SUBCOMMANDS.USERS.DESCRIBE}`]:
+    'Get detailed information about a user',
+  [`${COMMAND_GROUPS.USERS} ${SUBCOMMANDS.USERS.INVITE}`]: 'Invite a new user to your organization',
+  [`${COMMAND_GROUPS.USERS} ${SUBCOMMANDS.USERS.LIST}`]: 'List all users in your organization',
+  [`${COMMAND_GROUPS.USERS} ${SUBCOMMANDS.USERS.UPDATE}`]: 'Update user information',
+  // API Keys group
+  [COMMAND_GROUPS.API_KEYS]: 'Manage API keys',
+  // Apps group
+  [COMMAND_GROUPS.APPS]: 'Manage applications',
+  // Auth group
+  [COMMAND_GROUPS.AUTH]: 'Manage authentication and authorization',
+ 
+  // Billing group
+  [COMMAND_GROUPS.BILLING]: 'Manage billing and usage',
+  // Chat group
+  [COMMAND_GROUPS.CHAT]: 'Interact with AI chat models',
+  // Clusters group
+  [COMMAND_GROUPS.CLUSTERS]: 'Manage Kubernetes clusters',
+ 
+  // Code group
+  [COMMAND_GROUPS.CODE]: 'Configure Berget AI coding tools',
+  // Flux group
+  [COMMAND_GROUPS.FLUX]: 'Manage Flux CD',
+  // Helm group
+  [COMMAND_GROUPS.HELM]: 'Manage Helm charts',
+  // Kubectl group
+  [COMMAND_GROUPS.KUBECTL]: 'Manage Kubernetes resources',
+  // Models group
+  [COMMAND_GROUPS.MODELS]: 'Manage AI models',
+  // Users group
+  [COMMAND_GROUPS.USERS]: 'Manage users',
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/constants/index.html b/coverage/src/constants/index.html new file mode 100644 index 0000000..067a533 --- /dev/null +++ b/coverage/src/constants/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for src/constants + + + + + + + + + +
+
+

All files src/constants

+
+ +
+ 100% + Statements + 3/3 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 3/3 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
command-structure.ts +
+
100%3/3100%0/0100%0/0100%3/3
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/index.html b/coverage/src/index.html new file mode 100644 index 0000000..65bdd7d --- /dev/null +++ b/coverage/src/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for src + + + + + + + + + +
+
+

All files src

+
+ +
+ 0% + Statements + 0/11 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 0% + Lines + 0/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
client.ts +
+
0%0/110%0/20%0/30%0/11
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/services/api-key-service.ts.html b/coverage/src/services/api-key-service.ts.html new file mode 100644 index 0000000..a4c3ee5 --- /dev/null +++ b/coverage/src/services/api-key-service.ts.html @@ -0,0 +1,802 @@ + + + + + + Code coverage report for src/services/api-key-service.ts + + + + + + + + + +
+
+

All files / src/services api-key-service.ts

+
+ +
+ 2.73% + Statements + 2/73 +
+ + +
+ 0% + Branches + 0/48 +
+ + +
+ 9.09% + Functions + 1/11 +
+ + +
+ 2.89% + Lines + 2/69 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { createAuthenticatedClient } from '../client.js';
+import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure.js';
+import { handleError } from '../utils/error-handler.js';
+ 
+export interface ApiKey {
+  active: boolean;
+  created: string;
+  description: null | string;
+  id: number;
+  lastUsed: null | string;
+  modified: string;
+  name: string;
+  prefix: string;
+}
+ 
+export interface ApiKeyResponse {
+  created: string;
+  description: null | string;
+  id: number;
+  key: string;
+  name: string;
+}
+ 
+export interface CreateApiKeyOptions {
+  description?: string;
+  name: string;
+}
+ 
+/**
+ * Service for managing API keys
+ * Command group: api-keys
+ */
+export class ApiKeyService {
+  // Command group name for this service
+  public static readonly COMMAND_GROUP = COMMAND_GROUPS.API_KEYS;
+  // Subcommands for this service
+  public static readonly COMMANDS = SUBCOMMANDS.API_KEYS;
+ 
+  private static instance: ApiKeyService;
+ 
+  private client = createAuthenticatedClient();
+ 
+  private constructor() {}
+ 
+  public static getInstance(): ApiKeyService {
+    if (!ApiKeyService.instance) {
+      ApiKeyService.instance = new ApiKeyService();
+    }
+    return ApiKeyService.instance;
+  }
+ 
+  /**
+   * Create a new API key
+   * Command: berget api-keys create
+   */
+  public async create(options: CreateApiKeyOptions): Promise<ApiKeyResponse> {
+    try {
+      this.validateCreateOptions(options);
+ 
+      const { data, error } = await this.client.POST('/v1/api-keys', {
+        body: options,
+      });
+ 
+      if (error) {
+        throw this.mapCreateError(error);
+      }
+ 
+      if (!data) {
+        throw new Error('No data received from server');
+      }
+ 
+      return data;
+    } catch (error) {
+      throw this.enhanceNetworkError(error);
+    }
+  }
+ 
+  /**
+   * Delete an API key
+   * Command: berget api-keys delete
+   */
+  public async delete(id: string): Promise<boolean> {
+    try {
+      const { error } = await this.client.DELETE('/v1/api-keys/{id}', {
+        params: { path: { id } },
+      });
+      if (error) throw new Error(JSON.stringify(error));
+      return true;
+    } catch (error) {
+      console.error('Failed to delete API key:', error);
+      throw error;
+    }
+  }
+ 
+  /**
+   * Get usage statistics for an API key
+   * Command: berget api-keys describe
+   */
+  public async describe(id: string): Promise<any> {
+    try {
+      const { data, error } = await this.client.GET('/v1/api-keys/{id}/usage', {
+        params: { path: { id } },
+      });
+      if (error) throw new Error(JSON.stringify(error));
+      return data;
+    } catch (error) {
+      console.error('Failed to get API key usage:', error);
+      throw error;
+    }
+  }
+ 
+  /**
+   * List all API keys
+   * Command: berget api-keys list
+   */
+  public async list(): Promise<ApiKey[]> {
+    try {
+      const { data, error } = await this.client.GET('/v1/api-keys');
+      if (error) throw error;
+      return data || [];
+    } catch (error) {
+      handleError('Failed to list API keys', error);
+      throw error;
+    }
+  }
+ 
+  /**
+   * Rotate an API key
+   * Command: berget api-keys rotate
+   */
+  public async rotate(id: string): Promise<ApiKeyResponse> {
+    try {
+      const { data, error } = await this.client.PUT('/v1/api-keys/{id}/rotate', {
+        params: { path: { id } },
+      });
+      if (error) throw new Error(JSON.stringify(error));
+      return data!;
+    } catch (error) {
+      console.error('Failed to rotate API key:', error);
+      throw error;
+    }
+  }
+ 
+  private buildCreationFailedMessage(): string {
+    return (
+      'Failed to create API key. This could be due to:\n' +
+      '• Account limits or quota restrictions\n' +
+      '• Insufficient permissions for API key creation\n' +
+      '• Temporary server issues\n' +
+      '• Billing or subscription issues\n\n' +
+      'Troubleshooting steps:\n' +
+      '1. Check if you have reached your API key limit\n' +
+      '2. Verify your account has API key creation permissions\n' +
+      '3. Check your billing status and subscription\n' +
+      '4. Try again in a few minutes if this is a temporary issue\n' +
+      '5. Contact support if the problem persists'
+    );
+  }
+ 
+  private enhanceNetworkError(error: unknown): Error {
+    if (!(error instanceof Error)) {
+      throw error;
+    }
+ 
+    const message = error.message;
+ 
+    if (message.includes('ECONNREFUSED')) {
+      return new Error('Cannot connect to Berget API. Please check your internet connection.');
+    }
+ 
+    if (message.includes('ENOTFOUND')) {
+      return new Error('Cannot resolve Berget API hostname. Please check your DNS settings.');
+    }
+ 
+    if (message.includes('401') || message.includes('Unauthorized')) {
+      return new Error('Authentication failed. Please run `berget auth login` to log in again.');
+    }
+ 
+    if (message.includes('403')) {
+      return new Error(
+        'Access forbidden. Your account may not have permission to create API keys.',
+      );
+    }
+ 
+    throw error;
+  }
+ 
+  private mapCreateError(error: unknown): Error {
+    if (typeof error !== 'object' || error === null) {
+      return new Error(JSON.stringify(error));
+    }
+ 
+    const errorObject = error as any;
+    const code = errorObject.error?.code;
+ 
+    switch (code) {
+      case 'API_KEY_CREATION_FAILED': {
+        return new Error(this.buildCreationFailedMessage());
+      }
+      case 'BILLING_REQUIRED': {
+        return new Error(
+          'A valid billing method is required to create API keys. Please add a payment method.',
+        );
+      }
+      case 'INSUFFICIENT_PERMISSIONS': {
+        return new Error(
+          'Your account does not have permission to create API keys. Please contact your administrator.',
+        );
+      }
+      case 'QUOTA_EXCEEDED': {
+        return new Error(
+          'You have reached your API key limit. Please delete existing keys or contact support to increase your quota.',
+        );
+      }
+      case 'USER_NOT_FOUND': {
+        return new Error(
+          'Before you can create API keys, you need to finish setting up your account.\n\nCheck your inbox for a verification email from Berget AI and complete the account setup.',
+        );
+      }
+      default: {
+        return new Error(JSON.stringify(error));
+      }
+    }
+  }
+ 
+  private validateCreateOptions(options: CreateApiKeyOptions): void {
+    if (!options.name || options.name.trim().length === 0) {
+      throw new Error('API key name is required and cannot be empty');
+    }
+ 
+    if (options.name.length > 100) {
+      throw new Error('API key name must be 100 characters or less');
+    }
+ 
+    if (options.description && options.description.length > 500) {
+      throw new Error('API key description must be 500 characters or less');
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/services/auth-service.ts.html b/coverage/src/services/auth-service.ts.html new file mode 100644 index 0000000..478a33b --- /dev/null +++ b/coverage/src/services/auth-service.ts.html @@ -0,0 +1,445 @@ + + + + + + Code coverage report for src/services/auth-service.ts + + + + + + + + + +
+
+

All files / src/services auth-service.ts

+
+ +
+ 5.12% + Statements + 2/39 +
+ + +
+ 0% + Branches + 0/23 +
+ + +
+ 20% + Functions + 1/5 +
+ + +
+ 5.12% + Lines + 2/39 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import chalk from 'chalk';
+ 
+import { getAuthConfig } from '../auth/config.js';
+import { getConfiguration } from '../auth/issuer.js';
+import { extractJwtExpiresAt } from '../auth/jwt.js';
+import { startPkceFlow } from '../auth/oauth/pkce-flow.js';
+import { FileTokenStore } from '../auth/storage/token-store.js';
+import { createAuthenticatedClient } from '../client.js';
+import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure.js';
+import { handleError } from '../utils/error-handler.js';
+ 
+/**
+ * Service for authentication operations
+ * Command group: auth
+ */
+export class AuthService {
+  // Command group name for this service
+  public static readonly COMMAND_GROUP = COMMAND_GROUPS.AUTH;
+ 
+  // Subcommands for this service
+  public static readonly COMMANDS = SUBCOMMANDS.AUTH;
+ 
+  private static instance: AuthService;
+ 
+  private constructor() {}
+ 
+  public static getInstance(): AuthService {
+    if (!AuthService.instance) {
+      AuthService.instance = new AuthService();
+    }
+    return AuthService.instance;
+  }
+ 
+  /**
+   * Browser-based PKCE login for interactive CLI use.
+   * Prints status to stdout/stderr. Use loginInteractive() when you need
+   * a silent, UI-agnostic result (e.g. inside the setup wizard).
+   */
+  public async login(options?: { debug?: boolean; stage?: boolean }): Promise<boolean> {
+    try {
+      const result = await this.loginInteractive(options);
+ 
+      if (!result.success) {
+        console.log(chalk.red(`\nAuthentication failed: ${result.error || 'Unknown error'}`));
+        return false;
+      }
+ 
+      console.log(chalk.green('\n✓ Successfully logged in to Berget'));
+ 
+      try {
+        const profile = await this.whoami();
+        if (profile?.email) {
+          console.log(chalk.green(`Logged in as ${profile.name || profile.email}`));
+        }
+      } catch {
+        // Ignore errors fetching profile
+      }
+ 
+      console.log(chalk.cyan('\nNext steps:'));
+      console.log(chalk.cyan('  • Create an API key: berget api-keys create'));
+      console.log(chalk.cyan('  • Initialize OpenCode: berget code init'));
+ 
+      return true;
+    } catch (error) {
+      handleError('Login failed', error);
+      return false;
+    }
+  }
+ 
+  /**
+   * Browser-based PKCE login for wizard / programmatic use.
+   * Does NOT print to stdout — returns tokens so callers can display
+   * their own UI (e.g. via clack/prompts).
+   */
+  public async loginInteractive(options?: { debug?: boolean; stage?: boolean }): Promise<{
+    accessToken?: string;
+    error?: string;
+    expiresIn?: number;
+    refreshToken?: string;
+    success: boolean;
+  }> {
+    try {
+      const config = getAuthConfig(options);
+      const configuration = await getConfiguration(config);
+      const result = await startPkceFlow({ config: configuration, debug: options?.debug });
+ 
+      if (result.success && result.accessToken && result.refreshToken) {
+        const tokenStore = new FileTokenStore();
+        const jwtExpiresAt = extractJwtExpiresAt(result.accessToken);
+        const expiresAt =
+          jwtExpiresAt > 0 ? jwtExpiresAt : Date.now() + (result.expiresIn || 3600) * 1000;
+        await tokenStore.set({
+          access_token: result.accessToken,
+          expires_at: expiresAt,
+          refresh_token: result.refreshToken,
+        });
+      }
+ 
+      return result;
+    } catch (error) {
+      return {
+        error: error instanceof Error ? error.message : String(error),
+        success: false,
+      };
+    }
+  }
+ 
+  public async whoami(): Promise<any> {
+    try {
+      const client = createAuthenticatedClient();
+      const { data: profile, error } = await client.GET('/v1/users/me');
+      if (error) {
+        return null;
+      }
+      return profile;
+    } catch {
+      return null;
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/services/index.html b/coverage/src/services/index.html new file mode 100644 index 0000000..522877f --- /dev/null +++ b/coverage/src/services/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for src/services + + + + + + + + + +
+
+

All files src/services

+
+ +
+ 3.57% + Statements + 4/112 +
+ + +
+ 0% + Branches + 0/71 +
+ + +
+ 12.5% + Functions + 2/16 +
+ + +
+ 3.7% + Lines + 4/108 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
api-key-service.ts +
+
2.73%2/730%0/489.09%1/112.89%2/69
auth-service.ts +
+
5.12%2/390%0/2320%1/55.12%2/39
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/utils/error-handler.ts.html b/coverage/src/utils/error-handler.ts.html new file mode 100644 index 0000000..b623a81 --- /dev/null +++ b/coverage/src/utils/error-handler.ts.html @@ -0,0 +1,538 @@ + + + + + + Code coverage report for src/utils/error-handler.ts + + + + + + + + + +
+
+

All files / src/utils error-handler.ts

+
+ +
+ 0% + Statements + 0/62 +
+ + +
+ 0% + Branches + 0/58 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 0% + Lines + 0/62 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import chalk from 'chalk';
+ 
+/**
+ * Formats and prints error messages in a consistent way
+ */
+export function handleError(message: string, error: any): void {
+  console.error(chalk.red(`❌ Error: ${message}`));
+ 
+  let errorDetails = '';
+  let errorCode = '';
+  let errorType = '';
+ 
+  // If the error is a string (like JSON.stringify(error))
+  if (typeof error === 'string') {
+    try {
+      // Try to parse it as JSON
+      const parsedError = JSON.parse(error);
+      if (parsedError.error) {
+        errorDetails = parsedError.error.message || parsedError.error;
+        errorCode = parsedError.error.code || parsedError.code;
+        errorType = parsedError.error.type || '';
+      } else {
+        errorDetails = error;
+      }
+    } catch {
+      // If it's not valid JSON, just print the string
+      errorDetails = error;
+    }
+  } else if (error && error.message) {
+    // If it's an Error object
+    errorDetails = error.message;
+    errorCode = error.code;
+    errorType = error.type;
+  }
+ 
+  // Print error details
+  if (errorDetails) {
+    console.error(chalk.dim(`📝 Details: ${errorDetails}`));
+  }
+  if (errorCode) {
+    console.error(chalk.dim(`🔢 Code: ${errorCode}`));
+  }
+ 
+  // Provide helpful troubleshooting based on error type
+  provideTroubleshootingTips(errorType, errorCode, errorDetails);
+}
+ 
+/**
+ * Provides helpful troubleshooting tips based on error type
+ */
+function provideTroubleshootingTips(
+  errorType: string,
+  errorCode: string,
+  errorDetails: string,
+): void {
+  console.error(chalk.blue('\n💡 Troubleshooting tips:'));
+ 
+  // Authentication errors
+  if (
+    errorType === 'authentication_error' ||
+    errorCode === 'AUTH_FAILED' ||
+    errorDetails?.includes('Unauthorized') ||
+    errorDetails?.includes('Authentication failed')
+  ) {
+    console.error(chalk.yellow('   🔐 Authentication issue detected:'));
+    console.error(chalk.white('   • Run `berget auth login` to log in'));
+    console.error(chalk.white('   • Check if your session has expired'));
+    console.error(chalk.white('   • Verify you have the correct permissions'));
+  }
+ 
+  // Network/connection errors
+  if (
+    errorDetails?.includes('fetch failed') ||
+    errorDetails?.includes('ECONNREFUSED') ||
+    errorDetails?.includes('ENOTFOUND') ||
+    errorDetails?.includes('network')
+  ) {
+    console.error(chalk.yellow('   🌐 Network issue detected:'));
+    console.error(chalk.white('   • Check your internet connection'));
+    console.error(chalk.white('   • Verify you can reach api.berget.ai'));
+    console.error(chalk.white('   • Try again in a few minutes'));
+    console.error(chalk.white('   • Check if any firewall is blocking the request'));
+  }
+ 
+  // API key errors
+  if (
+    errorCode?.includes('API_KEY') ||
+    errorDetails?.includes('API key') ||
+    errorType === 'invalid_request_error'
+  ) {
+    console.error(chalk.yellow('   🔑 API key issue detected:'));
+    console.error(chalk.white('   • Run `berget api-keys list` to check your keys'));
+    console.error(
+      chalk.white('   • Create a new key with `berget api-keys create --name "My Key"`'),
+    );
+    console.error(chalk.white('   • Set a default key with `berget api-keys set-default <id>`'));
+    console.error(chalk.white('   • Check if your API key has expired'));
+  }
+ 
+  // Rate limiting
+  if (
+    errorCode === 'RATE_LIMIT_EXCEEDED' ||
+    errorDetails?.includes('rate limit') ||
+    errorDetails?.includes('too many requests')
+  ) {
+    console.error(chalk.yellow('   ⏱️  Rate limit exceeded:'));
+    console.error(chalk.white('   • Wait a few minutes before trying again'));
+    console.error(chalk.white('   • Consider upgrading your plan for higher limits'));
+    console.error(chalk.white('   • Use `berget billing get-usage` to check your usage'));
+  }
+ 
+  // Server errors
+  if (
+    errorCode?.includes('SERVER_ERROR') ||
+    errorType === 'server_error' ||
+    (errorCode && Number.parseInt(errorCode) >= 500)
+  ) {
+    console.error(chalk.yellow('   🖥️  Server issue detected:'));
+    console.error(chalk.white('   • This is a temporary problem on our end'));
+    console.error(chalk.white('   • Try again in a few minutes'));
+    console.error(chalk.white('   • Check status.berget.ai for service status'));
+    console.error(chalk.white('   • Contact support if the problem persists'));
+  }
+ 
+  // Cluster errors
+  if (errorCode?.includes('CLUSTERS') || errorDetails?.includes('cluster')) {
+    console.error(chalk.yellow('   🏗️  Cluster issue detected:'));
+    console.error(chalk.white('   • Clusters may be temporarily unavailable'));
+    console.error(chalk.white('   • Try again later or contact support'));
+    console.error(chalk.white('   • Check your cluster permissions'));
+  }
+ 
+  // Generic fallback
+  if (
+    !errorType?.includes('authentication') &&
+    !errorDetails?.includes('fetch failed') &&
+    !errorCode?.includes('API_KEY') &&
+    !errorCode?.includes('RATE_LIMIT') &&
+    !errorCode?.includes('SERVER_ERROR') &&
+    !errorCode?.includes('CLUSTERS')
+  ) {
+    console.error(chalk.yellow('   ❓ General issue:'));
+    console.error(chalk.white('   • Try running the command with --debug for more info'));
+    console.error(chalk.white('   • Check your configuration with `berget auth whoami`'));
+    console.error(chalk.white('   • Contact support if the problem persists'));
+  }
+ 
+  console.error(
+    chalk.dim('\nNeed more help? Visit https://docs.berget.ai or contact support@berget.ai'),
+  );
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/utils/index.html b/coverage/src/utils/index.html new file mode 100644 index 0000000..d8a1690 --- /dev/null +++ b/coverage/src/utils/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for src/utils + + + + + + + + + +
+
+

All files src/utils

+
+ +
+ 11.81% + Statements + 15/127 +
+ + +
+ 4.08% + Branches + 4/98 +
+ + +
+ 18.75% + Functions + 3/16 +
+ + +
+ 11.81% + Lines + 15/127 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
error-handler.ts +
+
0%0/620%0/580%0/20%0/62
logger.ts +
+
23.07%15/6510%4/4021.42%3/1423.07%15/65
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/utils/logger.ts.html b/coverage/src/utils/logger.ts.html new file mode 100644 index 0000000..d76d5fc --- /dev/null +++ b/coverage/src/utils/logger.ts.html @@ -0,0 +1,670 @@ + + + + + + Code coverage report for src/utils/logger.ts + + + + + + + + + +
+
+

All files / src/utils logger.ts

+
+ +
+ 23.07% + Statements + 15/65 +
+ + +
+ 10% + Branches + 4/40 +
+ + +
+ 21.42% + Functions + 3/14 +
+ + +
+ 23.07% + Lines + 15/65 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196  +  +  +  +  +1x +1x +1x +1x +1x +1x +  +  +1x +  +  +  +  +  +  +1x +  +  +  +1x +  +1x +  +1x +  +  +  +  +  +1x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x + 
import chalk from 'chalk';
+ 
+/**
+ * Log levels in order of increasing verbosity
+ */
+export enum LogLevel {
+  NONE = 0,
+  ERROR = 1,
+  WARN = 2,
+  INFO = 3,
+  DEBUG = 4,
+}
+ 
+const REDACTION = '[REDACTED]';
+ 
+/**
+ * Logger class for centralized logging with configurable log levels
+ */
+export class Logger {
+  private static instance: Logger;
+  private logLevel: LogLevel = LogLevel.INFO; // Default log level
+ 
+  private constructor() {
+    // Set log level from environment variable or command line argument
+    Iif (process.env.LOG_LEVEL) {
+      this.setLogLevelFromString(process.env.LOG_LEVEL);
+    } else Iif (process.argv.includes('--debug')) {
+      this.logLevel = LogLevel.DEBUG;
+    } else Iif (process.argv.includes('--quiet')) {
+      this.logLevel = LogLevel.ERROR;
+    }
+  }
+ 
+  public static getInstance(): Logger {
+    Eif (!Logger.instance) {
+      Logger.instance = new Logger();
+    }
+    return Logger.instance;
+  }
+ 
+  /**
+   * Log a debug message (only shown at DEBUG level).
+   * Automatically redacts known secrets from string arguments.
+   */
+  public debug(message: string, ...arguments_: any[]): void {
+    if (this.logLevel >= LogLevel.DEBUG) {
+      const redactedMessage = redactSecrets(message);
+      const redactedArgs = arguments_.map((arg) =>
+        typeof arg === 'string' ? redactSecrets(arg) : arg,
+      );
+      if (redactedArgs.length > 0) {
+        console.log(chalk.yellow(`DEBUG: ${redactedMessage}`), ...redactedArgs);
+      } else {
+        console.log(chalk.yellow(`DEBUG: ${redactedMessage}`));
+      }
+    }
+  }
+ 
+  /**
+   * Log an error message (shown at ERROR level and above)
+   */
+  public error(message: string, ...arguments_: any[]): void {
+    if (this.logLevel >= LogLevel.ERROR) {
+      if (arguments_.length > 0) {
+        console.error(chalk.red(message), ...arguments_);
+      } else {
+        console.error(chalk.red(message));
+      }
+    }
+  }
+ 
+  /**
+   * Get the current log level
+   */
+  public getLogLevel(): LogLevel {
+    return this.logLevel;
+  }
+ 
+  /**
+   * Log an info message (shown at INFO level and above)
+   */
+  public info(message: string, ...arguments_: any[]): void {
+    if (this.logLevel >= LogLevel.INFO) {
+      if (arguments_.length > 0) {
+        console.log(chalk.blue(message), ...arguments_);
+      } else {
+        console.log(chalk.blue(message));
+      }
+    }
+  }
+ 
+  /**
+   * Log a plain message without color (shown at INFO level and above)
+   */
+  public log(message: string, ...arguments_: any[]): void {
+    if (this.logLevel >= LogLevel.INFO) {
+      if (arguments_.length > 0) {
+        console.log(message, ...arguments_);
+      } else {
+        console.log(message);
+      }
+    }
+  }
+ 
+  /**
+   * Set the log level
+   */
+  public setLogLevel(level: LogLevel): void {
+    this.logLevel = level;
+  }
+ 
+  /**
+   * Log a success message (shown at INFO level and above)
+   */
+  public success(message: string, ...arguments_: any[]): void {
+    if (this.logLevel >= LogLevel.INFO) {
+      if (arguments_.length > 0) {
+        console.log(chalk.green(message), ...arguments_);
+      } else {
+        console.log(chalk.green(message));
+      }
+    }
+  }
+ 
+  /**
+   * Log a warning message (shown at WARN level and above)
+   */
+  public warn(message: string, ...arguments_: any[]): void {
+    if (this.logLevel >= LogLevel.WARN) {
+      if (arguments_.length > 0) {
+        console.log(chalk.yellow(message), ...arguments_);
+      } else {
+        console.log(chalk.yellow(message));
+      }
+    }
+  }
+ 
+  /**
+   * Set the log level from a string
+   */
+  private setLogLevelFromString(level: string): void {
+    switch (level.toLowerCase()) {
+      case 'debug': {
+        this.logLevel = LogLevel.DEBUG;
+        break;
+      }
+      case 'error': {
+        this.logLevel = LogLevel.ERROR;
+        break;
+      }
+      case 'info': {
+        this.logLevel = LogLevel.INFO;
+        break;
+      }
+      case 'none': {
+        this.logLevel = LogLevel.NONE;
+        break;
+      }
+      case 'warn': {
+        this.logLevel = LogLevel.WARN;
+        break;
+      }
+      default: {
+        // Invalid log level, keep default
+        console.warn(`Invalid log level: ${level}. Using default (INFO).`);
+      }
+    }
+  }
+}
+ 
+/**
+ * Redact known secret patterns from log strings.
+ * Handles Bearer tokens, URL query parameters (code, access_token,
+ * refresh_token), Berget API keys, and JWT-like strings.
+ */
+function redactSecrets(value: string): string {
+  let result = value;
+ 
+  // Bearer tokens
+  result = result.replace(/Bearer\s+\S+/gi, `Bearer ${REDACTION}`);
+ 
+  // URL query parameters: code=..., access_token=..., refresh_token=...
+  result = result.replace(/\b(code|access_token|refresh_token)=[^&\s]*/gi, `$1=${REDACTION}`);
+ 
+  // Berget API keys (sk_ber_*)
+  result = result.replace(/sk_ber_\w+/g, REDACTION);
+ 
+  // JWT-like strings (3 base64url segments separated by dots)
+  result = result.replace(/ey[A-Za-z0-9_-]*(?:\.[A-Za-z0-9_-]*){2,}/g, REDACTION);
+ 
+  return result;
+}
+ 
+// Export a singleton instance for easy import
+export const logger = Logger.getInstance();
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/src/commands/code/init.ts b/src/commands/code/init.ts index 98ccafa..44b93c3 100644 --- a/src/commands/code/init.ts +++ b/src/commands/code/init.ts @@ -83,76 +83,13 @@ export async function runInit(deps: WizardDeps): Promise { ], }); - // Check if the selected tool is installed const toolCheck = await checkTool(commands, tool); - let toolConfigured = toolCheck.installed; - - if (!toolCheck.installed) { - // Non-TTY guard: throw instead of exit so callers (including tests) - // can decide how to handle the failure. - if (isTty === false) { - throw new FatalError( - `${toolCheck.name} is not installed.\nInstall it first:\n ${toolCheck.installCommand}\nDocs: ${toolCheck.docsUrl}`, - ); - } - - const action = await promptForMissingTool(prompter, toolCheck); - - if (action === 'exit') { - throw new CancelledError(); - } - - if (action === 'retry') { - // Re-check once. If still missing, show prompt again. - const recheck = await checkTool(commands, tool); - if (recheck.installed) { - toolConfigured = true; - } else { - const secondAction = await promptForMissingTool(prompter, recheck); - if (secondAction === 'exit') throw new CancelledError(); - if (secondAction === 'continue') toolConfigured = false; - if (secondAction === 'retry') { - // One more check, then give up and treat as "continue" - const finalCheck = await checkTool(commands, tool); - toolConfigured = finalCheck.installed; - } - } - } - - if (action === 'continue') { - toolConfigured = false; - } - } + const toolConfigured = await resolveToolConfigured(commands, tool, toolCheck, isTty, prompter); const scope = await prompter.select<'global' | 'project'>({ initialValue: 'project', message: 'Where should the configuration apply?', - options: [ - { - hint: - tool === 'opencode' - ? ocState.project - ? 'Already configured' - : 'opencode.json in current directory' - : piState.project - ? 'Already configured' - : '.pi/settings.json in current directory', - label: 'This project only', - value: 'project', - }, - { - hint: - tool === 'opencode' - ? ocState.global - ? 'Already configured' - : '~/.config/opencode/opencode.json' - : piState.global - ? 'Already configured' - : '~/.pi/agent/settings.json', - label: 'Globally for all projects', - value: 'global', - }, - ], + options: buildScopeOptions(tool, ocState, piState), }); prompter.log('step', 'Configuring authentication...'); @@ -163,33 +100,11 @@ export async function runInit(deps: WizardDeps): Promise { cliAuth, ); - // Only configure the tool if it's installed (or user chose retry and it was found) if (toolConfigured) { - if (tool === 'opencode') { - await initOpenCode({ commands, cwd, files, homeDir, prompter, scope }); - await initOpenCodeAgents({ cwd, files, homeDir, prompter, scope }); - } else { - await initPi({ commands, cwd, files, homeDir, prompter, scope }); - await initPiAgent({ cwd, files, homeDir, prompter, scope }); - } + await configureTool(commands, cwd, files, homeDir, prompter, tool, scope); } - const nextSteps = toolConfigured - ? authResult.authenticated - ? tool === 'opencode' - ? "You're all set!\n\n1. Run: opencode\n2. Select model: /models" - : "You're all set!\n\n1. Restart Pi or run /reload\n2. Select model: /model" - : tool === 'opencode' - ? 'Next steps:\n\n1. Run: opencode\n2. Type: /connect\n3. Choose your auth method:\n • "Login with Berget" — Berget Code plan\n • "Enter Berget API Key manually"\n • (or set BERGET_API_KEY env var)\n4. Select model: /models' - : 'Next steps:\n\n1. Restart Pi or run /reload\n2. Type: /login\n3. Choose your auth method:\n • "Use a subscription" → Berget AI\n • (or set BERGET_API_KEY env var)\n4. Select model: /model' - : authResult.authenticated - ? tool === 'opencode' - ? `Auth is configured. Next steps:\n\n1. Install OpenCode:\n ${toolCheck.installCommand}\n2. Run: opencode\n3. Select model: /models` - : `Auth is configured. Next steps:\n\n1. Install Pi:\n ${toolCheck.installCommand}\n2. Run: pi\n3. Select model: /model` - : tool === 'opencode' - ? `Next steps:\n\n1. Install OpenCode:\n ${toolCheck.installCommand}\n2. Run: opencode\n3. Authenticate with Berget AI` - : `Next steps:\n\n1. Install Pi:\n ${toolCheck.installCommand}\n2. Run: pi\n3. Authenticate with Berget AI`; - + const nextSteps = buildNextSteps(tool, toolCheck, toolConfigured, authResult.authenticated); const toolName = tool === 'opencode' ? 'OpenCode' : 'Pi'; const docsUrl = tool === 'opencode' @@ -219,3 +134,127 @@ export async function runInitCommand(): Promise { if (result.stderr) console.error(result.stderr); process.exitCode = result.exitCode; } + +function buildNextSteps( + tool: 'opencode' | 'pi', + toolCheck: { installCommand: string }, + toolConfigured: boolean, + authenticated: boolean, +): string { + if (toolConfigured && authenticated) { + return tool === 'opencode' + ? "You're all set!\n\n1. Run: opencode\n2. Select model: /models" + : "You're all set!\n\n1. Restart Pi or run /reload\n2. Select model: /model"; + } + + if (toolConfigured && !authenticated) { + return tool === 'opencode' + ? 'Next steps:\n\n1. Run: opencode\n2. Type: /connect\n3. Choose your auth method:\n • "Login with Berget" — Berget Code plan\n • "Enter Berget API Key manually"\n • (or set BERGET_API_KEY env var)\n4. Select model: /models' + : 'Next steps:\n\n1. Restart Pi or run /reload\n2. Type: /login\n3. Choose your auth method:\n • "Use a subscription" → Berget AI\n • (or set BERGET_API_KEY env var)\n4. Select model: /model'; + } + + if (!toolConfigured && authenticated) { + return tool === 'opencode' + ? `Auth is configured. Next steps:\n\n1. Install OpenCode:\n ${toolCheck.installCommand}\n2. Run: opencode\n3. Select model: /models` + : `Auth is configured. Next steps:\n\n1. Install Pi:\n ${toolCheck.installCommand}\n2. Run: pi\n3. Select model: /model`; + } + + return tool === 'opencode' + ? `Next steps:\n\n1. Install OpenCode:\n ${toolCheck.installCommand}\n2. Run: opencode\n3. Authenticate with Berget AI` + : `Next steps:\n\n1. Install Pi:\n ${toolCheck.installCommand}\n2. Run: pi\n3. Authenticate with Berget AI`; +} + +function buildScopeOptions( + tool: 'opencode' | 'pi', + ocState: { global: boolean; project: boolean }, + piState: { global: boolean; project: boolean }, +): Array<{ hint: string; label: string; value: 'global' | 'project' }> { + const projectHint = + tool === 'opencode' + ? ocState.project + ? 'Already configured' + : 'opencode.json in current directory' + : piState.project + ? 'Already configured' + : '.pi/settings.json in current directory'; + + const globalHint = + tool === 'opencode' + ? ocState.global + ? 'Already configured' + : '~/.config/opencode/opencode.json' + : piState.global + ? 'Already configured' + : '~/.pi/agent/settings.json'; + + return [ + { hint: projectHint, label: 'This project only', value: 'project' }, + { hint: globalHint, label: 'Globally for all projects', value: 'global' }, + ]; +} + +async function configureTool( + commands: CommandRunner, + cwd: string, + files: FileStore, + homeDir: string, + prompter: Prompter, + tool: 'opencode' | 'pi', + scope: 'global' | 'project', +): Promise { + if (tool === 'opencode') { + await initOpenCode({ commands, cwd, files, homeDir, prompter, scope }); + await initOpenCodeAgents({ cwd, files, homeDir, prompter, scope }); + } else { + await initPi({ commands, cwd, files, homeDir, prompter, scope }); + await initPiAgent({ cwd, files, homeDir, prompter, scope }); + } +} + +async function resolveToolConfigured( + commands: CommandRunner, + tool: 'opencode' | 'pi', + toolCheck: { + description: string; + docsUrl: string; + installCommand: string; + installed: boolean; + name: string; + }, + isTty: boolean | undefined, + prompter: Prompter, +): Promise { + if (toolCheck.installed) { + return true; + } + + if (isTty === false) { + throw new FatalError( + `${toolCheck.name} is not installed.\nInstall it first:\n ${toolCheck.installCommand}\nDocs: ${toolCheck.docsUrl}`, + ); + } + + const action = await promptForMissingTool(prompter, toolCheck); + + if (action === 'exit') { + throw new CancelledError(); + } + + if (action === 'continue') { + return false; + } + + // action === 'retry' + const recheck = await checkTool(commands, tool); + if (recheck.installed) { + return true; + } + + const secondAction = await promptForMissingTool(prompter, recheck); + if (secondAction === 'exit') throw new CancelledError(); + if (secondAction === 'continue') return false; + + // secondAction === 'retry' + const finalCheck = await checkTool(commands, tool); + return finalCheck.installed; +} From 517d8e33c9001f1de633ed551f48df1b5fe434a0 Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Wed, 3 Jun 2026 03:27:29 +0200 Subject: [PATCH 4/8] refactor(commands/chat): reduce cognitive complexity from 79 to 25 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract resolveApiKey() for API key resolution logic - Extract resolveApiKeyFromId() for API key ID → key rotation - Extract resolveApiKeyForList() for list command key resolution - Extract resolveInputMessage() for stdin + argument combining - Extract verifyAuthentication() for auth check - Extract buildCompletionOptions() for options construction - Extract runSingleShotChat() for non-interactive chat - Extract runInteractiveChat() with createAskQuestion() for interactive mode - Extract runInteractiveStreaming() and runInteractiveNonStreaming() - Extract handleStreamingCompletion() and handleNonStreamingCompletion() - Extract displayResponse() and displayModels() for output formatting - Reorder functions alphabetically per perfectionist/sort-modules --- src/commands/chat.ts | 963 +++++++++++++++++------------------- tests/commands/chat.test.ts | 4 +- 2 files changed, 455 insertions(+), 512 deletions(-) diff --git a/src/commands/chat.ts b/src/commands/chat.ts index b2110b4..b99ba74 100644 --- a/src/commands/chat.ts +++ b/src/commands/chat.ts @@ -22,7 +22,6 @@ export function registerChatCommands(program: Command): void { .description('Run a chat session with a specified model') .argument('[message]', 'Message to send directly (skips interactive mode)') .option('-m, --model ', 'Model to use (default: kimi-k2.6)') - .option('-t, --temperature ', 'Temperature (0-1)', Number.parseFloat) .option('--max-tokens ', 'Maximum tokens to generate', Number.parseInt) .option('-k, --api-key ', 'API key to use for this chat session') @@ -30,454 +29,25 @@ export function registerChatCommands(program: Command): void { .option('--no-stream', 'Disable streaming (streaming is enabled by default)') .action(async (message, options) => { try { - const chatService = ChatService.getInstance(); - - // Check if we have an API key or need to get one - let apiKey = options.apiKey; - let apiKeyId = options.apiKeyId; - - // Check for environment variable first - const environmentApiKey = process.env.BERGET_API_KEY; - if (environmentApiKey) { - console.log(chalk.dim(`Using API key from BERGET_API_KEY environment variable`)); - apiKey = environmentApiKey; - - // Debug the API key (first few characters only) - if (process.argv.includes('--debug')) { - console.log( - chalk.yellow( - `DEBUG: API key from env starts with: ${environmentApiKey.slice(0, 4)}...`, - ), - ); - } - } - // If API key is already provided via command line, use it - else if (options.apiKey) { - console.log(chalk.dim(`Using API key from command line argument`)); - apiKey = options.apiKey; - } - // If no API key or API key ID provided and no env var, check for default API key - else if (!apiKey && !apiKeyId) { - try { - const defaultApiKeyManager = DefaultApiKeyManager.getInstance(); - const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData(); - - if (defaultApiKeyData) { - apiKeyId = defaultApiKeyData.id; - apiKey = defaultApiKeyData.key; - - if (apiKey) { - console.log(chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)); - } else { - console.log( - chalk.yellow( - `Default API key "${defaultApiKeyData.name}" exists but the key value is missing.`, - ), - ); - console.log( - chalk.yellow( - `Try rotating the key with: berget api-keys rotate ${defaultApiKeyData.id}`, - ), - ); - } - } else { - // No default API key, prompt the user to create one - console.log(chalk.yellow('No default API key set.')); - - // Try to prompt for a default API key - apiKey = await defaultApiKeyManager.promptForDefaultApiKey(); - - if (!apiKey) { - console.log(chalk.red('Error: An API key is required to use the chat command.')); - console.log(chalk.yellow('You can:')); - console.log( - chalk.yellow('1. Create an API key with: berget api-keys create --name "My Key"'), - ); - console.log( - chalk.yellow('2. Set a default API key with: berget api-keys set-default '), - ); - console.log(chalk.yellow('3. Provide an API key with the --api-key option')); - return; - } - } - } catch (error) { - if (process.argv.includes('--debug')) { - console.log(chalk.yellow('DEBUG: Error checking default API key:')); - console.log(chalk.yellow(String(error))); - } - } - } + let apiKey = await resolveApiKey(options); - // If no direct API key, try to get one from API key ID - if (!apiKey && apiKeyId) { - try { - const apiKeyService = ApiKeyService.getInstance(); - const keys = await apiKeyService.list(); - const selectedKey = keys.find((key) => key.id.toString() === options.apiKeyId); - - if (selectedKey) { - console.log(chalk.dim(`Using API key: ${selectedKey.name}`)); - - // We need to rotate the key to get the actual key value - const shouldRotate = await clackConfirm({ - message: `To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue?`, - }); - if (isCancel(shouldRotate)) { - console.log(chalk.yellow('Operation cancelled.')); - return; - } - if (shouldRotate) { - const rotatedKey = await apiKeyService.rotate(options.apiKeyId); - apiKey = rotatedKey.key; - console.log(chalk.green(`API key "${selectedKey.name}" rotated successfully.`)); - } else { - console.log(chalk.yellow('Using default authentication instead.')); - } - } else { - console.log( - chalk.yellow( - `API key with ID ${options.apiKeyId} not found. Using default authentication.`, - ), - ); - } - } catch (error) { - // Check if this is an authentication error - const errorMessage = error instanceof Error ? error.message : String(error); - const isAuthError = - errorMessage.includes('Unauthorized') || - errorMessage.includes('Authentication failed') || - errorMessage.includes('AUTH_FAILED'); - - if (isAuthError) { - console.log( - chalk.yellow('Authentication required. Please run `berget auth login` first.'), - ); - } else { - console.error(chalk.red('Error fetching API key:')); - console.error(error); - } - console.log(chalk.yellow('Using default authentication instead.')); - } + if (!apiKey && options.apiKeyId) { + apiKey = await resolveApiKeyFromId(options.apiKeyId); } - // Verify we have authentication before starting chat - if (!apiKey) { - try { - AuthService.getInstance(); - } catch { - console.log(chalk.red('Error: Authentication required for chat')); - console.log(chalk.yellow('Please either:')); - console.log(chalk.yellow('1. Log in with `berget auth login`')); - console.log(chalk.yellow('2. Provide an API key with `--api-key`')); - console.log(chalk.yellow('3. Provide an API key ID with `--api-key-id`')); - console.log( - chalk.yellow('4. Set a default API key with `berget api-keys set-default `'), - ); - return; - } + if (!(await verifyAuthentication(apiKey))) { + return; } - // Prepare messages array const messages: ChatMessage[] = []; + const inputMessage = await resolveInputMessage(message); - // Add system message if provided - if (options.system) { - messages.push({ - content: options.system, - role: 'system', - }); - } - - // Check if input is being piped in - let inputMessage = message; - let stdinContent = ''; - - if (!process.stdin.isTTY) { - // Read from stdin (piped input) - const chunks = []; - for await (const chunk of process.stdin) { - chunks.push(chunk); - } - stdinContent = Buffer.concat(chunks).toString('utf8').trim(); - } - - // Combine stdin content with message if both exist - if (stdinContent && message) { - inputMessage = `${stdinContent}\n\n${message}`; - } else if (stdinContent && !message) { - inputMessage = stdinContent; - } - - // If a message is provided (either as argument, from stdin, or both), send it directly and exit if (inputMessage) { - // Add user message - messages.push({ - content: inputMessage, - role: 'user', - }); - - try { - // Call the API - const completionOptions: ChatCompletionOptions = { - max_tokens: options.maxTokens || 4096, - messages: messages, - model: options.model || 'openai/gpt-oss', - stream: options.stream !== false, - temperature: options.temperature === undefined ? 0.7 : options.temperature, - }; - - // Only add apiKey if it actually exists - if (apiKey) { - completionOptions.apiKey = apiKey; - } - - // Add streaming support (now default) - if (completionOptions.stream) { - let assistantResponse = ''; - - // Stream the response in real-time - completionOptions.onChunk = (chunk: any) => { - if ( - chunk.choices && - chunk.choices[0] && - chunk.choices[0].delta && - chunk.choices[0].delta.content - ) { - const content = chunk.choices[0].delta.content; - try { - process.stdout.write(content); - } catch (error: any) { - // Handle EPIPE errors gracefully (when pipe is closed) - if (error.code === 'EPIPE') { - // Stop streaming if the pipe is closed - return; - } - throw error; - } - assistantResponse += content; - } - }; - - try { - await chatService.createCompletion(completionOptions); - } catch (streamError) { - console.error(chalk.red('\nStreaming error:'), streamError); - - // Fallback to non-streaming if streaming fails - console.log(chalk.yellow('Falling back to non-streaming mode...')); - completionOptions.stream = false; - delete completionOptions.onChunk; - - const response = await chatService.createCompletion(completionOptions); - - if ( - response && - response.choices && - response.choices[0] && - response.choices[0].message - ) { - assistantResponse = response.choices[0].message.content; - console.log(assistantResponse); - } - } - console.log(); // Add newline at the end - return; - } - - const response = await chatService.createCompletion(completionOptions); - - // Check if response has the expected structure - if ( - !response || - !response.choices || - !response.choices[0] || - !response.choices[0].message - ) { - console.error(chalk.red('Error: Unexpected response format from API')); - console.error(chalk.red('Response:', JSON.stringify(response, null, 2))); - throw new Error('Unexpected response format from API'); - } - - // Get assistant's response - const assistantMessage = response.choices[0].message.content; - - // Display the response - if (containsMarkdown(assistantMessage)) { - console.log(renderMarkdown(assistantMessage)); - } else { - console.log(assistantMessage); - } - - return; - } catch (error) { - console.error(chalk.red('Error: Failed to get response')); - if (error instanceof Error) { - console.error(chalk.red(error.message)); - } - process.exitCode = 1; - return; - } + await runSingleShotChat(inputMessage, options, apiKey); + return; } - // Set up readline interface for user input (only for interactive mode) - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - - console.log(chalk.cyan('Chat with Berget AI (type "exit" to quit)')); - console.log(chalk.cyan('----------------------------------------')); - - // Start the conversation loop - const askQuestion = () => { - rl.question(chalk.green('You: '), async (input) => { - // Check if user wants to exit - if (input.toLowerCase() === 'exit') { - console.log(chalk.cyan('Goodbye!')); - rl.close(); - return; - } - - // Add user message - messages.push({ - content: input, - role: 'user', - }); - - try { - // Call the API - const completionOptions: ChatCompletionOptions = { - max_tokens: options.maxTokens || 4096, - messages: messages, - model: options.model || 'openai/gpt-oss', - stream: options.stream !== false, - temperature: options.temperature === undefined ? 0.7 : options.temperature, - }; - - // Only add apiKey if it actually exists - if (apiKey) { - completionOptions.apiKey = apiKey; - } - - // Add streaming support (now default) - if (completionOptions.stream) { - let assistantResponse = ''; - console.log(chalk.blue('Assistant: ')); - - // Stream the response in real-time - completionOptions.onChunk = (chunk: any) => { - if ( - chunk.choices && - chunk.choices[0] && - chunk.choices[0].delta && - chunk.choices[0].delta.content - ) { - const content = chunk.choices[0].delta.content; - try { - process.stdout.write(content); - } catch (error: any) { - // Handle EPIPE errors gracefully (when pipe is closed) - if (error.code === 'EPIPE') { - // Stop streaming if the pipe is closed - return; - } - throw error; - } - assistantResponse += content; - } - }; - - try { - await chatService.createCompletion(completionOptions); - } catch (streamError) { - console.error(chalk.red('\nStreaming error:'), streamError); - - // Fallback to non-streaming if streaming fails - console.log(chalk.yellow('Falling back to non-streaming mode...')); - completionOptions.stream = false; - delete completionOptions.onChunk; - - const response = await chatService.createCompletion(completionOptions); - - if ( - response && - response.choices && - response.choices[0] && - response.choices[0].message - ) { - assistantResponse = response.choices[0].message.content; - console.log(assistantResponse); - } - } - console.log('\n'); - - // Add assistant response to messages - messages.push({ - content: assistantResponse, - role: 'assistant', - }); - - // Continue the conversation - askQuestion(); - return; - } - - const response = await chatService.createCompletion(completionOptions); - - // Debug output - if (program.opts().debug) { - console.log(chalk.yellow('DEBUG: Full response:')); - console.log(chalk.yellow(JSON.stringify(response, null, 2))); - } - - // Check if response has the expected structure - if ( - !response || - !response.choices || - !response.choices[0] || - !response.choices[0].message - ) { - console.error(chalk.red('Error: Unexpected response format from API')); - console.error(chalk.red('Response:', JSON.stringify(response, null, 2))); - throw new Error('Unexpected response format from API'); - } - - // Get assistant's response - const assistantMessage = response.choices[0].message.content; - - // Add to messages array - messages.push({ - content: assistantMessage, - role: 'assistant', - }); - - // Display the response - console.log(chalk.blue('Assistant: ')); - - // Check if the response contains markdown and render it if it does - if (containsMarkdown(assistantMessage)) { - console.log(renderMarkdown(assistantMessage)); - } else { - console.log(assistantMessage); - } - - console.log(); // Empty line for better readability - - // Continue the conversation - askQuestion(); - } catch (error) { - console.error(chalk.red('Error: Failed to get response')); - if (error instanceof Error) { - console.error(chalk.red(error.message)); - } - // Continue despite error - askQuestion(); - } - }); - }; - - // Start the conversation - askQuestion(); + await runInteractiveChat(options, apiKey, messages); } catch (error) { handleError('Failed to create chat completion', error); } @@ -490,89 +60,464 @@ export function registerChatCommands(program: Command): void { .option('--api-key-id ', 'ID of the API key to use from your saved keys') .action(async (options) => { try { - // If API key ID is provided, fetch the actual key - let apiKey = options.apiKey; - let apiKeyId = options.apiKeyId; - - // If no API key or API key ID provided, check for default API key - if (!apiKey && !apiKeyId) { - const defaultApiKeyManager = DefaultApiKeyManager.getInstance(); - const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData(); - - if (defaultApiKeyData) { - apiKeyId = defaultApiKeyData.id; - console.log(chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)); - } - } - - if (apiKeyId && !apiKey) { - try { - const apiKeyService = ApiKeyService.getInstance(); - const keys = await apiKeyService.list(); - const selectedKey = keys.find((key) => key.id.toString() === options.apiKeyId); - - if (selectedKey) { - console.log(chalk.dim(`Using API key: ${selectedKey.name}`)); - - // We need to rotate the key to get the actual key value - const shouldRotate = await clackConfirm({ - message: `To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue?`, - }); - if (isCancel(shouldRotate)) { - console.log(chalk.yellow('Operation cancelled.')); - return; - } - if (shouldRotate) { - const rotatedKey = await apiKeyService.rotate(options.apiKeyId); - apiKey = rotatedKey.key; - console.log(chalk.green(`API key "${selectedKey.name}" rotated successfully.`)); - } else { - console.log(chalk.yellow('Using default authentication instead.')); - } - } else { - console.log( - chalk.yellow( - `API key with ID ${options.apiKeyId} not found. Using default authentication.`, - ), - ); - } - } catch (error) { - console.error(chalk.red('Error fetching API key:')); - console.error(error); - console.log(chalk.yellow('Using default authentication instead.')); - } - } - + const apiKey = await resolveApiKeyForList(options); const chatService = ChatService.getInstance(); const models = await chatService.listModels(apiKey); - // Debug output if (program.opts().debug) { console.log(chalk.yellow('DEBUG: Models response:')); console.log(chalk.yellow(JSON.stringify(models, null, 2))); } - console.log(chalk.bold('Available Chat Models:')); - console.log(chalk.dim('─'.repeat(70))); - console.log(chalk.dim('MODEL ID'.padEnd(40)) + chalk.dim('CAPABILITIES')); - console.log(chalk.dim('─'.repeat(70))); + displayModels(models); + } catch (error) { + handleError('Failed to list chat models', error); + } + }); +} + +function buildCompletionOptions( + options: any, + messages: ChatMessage[], + apiKey: string | undefined, +): ChatCompletionOptions { + const completionOptions: ChatCompletionOptions = { + max_tokens: options.maxTokens || 4096, + messages: messages, + model: options.model || 'openai/gpt-oss', + stream: options.stream !== false, + temperature: options.temperature === undefined ? 0.7 : options.temperature, + }; + + if (apiKey) { + completionOptions.apiKey = apiKey; + } + + return completionOptions; +} + +function createAskQuestion( + rl: readline.Interface, + messages: ChatMessage[], + apiKey: string | undefined, + options: any, + chatService: ChatService, +): () => void { + return () => { + rl.question(chalk.green('You: '), async (input) => { + if (input.toLowerCase() === 'exit') { + console.log(chalk.cyan('Goodbye!')); + rl.close(); + return; + } - // Filter to only show active models - const activeModels = models.data.filter((model: any) => model.active === true); + messages.push({ content: input, role: 'user' }); - activeModels.forEach((model: any) => { - const capabilities = []; - if (model.capabilities.vision) capabilities.push('vision'); - if (model.capabilities.function_calling) capabilities.push('function_calling'); - if (model.capabilities.json_mode) capabilities.push('json_mode'); + try { + const completionOptions = buildCompletionOptions(options, messages, apiKey); - // Format model ID in Huggingface compatible format (owner/model) - const modelId = `${model.owned_by.toLowerCase()}/${model.id}`.padEnd(40); + if (completionOptions.stream) { + await runInteractiveStreaming(chatService, completionOptions, messages); + } else { + await runInteractiveNonStreaming(chatService, completionOptions, messages); + } - console.log(modelId + capabilities.join(', ')); - }); + createAskQuestion(rl, messages, apiKey, options, chatService)(); } catch (error) { - handleError('Failed to list chat models', error); + console.error(chalk.red('Error: Failed to get response')); + if (error instanceof Error) { + console.error(chalk.red(error.message)); + } + createAskQuestion(rl, messages, apiKey, options, chatService)(); + } + }); + }; +} + +function displayModels(models: any): void { + console.log(chalk.bold('Available Chat Models:')); + console.log(chalk.dim('─'.repeat(70))); + console.log(chalk.dim('MODEL ID'.padEnd(40)) + chalk.dim('CAPABILITIES')); + console.log(chalk.dim('─'.repeat(70))); + + const activeModels = models.data.filter((model: any) => model.active === true); + + for (const model of activeModels) { + const capabilities = []; + if (model.capabilities.vision) capabilities.push('vision'); + if (model.capabilities.function_calling) capabilities.push('function_calling'); + if (model.capabilities.json_mode) capabilities.push('json_mode'); + + const modelId = `${model.owned_by.toLowerCase()}/${model.id}`.padEnd(40); + console.log(modelId + capabilities.join(', ')); + } +} + +async function displayResponse(response: any): Promise { + if (!response || !response.choices || !response.choices[0] || !response.choices[0].message) { + console.error(chalk.red('Error: Unexpected response format from API')); + console.error(chalk.red('Response:', JSON.stringify(response, null, 2))); + throw new Error('Unexpected response format from API'); + } + + const assistantMessage = response.choices[0].message.content; + if (containsMarkdown(assistantMessage)) { + console.log(renderMarkdown(assistantMessage)); + } else { + console.log(assistantMessage); + } +} + +async function handleNonStreamingCompletion( + chatService: ChatService, + completionOptions: ChatCompletionOptions, +): Promise { + const response = await chatService.createCompletion(completionOptions); + await displayResponse(response); +} + +async function handleStreamingCompletion( + chatService: ChatService, + completionOptions: ChatCompletionOptions, +): Promise { + let assistantResponse = ''; + + completionOptions.onChunk = (chunk: any) => { + if ( + chunk.choices && + chunk.choices[0] && + chunk.choices[0].delta && + chunk.choices[0].delta.content + ) { + const content = chunk.choices[0].delta.content; + try { + process.stdout.write(content); + } catch (error: any) { + if (error.code === 'EPIPE') { + return; + } + throw error; + } + assistantResponse += content; + } + }; + + try { + await chatService.createCompletion(completionOptions); + } catch (streamError) { + console.error(chalk.red('\nStreaming error:'), streamError); + console.log(chalk.yellow('Falling back to non-streaming mode...')); + completionOptions.stream = false; + delete completionOptions.onChunk; + + const response = await chatService.createCompletion(completionOptions); + if (response && response.choices && response.choices[0] && response.choices[0].message) { + assistantResponse = response.choices[0].message.content; + console.log(assistantResponse); + } + } + + console.log(); +} + +async function resolveApiKey(options: any): Promise { + let apiKey = options.apiKey; + + const environmentApiKey = process.env.BERGET_API_KEY; + if (environmentApiKey) { + console.log(chalk.dim('Using API key from BERGET_API_KEY environment variable')); + apiKey = environmentApiKey; + + if (process.argv.includes('--debug')) { + console.log( + chalk.yellow(`DEBUG: API key from env starts with: ${environmentApiKey.slice(0, 4)}...`), + ); + } + return apiKey; + } + + if (options.apiKey) { + console.log(chalk.dim('Using API key from command line argument')); + return options.apiKey; + } + + if (!apiKey && !options.apiKeyId) { + try { + const defaultApiKeyManager = DefaultApiKeyManager.getInstance(); + const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData(); + + if (defaultApiKeyData) { + if (defaultApiKeyData.key) { + console.log(chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)); + return defaultApiKeyData.key; + } else { + console.log( + chalk.yellow( + `Default API key "${defaultApiKeyData.name}" exists but the key value is missing.`, + ), + ); + console.log( + chalk.yellow( + `Try rotating the key with: berget api-keys rotate ${defaultApiKeyData.id}`, + ), + ); + } + } else { + console.log(chalk.yellow('No default API key set.')); + apiKey = await defaultApiKeyManager.promptForDefaultApiKey(); + + if (!apiKey) { + console.log(chalk.red('Error: An API key is required to use the chat command.')); + console.log(chalk.yellow('You can:')); + console.log( + chalk.yellow('1. Create an API key with: berget api-keys create --name "My Key"'), + ); + console.log( + chalk.yellow('2. Set a default API key with: berget api-keys set-default '), + ); + console.log(chalk.yellow('3. Provide an API key with the --api-key option')); + return undefined; + } + } + } catch (error) { + if (process.argv.includes('--debug')) { + console.log(chalk.yellow('DEBUG: Error checking default API key:')); + console.log(chalk.yellow(String(error))); } + } + } + + return apiKey; +} + +async function resolveApiKeyForList(options: any): Promise { + const apiKey = options.apiKey; + let apiKeyId = options.apiKeyId; + + if (!apiKey && !apiKeyId) { + const defaultApiKeyManager = DefaultApiKeyManager.getInstance(); + const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData(); + + if (defaultApiKeyData) { + apiKeyId = defaultApiKeyData.id; + console.log(chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)); + } + } + + if (apiKeyId && !apiKey) { + return resolveApiKeyFromId(apiKeyId); + } + + return apiKey; +} + +async function resolveApiKeyFromId(apiKeyId: string): Promise { + try { + const apiKeyService = ApiKeyService.getInstance(); + const keys = await apiKeyService.list(); + const selectedKey = keys.find((key) => key.id.toString() === apiKeyId); + + if (!selectedKey) { + console.log( + chalk.yellow(`API key with ID ${apiKeyId} not found. Using default authentication.`), + ); + return undefined; + } + + console.log(chalk.dim(`Using API key: ${selectedKey.name}`)); + + const shouldRotate = await clackConfirm({ + message: `To use API key "${selectedKey.name}", it needs to be rotated. This will invalidate the current key. Continue?`, }); + if (isCancel(shouldRotate)) { + console.log(chalk.yellow('Operation cancelled.')); + return undefined; + } + + if (shouldRotate) { + const rotatedKey = await apiKeyService.rotate(apiKeyId); + console.log(chalk.green(`API key "${selectedKey.name}" rotated successfully.`)); + return rotatedKey.key; + } else { + console.log(chalk.yellow('Using default authentication instead.')); + return undefined; + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + const isAuthError = + errorMessage.includes('Unauthorized') || + errorMessage.includes('Authentication failed') || + errorMessage.includes('AUTH_FAILED'); + + if (isAuthError) { + console.log(chalk.yellow('Authentication required. Please run `berget auth login` first.')); + } else { + console.error(chalk.red('Error fetching API key:')); + console.error(error); + } + console.log(chalk.yellow('Using default authentication instead.')); + return undefined; + } +} + +async function resolveInputMessage(message: string | undefined): Promise { + let inputMessage = message; + let stdinContent = ''; + + if (!process.stdin.isTTY) { + const chunks = []; + for await (const chunk of process.stdin) { + chunks.push(chunk); + } + stdinContent = Buffer.concat(chunks).toString('utf8').trim(); + } + + if (stdinContent && message) { + inputMessage = `${stdinContent}\n\n${message}`; + } else if (stdinContent && !message) { + inputMessage = stdinContent; + } + + return inputMessage; +} + +async function runInteractiveChat( + options: any, + apiKey: string | undefined, + messages: ChatMessage[], +): Promise { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + console.log(chalk.cyan('Chat with Berget AI (type "exit" to quit)')); + console.log(chalk.cyan('----------------------------------------')); + + const chatService = ChatService.getInstance(); + const askQuestion = createAskQuestion(rl, messages, apiKey, options, chatService); + askQuestion(); +} + +async function runInteractiveNonStreaming( + chatService: ChatService, + completionOptions: ChatCompletionOptions, + messages: ChatMessage[], +): Promise { + const response = await chatService.createCompletion(completionOptions); + + if (!response || !response.choices || !response.choices[0] || !response.choices[0].message) { + console.error(chalk.red('Error: Unexpected response format from API')); + console.error(chalk.red('Response:', JSON.stringify(response, null, 2))); + throw new Error('Unexpected response format from API'); + } + + const assistantMessage = response.choices[0].message.content; + messages.push({ content: assistantMessage, role: 'assistant' }); + + console.log(chalk.blue('Assistant: ')); + if (containsMarkdown(assistantMessage)) { + console.log(renderMarkdown(assistantMessage)); + } else { + console.log(assistantMessage); + } + + console.log(); +} + +async function runInteractiveStreaming( + chatService: ChatService, + completionOptions: ChatCompletionOptions, + messages: ChatMessage[], +): Promise { + let assistantResponse = ''; + console.log(chalk.blue('Assistant: ')); + + completionOptions.onChunk = (chunk: any) => { + if ( + chunk.choices && + chunk.choices[0] && + chunk.choices[0].delta && + chunk.choices[0].delta.content + ) { + const content = chunk.choices[0].delta.content; + try { + process.stdout.write(content); + } catch (error: any) { + if (error.code === 'EPIPE') { + return; + } + throw error; + } + assistantResponse += content; + } + }; + + try { + await chatService.createCompletion(completionOptions); + } catch (streamError) { + console.error(chalk.red('\nStreaming error:'), streamError); + console.log(chalk.yellow('Falling back to non-streaming mode...')); + completionOptions.stream = false; + delete completionOptions.onChunk; + + const response = await chatService.createCompletion(completionOptions); + if (response && response.choices && response.choices[0] && response.choices[0].message) { + assistantResponse = response.choices[0].message.content; + console.log(assistantResponse); + } + } + + console.log('\n'); + messages.push({ content: assistantResponse, role: 'assistant' }); +} + +async function runSingleShotChat( + inputMessage: string, + options: any, + apiKey: string | undefined, +): Promise { + const messages: ChatMessage[] = []; + + if (options.system) { + messages.push({ content: options.system, role: 'system' }); + } + + messages.push({ content: inputMessage, role: 'user' }); + + try { + const chatService = ChatService.getInstance(); + const completionOptions = buildCompletionOptions(options, messages, apiKey); + + if (completionOptions.stream) { + await handleStreamingCompletion(chatService, completionOptions); + } else { + await handleNonStreamingCompletion(chatService, completionOptions); + } + } catch (error) { + console.error(chalk.red('Error: Failed to get response')); + if (error instanceof Error) { + console.error(chalk.red(error.message)); + } + process.exitCode = 1; + } +} + +async function verifyAuthentication(apiKey: string | undefined): Promise { + if (apiKey) { + return true; + } + + try { + AuthService.getInstance(); + return true; + } catch { + console.log(chalk.red('Error: Authentication required for chat')); + console.log(chalk.yellow('Please either:')); + console.log(chalk.yellow('1. Log in with `berget auth login`')); + console.log(chalk.yellow('2. Provide an API key with `--api-key`')); + console.log(chalk.yellow('3. Provide an API key ID with `--api-key-id`')); + console.log(chalk.yellow('4. Set a default API key with `berget api-keys set-default `')); + return false; + } } diff --git a/tests/commands/chat.test.ts b/tests/commands/chat.test.ts index 0a41f72..8ad3d4e 100644 --- a/tests/commands/chat.test.ts +++ b/tests/commands/chat.test.ts @@ -42,6 +42,7 @@ describe('Chat Commands', () => { afterEach(() => { vi.clearAllMocks(); + delete process.env.BERGET_API_KEY; }); describe('chat run command', () => { @@ -85,9 +86,6 @@ describe('Chat Commands', () => { // but since it involves readline interaction, we just verify // that the service would be called with correct defaults expect(mockChatService.createCompletion).not.toHaveBeenCalled(); - - // Clean up - delete process.env.BERGET_API_KEY; }); }); From 4b1d4cae5ae97a7514d9c8b7d41d2d72679457c1 Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:14:54 +0200 Subject: [PATCH 5/8] =?UTF-8?q?refactor(chat-service):=20reduce=20createCo?= =?UTF-8?q?mpletion=20and=20listModels=20complexity=20to=20=E2=89=A415?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract logCompletionOptions() for debug logging - Extract formatCompletionError() and formatListModelsError() - All 16 tests pass --- coverage/clover.xml | 1217 +---------------- coverage/coverage-final.json | 39 +- coverage/index.html | 202 +-- coverage/src/agents/app.ts.html | 166 --- coverage/src/agents/backend.ts.html | 157 --- coverage/src/agents/devops.ts.html | 184 --- coverage/src/agents/frontend.ts.html | 157 --- coverage/src/agents/fullstack.ts.html | 157 --- coverage/src/agents/index.html | 221 --- coverage/src/agents/index.ts.html | 304 ---- coverage/src/agents/quality.ts.html | 292 ---- coverage/src/agents/security.ts.html | 163 --- coverage/src/auth/config.ts.html | 217 --- coverage/src/auth/index.html | 146 -- coverage/src/auth/issuer.ts.html | 187 --- coverage/src/auth/jwt.ts.html | 274 ---- .../auth/middleware/auth-middleware.ts.html | 202 --- coverage/src/auth/middleware/index.html | 116 -- .../src/auth/oauth/callback-pages.ts.html | 472 ------- coverage/src/auth/oauth/index.html | 146 -- coverage/src/auth/oauth/pkce-flow.ts.html | 826 ----------- coverage/src/auth/oauth/token-refresh.ts.html | 463 ------- coverage/src/auth/storage/index.html | 116 -- coverage/src/auth/storage/token-store.ts.html | 328 ----- coverage/src/client.ts.html | 208 --- .../__tests__/fake-api-key-service.ts.html | 145 -- .../code/__tests__/fake-auth-service.ts.html | 241 ---- .../__tests__/fake-command-runner.ts.html | 235 ---- .../code/__tests__/fake-file-store.ts.html | 217 --- .../code/__tests__/fake-prompter.ts.html | 502 ------- .../src/commands/code/__tests__/index.html | 176 --- .../code/adapters/clack-prompter.ts.html | 316 ----- .../code/adapters/fs-file-store.ts.html | 199 --- .../src/commands/code/adapters/index.html | 146 -- .../adapters/spawn-command-runner.ts.html | 220 --- coverage/src/commands/code/auth-sync.ts.html | 1066 --------------- coverage/src/commands/code/errors.ts.html | 175 --- coverage/src/commands/code/index.html | 206 --- coverage/src/commands/code/init.ts.html | 748 ---------- coverage/src/commands/code/opencode.ts.html | 931 ------------- coverage/src/commands/code/pi.ts.html | 628 --------- coverage/src/commands/code/tool-check.ts.html | 319 ----- coverage/src/commands/code/utils.ts.html | 172 --- .../src/constants/command-structure.ts.html | 715 ---------- coverage/src/constants/index.html | 116 -- coverage/src/index.html | 116 -- coverage/src/services/api-key-service.ts.html | 802 ----------- coverage/src/services/auth-service.ts.html | 445 ------ coverage/src/services/index.html | 131 -- coverage/src/utils/error-handler.ts.html | 538 -------- coverage/src/utils/index.html | 131 -- coverage/src/utils/logger.ts.html | 670 --------- src/services/chat-service.ts | 146 +- 53 files changed, 90 insertions(+), 17322 deletions(-) delete mode 100644 coverage/src/agents/app.ts.html delete mode 100644 coverage/src/agents/backend.ts.html delete mode 100644 coverage/src/agents/devops.ts.html delete mode 100644 coverage/src/agents/frontend.ts.html delete mode 100644 coverage/src/agents/fullstack.ts.html delete mode 100644 coverage/src/agents/index.html delete mode 100644 coverage/src/agents/index.ts.html delete mode 100644 coverage/src/agents/quality.ts.html delete mode 100644 coverage/src/agents/security.ts.html delete mode 100644 coverage/src/auth/config.ts.html delete mode 100644 coverage/src/auth/index.html delete mode 100644 coverage/src/auth/issuer.ts.html delete mode 100644 coverage/src/auth/jwt.ts.html delete mode 100644 coverage/src/auth/middleware/auth-middleware.ts.html delete mode 100644 coverage/src/auth/middleware/index.html delete mode 100644 coverage/src/auth/oauth/callback-pages.ts.html delete mode 100644 coverage/src/auth/oauth/index.html delete mode 100644 coverage/src/auth/oauth/pkce-flow.ts.html delete mode 100644 coverage/src/auth/oauth/token-refresh.ts.html delete mode 100644 coverage/src/auth/storage/index.html delete mode 100644 coverage/src/auth/storage/token-store.ts.html delete mode 100644 coverage/src/client.ts.html delete mode 100644 coverage/src/commands/code/__tests__/fake-api-key-service.ts.html delete mode 100644 coverage/src/commands/code/__tests__/fake-auth-service.ts.html delete mode 100644 coverage/src/commands/code/__tests__/fake-command-runner.ts.html delete mode 100644 coverage/src/commands/code/__tests__/fake-file-store.ts.html delete mode 100644 coverage/src/commands/code/__tests__/fake-prompter.ts.html delete mode 100644 coverage/src/commands/code/__tests__/index.html delete mode 100644 coverage/src/commands/code/adapters/clack-prompter.ts.html delete mode 100644 coverage/src/commands/code/adapters/fs-file-store.ts.html delete mode 100644 coverage/src/commands/code/adapters/index.html delete mode 100644 coverage/src/commands/code/adapters/spawn-command-runner.ts.html delete mode 100644 coverage/src/commands/code/auth-sync.ts.html delete mode 100644 coverage/src/commands/code/errors.ts.html delete mode 100644 coverage/src/commands/code/index.html delete mode 100644 coverage/src/commands/code/init.ts.html delete mode 100644 coverage/src/commands/code/opencode.ts.html delete mode 100644 coverage/src/commands/code/pi.ts.html delete mode 100644 coverage/src/commands/code/tool-check.ts.html delete mode 100644 coverage/src/commands/code/utils.ts.html delete mode 100644 coverage/src/constants/command-structure.ts.html delete mode 100644 coverage/src/constants/index.html delete mode 100644 coverage/src/index.html delete mode 100644 coverage/src/services/api-key-service.ts.html delete mode 100644 coverage/src/services/auth-service.ts.html delete mode 100644 coverage/src/services/index.html delete mode 100644 coverage/src/utils/error-handler.ts.html delete mode 100644 coverage/src/utils/index.html delete mode 100644 coverage/src/utils/logger.ts.html diff --git a/coverage/clover.xml b/coverage/clover.xml index 85eb52a..95df54d 100644 --- a/coverage/clover.xml +++ b/coverage/clover.xml @@ -1,1217 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json index 2c79f10..0967ef4 100644 --- a/coverage/coverage-final.json +++ b/coverage/coverage-final.json @@ -1,38 +1 @@ -{"/Users/marcus/berget-monorepo/cli/src/client.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/client.ts","statementMap":{"0":{"start":{"line":12,"column":8},"end":{"line":12,"column":null}},"1":{"start":{"line":13,"column":8},"end":{"line":19,"column":null}},"2":{"start":{"line":21,"column":21},"end":{"line":21,"column":null}},"3":{"start":{"line":23,"column":2},"end":{"line":38,"column":null}},"4":{"start":{"line":26,"column":21},"end":{"line":26,"column":null}},"5":{"start":{"line":27,"column":8},"end":{"line":27,"column":null}},"6":{"start":{"line":30,"column":8},"end":{"line":35,"column":null}},"7":{"start":{"line":31,"column":32},"end":{"line":31,"column":null}},"8":{"start":{"line":32,"column":10},"end":{"line":32,"column":null}},"9":{"start":{"line":34,"column":10},"end":{"line":34,"column":null}},"10":{"start":{"line":40,"column":2},"end":{"line":40,"column":null}}},"fnMap":{"0":{"name":"createAuthenticatedClient","decl":{"start":{"line":11,"column":16},"end":{"line":11,"column":42}},"loc":{"start":{"line":11,"column":90},"end":{"line":41,"column":null}},"line":11},"1":{"name":"(anonymous_1)","decl":{"start":{"line":25,"column":16},"end":{"line":25,"column":28}},"loc":{"start":{"line":25,"column":28},"end":{"line":28,"column":null}},"line":25},"2":{"name":"(anonymous_2)","decl":{"start":{"line":29,"column":15},"end":{"line":29,"column":27}},"loc":{"start":{"line":29,"column":27},"end":{"line":36,"column":null}},"line":29}},"branchMap":{"0":{"loc":{"start":{"line":27,"column":15},"end":{"line":27,"column":null}},"type":"binary-expr","locations":[{"start":{"line":27,"column":15},"end":{"line":27,"column":37}},{"start":{"line":27,"column":37},"end":{"line":27,"column":null}}],"line":27}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0]},"meta":{"lastBranch":1,"lastFunction":3,"lastStatement":11,"seen":{"f:11:16:11:42":0,"s:12:8:12:Infinity":0,"s:13:8:19:Infinity":1,"s:21:21:21:Infinity":2,"s:23:2:38:Infinity":3,"f:25:16:25:28":1,"s:26:21:26:Infinity":4,"s:27:8:27:Infinity":5,"b:27:15:27:37:27:37:27:Infinity":0,"f:29:15:29:27":2,"s:30:8:35:Infinity":6,"s:31:32:31:Infinity":7,"s:32:10:32:Infinity":8,"s:34:10:34:Infinity":9,"s:40:2:40:Infinity":10}}} -,"/Users/marcus/berget-monorepo/cli/src/agents/app.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/app.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":27,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:27:Infinity":0}}} -,"/Users/marcus/berget-monorepo/cli/src/agents/backend.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/backend.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":24,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:24:Infinity":0}}} -,"/Users/marcus/berget-monorepo/cli/src/agents/devops.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/devops.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":33,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:33:Infinity":0}}} -,"/Users/marcus/berget-monorepo/cli/src/agents/frontend.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/frontend.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":24,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:24:Infinity":0}}} -,"/Users/marcus/berget-monorepo/cli/src/agents/fullstack.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/fullstack.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":24,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:24:Infinity":0}}} -,"/Users/marcus/berget-monorepo/cli/src/agents/index.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/index.ts","statementMap":{"0":{"start":{"line":11,"column":38},"end":{"line":19,"column":null}},"1":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"2":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"3":{"start":{"line":36,"column":2},"end":{"line":40,"column":null}},"4":{"start":{"line":44,"column":35},"end":{"line":44,"column":null}},"5":{"start":{"line":45,"column":20},"end":{"line":45,"column":null}},"6":{"start":{"line":47,"column":2},"end":{"line":49,"column":null}},"7":{"start":{"line":48,"column":4},"end":{"line":48,"column":null}},"8":{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},"9":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"10":{"start":{"line":55,"column":2},"end":{"line":57,"column":null}},"11":{"start":{"line":56,"column":4},"end":{"line":56,"column":null}},"12":{"start":{"line":59,"column":2},"end":{"line":64,"column":null}},"13":{"start":{"line":60,"column":4},"end":{"line":60,"column":null}},"14":{"start":{"line":61,"column":4},"end":{"line":63,"column":null}},"15":{"start":{"line":62,"column":6},"end":{"line":62,"column":null}},"16":{"start":{"line":66,"column":2},"end":{"line":66,"column":null}},"17":{"start":{"line":70,"column":2},"end":{"line":70,"column":null}}},"fnMap":{"0":{"name":"getAgent","decl":{"start":{"line":23,"column":16},"end":{"line":23,"column":25}},"loc":{"start":{"line":23,"column":58},"end":{"line":25,"column":null}},"line":23},"1":{"name":"getAllAgents","decl":{"start":{"line":27,"column":16},"end":{"line":27,"column":40}},"loc":{"start":{"line":27,"column":40},"end":{"line":29,"column":null}},"line":27},"2":{"name":"toAgentTemplate","decl":{"start":{"line":31,"column":16},"end":{"line":31,"column":32}},"loc":{"start":{"line":35,"column":2},"end":{"line":41,"column":null}},"line":35},"3":{"name":"toMarkdown","decl":{"start":{"line":43,"column":16},"end":{"line":43,"column":27}},"loc":{"start":{"line":43,"column":49},"end":{"line":67,"column":null}},"line":43},"4":{"name":"toPiPrompt","decl":{"start":{"line":69,"column":16},"end":{"line":69,"column":27}},"loc":{"start":{"line":69,"column":49},"end":{"line":71,"column":null}},"line":69}},"branchMap":{"0":{"loc":{"start":{"line":47,"column":2},"end":{"line":49,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":2},"end":{"line":49,"column":null}},{"start":{},"end":{}}],"line":47},"1":{"loc":{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},{"start":{},"end":{}}],"line":51},"2":{"loc":{"start":{"line":55,"column":2},"end":{"line":57,"column":null}},"type":"if","locations":[{"start":{"line":55,"column":2},"end":{"line":57,"column":null}},{"start":{},"end":{}}],"line":55},"3":{"loc":{"start":{"line":59,"column":2},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":59,"column":2},"end":{"line":64,"column":null}},{"start":{},"end":{}}],"line":59}},"s":{"0":1,"1":0,"2":28,"3":0,"4":7,"5":7,"6":7,"7":7,"8":7,"9":0,"10":7,"11":0,"12":7,"13":0,"14":0,"15":0,"16":7,"17":8},"f":{"0":0,"1":28,"2":0,"3":7,"4":8},"b":{"0":[7,0],"1":[0,7],"2":[0,7],"3":[0,7]},"meta":{"lastBranch":4,"lastFunction":5,"lastStatement":18,"seen":{"s:11:38:19:Infinity":0,"f:23:16:23:25":0,"s:24:2:24:Infinity":1,"f:27:16:27:40":1,"s:28:2:28:Infinity":2,"f:31:16:31:32":2,"s:36:2:40:Infinity":3,"f:43:16:43:27":3,"s:44:35:44:Infinity":4,"s:45:20:45:Infinity":5,"b:47:2:49:Infinity:undefined:undefined:undefined:undefined":0,"s:47:2:49:Infinity":6,"s:48:4:48:Infinity":7,"b:51:2:53:Infinity:undefined:undefined:undefined:undefined":1,"s:51:2:53:Infinity":8,"s:52:4:52:Infinity":9,"b:55:2:57:Infinity:undefined:undefined:undefined:undefined":2,"s:55:2:57:Infinity":10,"s:56:4:56:Infinity":11,"b:59:2:64:Infinity:undefined:undefined:undefined:undefined":3,"s:59:2:64:Infinity":12,"s:60:4:60:Infinity":13,"s:61:4:63:Infinity":14,"s:62:6:62:Infinity":15,"s:66:2:66:Infinity":16,"f:69:16:69:27":4,"s:70:2:70:Infinity":17}}} -,"/Users/marcus/berget-monorepo/cli/src/agents/quality.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/quality.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":69,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:69:Infinity":0}}} -,"/Users/marcus/berget-monorepo/cli/src/agents/security.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/agents/security.ts","statementMap":{"0":{"start":{"line":3,"column":28},"end":{"line":26,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:3:28:26:Infinity":0}}} -,"/Users/marcus/berget-monorepo/cli/src/auth/config.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/config.ts","statementMap":{"0":{"start":{"line":5,"column":2},"end":{"line":13,"column":null}},"1":{"start":{"line":6,"column":23},"end":{"line":6,"column":null}},"2":{"start":{"line":7,"column":4},"end":{"line":12,"column":null}},"3":{"start":{"line":19,"column":2},"end":{"line":36,"column":null}},"4":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"5":{"start":{"line":22,"column":4},"end":{"line":26,"column":null}},"6":{"start":{"line":23,"column":6},"end":{"line":23,"column":null}},"7":{"start":{"line":25,"column":6},"end":{"line":25,"column":null}},"8":{"start":{"line":27,"column":9},"end":{"line":36,"column":null}},"9":{"start":{"line":28,"column":4},"end":{"line":28,"column":null}},"10":{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},"11":{"start":{"line":30,"column":9},"end":{"line":36,"column":null}},"12":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"13":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"14":{"start":{"line":34,"column":4},"end":{"line":34,"column":null}},"15":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"16":{"start":{"line":38,"column":2},"end":{"line":43,"column":null}}},"fnMap":{"0":{"name":"getAuthConfig","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":30}},"loc":{"start":{"line":3,"column":90},"end":{"line":44,"column":null}},"line":3}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":2},"end":{"line":13,"column":null}},"type":"if","locations":[{"start":{"line":5,"column":2},"end":{"line":13,"column":null}},{"start":{},"end":{}}],"line":5},"1":{"loc":{"start":{"line":6,"column":23},"end":{"line":6,"column":null}},"type":"binary-expr","locations":[{"start":{"line":6,"column":23},"end":{"line":6,"column":53}},{"start":{"line":6,"column":53},"end":{"line":6,"column":null}}],"line":6},"2":{"loc":{"start":{"line":19,"column":2},"end":{"line":36,"column":null}},"type":"if","locations":[{"start":{"line":19,"column":2},"end":{"line":36,"column":null}},{"start":{"line":27,"column":9},"end":{"line":36,"column":null}}],"line":19},"3":{"loc":{"start":{"line":22,"column":4},"end":{"line":26,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":4},"end":{"line":26,"column":null}},{"start":{"line":24,"column":11},"end":{"line":26,"column":null}}],"line":22},"4":{"loc":{"start":{"line":22,"column":8},"end":{"line":22,"column":75}},"type":"binary-expr","locations":[{"start":{"line":22,"column":8},"end":{"line":22,"column":44}},{"start":{"line":22,"column":44},"end":{"line":22,"column":75}}],"line":22},"5":{"loc":{"start":{"line":27,"column":9},"end":{"line":36,"column":null}},"type":"if","locations":[{"start":{"line":27,"column":9},"end":{"line":36,"column":null}},{"start":{"line":30,"column":9},"end":{"line":36,"column":null}}],"line":27},"6":{"loc":{"start":{"line":30,"column":9},"end":{"line":36,"column":null}},"type":"if","locations":[{"start":{"line":30,"column":9},"end":{"line":36,"column":null}},{"start":{"line":33,"column":9},"end":{"line":36,"column":null}}],"line":30}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0},"f":{"0":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0]},"meta":{"lastBranch":7,"lastFunction":1,"lastStatement":17,"seen":{"f:3:16:3:30":0,"b:5:2:13:Infinity:undefined:undefined:undefined:undefined":0,"s:5:2:13:Infinity":0,"s:6:23:6:Infinity":1,"b:6:23:6:53:6:53:6:Infinity":1,"s:7:4:12:Infinity":2,"b:19:2:36:Infinity:27:9:36:Infinity":2,"s:19:2:36:Infinity":3,"s:20:4:20:Infinity":4,"b:22:4:26:Infinity:24:11:26:Infinity":3,"s:22:4:26:Infinity":5,"b:22:8:22:44:22:44:22:75":4,"s:23:6:23:Infinity":6,"s:25:6:25:Infinity":7,"b:27:9:36:Infinity:30:9:36:Infinity":5,"s:27:9:36:Infinity":8,"s:28:4:28:Infinity":9,"s:29:4:29:Infinity":10,"b:30:9:36:Infinity:33:9:36:Infinity":6,"s:30:9:36:Infinity":11,"s:31:4:31:Infinity":12,"s:32:4:32:Infinity":13,"s:34:4:34:Infinity":14,"s:35:4:35:Infinity":15,"s:38:2:43:Infinity":16}}} -,"/Users/marcus/berget-monorepo/cli/src/auth/issuer.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/issuer.ts","statementMap":{"0":{"start":{"line":13,"column":14},"end":{"line":13,"column":null}},"1":{"start":{"line":16,"column":2},"end":{"line":16,"column":null}},"2":{"start":{"line":20,"column":20},"end":{"line":20,"column":null}},"3":{"start":{"line":22,"column":17},"end":{"line":22,"column":null}},"4":{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},"5":{"start":{"line":23,"column":14},"end":{"line":23,"column":null}},"6":{"start":{"line":25,"column":24},"end":{"line":30,"column":null}},"7":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"8":{"start":{"line":33,"column":2},"end":{"line":33,"column":null}}},"fnMap":{"0":{"name":"clearConfigurationCache","decl":{"start":{"line":15,"column":16},"end":{"line":15,"column":48}},"loc":{"start":{"line":15,"column":48},"end":{"line":17,"column":null}},"line":15},"1":{"name":"getConfiguration","decl":{"start":{"line":19,"column":22},"end":{"line":19,"column":39}},"loc":{"start":{"line":19,"column":83},"end":{"line":34,"column":null}},"line":19}},"branchMap":{"0":{"loc":{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},"type":"if","locations":[{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},{"start":{},"end":{}}],"line":23}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0},"f":{"0":0,"1":0},"b":{"0":[0,0]},"meta":{"lastBranch":1,"lastFunction":2,"lastStatement":9,"seen":{"s:13:14:13:Infinity":0,"f:15:16:15:48":0,"s:16:2:16:Infinity":1,"f:19:22:19:39":1,"s:20:20:20:Infinity":2,"s:22:17:22:Infinity":3,"b:23:2:23:Infinity:undefined:undefined:undefined:undefined":0,"s:23:2:23:Infinity":4,"s:23:14:23:Infinity":5,"s:25:24:30:Infinity":6,"s:32:2:32:Infinity":7,"s:33:2:33:Infinity":8}}} -,"/Users/marcus/berget-monorepo/cli/src/auth/jwt.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/jwt.ts","statementMap":{"0":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"1":{"start":{"line":16,"column":18},"end":{"line":16,"column":null}},"2":{"start":{"line":17,"column":2},"end":{"line":19,"column":null}},"3":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"4":{"start":{"line":20,"column":2},"end":{"line":20,"column":null}},"5":{"start":{"line":29,"column":18},"end":{"line":29,"column":null}},"6":{"start":{"line":30,"column":2},"end":{"line":30,"column":null}},"7":{"start":{"line":30,"column":16},"end":{"line":30,"column":null}},"8":{"start":{"line":31,"column":22},"end":{"line":31,"column":null}},"9":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"10":{"start":{"line":32,"column":20},"end":{"line":32,"column":null}},"11":{"start":{"line":33,"column":16},"end":{"line":33,"column":null}},"12":{"start":{"line":34,"column":2},"end":{"line":34,"column":null}},"13":{"start":{"line":34,"column":29},"end":{"line":34,"column":null}},"14":{"start":{"line":35,"column":2},"end":{"line":35,"column":null}},"15":{"start":{"line":45,"column":14},"end":{"line":45,"column":null}},"16":{"start":{"line":46,"column":26},"end":{"line":46,"column":null}},"17":{"start":{"line":47,"column":17},"end":{"line":47,"column":null}},"18":{"start":{"line":48,"column":2},"end":{"line":48,"column":null}},"19":{"start":{"line":55,"column":2},"end":{"line":62,"column":null}},"20":{"start":{"line":56,"column":18},"end":{"line":56,"column":null}},"21":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"22":{"start":{"line":57,"column":28},"end":{"line":57,"column":null}},"23":{"start":{"line":58,"column":20},"end":{"line":58,"column":null}},"24":{"start":{"line":59,"column":4},"end":{"line":59,"column":null}},"25":{"start":{"line":61,"column":4},"end":{"line":61,"column":null}}},"fnMap":{"0":{"name":"decodeJwtPayload","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":33}},"loc":{"start":{"line":6,"column":64},"end":{"line":8,"column":null}},"line":6},"1":{"name":"extractJwtExpiresAt","decl":{"start":{"line":15,"column":16},"end":{"line":15,"column":36}},"loc":{"start":{"line":15,"column":65},"end":{"line":21,"column":null}},"line":15},"2":{"name":"hasBergetCodeSeat","decl":{"start":{"line":28,"column":16},"end":{"line":28,"column":34}},"loc":{"start":{"line":28,"column":64},"end":{"line":36,"column":null}},"line":28},"3":{"name":"isTokenExpired","decl":{"start":{"line":44,"column":16},"end":{"line":44,"column":31}},"loc":{"start":{"line":44,"column":59},"end":{"line":49,"column":null}},"line":44},"4":{"name":"parseJwtBody","decl":{"start":{"line":54,"column":9},"end":{"line":54,"column":22}},"loc":{"start":{"line":54,"column":69},"end":{"line":63,"column":null}},"line":54}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":2},"end":{"line":19,"column":null}},"type":"if","locations":[{"start":{"line":17,"column":2},"end":{"line":19,"column":null}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":6},"end":{"line":17,"column":50}},"type":"binary-expr","locations":[{"start":{"line":17,"column":6},"end":{"line":17,"column":17}},{"start":{"line":17,"column":17},"end":{"line":17,"column":50}}],"line":17},"2":{"loc":{"start":{"line":30,"column":2},"end":{"line":30,"column":null}},"type":"if","locations":[{"start":{"line":30,"column":2},"end":{"line":30,"column":null}},{"start":{},"end":{}}],"line":30},"3":{"loc":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"type":"if","locations":[{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},{"start":{},"end":{}}],"line":32},"4":{"loc":{"start":{"line":34,"column":2},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":34,"column":2},"end":{"line":34,"column":null}},{"start":{},"end":{}}],"line":34},"5":{"loc":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"type":"if","locations":[{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},{"start":{},"end":{}}],"line":57}},"s":{"0":3,"1":5,"2":5,"3":5,"4":0,"5":3,"6":3,"7":0,"8":3,"9":3,"10":0,"11":3,"12":3,"13":0,"14":3,"15":2,"16":2,"17":2,"18":2,"19":11,"20":11,"21":11,"22":0,"23":11,"24":11,"25":0},"f":{"0":3,"1":5,"2":3,"3":2,"4":11},"b":{"0":[5,0],"1":[5,5],"2":[0,3],"3":[0,3],"4":[0,3],"5":[0,11]},"meta":{"lastBranch":6,"lastFunction":5,"lastStatement":26,"seen":{"f:6:16:6:33":0,"s:7:2:7:Infinity":0,"f:15:16:15:36":1,"s:16:18:16:Infinity":1,"b:17:2:19:Infinity:undefined:undefined:undefined:undefined":0,"s:17:2:19:Infinity":2,"b:17:6:17:17:17:17:17:50":1,"s:18:4:18:Infinity":3,"s:20:2:20:Infinity":4,"f:28:16:28:34":2,"s:29:18:29:Infinity":5,"b:30:2:30:Infinity:undefined:undefined:undefined:undefined":2,"s:30:2:30:Infinity":6,"s:30:16:30:Infinity":7,"s:31:22:31:Infinity":8,"b:32:2:32:Infinity:undefined:undefined:undefined:undefined":3,"s:32:2:32:Infinity":9,"s:32:20:32:Infinity":10,"s:33:16:33:Infinity":11,"b:34:2:34:Infinity:undefined:undefined:undefined:undefined":4,"s:34:2:34:Infinity":12,"s:34:29:34:Infinity":13,"s:35:2:35:Infinity":14,"f:44:16:44:31":3,"s:45:14:45:Infinity":15,"s:46:26:46:Infinity":16,"s:47:17:47:Infinity":17,"s:48:2:48:Infinity":18,"f:54:9:54:22":4,"s:55:2:62:Infinity":19,"s:56:18:56:Infinity":20,"b:57:4:57:Infinity:undefined:undefined:undefined:undefined":5,"s:57:4:57:Infinity":21,"s:57:28:57:Infinity":22,"s:58:20:58:Infinity":23,"s:59:4:59:Infinity":24,"s:61:4:61:Infinity":25}}} -,"/Users/marcus/berget-monorepo/cli/src/auth/middleware/auth-middleware.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/middleware/auth-middleware.ts","statementMap":{"0":{"start":{"line":10,"column":4},"end":{"line":15,"column":null}},"1":{"start":{"line":12,"column":20},"end":{"line":12,"column":null}},"2":{"start":{"line":13,"column":19},"end":{"line":13,"column":null}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":null}},"4":{"start":{"line":17,"column":2},"end":{"line":38,"column":null}},"5":{"start":{"line":19,"column":20},"end":{"line":19,"column":null}},"6":{"start":{"line":20,"column":6},"end":{"line":22,"column":null}},"7":{"start":{"line":21,"column":8},"end":{"line":21,"column":null}},"8":{"start":{"line":23,"column":6},"end":{"line":23,"column":null}},"9":{"start":{"line":26,"column":6},"end":{"line":35,"column":null}},"10":{"start":{"line":27,"column":19},"end":{"line":27,"column":null}},"11":{"start":{"line":28,"column":8},"end":{"line":34,"column":null}},"12":{"start":{"line":29,"column":27},"end":{"line":29,"column":null}},"13":{"start":{"line":30,"column":10},"end":{"line":33,"column":null}},"14":{"start":{"line":31,"column":12},"end":{"line":31,"column":null}},"15":{"start":{"line":32,"column":12},"end":{"line":32,"column":null}},"16":{"start":{"line":36,"column":6},"end":{"line":36,"column":null}}},"fnMap":{"0":{"name":"authMiddleware","decl":{"start":{"line":5,"column":16},"end":{"line":5,"column":31}},"loc":{"start":{"line":8,"column":15},"end":{"line":39,"column":null}},"line":8},"1":{"name":"(anonymous_1)","decl":{"start":{"line":11,"column":5},"end":{"line":11,"column":17}},"loc":{"start":{"line":11,"column":17},"end":{"line":15,"column":null}},"line":11},"2":{"name":"onRequest","decl":{"start":{"line":18,"column":10},"end":{"line":18,"column":20}},"loc":{"start":{"line":18,"column":25},"end":{"line":24,"column":null}},"line":18},"3":{"name":"onResponse","decl":{"start":{"line":25,"column":10},"end":{"line":25,"column":21}},"loc":{"start":{"line":25,"column":41},"end":{"line":37,"column":null}},"line":25}},"branchMap":{"0":{"loc":{"start":{"line":10,"column":4},"end":{"line":15,"column":null}},"type":"binary-expr","locations":[{"start":{"line":10,"column":4},"end":{"line":10,"column":null}},{"start":{"line":11,"column":5},"end":{"line":15,"column":null}}],"line":10},"1":{"loc":{"start":{"line":14,"column":13},"end":{"line":14,"column":null}},"type":"binary-expr","locations":[{"start":{"line":14,"column":13},"end":{"line":14,"column":35}},{"start":{"line":14,"column":35},"end":{"line":14,"column":null}}],"line":14},"2":{"loc":{"start":{"line":20,"column":6},"end":{"line":22,"column":null}},"type":"if","locations":[{"start":{"line":20,"column":6},"end":{"line":22,"column":null}},{"start":{},"end":{}}],"line":20},"3":{"loc":{"start":{"line":20,"column":10},"end":{"line":20,"column":54}},"type":"binary-expr","locations":[{"start":{"line":20,"column":10},"end":{"line":20,"column":19}},{"start":{"line":20,"column":19},"end":{"line":20,"column":54}}],"line":20},"4":{"loc":{"start":{"line":26,"column":6},"end":{"line":35,"column":null}},"type":"if","locations":[{"start":{"line":26,"column":6},"end":{"line":35,"column":null}},{"start":{},"end":{}}],"line":26},"5":{"loc":{"start":{"line":26,"column":10},"end":{"line":26,"column":49}},"type":"binary-expr","locations":[{"start":{"line":26,"column":10},"end":{"line":26,"column":32}},{"start":{"line":26,"column":32},"end":{"line":26,"column":49}}],"line":26},"6":{"loc":{"start":{"line":28,"column":8},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":8},"end":{"line":34,"column":null}},{"start":{},"end":{}}],"line":28},"7":{"loc":{"start":{"line":30,"column":10},"end":{"line":33,"column":null}},"type":"if","locations":[{"start":{"line":30,"column":10},"end":{"line":33,"column":null}},{"start":{},"end":{}}],"line":30}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0},"f":{"0":0,"1":0,"2":0,"3":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0]},"meta":{"lastBranch":8,"lastFunction":4,"lastStatement":17,"seen":{"f:5:16:5:31":0,"s:10:4:15:Infinity":0,"b:10:4:10:Infinity:11:5:15:Infinity":0,"f:11:5:11:17":1,"s:12:20:12:Infinity":1,"s:13:19:13:Infinity":2,"s:14:6:14:Infinity":3,"b:14:13:14:35:14:35:14:Infinity":1,"s:17:2:38:Infinity":4,"f:18:10:18:20":2,"s:19:20:19:Infinity":5,"b:20:6:22:Infinity:undefined:undefined:undefined:undefined":2,"s:20:6:22:Infinity":6,"b:20:10:20:19:20:19:20:54":3,"s:21:8:21:Infinity":7,"s:23:6:23:Infinity":8,"f:25:10:25:21":3,"b:26:6:35:Infinity:undefined:undefined:undefined:undefined":4,"s:26:6:35:Infinity":9,"b:26:10:26:32:26:32:26:49":5,"s:27:19:27:Infinity":10,"b:28:8:34:Infinity:undefined:undefined:undefined:undefined":6,"s:28:8:34:Infinity":11,"s:29:27:29:Infinity":12,"b:30:10:33:Infinity:undefined:undefined:undefined:undefined":7,"s:30:10:33:Infinity":13,"s:31:12:31:Infinity":14,"s:32:12:32:Infinity":15,"s:36:6:36:Infinity":16}}} -,"/Users/marcus/berget-monorepo/cli/src/auth/oauth/callback-pages.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/oauth/callback-pages.ts","statementMap":{"0":{"start":{"line":7,"column":20},"end":{"line":7,"column":null}},"1":{"start":{"line":8,"column":22},"end":{"line":8,"column":null}},"2":{"start":{"line":9,"column":2},"end":{"line":57,"column":null}},"3":{"start":{"line":65,"column":2},"end":{"line":65,"column":null}},"4":{"start":{"line":123,"column":2},"end":{"line":128,"column":null}}},"fnMap":{"0":{"name":"getErrorPage","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":29}},"loc":{"start":{"line":6,"column":69},"end":{"line":62,"column":null}},"line":6},"1":{"name":"getSuccessPage","decl":{"start":{"line":64,"column":16},"end":{"line":64,"column":41}},"loc":{"start":{"line":64,"column":41},"end":{"line":117,"column":null}},"line":64},"2":{"name":"escapeHtml","decl":{"start":{"line":122,"column":9},"end":{"line":122,"column":20}},"loc":{"start":{"line":122,"column":42},"end":{"line":129,"column":null}},"line":122}},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0},"f":{"0":0,"1":0,"2":0},"b":{},"meta":{"lastBranch":0,"lastFunction":3,"lastStatement":5,"seen":{"f:6:16:6:29":0,"s:7:20:7:Infinity":0,"s:8:22:8:Infinity":1,"s:9:2:57:Infinity":2,"f:64:16:64:41":1,"s:65:2:65:Infinity":3,"f:122:9:122:20":2,"s:123:2:128:Infinity":4}}} -,"/Users/marcus/berget-monorepo/cli/src/auth/oauth/pkce-flow.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/oauth/pkce-flow.ts","statementMap":{"0":{"start":{"line":18,"column":31},"end":{"line":18,"column":null}},"1":{"start":{"line":19,"column":24},"end":{"line":19,"column":null}},"2":{"start":{"line":37,"column":6},"end":{"line":37,"column":null}},"3":{"start":{"line":38,"column":16},"end":{"line":38,"column":null}},"4":{"start":{"line":40,"column":8},"end":{"line":40,"column":null}},"5":{"start":{"line":41,"column":24},"end":{"line":41,"column":null}},"6":{"start":{"line":42,"column":16},"end":{"line":42,"column":null}},"7":{"start":{"line":44,"column":2},"end":{"line":208,"column":null}},"8":{"start":{"line":45,"column":29},"end":{"line":45,"column":null}},"9":{"start":{"line":46,"column":24},"end":{"line":46,"column":null}},"10":{"start":{"line":48,"column":4},"end":{"line":50,"column":null}},"11":{"start":{"line":49,"column":6},"end":{"line":49,"column":null}},"12":{"start":{"line":53,"column":10},"end":{"line":59,"column":null}},"13":{"start":{"line":61,"column":4},"end":{"line":63,"column":null}},"14":{"start":{"line":62,"column":6},"end":{"line":62,"column":null}},"15":{"start":{"line":66,"column":23},"end":{"line":160,"column":null}},"16":{"start":{"line":72,"column":21},"end":{"line":72,"column":null}},"17":{"start":{"line":73,"column":22},"end":{"line":73,"column":null}},"18":{"start":{"line":75,"column":12},"end":{"line":90,"column":null}},"19":{"start":{"line":81,"column":8},"end":{"line":81,"column":null}},"20":{"start":{"line":81,"column":22},"end":{"line":81,"column":null}},"21":{"start":{"line":82,"column":8},"end":{"line":82,"column":null}},"22":{"start":{"line":83,"column":8},"end":{"line":83,"column":null}},"23":{"start":{"line":84,"column":8},"end":{"line":84,"column":null}},"24":{"start":{"line":85,"column":8},"end":{"line":87,"column":null}},"25":{"start":{"line":86,"column":10},"end":{"line":86,"column":null}},"26":{"start":{"line":88,"column":8},"end":{"line":88,"column":null}},"27":{"start":{"line":89,"column":8},"end":{"line":89,"column":null}},"28":{"start":{"line":92,"column":6},"end":{"line":138,"column":null}},"29":{"start":{"line":93,"column":27},"end":{"line":93,"column":null}},"30":{"start":{"line":95,"column":8},"end":{"line":99,"column":null}},"31":{"start":{"line":96,"column":10},"end":{"line":96,"column":null}},"32":{"start":{"line":97,"column":10},"end":{"line":97,"column":null}},"33":{"start":{"line":98,"column":10},"end":{"line":98,"column":null}},"34":{"start":{"line":101,"column":30},"end":{"line":101,"column":null}},"35":{"start":{"line":102,"column":21},"end":{"line":102,"column":null}},"36":{"start":{"line":103,"column":22},"end":{"line":103,"column":null}},"37":{"start":{"line":105,"column":8},"end":{"line":114,"column":null}},"38":{"start":{"line":106,"column":30},"end":{"line":106,"column":null}},"39":{"start":{"line":107,"column":10},"end":{"line":109,"column":null}},"40":{"start":{"line":108,"column":12},"end":{"line":108,"column":null}},"41":{"start":{"line":110,"column":10},"end":{"line":110,"column":null}},"42":{"start":{"line":111,"column":10},"end":{"line":111,"column":null}},"43":{"start":{"line":112,"column":10},"end":{"line":112,"column":null}},"44":{"start":{"line":113,"column":10},"end":{"line":113,"column":null}},"45":{"start":{"line":116,"column":8},"end":{"line":126,"column":null}},"46":{"start":{"line":117,"column":10},"end":{"line":119,"column":null}},"47":{"start":{"line":118,"column":12},"end":{"line":118,"column":null}},"48":{"start":{"line":120,"column":10},"end":{"line":120,"column":null}},"49":{"start":{"line":121,"column":10},"end":{"line":123,"column":null}},"50":{"start":{"line":124,"column":10},"end":{"line":124,"column":null}},"51":{"start":{"line":125,"column":10},"end":{"line":125,"column":null}},"52":{"start":{"line":128,"column":8},"end":{"line":133,"column":null}},"53":{"start":{"line":129,"column":10},"end":{"line":129,"column":null}},"54":{"start":{"line":130,"column":10},"end":{"line":130,"column":null}},"55":{"start":{"line":131,"column":10},"end":{"line":131,"column":null}},"56":{"start":{"line":132,"column":10},"end":{"line":132,"column":null}},"57":{"start":{"line":135,"column":8},"end":{"line":135,"column":null}},"58":{"start":{"line":136,"column":8},"end":{"line":136,"column":null}},"59":{"start":{"line":137,"column":8},"end":{"line":137,"column":null}},"60":{"start":{"line":140,"column":6},"end":{"line":143,"column":null}},"61":{"start":{"line":141,"column":8},"end":{"line":141,"column":null}},"62":{"start":{"line":142,"column":8},"end":{"line":142,"column":null}},"63":{"start":{"line":142,"column":33},"end":{"line":142,"column":55}},"64":{"start":{"line":145,"column":28},"end":{"line":148,"column":null}},"65":{"start":{"line":146,"column":14},"end":{"line":146,"column":null}},"66":{"start":{"line":151,"column":6},"end":{"line":159,"column":null}},"67":{"start":{"line":152,"column":8},"end":{"line":158,"column":null}},"68":{"start":{"line":153,"column":23},"end":{"line":153,"column":null}},"69":{"start":{"line":153,"column":65},"end":{"line":153,"column":null}},"70":{"start":{"line":154,"column":10},"end":{"line":154,"column":null}},"71":{"start":{"line":156,"column":10},"end":{"line":156,"column":null}},"72":{"start":{"line":157,"column":10},"end":{"line":157,"column":null}},"73":{"start":{"line":162,"column":4},"end":{"line":167,"column":null}},"74":{"start":{"line":163,"column":6},"end":{"line":166,"column":null}},"75":{"start":{"line":170,"column":24},"end":{"line":170,"column":null}},"76":{"start":{"line":172,"column":4},"end":{"line":175,"column":null}},"77":{"start":{"line":173,"column":6},"end":{"line":173,"column":null}},"78":{"start":{"line":174,"column":6},"end":{"line":174,"column":null}},"79":{"start":{"line":177,"column":4},"end":{"line":202,"column":null}},"80":{"start":{"line":178,"column":26},"end":{"line":181,"column":null}},"81":{"start":{"line":183,"column":6},"end":{"line":185,"column":null}},"82":{"start":{"line":184,"column":8},"end":{"line":184,"column":null}},"83":{"start":{"line":187,"column":6},"end":{"line":192,"column":null}},"84":{"start":{"line":194,"column":6},"end":{"line":200,"column":null}},"85":{"start":{"line":195,"column":8},"end":{"line":195,"column":null}},"86":{"start":{"line":196,"column":8},"end":{"line":199,"column":null}},"87":{"start":{"line":197,"column":10},"end":{"line":197,"column":null}},"88":{"start":{"line":198,"column":10},"end":{"line":198,"column":null}},"89":{"start":{"line":201,"column":6},"end":{"line":201,"column":null}},"90":{"start":{"line":204,"column":4},"end":{"line":207,"column":null}},"91":{"start":{"line":218,"column":2},"end":{"line":246,"column":null}},"92":{"start":{"line":222,"column":19},"end":{"line":222,"column":null}},"93":{"start":{"line":225,"column":6},"end":{"line":231,"column":null}},"94":{"start":{"line":226,"column":8},"end":{"line":230,"column":null}},"95":{"start":{"line":227,"column":10},"end":{"line":227,"column":null}},"96":{"start":{"line":227,"column":29},"end":{"line":227,"column":45}},"97":{"start":{"line":229,"column":10},"end":{"line":229,"column":null}},"98":{"start":{"line":233,"column":6},"end":{"line":240,"column":null}},"99":{"start":{"line":234,"column":24},"end":{"line":234,"column":null}},"100":{"start":{"line":235,"column":8},"end":{"line":239,"column":null}},"101":{"start":{"line":236,"column":10},"end":{"line":236,"column":null}},"102":{"start":{"line":238,"column":10},"end":{"line":238,"column":null}},"103":{"start":{"line":242,"column":6},"end":{"line":242,"column":null}},"104":{"start":{"line":245,"column":4},"end":{"line":245,"column":null}}},"fnMap":{"0":{"name":"startPkceFlow","decl":{"start":{"line":32,"column":22},"end":{"line":32,"column":36}},"loc":{"start":{"line":32,"column":90},"end":{"line":209,"column":null}},"line":32},"1":{"name":"(anonymous_1)","decl":{"start":{"line":66,"column":33},"end":{"line":66,"column":null}},"loc":{"start":{"line":71,"column":20},"end":{"line":160,"column":5}},"line":71},"2":{"name":"(anonymous_2)","decl":{"start":{"line":75,"column":12},"end":{"line":75,"column":27}},"loc":{"start":{"line":80,"column":12},"end":{"line":90,"column":null}},"line":80},"3":{"name":"(anonymous_3)","decl":{"start":{"line":92,"column":16},"end":{"line":92,"column":28}},"loc":{"start":{"line":92,"column":45},"end":{"line":138,"column":7}},"line":92},"4":{"name":"(anonymous_4)","decl":{"start":{"line":140,"column":16},"end":{"line":140,"column":31}},"loc":{"start":{"line":140,"column":54},"end":{"line":143,"column":7}},"line":140},"5":{"name":"(anonymous_5)","decl":{"start":{"line":142,"column":18},"end":{"line":142,"column":33}},"loc":{"start":{"line":142,"column":33},"end":{"line":142,"column":55}},"line":142},"6":{"name":"(anonymous_6)","decl":{"start":{"line":145,"column":28},"end":{"line":145,"column":null}},"loc":{"start":{"line":146,"column":14},"end":{"line":146,"column":null}},"line":146},"7":{"name":"(anonymous_7)","decl":{"start":{"line":151,"column":7},"end":{"line":151,"column":19}},"loc":{"start":{"line":151,"column":19},"end":{"line":159,"column":9}},"line":151},"8":{"name":"(anonymous_8)","decl":{"start":{"line":153,"column":65},"end":{"line":153,"column":null}},"loc":{"start":{"line":153,"column":65},"end":{"line":153,"column":null}},"line":153},"9":{"name":"startCallbackServer","decl":{"start":{"line":215,"column":9},"end":{"line":215,"column":null}},"loc":{"start":{"line":217,"column":50},"end":{"line":247,"column":null}},"line":217},"10":{"name":"(anonymous_10)","decl":{"start":{"line":218,"column":13},"end":{"line":218,"column":22}},"loc":{"start":{"line":218,"column":42},"end":{"line":246,"column":3}},"line":218},"11":{"name":"attemptListen","decl":{"start":{"line":224,"column":13},"end":{"line":224,"column":27}},"loc":{"start":{"line":224,"column":41},"end":{"line":243,"column":null}},"line":224},"12":{"name":"(anonymous_12)","decl":{"start":{"line":225,"column":18},"end":{"line":225,"column":28}},"loc":{"start":{"line":225,"column":61},"end":{"line":231,"column":7}},"line":225},"13":{"name":"(anonymous_13)","decl":{"start":{"line":227,"column":17},"end":{"line":227,"column":29}},"loc":{"start":{"line":227,"column":29},"end":{"line":227,"column":45}},"line":227},"14":{"name":"(anonymous_14)","decl":{"start":{"line":233,"column":18},"end":{"line":233,"column":37}},"loc":{"start":{"line":233,"column":37},"end":{"line":240,"column":7}},"line":233}},"branchMap":{"0":{"loc":{"start":{"line":35,"column":18},"end":{"line":35,"column":null}},"type":"default-arg","locations":[{"start":{"line":35,"column":40},"end":{"line":35,"column":null}}],"line":35},"1":{"loc":{"start":{"line":38,"column":16},"end":{"line":38,"column":null}},"type":"binary-expr","locations":[{"start":{"line":38,"column":16},"end":{"line":38,"column":31}},{"start":{"line":38,"column":31},"end":{"line":38,"column":null}}],"line":38},"2":{"loc":{"start":{"line":48,"column":4},"end":{"line":50,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":4},"end":{"line":50,"column":null}},{"start":{},"end":{}}],"line":48},"3":{"loc":{"start":{"line":61,"column":4},"end":{"line":63,"column":null}},"type":"if","locations":[{"start":{"line":61,"column":4},"end":{"line":63,"column":null}},{"start":{},"end":{}}],"line":61},"4":{"loc":{"start":{"line":81,"column":8},"end":{"line":81,"column":null}},"type":"if","locations":[{"start":{"line":81,"column":8},"end":{"line":81,"column":null}},{"start":{},"end":{}}],"line":81},"5":{"loc":{"start":{"line":93,"column":35},"end":{"line":93,"column":54}},"type":"binary-expr","locations":[{"start":{"line":93,"column":35},"end":{"line":93,"column":50}},{"start":{"line":93,"column":50},"end":{"line":93,"column":54}}],"line":93},"6":{"loc":{"start":{"line":95,"column":8},"end":{"line":99,"column":null}},"type":"if","locations":[{"start":{"line":95,"column":8},"end":{"line":99,"column":null}},{"start":{},"end":{}}],"line":95},"7":{"loc":{"start":{"line":101,"column":30},"end":{"line":101,"column":null}},"type":"binary-expr","locations":[{"start":{"line":101,"column":30},"end":{"line":101,"column":70}},{"start":{"line":101,"column":70},"end":{"line":101,"column":null}}],"line":101},"8":{"loc":{"start":{"line":102,"column":21},"end":{"line":102,"column":null}},"type":"binary-expr","locations":[{"start":{"line":102,"column":21},"end":{"line":102,"column":60}},{"start":{"line":102,"column":60},"end":{"line":102,"column":null}}],"line":102},"9":{"loc":{"start":{"line":103,"column":22},"end":{"line":103,"column":null}},"type":"binary-expr","locations":[{"start":{"line":103,"column":22},"end":{"line":103,"column":62}},{"start":{"line":103,"column":62},"end":{"line":103,"column":null}}],"line":103},"10":{"loc":{"start":{"line":105,"column":8},"end":{"line":114,"column":null}},"type":"if","locations":[{"start":{"line":105,"column":8},"end":{"line":114,"column":null}},{"start":{},"end":{}}],"line":105},"11":{"loc":{"start":{"line":106,"column":30},"end":{"line":106,"column":null}},"type":"binary-expr","locations":[{"start":{"line":106,"column":30},"end":{"line":106,"column":82}},{"start":{"line":106,"column":82},"end":{"line":106,"column":null}}],"line":106},"12":{"loc":{"start":{"line":107,"column":10},"end":{"line":109,"column":null}},"type":"if","locations":[{"start":{"line":107,"column":10},"end":{"line":109,"column":null}},{"start":{},"end":{}}],"line":107},"13":{"loc":{"start":{"line":116,"column":8},"end":{"line":126,"column":null}},"type":"if","locations":[{"start":{"line":116,"column":8},"end":{"line":126,"column":null}},{"start":{},"end":{}}],"line":116},"14":{"loc":{"start":{"line":117,"column":10},"end":{"line":119,"column":null}},"type":"if","locations":[{"start":{"line":117,"column":10},"end":{"line":119,"column":null}},{"start":{},"end":{}}],"line":117},"15":{"loc":{"start":{"line":128,"column":8},"end":{"line":133,"column":null}},"type":"if","locations":[{"start":{"line":128,"column":8},"end":{"line":133,"column":null}},{"start":{},"end":{}}],"line":128},"16":{"loc":{"start":{"line":162,"column":4},"end":{"line":167,"column":null}},"type":"if","locations":[{"start":{"line":162,"column":4},"end":{"line":167,"column":null}},{"start":{},"end":{}}],"line":162},"17":{"loc":{"start":{"line":162,"column":8},"end":{"line":162,"column":76}},"type":"binary-expr","locations":[{"start":{"line":162,"column":8},"end":{"line":162,"column":31}},{"start":{"line":162,"column":31},"end":{"line":162,"column":51}},{"start":{"line":162,"column":51},"end":{"line":162,"column":76}}],"line":162},"18":{"loc":{"start":{"line":164,"column":15},"end":{"line":164,"column":null}},"type":"binary-expr","locations":[{"start":{"line":164,"column":15},"end":{"line":164,"column":35}},{"start":{"line":164,"column":35},"end":{"line":164,"column":null}}],"line":164},"19":{"loc":{"start":{"line":172,"column":4},"end":{"line":175,"column":null}},"type":"if","locations":[{"start":{"line":172,"column":4},"end":{"line":175,"column":null}},{"start":{},"end":{}}],"line":172},"20":{"loc":{"start":{"line":183,"column":6},"end":{"line":185,"column":null}},"type":"if","locations":[{"start":{"line":183,"column":6},"end":{"line":185,"column":null}},{"start":{},"end":{}}],"line":183},"21":{"loc":{"start":{"line":194,"column":6},"end":{"line":200,"column":null}},"type":"if","locations":[{"start":{"line":194,"column":6},"end":{"line":200,"column":null}},{"start":{},"end":{}}],"line":194},"22":{"loc":{"start":{"line":196,"column":8},"end":{"line":199,"column":null}},"type":"if","locations":[{"start":{"line":196,"column":8},"end":{"line":199,"column":null}},{"start":{},"end":{}}],"line":196},"23":{"loc":{"start":{"line":205,"column":13},"end":{"line":205,"column":null}},"type":"cond-expr","locations":[{"start":{"line":205,"column":38},"end":{"line":205,"column":54}},{"start":{"line":205,"column":54},"end":{"line":205,"column":null}}],"line":205},"24":{"loc":{"start":{"line":226,"column":8},"end":{"line":230,"column":null}},"type":"if","locations":[{"start":{"line":226,"column":8},"end":{"line":230,"column":null}},{"start":{"line":228,"column":15},"end":{"line":230,"column":null}}],"line":226},"25":{"loc":{"start":{"line":226,"column":12},"end":{"line":226,"column":76}},"type":"binary-expr","locations":[{"start":{"line":226,"column":12},"end":{"line":226,"column":43}},{"start":{"line":226,"column":43},"end":{"line":226,"column":76}}],"line":226},"26":{"loc":{"start":{"line":235,"column":8},"end":{"line":239,"column":null}},"type":"if","locations":[{"start":{"line":235,"column":8},"end":{"line":239,"column":null}},{"start":{"line":237,"column":15},"end":{"line":239,"column":null}}],"line":235},"27":{"loc":{"start":{"line":235,"column":12},"end":{"line":235,"column":52}},"type":"binary-expr","locations":[{"start":{"line":235,"column":12},"end":{"line":235,"column":23}},{"start":{"line":235,"column":23},"end":{"line":235,"column":52}}],"line":235}},"s":{"0":1,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0,"103":0,"104":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0},"b":{"0":[0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0,0],"18":[0,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0],"23":[0,0],"24":[0,0],"25":[0,0],"26":[0,0],"27":[0,0]},"meta":{"lastBranch":28,"lastFunction":15,"lastStatement":105,"seen":{"s:18:31:18:Infinity":0,"s:19:24:19:Infinity":1,"f:32:22:32:36":0,"s:37:6:37:Infinity":2,"b:35:40:35:Infinity":0,"s:38:16:38:Infinity":3,"b:38:16:38:31:38:31:38:Infinity":1,"s:40:8:40:Infinity":4,"s:41:24:41:Infinity":5,"s:42:16:42:Infinity":6,"s:44:2:208:Infinity":7,"s:45:29:45:Infinity":8,"s:46:24:46:Infinity":9,"b:48:4:50:Infinity:undefined:undefined:undefined:undefined":2,"s:48:4:50:Infinity":10,"s:49:6:49:Infinity":11,"s:53:10:59:Infinity":12,"b:61:4:63:Infinity:undefined:undefined:undefined:undefined":3,"s:61:4:63:Infinity":13,"s:62:6:62:Infinity":14,"s:66:23:160:Infinity":15,"f:66:33:66:Infinity":1,"s:72:21:72:Infinity":16,"s:73:22:73:Infinity":17,"s:75:12:90:Infinity":18,"f:75:12:75:27":2,"b:81:8:81:Infinity:undefined:undefined:undefined:undefined":4,"s:81:8:81:Infinity":19,"s:81:22:81:Infinity":20,"s:82:8:82:Infinity":21,"s:83:8:83:Infinity":22,"s:84:8:84:Infinity":23,"s:85:8:87:Infinity":24,"s:86:10:86:Infinity":25,"s:88:8:88:Infinity":26,"s:89:8:89:Infinity":27,"s:92:6:138:Infinity":28,"f:92:16:92:28":3,"s:93:27:93:Infinity":29,"b:93:35:93:50:93:50:93:54":5,"b:95:8:99:Infinity:undefined:undefined:undefined:undefined":6,"s:95:8:99:Infinity":30,"s:96:10:96:Infinity":31,"s:97:10:97:Infinity":32,"s:98:10:98:Infinity":33,"s:101:30:101:Infinity":34,"b:101:30:101:70:101:70:101:Infinity":7,"s:102:21:102:Infinity":35,"b:102:21:102:60:102:60:102:Infinity":8,"s:103:22:103:Infinity":36,"b:103:22:103:62:103:62:103:Infinity":9,"b:105:8:114:Infinity:undefined:undefined:undefined:undefined":10,"s:105:8:114:Infinity":37,"s:106:30:106:Infinity":38,"b:106:30:106:82:106:82:106:Infinity":11,"b:107:10:109:Infinity:undefined:undefined:undefined:undefined":12,"s:107:10:109:Infinity":39,"s:108:12:108:Infinity":40,"s:110:10:110:Infinity":41,"s:111:10:111:Infinity":42,"s:112:10:112:Infinity":43,"s:113:10:113:Infinity":44,"b:116:8:126:Infinity:undefined:undefined:undefined:undefined":13,"s:116:8:126:Infinity":45,"b:117:10:119:Infinity:undefined:undefined:undefined:undefined":14,"s:117:10:119:Infinity":46,"s:118:12:118:Infinity":47,"s:120:10:120:Infinity":48,"s:121:10:123:Infinity":49,"s:124:10:124:Infinity":50,"s:125:10:125:Infinity":51,"b:128:8:133:Infinity:undefined:undefined:undefined:undefined":15,"s:128:8:133:Infinity":52,"s:129:10:129:Infinity":53,"s:130:10:130:Infinity":54,"s:131:10:131:Infinity":55,"s:132:10:132:Infinity":56,"s:135:8:135:Infinity":57,"s:136:8:136:Infinity":58,"s:137:8:137:Infinity":59,"s:140:6:143:Infinity":60,"f:140:16:140:31":4,"s:141:8:141:Infinity":61,"s:142:8:142:Infinity":62,"f:142:18:142:33":5,"s:142:33:142:55":63,"s:145:28:148:Infinity":64,"f:145:28:145:Infinity":6,"s:146:14:146:Infinity":65,"s:151:6:159:Infinity":66,"f:151:7:151:19":7,"s:152:8:158:Infinity":67,"s:153:23:153:Infinity":68,"f:153:65:153:Infinity":8,"s:153:65:153:Infinity":69,"s:154:10:154:Infinity":70,"s:156:10:156:Infinity":71,"s:157:10:157:Infinity":72,"b:162:4:167:Infinity:undefined:undefined:undefined:undefined":16,"s:162:4:167:Infinity":73,"b:162:8:162:31:162:31:162:51:162:51:162:76":17,"s:163:6:166:Infinity":74,"b:164:15:164:35:164:35:164:Infinity":18,"s:170:24:170:Infinity":75,"b:172:4:175:Infinity:undefined:undefined:undefined:undefined":19,"s:172:4:175:Infinity":76,"s:173:6:173:Infinity":77,"s:174:6:174:Infinity":78,"s:177:4:202:Infinity":79,"s:178:26:181:Infinity":80,"b:183:6:185:Infinity:undefined:undefined:undefined:undefined":20,"s:183:6:185:Infinity":81,"s:184:8:184:Infinity":82,"s:187:6:192:Infinity":83,"b:194:6:200:Infinity:undefined:undefined:undefined:undefined":21,"s:194:6:200:Infinity":84,"s:195:8:195:Infinity":85,"b:196:8:199:Infinity:undefined:undefined:undefined:undefined":22,"s:196:8:199:Infinity":86,"s:197:10:197:Infinity":87,"s:198:10:198:Infinity":88,"s:201:6:201:Infinity":89,"s:204:4:207:Infinity":90,"b:205:38:205:54:205:54:205:Infinity":23,"f:215:9:215:Infinity":9,"s:218:2:246:Infinity":91,"f:218:13:218:22":10,"s:222:19:222:Infinity":92,"f:224:13:224:27":11,"s:225:6:231:Infinity":93,"f:225:18:225:28":12,"b:226:8:230:Infinity:228:15:230:Infinity":24,"s:226:8:230:Infinity":94,"b:226:12:226:43:226:43:226:76":25,"s:227:10:227:Infinity":95,"f:227:17:227:29":13,"s:227:29:227:45":96,"s:229:10:229:Infinity":97,"s:233:6:240:Infinity":98,"f:233:18:233:37":14,"s:234:24:234:Infinity":99,"b:235:8:239:Infinity:237:15:239:Infinity":26,"s:235:8:239:Infinity":100,"b:235:12:235:23:235:23:235:52":27,"s:236:10:236:Infinity":101,"s:238:10:238:Infinity":102,"s:242:6:242:Infinity":103,"s:245:4:245:Infinity":104}}} -,"/Users/marcus/berget-monorepo/cli/src/auth/oauth/token-refresh.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/oauth/token-refresh.ts","statementMap":{"0":{"start":{"line":13,"column":30},"end":{"line":20,"column":null}},"1":{"start":{"line":22,"column":20},"end":{"line":22,"column":null}},"2":{"start":{"line":23,"column":27},"end":{"line":23,"column":null}},"3":{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},"4":{"start":{"line":26,"column":33},"end":{"line":26,"column":null}},"5":{"start":{"line":27,"column":16},"end":{"line":27,"column":null}},"6":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"7":{"start":{"line":28,"column":47},"end":{"line":28,"column":null}},"8":{"start":{"line":29,"column":2},"end":{"line":29,"column":null}},"9":{"start":{"line":35,"column":25},"end":{"line":35,"column":null}},"10":{"start":{"line":41,"column":17},"end":{"line":41,"column":null}},"11":{"start":{"line":42,"column":2},"end":{"line":45,"column":null}},"12":{"start":{"line":43,"column":4},"end":{"line":43,"column":null}},"13":{"start":{"line":44,"column":4},"end":{"line":44,"column":null}},"14":{"start":{"line":47,"column":19},"end":{"line":47,"column":null}},"15":{"start":{"line":48,"column":2},"end":{"line":50,"column":null}},"16":{"start":{"line":49,"column":4},"end":{"line":49,"column":null}},"17":{"start":{"line":52,"column":18},"end":{"line":54,"column":null}},"18":{"start":{"line":53,"column":4},"end":{"line":53,"column":null}},"19":{"start":{"line":56,"column":2},"end":{"line":56,"column":null}},"20":{"start":{"line":57,"column":2},"end":{"line":57,"column":null}},"21":{"start":{"line":66,"column":20},"end":{"line":66,"column":null}},"22":{"start":{"line":67,"column":2},"end":{"line":67,"column":null}},"23":{"start":{"line":67,"column":33},"end":{"line":67,"column":null}},"24":{"start":{"line":69,"column":16},"end":{"line":69,"column":null}},"25":{"start":{"line":71,"column":2},"end":{"line":121,"column":null}},"26":{"start":{"line":72,"column":4},"end":{"line":120,"column":null}},"27":{"start":{"line":73,"column":21},"end":{"line":73,"column":null}},"28":{"start":{"line":76,"column":26},"end":{"line":76,"column":null}},"29":{"start":{"line":77,"column":27},"end":{"line":77,"column":null}},"30":{"start":{"line":78,"column":24},"end":{"line":78,"column":null}},"31":{"start":{"line":81,"column":12},"end":{"line":81,"column":null}},"32":{"start":{"line":82,"column":24},"end":{"line":82,"column":null}},"33":{"start":{"line":84,"column":38},"end":{"line":88,"column":null}},"34":{"start":{"line":90,"column":6},"end":{"line":90,"column":null}},"35":{"start":{"line":91,"column":6},"end":{"line":91,"column":null}},"36":{"start":{"line":95,"column":6},"end":{"line":100,"column":null}},"37":{"start":{"line":96,"column":8},"end":{"line":98,"column":null}},"38":{"start":{"line":97,"column":10},"end":{"line":97,"column":null}},"39":{"start":{"line":99,"column":8},"end":{"line":99,"column":null}},"40":{"start":{"line":102,"column":6},"end":{"line":111,"column":null}},"41":{"start":{"line":109,"column":8},"end":{"line":109,"column":null}},"42":{"start":{"line":110,"column":8},"end":{"line":110,"column":null}},"43":{"start":{"line":113,"column":6},"end":{"line":117,"column":null}},"44":{"start":{"line":114,"column":8},"end":{"line":114,"column":null}},"45":{"start":{"line":115,"column":8},"end":{"line":115,"column":null}},"46":{"start":{"line":116,"column":8},"end":{"line":116,"column":null}},"47":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"48":{"start":{"line":125,"column":2},"end":{"line":125,"column":null}},"49":{"start":{"line":125,"column":34},"end":{"line":125,"column":57}}},"fnMap":{"0":{"name":"isTransientError","decl":{"start":{"line":25,"column":9},"end":{"line":25,"column":26}},"loc":{"start":{"line":25,"column":51},"end":{"line":30,"column":null}},"line":25},"1":{"name":"refreshAccessToken","decl":{"start":{"line":37,"column":22},"end":{"line":37,"column":null}},"loc":{"start":{"line":40,"column":20},"end":{"line":58,"column":null}},"line":40},"2":{"name":"(anonymous_2)","decl":{"start":{"line":52,"column":48},"end":{"line":52,"column":62}},"loc":{"start":{"line":52,"column":62},"end":{"line":54,"column":3}},"line":52},"3":{"name":"doRefresh","decl":{"start":{"line":65,"column":15},"end":{"line":65,"column":25}},"loc":{"start":{"line":65,"column":90},"end":{"line":122,"column":null}},"line":65},"4":{"name":"sleep","decl":{"start":{"line":124,"column":9},"end":{"line":124,"column":15}},"loc":{"start":{"line":124,"column":42},"end":{"line":126,"column":null}},"line":124},"5":{"name":"(anonymous_5)","decl":{"start":{"line":125,"column":13},"end":{"line":125,"column":22}},"loc":{"start":{"line":125,"column":34},"end":{"line":125,"column":57}},"line":125}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},"type":"if","locations":[{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},{"start":{},"end":{}}],"line":28},"2":{"loc":{"start":{"line":28,"column":6},"end":{"line":28,"column":47}},"type":"binary-expr","locations":[{"start":{"line":28,"column":6},"end":{"line":28,"column":14}},{"start":{"line":28,"column":14},"end":{"line":28,"column":47}}],"line":28},"3":{"loc":{"start":{"line":42,"column":2},"end":{"line":45,"column":null}},"type":"if","locations":[{"start":{"line":42,"column":2},"end":{"line":45,"column":null}},{"start":{},"end":{}}],"line":42},"4":{"loc":{"start":{"line":48,"column":2},"end":{"line":50,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":2},"end":{"line":50,"column":null}},{"start":{},"end":{}}],"line":48},"5":{"loc":{"start":{"line":67,"column":2},"end":{"line":67,"column":null}},"type":"if","locations":[{"start":{"line":67,"column":2},"end":{"line":67,"column":null}},{"start":{},"end":{}}],"line":67},"6":{"loc":{"start":{"line":77,"column":27},"end":{"line":77,"column":null}},"type":"binary-expr","locations":[{"start":{"line":77,"column":27},"end":{"line":77,"column":51}},{"start":{"line":77,"column":51},"end":{"line":77,"column":null}}],"line":77},"7":{"loc":{"start":{"line":78,"column":24},"end":{"line":78,"column":null}},"type":"binary-expr","locations":[{"start":{"line":78,"column":24},"end":{"line":78,"column":45}},{"start":{"line":78,"column":45},"end":{"line":78,"column":null}}],"line":78},"8":{"loc":{"start":{"line":82,"column":24},"end":{"line":82,"column":null}},"type":"cond-expr","locations":[{"start":{"line":82,"column":43},"end":{"line":82,"column":58}},{"start":{"line":82,"column":58},"end":{"line":82,"column":null}}],"line":82},"9":{"loc":{"start":{"line":95,"column":6},"end":{"line":100,"column":null}},"type":"if","locations":[{"start":{"line":95,"column":6},"end":{"line":100,"column":null}},{"start":{},"end":{}}],"line":95},"10":{"loc":{"start":{"line":96,"column":8},"end":{"line":98,"column":null}},"type":"if","locations":[{"start":{"line":96,"column":8},"end":{"line":98,"column":null}},{"start":{},"end":{}}],"line":96},"11":{"loc":{"start":{"line":96,"column":12},"end":{"line":96,"column":93}},"type":"binary-expr","locations":[{"start":{"line":96,"column":12},"end":{"line":96,"column":47}},{"start":{"line":96,"column":47},"end":{"line":96,"column":71}},{"start":{"line":96,"column":71},"end":{"line":96,"column":93}}],"line":96},"12":{"loc":{"start":{"line":102,"column":6},"end":{"line":111,"column":null}},"type":"if","locations":[{"start":{"line":102,"column":6},"end":{"line":111,"column":null}},{"start":{},"end":{}}],"line":102},"13":{"loc":{"start":{"line":103,"column":8},"end":{"line":106,"column":null}},"type":"binary-expr","locations":[{"start":{"line":103,"column":8},"end":{"line":103,"column":null}},{"start":{"line":104,"column":9},"end":{"line":104,"column":null}},{"start":{"line":105,"column":10},"end":{"line":105,"column":null}},{"start":{"line":106,"column":10},"end":{"line":106,"column":null}}],"line":103},"14":{"loc":{"start":{"line":113,"column":6},"end":{"line":117,"column":null}},"type":"if","locations":[{"start":{"line":113,"column":6},"end":{"line":117,"column":null}},{"start":{},"end":{}}],"line":113},"15":{"loc":{"start":{"line":113,"column":10},"end":{"line":113,"column":64}},"type":"binary-expr","locations":[{"start":{"line":113,"column":10},"end":{"line":113,"column":37}},{"start":{"line":113,"column":37},"end":{"line":113,"column":64}}],"line":113}},"s":{"0":1,"1":1,"2":1,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":1,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0,0],"12":[0,0],"13":[0,0,0,0],"14":[0,0],"15":[0,0]},"meta":{"lastBranch":16,"lastFunction":6,"lastStatement":50,"seen":{"s:13:30:20:Infinity":0,"s:22:20:22:Infinity":1,"s:23:27:23:Infinity":2,"f:25:9:25:26":0,"b:26:2:26:Infinity:undefined:undefined:undefined:undefined":0,"s:26:2:26:Infinity":3,"s:26:33:26:Infinity":4,"s:27:16:27:Infinity":5,"b:28:2:28:Infinity:undefined:undefined:undefined:undefined":1,"s:28:2:28:Infinity":6,"b:28:6:28:14:28:14:28:47":2,"s:28:47:28:Infinity":7,"s:29:2:29:Infinity":8,"s:35:25:35:Infinity":9,"f:37:22:37:Infinity":1,"s:41:17:41:Infinity":10,"b:42:2:45:Infinity:undefined:undefined:undefined:undefined":3,"s:42:2:45:Infinity":11,"s:43:4:43:Infinity":12,"s:44:4:44:Infinity":13,"s:47:19:47:Infinity":14,"b:48:2:50:Infinity:undefined:undefined:undefined:undefined":4,"s:48:2:50:Infinity":15,"s:49:4:49:Infinity":16,"s:52:18:54:Infinity":17,"f:52:48:52:62":2,"s:53:4:53:Infinity":18,"s:56:2:56:Infinity":19,"s:57:2:57:Infinity":20,"f:65:15:65:25":3,"s:66:20:66:Infinity":21,"b:67:2:67:Infinity:undefined:undefined:undefined:undefined":5,"s:67:2:67:Infinity":22,"s:67:33:67:Infinity":23,"s:69:16:69:Infinity":24,"s:71:2:121:Infinity":25,"s:72:4:120:Infinity":26,"s:73:21:73:Infinity":27,"s:76:26:76:Infinity":28,"s:77:27:77:Infinity":29,"b:77:27:77:51:77:51:77:Infinity":6,"s:78:24:78:Infinity":30,"b:78:24:78:45:78:45:78:Infinity":7,"s:81:12:81:Infinity":31,"s:82:24:82:Infinity":32,"b:82:43:82:58:82:58:82:Infinity":8,"s:84:38:88:Infinity":33,"s:90:6:90:Infinity":34,"s:91:6:91:Infinity":35,"b:95:6:100:Infinity:undefined:undefined:undefined:undefined":9,"s:95:6:100:Infinity":36,"b:96:8:98:Infinity:undefined:undefined:undefined:undefined":10,"s:96:8:98:Infinity":37,"b:96:12:96:47:96:47:96:71:96:71:96:93":11,"s:97:10:97:Infinity":38,"s:99:8:99:Infinity":39,"b:102:6:111:Infinity:undefined:undefined:undefined:undefined":12,"s:102:6:111:Infinity":40,"b:103:8:103:Infinity:104:9:104:Infinity:105:10:105:Infinity:106:10:106:Infinity":13,"s:109:8:109:Infinity":41,"s:110:8:110:Infinity":42,"b:113:6:117:Infinity:undefined:undefined:undefined:undefined":14,"s:113:6:117:Infinity":43,"b:113:10:113:37:113:37:113:64":15,"s:114:8:114:Infinity":44,"s:115:8:115:Infinity":45,"s:116:8:116:Infinity":46,"s:119:6:119:Infinity":47,"f:124:9:124:15":4,"s:125:2:125:Infinity":48,"f:125:13:125:22":5,"s:125:34:125:57":49}}} -,"/Users/marcus/berget-monorepo/cli/src/auth/storage/token-store.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/auth/storage/token-store.ts","statementMap":{"0":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"1":{"start":{"line":23,"column":4},"end":{"line":27,"column":null}},"2":{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},"3":{"start":{"line":32,"column":4},"end":{"line":44,"column":null}},"4":{"start":{"line":33,"column":6},"end":{"line":33,"column":null}},"5":{"start":{"line":35,"column":20},"end":{"line":35,"column":null}},"6":{"start":{"line":36,"column":6},"end":{"line":38,"column":null}},"7":{"start":{"line":37,"column":8},"end":{"line":37,"column":null}},"8":{"start":{"line":39,"column":6},"end":{"line":42,"column":null}},"9":{"start":{"line":43,"column":6},"end":{"line":43,"column":null}},"10":{"start":{"line":46,"column":4},"end":{"line":63,"column":null}},"11":{"start":{"line":47,"column":21},"end":{"line":47,"column":null}},"12":{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},"13":{"start":{"line":54,"column":8},"end":{"line":54,"column":null}},"14":{"start":{"line":56,"column":6},"end":{"line":56,"column":null}},"15":{"start":{"line":58,"column":6},"end":{"line":61,"column":null}},"16":{"start":{"line":62,"column":6},"end":{"line":62,"column":null}},"17":{"start":{"line":67,"column":22},"end":{"line":67,"column":null}},"18":{"start":{"line":68,"column":4},"end":{"line":72,"column":null}},"19":{"start":{"line":69,"column":6},"end":{"line":69,"column":null}},"20":{"start":{"line":73,"column":4},"end":{"line":73,"column":null}},"21":{"start":{"line":74,"column":4},"end":{"line":74,"column":null}},"22":{"start":{"line":79,"column":20},"end":{"line":79,"column":null}},"23":{"start":{"line":80,"column":2},"end":{"line":80,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":18,"column":2},"end":{"line":18,"column":14}},"loc":{"start":{"line":18,"column":33},"end":{"line":20,"column":null}},"line":18},"1":{"name":"clear","decl":{"start":{"line":22,"column":8},"end":{"line":22,"column":31}},"loc":{"start":{"line":22,"column":31},"end":{"line":28,"column":null}},"line":22},"2":{"name":"get","decl":{"start":{"line":30,"column":8},"end":{"line":30,"column":41}},"loc":{"start":{"line":30,"column":41},"end":{"line":64,"column":null}},"line":30},"3":{"name":"set","decl":{"start":{"line":66,"column":8},"end":{"line":66,"column":12}},"loc":{"start":{"line":66,"column":44},"end":{"line":75,"column":null}},"line":66},"4":{"name":"getDefaultTokenFilePath","decl":{"start":{"line":78,"column":9},"end":{"line":78,"column":43}},"loc":{"start":{"line":78,"column":43},"end":{"line":81,"column":null}},"line":78}},"branchMap":{"0":{"loc":{"start":{"line":19,"column":25},"end":{"line":19,"column":null}},"type":"binary-expr","locations":[{"start":{"line":19,"column":25},"end":{"line":19,"column":37}},{"start":{"line":19,"column":37},"end":{"line":19,"column":null}}],"line":19},"1":{"loc":{"start":{"line":36,"column":6},"end":{"line":38,"column":null}},"type":"if","locations":[{"start":{"line":36,"column":6},"end":{"line":38,"column":null}},{"start":{},"end":{}}],"line":36},"2":{"loc":{"start":{"line":40,"column":37},"end":{"line":40,"column":61}},"type":"binary-expr","locations":[{"start":{"line":40,"column":37},"end":{"line":40,"column":45}},{"start":{"line":40,"column":45},"end":{"line":40,"column":61}}],"line":40},"3":{"loc":{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},"type":"if","locations":[{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},{"start":{},"end":{}}],"line":49},"4":{"loc":{"start":{"line":50,"column":8},"end":{"line":52,"column":null}},"type":"binary-expr","locations":[{"start":{"line":50,"column":8},"end":{"line":50,"column":null}},{"start":{"line":51,"column":8},"end":{"line":51,"column":null}},{"start":{"line":52,"column":8},"end":{"line":52,"column":null}}],"line":50}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0,0]},"meta":{"lastBranch":5,"lastFunction":5,"lastStatement":24,"seen":{"f:18:2:18:14":0,"s:19:4:19:Infinity":0,"b:19:25:19:37:19:37:19:Infinity":0,"f:22:8:22:31":1,"s:23:4:27:Infinity":1,"s:24:6:24:Infinity":2,"f:30:8:30:41":2,"s:32:4:44:Infinity":3,"s:33:6:33:Infinity":4,"s:35:20:35:Infinity":5,"b:36:6:38:Infinity:undefined:undefined:undefined:undefined":1,"s:36:6:38:Infinity":6,"s:37:8:37:Infinity":7,"s:39:6:42:Infinity":8,"b:40:37:40:45:40:45:40:61":2,"s:43:6:43:Infinity":9,"s:46:4:63:Infinity":10,"s:47:21:47:Infinity":11,"b:49:6:55:Infinity:undefined:undefined:undefined:undefined":3,"s:49:6:55:Infinity":12,"b:50:8:50:Infinity:51:8:51:Infinity:52:8:52:Infinity":4,"s:54:8:54:Infinity":13,"s:56:6:56:Infinity":14,"s:58:6:61:Infinity":15,"s:62:6:62:Infinity":16,"f:66:8:66:12":3,"s:67:22:67:Infinity":17,"s:68:4:72:Infinity":18,"s:69:6:69:Infinity":19,"s:73:4:73:Infinity":20,"s:74:4:74:Infinity":21,"f:78:9:78:43":4,"s:79:20:79:Infinity":22,"s:80:2:80:Infinity":23}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/auth-sync.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/auth-sync.ts","statementMap":{"0":{"start":{"line":32,"column":6},"end":{"line":32,"column":null}},"1":{"start":{"line":32,"column":43},"end":{"line":32,"column":null}},"2":{"start":{"line":34,"column":24},"end":{"line":37,"column":null}},"3":{"start":{"line":35,"column":33},"end":{"line":35,"column":null}},"4":{"start":{"line":36,"column":27},"end":{"line":36,"column":null}},"5":{"start":{"line":39,"column":62},"end":{"line":42,"column":null}},"6":{"start":{"line":49,"column":54},"end":{"line":49,"column":null}},"7":{"start":{"line":51,"column":22},"end":{"line":51,"column":null}},"8":{"start":{"line":53,"column":2},"end":{"line":68,"column":null}},"9":{"start":{"line":54,"column":19},"end":{"line":60,"column":null}},"10":{"start":{"line":62,"column":4},"end":{"line":64,"column":null}},"11":{"start":{"line":63,"column":6},"end":{"line":63,"column":null}},"12":{"start":{"line":66,"column":9},"end":{"line":68,"column":null}},"13":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"14":{"start":{"line":70,"column":2},"end":{"line":72,"column":null}},"15":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"16":{"start":{"line":75,"column":8},"end":{"line":75,"column":null}},"17":{"start":{"line":79,"column":2},"end":{"line":94,"column":null}},"18":{"start":{"line":80,"column":14},"end":{"line":80,"column":null}},"19":{"start":{"line":81,"column":4},"end":{"line":81,"column":null}},"20":{"start":{"line":82,"column":4},"end":{"line":88,"column":null}},"21":{"start":{"line":83,"column":6},"end":{"line":83,"column":null}},"22":{"start":{"line":84,"column":6},"end":{"line":84,"column":null}},"23":{"start":{"line":86,"column":6},"end":{"line":86,"column":null}},"24":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"25":{"start":{"line":89,"column":4},"end":{"line":92,"column":null}},"26":{"start":{"line":93,"column":4},"end":{"line":93,"column":null}},"27":{"start":{"line":97,"column":8},"end":{"line":97,"column":null}},"28":{"start":{"line":99,"column":2},"end":{"line":140,"column":null}},"29":{"start":{"line":101,"column":19},"end":{"line":107,"column":null}},"30":{"start":{"line":109,"column":4},"end":{"line":120,"column":null}},"31":{"start":{"line":110,"column":16},"end":{"line":110,"column":null}},"32":{"start":{"line":111,"column":6},"end":{"line":111,"column":null}},"33":{"start":{"line":112,"column":6},"end":{"line":118,"column":null}},"34":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"35":{"start":{"line":114,"column":8},"end":{"line":114,"column":null}},"36":{"start":{"line":116,"column":8},"end":{"line":116,"column":null}},"37":{"start":{"line":117,"column":8},"end":{"line":117,"column":null}},"38":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"39":{"start":{"line":123,"column":14},"end":{"line":123,"column":null}},"40":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"41":{"start":{"line":125,"column":4},"end":{"line":139,"column":null}},"42":{"start":{"line":126,"column":22},"end":{"line":129,"column":null}},"43":{"start":{"line":130,"column":6},"end":{"line":130,"column":null}},"44":{"start":{"line":131,"column":6},"end":{"line":131,"column":null}},"45":{"start":{"line":132,"column":6},"end":{"line":132,"column":null}},"46":{"start":{"line":134,"column":6},"end":{"line":134,"column":null}},"47":{"start":{"line":135,"column":6},"end":{"line":138,"column":null}},"48":{"start":{"line":143,"column":23},"end":{"line":146,"column":null}},"49":{"start":{"line":148,"column":2},"end":{"line":166,"column":null}},"50":{"start":{"line":149,"column":14},"end":{"line":149,"column":null}},"51":{"start":{"line":150,"column":4},"end":{"line":150,"column":null}},"52":{"start":{"line":151,"column":4},"end":{"line":165,"column":null}},"53":{"start":{"line":152,"column":22},"end":{"line":155,"column":null}},"54":{"start":{"line":156,"column":6},"end":{"line":156,"column":null}},"55":{"start":{"line":157,"column":6},"end":{"line":157,"column":null}},"56":{"start":{"line":158,"column":6},"end":{"line":158,"column":null}},"57":{"start":{"line":160,"column":6},"end":{"line":160,"column":null}},"58":{"start":{"line":161,"column":6},"end":{"line":164,"column":null}},"59":{"start":{"line":169,"column":2},"end":{"line":172,"column":null}},"60":{"start":{"line":173,"column":2},"end":{"line":173,"column":null}},"61":{"start":{"line":179,"column":52},"end":{"line":179,"column":null}},"62":{"start":{"line":181,"column":34},"end":{"line":181,"column":null}},"63":{"start":{"line":183,"column":2},"end":{"line":185,"column":null}},"64":{"start":{"line":184,"column":4},"end":{"line":184,"column":null}},"65":{"start":{"line":187,"column":2},"end":{"line":187,"column":null}},"66":{"start":{"line":189,"column":12},"end":{"line":189,"column":null}},"67":{"start":{"line":190,"column":2},"end":{"line":190,"column":null}},"68":{"start":{"line":192,"column":22},"end":{"line":194,"column":null}},"69":{"start":{"line":195,"column":2},"end":{"line":202,"column":null}},"70":{"start":{"line":196,"column":4},"end":{"line":196,"column":null}},"71":{"start":{"line":197,"column":4},"end":{"line":200,"column":null}},"72":{"start":{"line":201,"column":4},"end":{"line":201,"column":null}},"73":{"start":{"line":204,"column":2},"end":{"line":204,"column":null}},"74":{"start":{"line":206,"column":8},"end":{"line":206,"column":null}},"75":{"start":{"line":207,"column":2},"end":{"line":211,"column":null}},"76":{"start":{"line":208,"column":4},"end":{"line":208,"column":null}},"77":{"start":{"line":209,"column":4},"end":{"line":209,"column":null}},"78":{"start":{"line":210,"column":4},"end":{"line":210,"column":null}},"79":{"start":{"line":213,"column":2},"end":{"line":217,"column":null}},"80":{"start":{"line":225,"column":18},"end":{"line":225,"column":null}},"81":{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},"82":{"start":{"line":226,"column":16},"end":{"line":226,"column":null}},"83":{"start":{"line":227,"column":2},"end":{"line":232,"column":null}},"84":{"start":{"line":228,"column":19},"end":{"line":228,"column":null}},"85":{"start":{"line":229,"column":4},"end":{"line":229,"column":null}},"86":{"start":{"line":231,"column":4},"end":{"line":231,"column":null}},"87":{"start":{"line":236,"column":18},"end":{"line":236,"column":null}},"88":{"start":{"line":237,"column":2},"end":{"line":237,"column":null}},"89":{"start":{"line":237,"column":16},"end":{"line":237,"column":null}},"90":{"start":{"line":239,"column":2},"end":{"line":247,"column":null}},"91":{"start":{"line":240,"column":4},"end":{"line":240,"column":null}},"92":{"start":{"line":242,"column":4},"end":{"line":245,"column":null}},"93":{"start":{"line":246,"column":4},"end":{"line":246,"column":null}},"94":{"start":{"line":248,"column":2},"end":{"line":260,"column":null}},"95":{"start":{"line":250,"column":10},"end":{"line":250,"column":null}},"96":{"start":{"line":251,"column":4},"end":{"line":254,"column":null}},"97":{"start":{"line":253,"column":6},"end":{"line":253,"column":null}},"98":{"start":{"line":255,"column":4},"end":{"line":259,"column":null}},"99":{"start":{"line":261,"column":2},"end":{"line":261,"column":null}},"100":{"start":{"line":270,"column":19},"end":{"line":270,"column":null}},"101":{"start":{"line":271,"column":42},"end":{"line":271,"column":null}},"102":{"start":{"line":273,"column":18},"end":{"line":273,"column":null}},"103":{"start":{"line":274,"column":2},"end":{"line":280,"column":null}},"104":{"start":{"line":275,"column":4},"end":{"line":279,"column":null}},"105":{"start":{"line":276,"column":6},"end":{"line":276,"column":null}},"106":{"start":{"line":278,"column":6},"end":{"line":278,"column":null}},"107":{"start":{"line":282,"column":18},"end":{"line":288,"column":null}},"108":{"start":{"line":290,"column":2},"end":{"line":290,"column":null}},"109":{"start":{"line":291,"column":2},"end":{"line":291,"column":null}},"110":{"start":{"line":300,"column":19},"end":{"line":300,"column":null}},"111":{"start":{"line":301,"column":42},"end":{"line":301,"column":null}},"112":{"start":{"line":303,"column":18},"end":{"line":303,"column":null}},"113":{"start":{"line":304,"column":2},"end":{"line":310,"column":null}},"114":{"start":{"line":305,"column":4},"end":{"line":309,"column":null}},"115":{"start":{"line":306,"column":6},"end":{"line":306,"column":null}},"116":{"start":{"line":308,"column":6},"end":{"line":308,"column":null}},"117":{"start":{"line":313,"column":8},"end":{"line":313,"column":null}},"118":{"start":{"line":315,"column":18},"end":{"line":323,"column":null}},"119":{"start":{"line":325,"column":2},"end":{"line":325,"column":null}},"120":{"start":{"line":326,"column":2},"end":{"line":326,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":32,"column":6},"end":{"line":32,"column":23}},"loc":{"start":{"line":32,"column":43},"end":{"line":32,"column":null}},"line":32},"1":{"name":"(anonymous_1)","decl":{"start":{"line":35,"column":2},"end":{"line":35,"column":13}},"loc":{"start":{"line":35,"column":33},"end":{"line":35,"column":null}},"line":35},"2":{"name":"(anonymous_2)","decl":{"start":{"line":36,"column":2},"end":{"line":36,"column":7}},"loc":{"start":{"line":36,"column":27},"end":{"line":36,"column":null}},"line":36},"3":{"name":"configureAuth","decl":{"start":{"line":44,"column":22},"end":{"line":44,"column":null}},"loc":{"start":{"line":48,"column":23},"end":{"line":174,"column":null}},"line":48},"4":{"name":"ensureCliAuth","decl":{"start":{"line":176,"column":22},"end":{"line":176,"column":null}},"loc":{"start":{"line":178,"column":27},"end":{"line":218,"column":null}},"line":178},"5":{"name":"isToolAuthenticated","decl":{"start":{"line":220,"column":22},"end":{"line":220,"column":null}},"loc":{"start":{"line":224,"column":20},"end":{"line":233,"column":null}},"line":224},"6":{"name":"readCliAuth","decl":{"start":{"line":235,"column":22},"end":{"line":235,"column":34}},"loc":{"start":{"line":235,"column":94},"end":{"line":262,"column":null}},"line":235},"7":{"name":"syncApiKeyToTool","decl":{"start":{"line":264,"column":22},"end":{"line":264,"column":null}},"loc":{"start":{"line":269,"column":17},"end":{"line":292,"column":null}},"line":269},"8":{"name":"syncOAuthToTool","decl":{"start":{"line":294,"column":22},"end":{"line":294,"column":null}},"loc":{"start":{"line":299,"column":17},"end":{"line":327,"column":null}},"line":299}},"branchMap":{"0":{"loc":{"start":{"line":53,"column":2},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":2},"end":{"line":68,"column":null}},{"start":{"line":66,"column":9},"end":{"line":68,"column":null}}],"line":53},"1":{"loc":{"start":{"line":55,"column":61},"end":{"line":55,"column":101}},"type":"cond-expr","locations":[{"start":{"line":55,"column":83},"end":{"line":55,"column":96}},{"start":{"line":55,"column":96},"end":{"line":55,"column":101}}],"line":55},"2":{"loc":{"start":{"line":62,"column":4},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":62,"column":4},"end":{"line":64,"column":null}},{"start":{},"end":{}}],"line":62},"3":{"loc":{"start":{"line":66,"column":9},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":66,"column":9},"end":{"line":68,"column":null}},{"start":{},"end":{}}],"line":66},"4":{"loc":{"start":{"line":70,"column":2},"end":{"line":72,"column":null}},"type":"if","locations":[{"start":{"line":70,"column":2},"end":{"line":72,"column":null}},{"start":{},"end":{}}],"line":70},"5":{"loc":{"start":{"line":79,"column":2},"end":{"line":94,"column":null}},"type":"if","locations":[{"start":{"line":79,"column":2},"end":{"line":94,"column":null}},{"start":{},"end":{}}],"line":79},"6":{"loc":{"start":{"line":99,"column":2},"end":{"line":140,"column":null}},"type":"if","locations":[{"start":{"line":99,"column":2},"end":{"line":140,"column":null}},{"start":{},"end":{}}],"line":99},"7":{"loc":{"start":{"line":109,"column":4},"end":{"line":120,"column":null}},"type":"if","locations":[{"start":{"line":109,"column":4},"end":{"line":120,"column":null}},{"start":{},"end":{}}],"line":109},"8":{"loc":{"start":{"line":128,"column":17},"end":{"line":128,"column":57}},"type":"cond-expr","locations":[{"start":{"line":128,"column":39},"end":{"line":128,"column":52}},{"start":{"line":128,"column":52},"end":{"line":128,"column":57}}],"line":128},"9":{"loc":{"start":{"line":136,"column":8},"end":{"line":137,"column":null}},"type":"binary-expr","locations":[{"start":{"line":136,"column":8},"end":{"line":136,"column":null}},{"start":{"line":137,"column":10},"end":{"line":137,"column":null}}],"line":136},"10":{"loc":{"start":{"line":148,"column":2},"end":{"line":166,"column":null}},"type":"if","locations":[{"start":{"line":148,"column":2},"end":{"line":166,"column":null}},{"start":{},"end":{}}],"line":148},"11":{"loc":{"start":{"line":154,"column":17},"end":{"line":154,"column":57}},"type":"cond-expr","locations":[{"start":{"line":154,"column":39},"end":{"line":154,"column":52}},{"start":{"line":154,"column":52},"end":{"line":154,"column":57}}],"line":154},"12":{"loc":{"start":{"line":162,"column":8},"end":{"line":163,"column":null}},"type":"binary-expr","locations":[{"start":{"line":162,"column":8},"end":{"line":162,"column":null}},{"start":{"line":163,"column":10},"end":{"line":163,"column":null}}],"line":162},"13":{"loc":{"start":{"line":183,"column":2},"end":{"line":185,"column":null}},"type":"if","locations":[{"start":{"line":183,"column":2},"end":{"line":185,"column":null}},{"start":{},"end":{}}],"line":183},"14":{"loc":{"start":{"line":183,"column":6},"end":{"line":183,"column":54}},"type":"binary-expr","locations":[{"start":{"line":183,"column":6},"end":{"line":183,"column":17}},{"start":{"line":183,"column":17},"end":{"line":183,"column":54}}],"line":183},"15":{"loc":{"start":{"line":195,"column":2},"end":{"line":202,"column":null}},"type":"if","locations":[{"start":{"line":195,"column":2},"end":{"line":202,"column":null}},{"start":{},"end":{}}],"line":195},"16":{"loc":{"start":{"line":198,"column":9},"end":{"line":198,"column":66}},"type":"binary-expr","locations":[{"start":{"line":198,"column":9},"end":{"line":198,"column":30}},{"start":{"line":198,"column":30},"end":{"line":198,"column":66}}],"line":198},"17":{"loc":{"start":{"line":207,"column":2},"end":{"line":211,"column":null}},"type":"if","locations":[{"start":{"line":207,"column":2},"end":{"line":211,"column":null}},{"start":{},"end":{}}],"line":207},"18":{"loc":{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},"type":"if","locations":[{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},{"start":{},"end":{}}],"line":226},"19":{"loc":{"start":{"line":229,"column":11},"end":{"line":229,"column":null}},"type":"binary-expr","locations":[{"start":{"line":229,"column":11},"end":{"line":229,"column":48}},{"start":{"line":229,"column":48},"end":{"line":229,"column":null}}],"line":229},"20":{"loc":{"start":{"line":237,"column":2},"end":{"line":237,"column":null}},"type":"if","locations":[{"start":{"line":237,"column":2},"end":{"line":237,"column":null}},{"start":{},"end":{}}],"line":237},"21":{"loc":{"start":{"line":248,"column":2},"end":{"line":260,"column":null}},"type":"if","locations":[{"start":{"line":248,"column":2},"end":{"line":260,"column":null}},{"start":{},"end":{}}],"line":248},"22":{"loc":{"start":{"line":248,"column":6},"end":{"line":248,"column":51}},"type":"binary-expr","locations":[{"start":{"line":248,"column":6},"end":{"line":248,"column":29}},{"start":{"line":248,"column":29},"end":{"line":248,"column":51}}],"line":248},"23":{"loc":{"start":{"line":251,"column":4},"end":{"line":254,"column":null}},"type":"if","locations":[{"start":{"line":251,"column":4},"end":{"line":254,"column":null}},{"start":{},"end":{}}],"line":251},"24":{"loc":{"start":{"line":274,"column":2},"end":{"line":280,"column":null}},"type":"if","locations":[{"start":{"line":274,"column":2},"end":{"line":280,"column":null}},{"start":{},"end":{}}],"line":274},"25":{"loc":{"start":{"line":304,"column":2},"end":{"line":310,"column":null}},"type":"if","locations":[{"start":{"line":304,"column":2},"end":{"line":310,"column":null}},{"start":{},"end":{}}],"line":304}},"s":{"0":1,"1":46,"2":1,"3":24,"4":15,"5":1,"6":36,"7":36,"8":36,"9":1,"10":1,"11":1,"12":35,"13":3,"14":35,"15":32,"16":3,"17":3,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":3,"28":3,"29":2,"30":2,"31":2,"32":2,"33":2,"34":2,"35":2,"36":0,"37":0,"38":2,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":1,"49":1,"50":1,"51":1,"52":1,"53":1,"54":1,"55":1,"56":1,"57":0,"58":0,"59":0,"60":0,"61":46,"62":46,"63":46,"64":2,"65":44,"66":44,"67":44,"68":44,"69":44,"70":43,"71":43,"72":43,"73":1,"74":1,"75":1,"76":0,"77":0,"78":0,"79":1,"80":36,"81":36,"82":35,"83":1,"84":1,"85":1,"86":0,"87":46,"88":46,"89":44,"90":2,"91":2,"92":0,"93":0,"94":2,"95":2,"96":2,"97":0,"98":2,"99":0,"100":1,"101":1,"102":1,"103":1,"104":0,"105":0,"106":0,"107":1,"108":1,"109":1,"110":2,"111":2,"112":2,"113":2,"114":0,"115":0,"116":0,"117":2,"118":2,"119":2,"120":2},"f":{"0":46,"1":24,"2":15,"3":36,"4":46,"5":36,"6":46,"7":1,"8":2},"b":{"0":[1,35],"1":[1,0],"2":[1,0],"3":[3,32],"4":[32,3],"5":[0,3],"6":[2,1],"7":[2,0],"8":[0,0],"9":[0,0],"10":[1,0],"11":[0,1],"12":[0,0],"13":[2,44],"14":[46,2],"15":[43,1],"16":[43,0],"17":[0,1],"18":[35,1],"19":[1,1],"20":[44,2],"21":[2,0],"22":[2,2],"23":[0,2],"24":[0,1],"25":[0,2]},"meta":{"lastBranch":26,"lastFunction":9,"lastStatement":121,"seen":{"s:32:6:32:Infinity":0,"f:32:6:32:23":0,"s:32:43:32:Infinity":1,"s:34:24:37:Infinity":2,"f:35:2:35:13":1,"s:35:33:35:Infinity":3,"f:36:2:36:7":2,"s:36:27:36:Infinity":4,"s:39:62:42:Infinity":5,"f:44:22:44:Infinity":3,"s:49:54:49:Infinity":6,"s:51:22:51:Infinity":7,"b:53:2:68:Infinity:66:9:68:Infinity":0,"s:53:2:68:Infinity":8,"s:54:19:60:Infinity":9,"b:55:83:55:96:55:96:55:101":1,"b:62:4:64:Infinity:undefined:undefined:undefined:undefined":2,"s:62:4:64:Infinity":10,"s:63:6:63:Infinity":11,"b:66:9:68:Infinity:undefined:undefined:undefined:undefined":3,"s:66:9:68:Infinity":12,"s:67:4:67:Infinity":13,"b:70:2:72:Infinity:undefined:undefined:undefined:undefined":4,"s:70:2:72:Infinity":14,"s:71:4:71:Infinity":15,"s:75:8:75:Infinity":16,"b:79:2:94:Infinity:undefined:undefined:undefined:undefined":5,"s:79:2:94:Infinity":17,"s:80:14:80:Infinity":18,"s:81:4:81:Infinity":19,"s:82:4:88:Infinity":20,"s:83:6:83:Infinity":21,"s:84:6:84:Infinity":22,"s:86:6:86:Infinity":23,"s:87:6:87:Infinity":24,"s:89:4:92:Infinity":25,"s:93:4:93:Infinity":26,"s:97:8:97:Infinity":27,"b:99:2:140:Infinity:undefined:undefined:undefined:undefined":6,"s:99:2:140:Infinity":28,"s:101:19:107:Infinity":29,"b:109:4:120:Infinity:undefined:undefined:undefined:undefined":7,"s:109:4:120:Infinity":30,"s:110:16:110:Infinity":31,"s:111:6:111:Infinity":32,"s:112:6:118:Infinity":33,"s:113:8:113:Infinity":34,"s:114:8:114:Infinity":35,"s:116:8:116:Infinity":36,"s:117:8:117:Infinity":37,"s:119:6:119:Infinity":38,"s:123:14:123:Infinity":39,"s:124:4:124:Infinity":40,"s:125:4:139:Infinity":41,"s:126:22:129:Infinity":42,"b:128:39:128:52:128:52:128:57":8,"s:130:6:130:Infinity":43,"s:131:6:131:Infinity":44,"s:132:6:132:Infinity":45,"s:134:6:134:Infinity":46,"s:135:6:138:Infinity":47,"b:136:8:136:Infinity:137:10:137:Infinity":9,"s:143:23:146:Infinity":48,"b:148:2:166:Infinity:undefined:undefined:undefined:undefined":10,"s:148:2:166:Infinity":49,"s:149:14:149:Infinity":50,"s:150:4:150:Infinity":51,"s:151:4:165:Infinity":52,"s:152:22:155:Infinity":53,"b:154:39:154:52:154:52:154:57":11,"s:156:6:156:Infinity":54,"s:157:6:157:Infinity":55,"s:158:6:158:Infinity":56,"s:160:6:160:Infinity":57,"s:161:6:164:Infinity":58,"b:162:8:162:Infinity:163:10:163:Infinity":12,"s:169:2:172:Infinity":59,"s:173:2:173:Infinity":60,"f:176:22:176:Infinity":4,"s:179:52:179:Infinity":61,"s:181:34:181:Infinity":62,"b:183:2:185:Infinity:undefined:undefined:undefined:undefined":13,"s:183:2:185:Infinity":63,"b:183:6:183:17:183:17:183:54":14,"s:184:4:184:Infinity":64,"s:187:2:187:Infinity":65,"s:189:12:189:Infinity":66,"s:190:2:190:Infinity":67,"s:192:22:194:Infinity":68,"b:195:2:202:Infinity:undefined:undefined:undefined:undefined":15,"s:195:2:202:Infinity":69,"s:196:4:196:Infinity":70,"s:197:4:200:Infinity":71,"b:198:9:198:30:198:30:198:66":16,"s:201:4:201:Infinity":72,"s:204:2:204:Infinity":73,"s:206:8:206:Infinity":74,"b:207:2:211:Infinity:undefined:undefined:undefined:undefined":17,"s:207:2:211:Infinity":75,"s:208:4:208:Infinity":76,"s:209:4:209:Infinity":77,"s:210:4:210:Infinity":78,"s:213:2:217:Infinity":79,"f:220:22:220:Infinity":5,"s:225:18:225:Infinity":80,"b:226:2:226:Infinity:undefined:undefined:undefined:undefined":18,"s:226:2:226:Infinity":81,"s:226:16:226:Infinity":82,"s:227:2:232:Infinity":83,"s:228:19:228:Infinity":84,"s:229:4:229:Infinity":85,"b:229:11:229:48:229:48:229:Infinity":19,"s:231:4:231:Infinity":86,"f:235:22:235:34":6,"s:236:18:236:Infinity":87,"b:237:2:237:Infinity:undefined:undefined:undefined:undefined":20,"s:237:2:237:Infinity":88,"s:237:16:237:Infinity":89,"s:239:2:247:Infinity":90,"s:240:4:240:Infinity":91,"s:242:4:245:Infinity":92,"s:246:4:246:Infinity":93,"b:248:2:260:Infinity:undefined:undefined:undefined:undefined":21,"s:248:2:260:Infinity":94,"b:248:6:248:29:248:29:248:51":22,"s:250:10:250:Infinity":95,"b:251:4:254:Infinity:undefined:undefined:undefined:undefined":23,"s:251:4:254:Infinity":96,"s:253:6:253:Infinity":97,"s:255:4:259:Infinity":98,"s:261:2:261:Infinity":99,"f:264:22:264:Infinity":7,"s:270:19:270:Infinity":100,"s:271:42:271:Infinity":101,"s:273:18:273:Infinity":102,"b:274:2:280:Infinity:undefined:undefined:undefined:undefined":24,"s:274:2:280:Infinity":103,"s:275:4:279:Infinity":104,"s:276:6:276:Infinity":105,"s:278:6:278:Infinity":106,"s:282:18:288:Infinity":107,"s:290:2:290:Infinity":108,"s:291:2:291:Infinity":109,"f:294:22:294:Infinity":8,"s:300:19:300:Infinity":110,"s:301:42:301:Infinity":111,"s:303:18:303:Infinity":112,"b:304:2:310:Infinity:undefined:undefined:undefined:undefined":25,"s:304:2:310:Infinity":113,"s:305:4:309:Infinity":114,"s:306:6:306:Infinity":115,"s:308:6:308:Infinity":116,"s:313:8:313:Infinity":117,"s:315:18:323:Infinity":118,"s:325:2:325:Infinity":119,"s:326:2:326:Infinity":120}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/errors.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/errors.ts","statementMap":{"0":{"start":{"line":3,"column":4},"end":{"line":3,"column":null}},"1":{"start":{"line":4,"column":4},"end":{"line":4,"column":null}},"2":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"3":{"start":{"line":10,"column":20},"end":{"line":10,"column":null}},"4":{"start":{"line":11,"column":20},"end":{"line":11,"column":null}},"5":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"6":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"7":{"start":{"line":21,"column":4},"end":{"line":21,"column":null}},"8":{"start":{"line":27,"column":4},"end":{"line":27,"column":null}},"9":{"start":{"line":26,"column":30},"end":{"line":26,"column":46}},"10":{"start":{"line":28,"column":4},"end":{"line":28,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":2,"column":2},"end":{"line":2,"column":16}},"loc":{"start":{"line":2,"column":16},"end":{"line":5,"column":null}},"line":2},"1":{"name":"constructor","decl":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"loc":{"start":{"line":12,"column":4},"end":{"line":15,"column":null}},"line":12},"2":{"name":"constructor","decl":{"start":{"line":19,"column":2},"end":{"line":19,"column":14}},"loc":{"start":{"line":19,"column":31},"end":{"line":22,"column":null}},"line":19},"3":{"name":"constructor","decl":{"start":{"line":26,"column":2},"end":{"line":26,"column":14}},"loc":{"start":{"line":26,"column":46},"end":{"line":29,"column":null}},"line":26}},"branchMap":{},"s":{"0":6,"1":6,"2":2,"3":2,"4":2,"5":2,"6":5,"7":5,"8":1,"9":1,"10":1},"f":{"0":6,"1":2,"2":5,"3":1},"b":{},"meta":{"lastBranch":0,"lastFunction":4,"lastStatement":11,"seen":{"f:2:2:2:16":0,"s:3:4:3:Infinity":0,"s:4:4:4:Infinity":1,"f:9:2:9:Infinity":1,"s:13:4:13:Infinity":2,"s:10:20:10:Infinity":3,"s:11:20:11:Infinity":4,"s:14:4:14:Infinity":5,"f:19:2:19:14":2,"s:20:4:20:Infinity":6,"s:21:4:21:Infinity":7,"f:26:2:26:14":3,"s:27:4:27:Infinity":8,"s:26:30:26:46":9,"s:28:4:28:Infinity":10}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/init.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/init.ts","statementMap":{"0":{"start":{"line":42,"column":2},"end":{"line":52,"column":null}},"1":{"start":{"line":43,"column":4},"end":{"line":43,"column":null}},"2":{"start":{"line":44,"column":4},"end":{"line":44,"column":null}},"3":{"start":{"line":46,"column":4},"end":{"line":46,"column":null}},"4":{"start":{"line":46,"column":41},"end":{"line":46,"column":null}},"5":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"6":{"start":{"line":47,"column":37},"end":{"line":47,"column":null}},"7":{"start":{"line":48,"column":4},"end":{"line":49,"column":null}},"8":{"start":{"line":49,"column":6},"end":{"line":49,"column":null}},"9":{"start":{"line":50,"column":4},"end":{"line":50,"column":null}},"10":{"start":{"line":50,"column":45},"end":{"line":50,"column":null}},"11":{"start":{"line":51,"column":4},"end":{"line":51,"column":null}},"12":{"start":{"line":56,"column":89},"end":{"line":56,"column":null}},"13":{"start":{"line":58,"column":2},"end":{"line":58,"column":null}},"14":{"start":{"line":59,"column":2},"end":{"line":62,"column":null}},"15":{"start":{"line":64,"column":18},"end":{"line":64,"column":null}},"16":{"start":{"line":66,"column":18},"end":{"line":66,"column":null}},"17":{"start":{"line":67,"column":18},"end":{"line":67,"column":null}},"18":{"start":{"line":69,"column":15},"end":{"line":84,"column":null}},"19":{"start":{"line":87,"column":20},"end":{"line":87,"column":null}},"20":{"start":{"line":88,"column":23},"end":{"line":88,"column":null}},"21":{"start":{"line":90,"column":2},"end":{"line":125,"column":null}},"22":{"start":{"line":93,"column":4},"end":{"line":97,"column":null}},"23":{"start":{"line":94,"column":6},"end":{"line":96,"column":null}},"24":{"start":{"line":99,"column":19},"end":{"line":99,"column":null}},"25":{"start":{"line":101,"column":4},"end":{"line":103,"column":null}},"26":{"start":{"line":102,"column":6},"end":{"line":102,"column":null}},"27":{"start":{"line":105,"column":4},"end":{"line":120,"column":null}},"28":{"start":{"line":107,"column":22},"end":{"line":107,"column":null}},"29":{"start":{"line":108,"column":6},"end":{"line":119,"column":null}},"30":{"start":{"line":109,"column":8},"end":{"line":109,"column":null}},"31":{"start":{"line":111,"column":29},"end":{"line":111,"column":null}},"32":{"start":{"line":112,"column":8},"end":{"line":112,"column":null}},"33":{"start":{"line":112,"column":37},"end":{"line":112,"column":null}},"34":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"35":{"start":{"line":113,"column":41},"end":{"line":113,"column":null}},"36":{"start":{"line":114,"column":8},"end":{"line":118,"column":null}},"37":{"start":{"line":116,"column":29},"end":{"line":116,"column":null}},"38":{"start":{"line":117,"column":10},"end":{"line":117,"column":null}},"39":{"start":{"line":122,"column":4},"end":{"line":124,"column":null}},"40":{"start":{"line":123,"column":6},"end":{"line":123,"column":null}},"41":{"start":{"line":127,"column":16},"end":{"line":156,"column":null}},"42":{"start":{"line":158,"column":2},"end":{"line":158,"column":null}},"43":{"start":{"line":160,"column":21},"end":{"line":164,"column":null}},"44":{"start":{"line":167,"column":2},"end":{"line":175,"column":null}},"45":{"start":{"line":168,"column":4},"end":{"line":174,"column":null}},"46":{"start":{"line":169,"column":6},"end":{"line":169,"column":null}},"47":{"start":{"line":170,"column":6},"end":{"line":170,"column":null}},"48":{"start":{"line":172,"column":6},"end":{"line":172,"column":null}},"49":{"start":{"line":173,"column":6},"end":{"line":173,"column":null}},"50":{"start":{"line":177,"column":20},"end":{"line":191,"column":null}},"51":{"start":{"line":193,"column":19},"end":{"line":193,"column":null}},"52":{"start":{"line":195,"column":4},"end":{"line":197,"column":null}},"53":{"start":{"line":199,"column":2},"end":{"line":202,"column":null}},"54":{"start":{"line":204,"column":2},"end":{"line":204,"column":null}},"55":{"start":{"line":208,"column":17},"end":{"line":217,"column":null}},"56":{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},"57":{"start":{"line":219,"column":21},"end":{"line":219,"column":null}},"58":{"start":{"line":220,"column":2},"end":{"line":220,"column":null}}},"fnMap":{"0":{"name":"executeInitCommand","decl":{"start":{"line":41,"column":22},"end":{"line":41,"column":41}},"loc":{"start":{"line":41,"column":87},"end":{"line":53,"column":null}},"line":41},"1":{"name":"runInit","decl":{"start":{"line":55,"column":22},"end":{"line":55,"column":30}},"loc":{"start":{"line":55,"column":63},"end":{"line":205,"column":null}},"line":55},"2":{"name":"runInitCommand","decl":{"start":{"line":207,"column":22},"end":{"line":207,"column":54}},"loc":{"start":{"line":207,"column":54},"end":{"line":221,"column":null}},"line":207}},"branchMap":{"0":{"loc":{"start":{"line":46,"column":4},"end":{"line":46,"column":null}},"type":"if","locations":[{"start":{"line":46,"column":4},"end":{"line":46,"column":null}},{"start":{},"end":{}}],"line":46},"1":{"loc":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},{"start":{},"end":{}}],"line":47},"2":{"loc":{"start":{"line":48,"column":4},"end":{"line":49,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":4},"end":{"line":49,"column":null}},{"start":{},"end":{}}],"line":48},"3":{"loc":{"start":{"line":50,"column":4},"end":{"line":50,"column":null}},"type":"if","locations":[{"start":{"line":50,"column":4},"end":{"line":50,"column":null}},{"start":{},"end":{}}],"line":50},"4":{"loc":{"start":{"line":90,"column":2},"end":{"line":125,"column":null}},"type":"if","locations":[{"start":{"line":90,"column":2},"end":{"line":125,"column":null}},{"start":{},"end":{}}],"line":90},"5":{"loc":{"start":{"line":93,"column":4},"end":{"line":97,"column":null}},"type":"if","locations":[{"start":{"line":93,"column":4},"end":{"line":97,"column":null}},{"start":{},"end":{}}],"line":93},"6":{"loc":{"start":{"line":101,"column":4},"end":{"line":103,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":4},"end":{"line":103,"column":null}},{"start":{},"end":{}}],"line":101},"7":{"loc":{"start":{"line":105,"column":4},"end":{"line":120,"column":null}},"type":"if","locations":[{"start":{"line":105,"column":4},"end":{"line":120,"column":null}},{"start":{},"end":{}}],"line":105},"8":{"loc":{"start":{"line":108,"column":6},"end":{"line":119,"column":null}},"type":"if","locations":[{"start":{"line":108,"column":6},"end":{"line":119,"column":null}},{"start":{"line":110,"column":13},"end":{"line":119,"column":null}}],"line":108},"9":{"loc":{"start":{"line":112,"column":8},"end":{"line":112,"column":null}},"type":"if","locations":[{"start":{"line":112,"column":8},"end":{"line":112,"column":null}},{"start":{},"end":{}}],"line":112},"10":{"loc":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"type":"if","locations":[{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},{"start":{},"end":{}}],"line":113},"11":{"loc":{"start":{"line":114,"column":8},"end":{"line":118,"column":null}},"type":"if","locations":[{"start":{"line":114,"column":8},"end":{"line":118,"column":null}},{"start":{},"end":{}}],"line":114},"12":{"loc":{"start":{"line":122,"column":4},"end":{"line":124,"column":null}},"type":"if","locations":[{"start":{"line":122,"column":4},"end":{"line":124,"column":null}},{"start":{},"end":{}}],"line":122},"13":{"loc":{"start":{"line":133,"column":10},"end":{"line":139,"column":null}},"type":"cond-expr","locations":[{"start":{"line":134,"column":14},"end":{"line":136,"column":null}},{"start":{"line":137,"column":14},"end":{"line":139,"column":null}}],"line":133},"14":{"loc":{"start":{"line":134,"column":14},"end":{"line":136,"column":null}},"type":"cond-expr","locations":[{"start":{"line":135,"column":16},"end":{"line":135,"column":null}},{"start":{"line":136,"column":16},"end":{"line":136,"column":null}}],"line":134},"15":{"loc":{"start":{"line":137,"column":14},"end":{"line":139,"column":null}},"type":"cond-expr","locations":[{"start":{"line":138,"column":16},"end":{"line":138,"column":null}},{"start":{"line":139,"column":16},"end":{"line":139,"column":null}}],"line":137},"16":{"loc":{"start":{"line":145,"column":10},"end":{"line":151,"column":null}},"type":"cond-expr","locations":[{"start":{"line":146,"column":14},"end":{"line":148,"column":null}},{"start":{"line":149,"column":14},"end":{"line":151,"column":null}}],"line":145},"17":{"loc":{"start":{"line":146,"column":14},"end":{"line":148,"column":null}},"type":"cond-expr","locations":[{"start":{"line":147,"column":16},"end":{"line":147,"column":null}},{"start":{"line":148,"column":16},"end":{"line":148,"column":null}}],"line":146},"18":{"loc":{"start":{"line":149,"column":14},"end":{"line":151,"column":null}},"type":"cond-expr","locations":[{"start":{"line":150,"column":16},"end":{"line":150,"column":null}},{"start":{"line":151,"column":16},"end":{"line":151,"column":null}}],"line":149},"19":{"loc":{"start":{"line":167,"column":2},"end":{"line":175,"column":null}},"type":"if","locations":[{"start":{"line":167,"column":2},"end":{"line":175,"column":null}},{"start":{},"end":{}}],"line":167},"20":{"loc":{"start":{"line":168,"column":4},"end":{"line":174,"column":null}},"type":"if","locations":[{"start":{"line":168,"column":4},"end":{"line":174,"column":null}},{"start":{"line":171,"column":11},"end":{"line":174,"column":null}}],"line":168},"21":{"loc":{"start":{"line":177,"column":20},"end":{"line":191,"column":null}},"type":"cond-expr","locations":[{"start":{"line":178,"column":6},"end":{"line":184,"column":null}},{"start":{"line":185,"column":6},"end":{"line":191,"column":null}}],"line":177},"22":{"loc":{"start":{"line":178,"column":6},"end":{"line":184,"column":null}},"type":"cond-expr","locations":[{"start":{"line":179,"column":8},"end":{"line":181,"column":null}},{"start":{"line":182,"column":8},"end":{"line":184,"column":null}}],"line":178},"23":{"loc":{"start":{"line":179,"column":8},"end":{"line":181,"column":null}},"type":"cond-expr","locations":[{"start":{"line":180,"column":10},"end":{"line":180,"column":null}},{"start":{"line":181,"column":10},"end":{"line":181,"column":null}}],"line":179},"24":{"loc":{"start":{"line":182,"column":8},"end":{"line":184,"column":null}},"type":"cond-expr","locations":[{"start":{"line":183,"column":10},"end":{"line":183,"column":null}},{"start":{"line":184,"column":10},"end":{"line":184,"column":null}}],"line":182},"25":{"loc":{"start":{"line":185,"column":6},"end":{"line":191,"column":null}},"type":"cond-expr","locations":[{"start":{"line":186,"column":8},"end":{"line":188,"column":null}},{"start":{"line":189,"column":8},"end":{"line":191,"column":null}}],"line":185},"26":{"loc":{"start":{"line":186,"column":8},"end":{"line":188,"column":null}},"type":"cond-expr","locations":[{"start":{"line":187,"column":10},"end":{"line":187,"column":null}},{"start":{"line":188,"column":10},"end":{"line":188,"column":null}}],"line":186},"27":{"loc":{"start":{"line":189,"column":8},"end":{"line":191,"column":null}},"type":"cond-expr","locations":[{"start":{"line":190,"column":10},"end":{"line":190,"column":null}},{"start":{"line":191,"column":10},"end":{"line":191,"column":null}}],"line":189},"28":{"loc":{"start":{"line":193,"column":19},"end":{"line":193,"column":null}},"type":"cond-expr","locations":[{"start":{"line":193,"column":41},"end":{"line":193,"column":54}},{"start":{"line":193,"column":54},"end":{"line":193,"column":null}}],"line":193},"29":{"loc":{"start":{"line":195,"column":4},"end":{"line":197,"column":null}},"type":"cond-expr","locations":[{"start":{"line":196,"column":8},"end":{"line":196,"column":null}},{"start":{"line":197,"column":8},"end":{"line":197,"column":null}}],"line":195},"30":{"loc":{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},"type":"if","locations":[{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},{"start":{},"end":{}}],"line":219}},"s":{"0":8,"1":8,"2":1,"3":7,"4":1,"5":6,"6":6,"7":3,"8":1,"9":2,"10":2,"11":1,"12":46,"13":46,"14":46,"15":46,"16":46,"17":46,"18":46,"19":44,"20":42,"21":42,"22":13,"23":5,"24":8,"25":8,"26":1,"27":7,"28":4,"29":4,"30":1,"31":3,"32":3,"33":0,"34":3,"35":1,"36":3,"37":2,"38":2,"39":7,"40":3,"41":36,"42":36,"43":36,"44":36,"45":31,"46":19,"47":18,"48":12,"49":10,"50":31,"51":46,"52":46,"53":46,"54":46,"55":0,"56":0,"57":0,"58":0},"f":{"0":8,"1":46,"2":0},"b":{"0":[1,6],"1":[3,3],"2":[1,2],"3":[1,1],"4":[13,29],"5":[5,8],"6":[1,7],"7":[4,3],"8":[1,3],"9":[0,3],"10":[1,2],"11":[2,1],"12":[3,4],"13":[23,13],"14":[2,21],"15":[0,13],"16":[23,13],"17":[0,23],"18":[0,13],"19":[31,5],"20":[19,12],"21":[26,5],"22":[3,23],"23":[2,1],"24":[15,8],"25":[1,4],"26":[0,1],"27":[4,0],"28":[21,10],"29":[21,10],"30":[0,0]},"meta":{"lastBranch":31,"lastFunction":3,"lastStatement":59,"seen":{"f:41:22:41:41":0,"s:42:2:52:Infinity":0,"s:43:4:43:Infinity":1,"s:44:4:44:Infinity":2,"b:46:4:46:Infinity:undefined:undefined:undefined:undefined":0,"s:46:4:46:Infinity":3,"s:46:41:46:Infinity":4,"b:47:4:47:Infinity:undefined:undefined:undefined:undefined":1,"s:47:4:47:Infinity":5,"s:47:37:47:Infinity":6,"b:48:4:49:Infinity:undefined:undefined:undefined:undefined":2,"s:48:4:49:Infinity":7,"s:49:6:49:Infinity":8,"b:50:4:50:Infinity:undefined:undefined:undefined:undefined":3,"s:50:4:50:Infinity":9,"s:50:45:50:Infinity":10,"s:51:4:51:Infinity":11,"f:55:22:55:30":1,"s:56:89:56:Infinity":12,"s:58:2:58:Infinity":13,"s:59:2:62:Infinity":14,"s:64:18:64:Infinity":15,"s:66:18:66:Infinity":16,"s:67:18:67:Infinity":17,"s:69:15:84:Infinity":18,"s:87:20:87:Infinity":19,"s:88:23:88:Infinity":20,"b:90:2:125:Infinity:undefined:undefined:undefined:undefined":4,"s:90:2:125:Infinity":21,"b:93:4:97:Infinity:undefined:undefined:undefined:undefined":5,"s:93:4:97:Infinity":22,"s:94:6:96:Infinity":23,"s:99:19:99:Infinity":24,"b:101:4:103:Infinity:undefined:undefined:undefined:undefined":6,"s:101:4:103:Infinity":25,"s:102:6:102:Infinity":26,"b:105:4:120:Infinity:undefined:undefined:undefined:undefined":7,"s:105:4:120:Infinity":27,"s:107:22:107:Infinity":28,"b:108:6:119:Infinity:110:13:119:Infinity":8,"s:108:6:119:Infinity":29,"s:109:8:109:Infinity":30,"s:111:29:111:Infinity":31,"b:112:8:112:Infinity:undefined:undefined:undefined:undefined":9,"s:112:8:112:Infinity":32,"s:112:37:112:Infinity":33,"b:113:8:113:Infinity:undefined:undefined:undefined:undefined":10,"s:113:8:113:Infinity":34,"s:113:41:113:Infinity":35,"b:114:8:118:Infinity:undefined:undefined:undefined:undefined":11,"s:114:8:118:Infinity":36,"s:116:29:116:Infinity":37,"s:117:10:117:Infinity":38,"b:122:4:124:Infinity:undefined:undefined:undefined:undefined":12,"s:122:4:124:Infinity":39,"s:123:6:123:Infinity":40,"s:127:16:156:Infinity":41,"b:134:14:136:Infinity:137:14:139:Infinity":13,"b:135:16:135:Infinity:136:16:136:Infinity":14,"b:138:16:138:Infinity:139:16:139:Infinity":15,"b:146:14:148:Infinity:149:14:151:Infinity":16,"b:147:16:147:Infinity:148:16:148:Infinity":17,"b:150:16:150:Infinity:151:16:151:Infinity":18,"s:158:2:158:Infinity":42,"s:160:21:164:Infinity":43,"b:167:2:175:Infinity:undefined:undefined:undefined:undefined":19,"s:167:2:175:Infinity":44,"b:168:4:174:Infinity:171:11:174:Infinity":20,"s:168:4:174:Infinity":45,"s:169:6:169:Infinity":46,"s:170:6:170:Infinity":47,"s:172:6:172:Infinity":48,"s:173:6:173:Infinity":49,"s:177:20:191:Infinity":50,"b:178:6:184:Infinity:185:6:191:Infinity":21,"b:179:8:181:Infinity:182:8:184:Infinity":22,"b:180:10:180:Infinity:181:10:181:Infinity":23,"b:183:10:183:Infinity:184:10:184:Infinity":24,"b:186:8:188:Infinity:189:8:191:Infinity":25,"b:187:10:187:Infinity:188:10:188:Infinity":26,"b:190:10:190:Infinity:191:10:191:Infinity":27,"s:193:19:193:Infinity":51,"b:193:41:193:54:193:54:193:Infinity":28,"s:195:4:197:Infinity":52,"b:196:8:196:Infinity:197:8:197:Infinity":29,"s:199:2:202:Infinity":53,"s:204:2:204:Infinity":54,"f:207:22:207:54":2,"s:208:17:217:Infinity":55,"b:219:2:219:Infinity:undefined:undefined:undefined:undefined":30,"s:219:2:219:Infinity":56,"s:219:21:219:Infinity":57,"s:220:2:220:Infinity":58}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/opencode.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/opencode.ts","statementMap":{"0":{"start":{"line":12,"column":24},"end":{"line":12,"column":null}},"1":{"start":{"line":13,"column":29},"end":{"line":13,"column":null}},"2":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"3":{"start":{"line":25,"column":37},"end":{"line":25,"column":null}},"4":{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},"5":{"start":{"line":34,"column":23},"end":{"line":34,"column":null}},"6":{"start":{"line":35,"column":22},"end":{"line":35,"column":null}},"7":{"start":{"line":36,"column":22},"end":{"line":39,"column":null}},"8":{"start":{"line":40,"column":21},"end":{"line":43,"column":null}},"9":{"start":{"line":45,"column":2},"end":{"line":48,"column":null}},"10":{"start":{"line":54,"column":72},"end":{"line":54,"column":null}},"11":{"start":{"line":56,"column":21},"end":{"line":56,"column":null}},"12":{"start":{"line":57,"column":26},"end":{"line":57,"column":null}},"13":{"start":{"line":58,"column":21},"end":{"line":58,"column":null}},"14":{"start":{"line":60,"column":2},"end":{"line":62,"column":null}},"15":{"start":{"line":61,"column":4},"end":{"line":61,"column":null}},"16":{"start":{"line":64,"column":2},"end":{"line":68,"column":null}},"17":{"start":{"line":65,"column":4},"end":{"line":65,"column":null}},"18":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"19":{"start":{"line":70,"column":22},"end":{"line":73,"column":null}},"20":{"start":{"line":74,"column":2},"end":{"line":74,"column":null}},"21":{"start":{"line":74,"column":20},"end":{"line":74,"column":null}},"22":{"start":{"line":76,"column":12},"end":{"line":76,"column":null}},"23":{"start":{"line":77,"column":2},"end":{"line":77,"column":null}},"24":{"start":{"line":78,"column":2},"end":{"line":84,"column":null}},"25":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"26":{"start":{"line":80,"column":4},"end":{"line":80,"column":null}},"27":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"28":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"29":{"start":{"line":94,"column":51},"end":{"line":94,"column":null}},"30":{"start":{"line":96,"column":8},"end":{"line":96,"column":null}},"31":{"start":{"line":96,"column":46},"end":{"line":96,"column":73}},"32":{"start":{"line":98,"column":2},"end":{"line":100,"column":null}},"33":{"start":{"line":99,"column":4},"end":{"line":99,"column":null}},"34":{"start":{"line":103,"column":4},"end":{"line":105,"column":null}},"35":{"start":{"line":107,"column":2},"end":{"line":107,"column":null}},"36":{"start":{"line":109,"column":23},"end":{"line":119,"column":null}},"37":{"start":{"line":111,"column":24},"end":{"line":111,"column":null}},"38":{"start":{"line":112,"column":21},"end":{"line":112,"column":null}},"39":{"start":{"line":113,"column":6},"end":{"line":117,"column":null}},"40":{"start":{"line":121,"column":25},"end":{"line":125,"column":null}},"41":{"start":{"line":127,"column":2},"end":{"line":129,"column":null}},"42":{"start":{"line":128,"column":4},"end":{"line":128,"column":null}},"43":{"start":{"line":131,"column":30},"end":{"line":131,"column":null}},"44":{"start":{"line":132,"column":35},"end":{"line":132,"column":null}},"45":{"start":{"line":133,"column":2},"end":{"line":139,"column":null}},"46":{"start":{"line":135,"column":24},"end":{"line":135,"column":null}},"47":{"start":{"line":136,"column":21},"end":{"line":136,"column":null}},"48":{"start":{"line":137,"column":6},"end":{"line":137,"column":null}},"49":{"start":{"line":141,"column":33},"end":{"line":141,"column":null}},"50":{"start":{"line":142,"column":2},"end":{"line":142,"column":null}},"51":{"start":{"line":142,"column":28},"end":{"line":142,"column":null}},"52":{"start":{"line":143,"column":2},"end":{"line":143,"column":null}},"53":{"start":{"line":143,"column":33},"end":{"line":143,"column":null}},"54":{"start":{"line":144,"column":2},"end":{"line":149,"column":null}},"55":{"start":{"line":145,"column":4},"end":{"line":148,"column":null}},"56":{"start":{"line":146,"column":60},"end":{"line":146,"column":71}},"57":{"start":{"line":151,"column":22},"end":{"line":154,"column":null}},"58":{"start":{"line":156,"column":2},"end":{"line":158,"column":null}},"59":{"start":{"line":157,"column":4},"end":{"line":157,"column":null}},"60":{"start":{"line":160,"column":2},"end":{"line":160,"column":null}},"61":{"start":{"line":162,"column":12},"end":{"line":162,"column":null}},"62":{"start":{"line":163,"column":2},"end":{"line":163,"column":null}},"63":{"start":{"line":164,"column":2},"end":{"line":177,"column":null}},"64":{"start":{"line":165,"column":4},"end":{"line":172,"column":null}},"65":{"start":{"line":166,"column":20},"end":{"line":166,"column":null}},"66":{"start":{"line":166,"column":39},"end":{"line":166,"column":66}},"67":{"start":{"line":167,"column":6},"end":{"line":167,"column":null}},"68":{"start":{"line":167,"column":18},"end":{"line":167,"column":null}},"69":{"start":{"line":169,"column":24},"end":{"line":169,"column":null}},"70":{"start":{"line":170,"column":12},"end":{"line":170,"column":null}},"71":{"start":{"line":171,"column":6},"end":{"line":171,"column":null}},"72":{"start":{"line":173,"column":4},"end":{"line":173,"column":null}},"73":{"start":{"line":175,"column":4},"end":{"line":175,"column":null}},"74":{"start":{"line":176,"column":4},"end":{"line":176,"column":null}},"75":{"start":{"line":178,"column":2},"end":{"line":178,"column":null}},"76":{"start":{"line":182,"column":2},"end":{"line":233,"column":null}},"77":{"start":{"line":183,"column":20},"end":{"line":183,"column":null}},"78":{"start":{"line":184,"column":31},"end":{"line":184,"column":null}},"79":{"start":{"line":185,"column":10},"end":{"line":188,"column":null}},"80":{"start":{"line":190,"column":44},"end":{"line":190,"column":null}},"81":{"start":{"line":192,"column":6},"end":{"line":195,"column":null}},"82":{"start":{"line":197,"column":4},"end":{"line":199,"column":null}},"83":{"start":{"line":198,"column":6},"end":{"line":198,"column":null}},"84":{"start":{"line":201,"column":23},"end":{"line":201,"column":null}},"85":{"start":{"line":202,"column":39},"end":{"line":202,"column":null}},"86":{"start":{"line":203,"column":21},"end":{"line":203,"column":null}},"87":{"start":{"line":203,"column":59},"end":{"line":203,"column":92}},"88":{"start":{"line":204,"column":4},"end":{"line":204,"column":null}},"89":{"start":{"line":206,"column":4},"end":{"line":226,"column":null}},"90":{"start":{"line":207,"column":28},"end":{"line":207,"column":null}},"91":{"start":{"line":208,"column":12},"end":{"line":210,"column":null}},"92":{"start":{"line":211,"column":6},"end":{"line":211,"column":null}},"93":{"start":{"line":213,"column":6},"end":{"line":223,"column":null}},"94":{"start":{"line":214,"column":14},"end":{"line":221,"column":null}},"95":{"start":{"line":222,"column":8},"end":{"line":222,"column":null}},"96":{"start":{"line":225,"column":6},"end":{"line":225,"column":null}},"97":{"start":{"line":228,"column":44},"end":{"line":231,"column":null}},"98":{"start":{"line":232,"column":4},"end":{"line":232,"column":null}},"99":{"start":{"line":235,"column":40},"end":{"line":235,"column":null}},"100":{"start":{"line":236,"column":2},"end":{"line":242,"column":null}},"101":{"start":{"line":237,"column":4},"end":{"line":241,"column":null}},"102":{"start":{"line":238,"column":6},"end":{"line":238,"column":null}},"103":{"start":{"line":244,"column":21},"end":{"line":244,"column":null}},"104":{"start":{"line":245,"column":37},"end":{"line":245,"column":null}},"105":{"start":{"line":246,"column":19},"end":{"line":246,"column":null}},"106":{"start":{"line":246,"column":57},"end":{"line":246,"column":90}},"107":{"start":{"line":247,"column":2},"end":{"line":247,"column":null}},"108":{"start":{"line":248,"column":2},"end":{"line":248,"column":null}},"109":{"start":{"line":249,"column":2},"end":{"line":249,"column":null}},"110":{"start":{"line":251,"column":2},"end":{"line":251,"column":null}},"111":{"start":{"line":255,"column":2},"end":{"line":255,"column":null}},"112":{"start":{"line":255,"column":45},"end":{"line":255,"column":null}},"113":{"start":{"line":257,"column":5},"end":{"line":257,"column":null}},"114":{"start":{"line":258,"column":2},"end":{"line":258,"column":null}},"115":{"start":{"line":258,"column":31},"end":{"line":258,"column":null}},"116":{"start":{"line":259,"column":2},"end":{"line":259,"column":null}},"117":{"start":{"line":259,"column":38},"end":{"line":259,"column":95}},"118":{"start":{"line":268,"column":2},"end":{"line":274,"column":null}},"119":{"start":{"line":269,"column":22},"end":{"line":269,"column":null}},"120":{"start":{"line":270,"column":21},"end":{"line":270,"column":null}},"121":{"start":{"line":271,"column":4},"end":{"line":271,"column":null}},"122":{"start":{"line":271,"column":39},"end":{"line":271,"column":null}},"123":{"start":{"line":272,"column":4},"end":{"line":272,"column":null}},"124":{"start":{"line":272,"column":38},"end":{"line":272,"column":null}},"125":{"start":{"line":273,"column":4},"end":{"line":273,"column":null}},"126":{"start":{"line":276,"column":20},"end":{"line":276,"column":null}},"127":{"start":{"line":277,"column":20},"end":{"line":277,"column":null}},"128":{"start":{"line":278,"column":19},"end":{"line":278,"column":null}},"129":{"start":{"line":279,"column":2},"end":{"line":279,"column":null}},"130":{"start":{"line":279,"column":37},"end":{"line":279,"column":null}},"131":{"start":{"line":280,"column":2},"end":{"line":280,"column":null}},"132":{"start":{"line":280,"column":36},"end":{"line":280,"column":null}},"133":{"start":{"line":281,"column":2},"end":{"line":281,"column":null}}},"fnMap":{"0":{"name":"getOpencodeLabel","decl":{"start":{"line":24,"column":16},"end":{"line":24,"column":33}},"loc":{"start":{"line":24,"column":87},"end":{"line":27,"column":null}},"line":24},"1":{"name":"getOpencodeState","decl":{"start":{"line":29,"column":22},"end":{"line":29,"column":null}},"loc":{"start":{"line":33,"column":50},"end":{"line":49,"column":null}},"line":33},"2":{"name":"initOpenCode","decl":{"start":{"line":53,"column":22},"end":{"line":53,"column":35}},"loc":{"start":{"line":53,"column":74},"end":{"line":85,"column":null}},"line":53},"3":{"name":"initOpenCodeAgents","decl":{"start":{"line":87,"column":22},"end":{"line":87,"column":41}},"loc":{"start":{"line":93,"column":21},"end":{"line":179,"column":null}},"line":93},"4":{"name":"(anonymous_4)","decl":{"start":{"line":96,"column":32},"end":{"line":96,"column":40}},"loc":{"start":{"line":96,"column":46},"end":{"line":96,"column":73}},"line":96},"5":{"name":"(anonymous_5)","decl":{"start":{"line":110,"column":15},"end":{"line":110,"column":22}},"loc":{"start":{"line":110,"column":32},"end":{"line":118,"column":5}},"line":110},"6":{"name":"(anonymous_6)","decl":{"start":{"line":134,"column":23},"end":{"line":134,"column":30}},"loc":{"start":{"line":134,"column":52},"end":{"line":138,"column":5}},"line":134},"7":{"name":"(anonymous_7)","decl":{"start":{"line":146,"column":46},"end":{"line":146,"column":51}},"loc":{"start":{"line":146,"column":60},"end":{"line":146,"column":71}},"line":146},"8":{"name":"(anonymous_8)","decl":{"start":{"line":166,"column":27},"end":{"line":166,"column":33}},"loc":{"start":{"line":166,"column":39},"end":{"line":166,"column":66}},"line":166},"9":{"name":"generateModifiedContent","decl":{"start":{"line":181,"column":9},"end":{"line":181,"column":33}},"loc":{"start":{"line":181,"column":93},"end":{"line":252,"column":null}},"line":181},"10":{"name":"(anonymous_10)","decl":{"start":{"line":203,"column":37},"end":{"line":203,"column":45}},"loc":{"start":{"line":203,"column":59},"end":{"line":203,"column":92}},"line":203},"11":{"name":"(anonymous_11)","decl":{"start":{"line":246,"column":35},"end":{"line":246,"column":43}},"loc":{"start":{"line":246,"column":57},"end":{"line":246,"column":90}},"line":246},"12":{"name":"hasPluginInConfig","decl":{"start":{"line":254,"column":9},"end":{"line":254,"column":27}},"loc":{"start":{"line":254,"column":53},"end":{"line":260,"column":null}},"line":254},"13":{"name":"(anonymous_13)","decl":{"start":{"line":259,"column":17},"end":{"line":259,"column":23}},"loc":{"start":{"line":259,"column":38},"end":{"line":259,"column":95}},"line":259},"14":{"name":"resolveOpencodeConfigPath","decl":{"start":{"line":262,"column":15},"end":{"line":262,"column":null}},"loc":{"start":{"line":267,"column":19},"end":{"line":282,"column":null}},"line":267}},"branchMap":{"0":{"loc":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},{"start":{},"end":{}}],"line":25},"1":{"loc":{"start":{"line":25,"column":6},"end":{"line":25,"column":37}},"type":"binary-expr","locations":[{"start":{"line":25,"column":6},"end":{"line":25,"column":23}},{"start":{"line":25,"column":23},"end":{"line":25,"column":37}}],"line":25},"2":{"loc":{"start":{"line":46,"column":12},"end":{"line":46,"column":null}},"type":"binary-expr","locations":[{"start":{"line":46,"column":12},"end":{"line":46,"column":46}},{"start":{"line":46,"column":46},"end":{"line":46,"column":null}}],"line":46},"3":{"loc":{"start":{"line":47,"column":13},"end":{"line":47,"column":null}},"type":"binary-expr","locations":[{"start":{"line":47,"column":13},"end":{"line":47,"column":48}},{"start":{"line":47,"column":48},"end":{"line":47,"column":null}}],"line":47},"4":{"loc":{"start":{"line":60,"column":2},"end":{"line":62,"column":null}},"type":"if","locations":[{"start":{"line":60,"column":2},"end":{"line":62,"column":null}},{"start":{},"end":{}}],"line":60},"5":{"loc":{"start":{"line":60,"column":6},"end":{"line":60,"column":57}},"type":"binary-expr","locations":[{"start":{"line":60,"column":6},"end":{"line":60,"column":25}},{"start":{"line":60,"column":25},"end":{"line":60,"column":57}}],"line":60},"6":{"loc":{"start":{"line":64,"column":2},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":2},"end":{"line":68,"column":null}},{"start":{"line":66,"column":9},"end":{"line":68,"column":null}}],"line":64},"7":{"loc":{"start":{"line":72,"column":13},"end":{"line":72,"column":null}},"type":"cond-expr","locations":[{"start":{"line":72,"column":31},"end":{"line":72,"column":73}},{"start":{"line":72,"column":73},"end":{"line":72,"column":null}}],"line":72},"8":{"loc":{"start":{"line":74,"column":2},"end":{"line":74,"column":null}},"type":"if","locations":[{"start":{"line":74,"column":2},"end":{"line":74,"column":null}},{"start":{},"end":{}}],"line":74},"9":{"loc":{"start":{"line":98,"column":2},"end":{"line":100,"column":null}},"type":"if","locations":[{"start":{"line":98,"column":2},"end":{"line":100,"column":null}},{"start":{},"end":{}}],"line":98},"10":{"loc":{"start":{"line":103,"column":4},"end":{"line":105,"column":null}},"type":"cond-expr","locations":[{"start":{"line":104,"column":8},"end":{"line":104,"column":null}},{"start":{"line":105,"column":8},"end":{"line":105,"column":null}}],"line":103},"11":{"loc":{"start":{"line":114,"column":14},"end":{"line":114,"column":null}},"type":"cond-expr","locations":[{"start":{"line":114,"column":23},"end":{"line":114,"column":46}},{"start":{"line":114,"column":46},"end":{"line":114,"column":null}}],"line":114},"12":{"loc":{"start":{"line":127,"column":2},"end":{"line":129,"column":null}},"type":"if","locations":[{"start":{"line":127,"column":2},"end":{"line":129,"column":null}},{"start":{},"end":{}}],"line":127},"13":{"loc":{"start":{"line":137,"column":7},"end":{"line":137,"column":44}},"type":"cond-expr","locations":[{"start":{"line":137,"column":16},"end":{"line":137,"column":33}},{"start":{"line":137,"column":33},"end":{"line":137,"column":44}}],"line":137},"14":{"loc":{"start":{"line":142,"column":2},"end":{"line":142,"column":null}},"type":"if","locations":[{"start":{"line":142,"column":2},"end":{"line":142,"column":null}},{"start":{},"end":{}}],"line":142},"15":{"loc":{"start":{"line":143,"column":2},"end":{"line":143,"column":null}},"type":"if","locations":[{"start":{"line":143,"column":2},"end":{"line":143,"column":null}},{"start":{},"end":{}}],"line":143},"16":{"loc":{"start":{"line":144,"column":2},"end":{"line":149,"column":null}},"type":"if","locations":[{"start":{"line":144,"column":2},"end":{"line":149,"column":null}},{"start":{},"end":{}}],"line":144},"17":{"loc":{"start":{"line":156,"column":2},"end":{"line":158,"column":null}},"type":"if","locations":[{"start":{"line":156,"column":2},"end":{"line":158,"column":null}},{"start":{},"end":{}}],"line":156},"18":{"loc":{"start":{"line":167,"column":6},"end":{"line":167,"column":null}},"type":"if","locations":[{"start":{"line":167,"column":6},"end":{"line":167,"column":null}},{"start":{},"end":{}}],"line":167},"19":{"loc":{"start":{"line":182,"column":2},"end":{"line":233,"column":null}},"type":"if","locations":[{"start":{"line":182,"column":2},"end":{"line":233,"column":null}},{"start":{},"end":{}}],"line":182},"20":{"loc":{"start":{"line":183,"column":20},"end":{"line":183,"column":null}},"type":"binary-expr","locations":[{"start":{"line":183,"column":20},"end":{"line":183,"column":39}},{"start":{"line":183,"column":39},"end":{"line":183,"column":null}}],"line":183},"21":{"loc":{"start":{"line":192,"column":6},"end":{"line":195,"column":null}},"type":"binary-expr","locations":[{"start":{"line":192,"column":6},"end":{"line":192,"column":null}},{"start":{"line":193,"column":6},"end":{"line":193,"column":null}},{"start":{"line":194,"column":6},"end":{"line":194,"column":null}},{"start":{"line":195,"column":6},"end":{"line":195,"column":null}}],"line":192},"22":{"loc":{"start":{"line":197,"column":4},"end":{"line":199,"column":null}},"type":"if","locations":[{"start":{"line":197,"column":4},"end":{"line":199,"column":null}},{"start":{},"end":{}}],"line":197},"23":{"loc":{"start":{"line":201,"column":23},"end":{"line":201,"column":null}},"type":"cond-expr","locations":[{"start":{"line":201,"column":56},"end":{"line":201,"column":67}},{"start":{"line":201,"column":67},"end":{"line":201,"column":null}}],"line":201},"24":{"loc":{"start":{"line":202,"column":39},"end":{"line":202,"column":null}},"type":"binary-expr","locations":[{"start":{"line":202,"column":39},"end":{"line":202,"column":76}},{"start":{"line":202,"column":76},"end":{"line":202,"column":null}}],"line":202},"25":{"loc":{"start":{"line":206,"column":4},"end":{"line":226,"column":null}},"type":"if","locations":[{"start":{"line":206,"column":4},"end":{"line":226,"column":null}},{"start":{},"end":{}}],"line":206},"26":{"loc":{"start":{"line":213,"column":6},"end":{"line":223,"column":null}},"type":"if","locations":[{"start":{"line":213,"column":6},"end":{"line":223,"column":null}},{"start":{},"end":{}}],"line":213},"27":{"loc":{"start":{"line":236,"column":2},"end":{"line":242,"column":null}},"type":"if","locations":[{"start":{"line":236,"column":2},"end":{"line":242,"column":null}},{"start":{},"end":{}}],"line":236},"28":{"loc":{"start":{"line":244,"column":21},"end":{"line":244,"column":null}},"type":"cond-expr","locations":[{"start":{"line":244,"column":52},"end":{"line":244,"column":63}},{"start":{"line":244,"column":63},"end":{"line":244,"column":null}}],"line":244},"29":{"loc":{"start":{"line":245,"column":37},"end":{"line":245,"column":null}},"type":"binary-expr","locations":[{"start":{"line":245,"column":37},"end":{"line":245,"column":72}},{"start":{"line":245,"column":72},"end":{"line":245,"column":null}}],"line":245},"30":{"loc":{"start":{"line":249,"column":19},"end":{"line":249,"column":null}},"type":"binary-expr","locations":[{"start":{"line":249,"column":19},"end":{"line":249,"column":37}},{"start":{"line":249,"column":37},"end":{"line":249,"column":null}}],"line":249},"31":{"loc":{"start":{"line":255,"column":2},"end":{"line":255,"column":null}},"type":"if","locations":[{"start":{"line":255,"column":2},"end":{"line":255,"column":null}},{"start":{},"end":{}}],"line":255},"32":{"loc":{"start":{"line":255,"column":6},"end":{"line":255,"column":45}},"type":"binary-expr","locations":[{"start":{"line":255,"column":6},"end":{"line":255,"column":17}},{"start":{"line":255,"column":17},"end":{"line":255,"column":45}}],"line":255},"33":{"loc":{"start":{"line":257,"column":5},"end":{"line":257,"column":null}},"type":"binary-expr","locations":[{"start":{"line":257,"column":5},"end":{"line":257,"column":51}},{"start":{"line":257,"column":51},"end":{"line":257,"column":null}}],"line":257},"34":{"loc":{"start":{"line":258,"column":2},"end":{"line":258,"column":null}},"type":"if","locations":[{"start":{"line":258,"column":2},"end":{"line":258,"column":null}},{"start":{},"end":{}}],"line":258},"35":{"loc":{"start":{"line":259,"column":38},"end":{"line":259,"column":95}},"type":"binary-expr","locations":[{"start":{"line":259,"column":38},"end":{"line":259,"column":63}},{"start":{"line":259,"column":63},"end":{"line":259,"column":95}}],"line":259},"36":{"loc":{"start":{"line":268,"column":2},"end":{"line":274,"column":null}},"type":"if","locations":[{"start":{"line":268,"column":2},"end":{"line":274,"column":null}},{"start":{},"end":{}}],"line":268},"37":{"loc":{"start":{"line":271,"column":4},"end":{"line":271,"column":null}},"type":"if","locations":[{"start":{"line":271,"column":4},"end":{"line":271,"column":null}},{"start":{},"end":{}}],"line":271},"38":{"loc":{"start":{"line":272,"column":4},"end":{"line":272,"column":null}},"type":"if","locations":[{"start":{"line":272,"column":4},"end":{"line":272,"column":null}},{"start":{},"end":{}}],"line":272},"39":{"loc":{"start":{"line":279,"column":2},"end":{"line":279,"column":null}},"type":"if","locations":[{"start":{"line":279,"column":2},"end":{"line":279,"column":null}},{"start":{},"end":{}}],"line":279},"40":{"loc":{"start":{"line":280,"column":2},"end":{"line":280,"column":null}},"type":"if","locations":[{"start":{"line":280,"column":2},"end":{"line":280,"column":null}},{"start":{},"end":{}}],"line":280}},"s":{"0":1,"1":1,"2":46,"3":2,"4":44,"5":46,"6":46,"7":46,"8":46,"9":46,"10":19,"11":19,"12":19,"13":19,"14":19,"15":2,"16":17,"17":2,"18":15,"19":17,"20":17,"21":17,"22":16,"23":16,"24":16,"25":16,"26":16,"27":0,"28":0,"29":18,"30":18,"31":126,"32":18,"33":0,"34":18,"35":18,"36":18,"37":90,"38":90,"39":90,"40":18,"41":18,"42":13,"43":5,"44":5,"45":5,"46":9,"47":9,"48":9,"49":5,"50":5,"51":4,"52":5,"53":5,"54":5,"55":5,"56":5,"57":5,"58":5,"59":1,"60":4,"61":4,"62":4,"63":4,"64":4,"65":7,"66":23,"67":7,"68":0,"69":7,"70":7,"71":7,"72":4,"73":0,"74":0,"75":4,"76":19,"77":1,"78":1,"79":1,"80":1,"81":1,"82":1,"83":1,"84":1,"85":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1,"97":0,"98":0,"99":18,"100":18,"101":3,"102":3,"103":18,"104":19,"105":19,"106":3,"107":19,"108":19,"109":19,"110":19,"111":184,"112":180,"113":4,"114":184,"115":0,"116":4,"117":4,"118":19,"119":16,"120":16,"121":16,"122":1,"123":15,"124":3,"125":12,"126":3,"127":3,"128":3,"129":3,"130":0,"131":3,"132":0,"133":3},"f":{"0":46,"1":46,"2":19,"3":18,"4":126,"5":90,"6":9,"7":5,"8":23,"9":19,"10":1,"11":3,"12":184,"13":4,"14":19},"b":{"0":[2,44],"1":[46,44],"2":[46,46],"3":[46,46],"4":[2,17],"5":[19,4],"6":[2,15],"7":[2,15],"8":[1,16],"9":[0,18],"10":[15,3],"11":[2,88],"12":[13,5],"13":[2,7],"14":[4,1],"15":[1,4],"16":[5,0],"17":[1,4],"18":[0,7],"19":[1,18],"20":[1,0],"21":[1,1,1,1],"22":[1,0],"23":[1,0],"24":[1,0],"25":[1,0],"26":[1,0],"27":[3,15],"28":[18,0],"29":[19,15],"30":[19,16],"31":[180,4],"32":[184,4],"33":[4,0],"34":[0,184],"35":[4,4],"36":[16,3],"37":[1,15],"38":[3,12],"39":[0,3],"40":[0,3]},"meta":{"lastBranch":41,"lastFunction":15,"lastStatement":134,"seen":{"s:12:24:12:Infinity":0,"s:13:29:13:Infinity":1,"f:24:16:24:33":0,"b:25:2:25:Infinity:undefined:undefined:undefined:undefined":0,"s:25:2:25:Infinity":2,"b:25:6:25:23:25:23:25:37":1,"s:25:37:25:Infinity":3,"s:26:2:26:Infinity":4,"f:29:22:29:Infinity":1,"s:34:23:34:Infinity":5,"s:35:22:35:Infinity":6,"s:36:22:39:Infinity":7,"s:40:21:43:Infinity":8,"s:45:2:48:Infinity":9,"b:46:12:46:46:46:46:46:Infinity":2,"b:47:13:47:48:47:48:47:Infinity":3,"f:53:22:53:35":2,"s:54:72:54:Infinity":10,"s:56:21:56:Infinity":11,"s:57:26:57:Infinity":12,"s:58:21:58:Infinity":13,"b:60:2:62:Infinity:undefined:undefined:undefined:undefined":4,"s:60:2:62:Infinity":14,"b:60:6:60:25:60:25:60:57":5,"s:61:4:61:Infinity":15,"b:64:2:68:Infinity:66:9:68:Infinity":6,"s:64:2:68:Infinity":16,"s:65:4:65:Infinity":17,"s:67:4:67:Infinity":18,"s:70:22:73:Infinity":19,"b:72:31:72:73:72:73:72:Infinity":7,"b:74:2:74:Infinity:undefined:undefined:undefined:undefined":8,"s:74:2:74:Infinity":20,"s:74:20:74:Infinity":21,"s:76:12:76:Infinity":22,"s:77:2:77:Infinity":23,"s:78:2:84:Infinity":24,"s:79:4:79:Infinity":25,"s:80:4:80:Infinity":26,"s:82:4:82:Infinity":27,"s:83:4:83:Infinity":28,"f:87:22:87:41":3,"s:94:51:94:Infinity":29,"s:96:8:96:Infinity":30,"f:96:32:96:40":4,"s:96:46:96:73":31,"b:98:2:100:Infinity:undefined:undefined:undefined:undefined":9,"s:98:2:100:Infinity":32,"s:99:4:99:Infinity":33,"s:103:4:105:Infinity":34,"b:104:8:104:Infinity:105:8:105:Infinity":10,"s:107:2:107:Infinity":35,"s:109:23:119:Infinity":36,"f:110:15:110:22":5,"s:111:24:111:Infinity":37,"s:112:21:112:Infinity":38,"s:113:6:117:Infinity":39,"b:114:23:114:46:114:46:114:Infinity":11,"s:121:25:125:Infinity":40,"b:127:2:129:Infinity:undefined:undefined:undefined:undefined":12,"s:127:2:129:Infinity":41,"s:128:4:128:Infinity":42,"s:131:30:131:Infinity":43,"s:132:35:132:Infinity":44,"s:133:2:139:Infinity":45,"f:134:23:134:30":6,"s:135:24:135:Infinity":46,"s:136:21:136:Infinity":47,"s:137:6:137:Infinity":48,"b:137:16:137:33:137:33:137:44":13,"s:141:33:141:Infinity":49,"b:142:2:142:Infinity:undefined:undefined:undefined:undefined":14,"s:142:2:142:Infinity":50,"s:142:28:142:Infinity":51,"b:143:2:143:Infinity:undefined:undefined:undefined:undefined":15,"s:143:2:143:Infinity":52,"s:143:33:143:Infinity":53,"b:144:2:149:Infinity:undefined:undefined:undefined:undefined":16,"s:144:2:149:Infinity":54,"s:145:4:148:Infinity":55,"f:146:46:146:51":7,"s:146:60:146:71":56,"s:151:22:154:Infinity":57,"b:156:2:158:Infinity:undefined:undefined:undefined:undefined":17,"s:156:2:158:Infinity":58,"s:157:4:157:Infinity":59,"s:160:2:160:Infinity":60,"s:162:12:162:Infinity":61,"s:163:2:163:Infinity":62,"s:164:2:177:Infinity":63,"s:165:4:172:Infinity":64,"s:166:20:166:Infinity":65,"f:166:27:166:33":8,"s:166:39:166:66":66,"b:167:6:167:Infinity:undefined:undefined:undefined:undefined":18,"s:167:6:167:Infinity":67,"s:167:18:167:Infinity":68,"s:169:24:169:Infinity":69,"s:170:12:170:Infinity":70,"s:171:6:171:Infinity":71,"s:173:4:173:Infinity":72,"s:175:4:175:Infinity":73,"s:176:4:176:Infinity":74,"s:178:2:178:Infinity":75,"f:181:9:181:33":9,"b:182:2:233:Infinity:undefined:undefined:undefined:undefined":19,"s:182:2:233:Infinity":76,"s:183:20:183:Infinity":77,"b:183:20:183:39:183:39:183:Infinity":20,"s:184:31:184:Infinity":78,"s:185:10:188:Infinity":79,"s:190:44:190:Infinity":80,"s:192:6:195:Infinity":81,"b:192:6:192:Infinity:193:6:193:Infinity:194:6:194:Infinity:195:6:195:Infinity":21,"b:197:4:199:Infinity:undefined:undefined:undefined:undefined":22,"s:197:4:199:Infinity":82,"s:198:6:198:Infinity":83,"s:201:23:201:Infinity":84,"b:201:56:201:67:201:67:201:Infinity":23,"s:202:39:202:Infinity":85,"b:202:39:202:76:202:76:202:Infinity":24,"s:203:21:203:Infinity":86,"f:203:37:203:45":10,"s:203:59:203:92":87,"s:204:4:204:Infinity":88,"b:206:4:226:Infinity:undefined:undefined:undefined:undefined":25,"s:206:4:226:Infinity":89,"s:207:28:207:Infinity":90,"s:208:12:210:Infinity":91,"s:211:6:211:Infinity":92,"b:213:6:223:Infinity:undefined:undefined:undefined:undefined":26,"s:213:6:223:Infinity":93,"s:214:14:221:Infinity":94,"s:222:8:222:Infinity":95,"s:225:6:225:Infinity":96,"s:228:44:231:Infinity":97,"s:232:4:232:Infinity":98,"s:235:40:235:Infinity":99,"b:236:2:242:Infinity:undefined:undefined:undefined:undefined":27,"s:236:2:242:Infinity":100,"s:237:4:241:Infinity":101,"s:238:6:238:Infinity":102,"s:244:21:244:Infinity":103,"b:244:52:244:63:244:63:244:Infinity":28,"s:245:37:245:Infinity":104,"b:245:37:245:72:245:72:245:Infinity":29,"s:246:19:246:Infinity":105,"f:246:35:246:43":11,"s:246:57:246:90":106,"s:247:2:247:Infinity":107,"s:248:2:248:Infinity":108,"s:249:2:249:Infinity":109,"b:249:19:249:37:249:37:249:Infinity":30,"s:251:2:251:Infinity":110,"f:254:9:254:27":12,"b:255:2:255:Infinity:undefined:undefined:undefined:undefined":31,"s:255:2:255:Infinity":111,"b:255:6:255:17:255:17:255:45":32,"s:255:45:255:Infinity":112,"s:257:5:257:Infinity":113,"b:257:5:257:51:257:51:257:Infinity":33,"b:258:2:258:Infinity:undefined:undefined:undefined:undefined":34,"s:258:2:258:Infinity":114,"s:258:31:258:Infinity":115,"s:259:2:259:Infinity":116,"f:259:17:259:23":13,"s:259:38:259:95":117,"b:259:38:259:63:259:63:259:95":35,"f:262:15:262:Infinity":14,"b:268:2:274:Infinity:undefined:undefined:undefined:undefined":36,"s:268:2:274:Infinity":118,"s:269:22:269:Infinity":119,"s:270:21:270:Infinity":120,"b:271:4:271:Infinity:undefined:undefined:undefined:undefined":37,"s:271:4:271:Infinity":121,"s:271:39:271:Infinity":122,"b:272:4:272:Infinity:undefined:undefined:undefined:undefined":38,"s:272:4:272:Infinity":123,"s:272:38:272:Infinity":124,"s:273:4:273:Infinity":125,"s:276:20:276:Infinity":126,"s:277:20:277:Infinity":127,"s:278:19:278:Infinity":128,"b:279:2:279:Infinity:undefined:undefined:undefined:undefined":39,"s:279:2:279:Infinity":129,"s:279:37:279:Infinity":130,"b:280:2:280:Infinity:undefined:undefined:undefined:undefined":40,"s:280:2:280:Infinity":131,"s:280:36:280:Infinity":132,"s:281:2:281:Infinity":133}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/pi.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/pi.ts","statementMap":{"0":{"start":{"line":11,"column":20},"end":{"line":11,"column":null}},"1":{"start":{"line":12,"column":25},"end":{"line":12,"column":null}},"2":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"3":{"start":{"line":24,"column":37},"end":{"line":24,"column":null}},"4":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"5":{"start":{"line":33,"column":26},"end":{"line":33,"column":null}},"6":{"start":{"line":34,"column":25},"end":{"line":37,"column":null}},"7":{"start":{"line":39,"column":2},"end":{"line":42,"column":null}},"8":{"start":{"line":48,"column":61},"end":{"line":48,"column":null}},"9":{"start":{"line":49,"column":12},"end":{"line":49,"column":null}},"10":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"11":{"start":{"line":54,"column":2},"end":{"line":54,"column":null}},"12":{"start":{"line":55,"column":2},"end":{"line":61,"column":null}},"13":{"start":{"line":56,"column":4},"end":{"line":56,"column":null}},"14":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"15":{"start":{"line":59,"column":4},"end":{"line":59,"column":null}},"16":{"start":{"line":60,"column":4},"end":{"line":60,"column":null}},"17":{"start":{"line":64,"column":4},"end":{"line":66,"column":null}},"18":{"start":{"line":68,"column":14},"end":{"line":68,"column":null}},"19":{"start":{"line":70,"column":4},"end":{"line":72,"column":null}},"20":{"start":{"line":74,"column":2},"end":{"line":80,"column":null}},"21":{"start":{"line":75,"column":4},"end":{"line":78,"column":null}},"22":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"23":{"start":{"line":82,"column":2},"end":{"line":96,"column":null}},"24":{"start":{"line":83,"column":24},"end":{"line":86,"column":null}},"25":{"start":{"line":87,"column":4},"end":{"line":91,"column":null}},"26":{"start":{"line":88,"column":6},"end":{"line":88,"column":null}},"27":{"start":{"line":89,"column":6},"end":{"line":89,"column":null}},"28":{"start":{"line":90,"column":6},"end":{"line":90,"column":null}},"29":{"start":{"line":93,"column":4},"end":{"line":93,"column":null}},"30":{"start":{"line":94,"column":4},"end":{"line":94,"column":null}},"31":{"start":{"line":95,"column":4},"end":{"line":95,"column":null}},"32":{"start":{"line":106,"column":51},"end":{"line":106,"column":null}},"33":{"start":{"line":108,"column":8},"end":{"line":108,"column":null}},"34":{"start":{"line":108,"column":46},"end":{"line":108,"column":73}},"35":{"start":{"line":110,"column":2},"end":{"line":112,"column":null}},"36":{"start":{"line":111,"column":4},"end":{"line":111,"column":null}},"37":{"start":{"line":115,"column":4},"end":{"line":117,"column":null}},"38":{"start":{"line":119,"column":2},"end":{"line":119,"column":null}},"39":{"start":{"line":121,"column":26},"end":{"line":124,"column":null}},"40":{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},"41":{"start":{"line":126,"column":24},"end":{"line":126,"column":null}},"42":{"start":{"line":128,"column":28},"end":{"line":135,"column":null}},"43":{"start":{"line":130,"column":36},"end":{"line":134,"column":6}},"44":{"start":{"line":137,"column":16},"end":{"line":137,"column":null}},"45":{"start":{"line":137,"column":35},"end":{"line":137,"column":70}},"46":{"start":{"line":138,"column":2},"end":{"line":138,"column":null}},"47":{"start":{"line":138,"column":14},"end":{"line":138,"column":null}},"48":{"start":{"line":140,"column":23},"end":{"line":140,"column":null}},"49":{"start":{"line":141,"column":21},"end":{"line":143,"column":null}},"50":{"start":{"line":145,"column":22},"end":{"line":148,"column":null}},"51":{"start":{"line":150,"column":2},"end":{"line":152,"column":null}},"52":{"start":{"line":151,"column":4},"end":{"line":151,"column":null}},"53":{"start":{"line":154,"column":12},"end":{"line":154,"column":null}},"54":{"start":{"line":155,"column":2},"end":{"line":155,"column":null}},"55":{"start":{"line":156,"column":2},"end":{"line":165,"column":null}},"56":{"start":{"line":158,"column":6},"end":{"line":158,"column":null}},"57":{"start":{"line":159,"column":4},"end":{"line":159,"column":null}},"58":{"start":{"line":160,"column":4},"end":{"line":160,"column":null}},"59":{"start":{"line":161,"column":4},"end":{"line":161,"column":null}},"60":{"start":{"line":163,"column":4},"end":{"line":163,"column":null}},"61":{"start":{"line":164,"column":4},"end":{"line":164,"column":null}},"62":{"start":{"line":166,"column":2},"end":{"line":166,"column":null}},"63":{"start":{"line":170,"column":2},"end":{"line":170,"column":null}},"64":{"start":{"line":170,"column":49},"end":{"line":170,"column":null}},"65":{"start":{"line":171,"column":20},"end":{"line":171,"column":null}},"66":{"start":{"line":172,"column":2},"end":{"line":172,"column":null}},"67":{"start":{"line":172,"column":32},"end":{"line":172,"column":null}},"68":{"start":{"line":173,"column":2},"end":{"line":180,"column":null}},"69":{"start":{"line":174,"column":4},"end":{"line":174,"column":null}},"70":{"start":{"line":174,"column":31},"end":{"line":174,"column":null}},"71":{"start":{"line":175,"column":4},"end":{"line":178,"column":null}},"72":{"start":{"line":176,"column":22},"end":{"line":176,"column":null}},"73":{"start":{"line":177,"column":6},"end":{"line":177,"column":null}},"74":{"start":{"line":179,"column":4},"end":{"line":179,"column":null}}},"fnMap":{"0":{"name":"getPiLabel","decl":{"start":{"line":23,"column":16},"end":{"line":23,"column":27}},"loc":{"start":{"line":23,"column":81},"end":{"line":26,"column":null}},"line":23},"1":{"name":"getPiState","decl":{"start":{"line":28,"column":22},"end":{"line":28,"column":null}},"loc":{"start":{"line":32,"column":50},"end":{"line":43,"column":null}},"line":32},"2":{"name":"initPi","decl":{"start":{"line":47,"column":22},"end":{"line":47,"column":29}},"loc":{"start":{"line":47,"column":62},"end":{"line":97,"column":null}},"line":47},"3":{"name":"initPiAgent","decl":{"start":{"line":99,"column":22},"end":{"line":99,"column":34}},"loc":{"start":{"line":105,"column":21},"end":{"line":167,"column":null}},"line":105},"4":{"name":"(anonymous_4)","decl":{"start":{"line":108,"column":32},"end":{"line":108,"column":40}},"loc":{"start":{"line":108,"column":46},"end":{"line":108,"column":73}},"line":108},"5":{"name":"(anonymous_5)","decl":{"start":{"line":130,"column":20},"end":{"line":130,"column":25}},"loc":{"start":{"line":130,"column":36},"end":{"line":134,"column":6}},"line":130},"6":{"name":"(anonymous_6)","decl":{"start":{"line":137,"column":23},"end":{"line":137,"column":29}},"loc":{"start":{"line":137,"column":35},"end":{"line":137,"column":70}},"line":137},"7":{"name":"hasPiProviderInSettings","decl":{"start":{"line":169,"column":9},"end":{"line":169,"column":33}},"loc":{"start":{"line":169,"column":61},"end":{"line":181,"column":null}},"line":169},"8":{"name":"(anonymous_8)","decl":{"start":{"line":173,"column":18},"end":{"line":173,"column":24}},"loc":{"start":{"line":173,"column":39},"end":{"line":180,"column":3}},"line":173}},"branchMap":{"0":{"loc":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":24},"1":{"loc":{"start":{"line":24,"column":6},"end":{"line":24,"column":37}},"type":"binary-expr","locations":[{"start":{"line":24,"column":6},"end":{"line":24,"column":23}},{"start":{"line":24,"column":23},"end":{"line":24,"column":37}}],"line":24},"2":{"loc":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"type":"cond-expr","locations":[{"start":{"line":52,"column":26},"end":{"line":52,"column":59}},{"start":{"line":52,"column":59},"end":{"line":52,"column":null}}],"line":52},"3":{"loc":{"start":{"line":64,"column":4},"end":{"line":66,"column":null}},"type":"cond-expr","locations":[{"start":{"line":65,"column":8},"end":{"line":65,"column":null}},{"start":{"line":66,"column":8},"end":{"line":66,"column":null}}],"line":64},"4":{"loc":{"start":{"line":70,"column":4},"end":{"line":72,"column":null}},"type":"cond-expr","locations":[{"start":{"line":71,"column":9},"end":{"line":71,"column":null}},{"start":{"line":72,"column":8},"end":{"line":72,"column":null}}],"line":70},"5":{"loc":{"start":{"line":70,"column":4},"end":{"line":70,"column":null}},"type":"binary-expr","locations":[{"start":{"line":70,"column":4},"end":{"line":70,"column":31}},{"start":{"line":70,"column":31},"end":{"line":70,"column":47}},{"start":{"line":70,"column":47},"end":{"line":70,"column":null}}],"line":70},"6":{"loc":{"start":{"line":74,"column":2},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":74,"column":2},"end":{"line":80,"column":null}},{"start":{},"end":{}}],"line":74},"7":{"loc":{"start":{"line":82,"column":2},"end":{"line":96,"column":null}},"type":"if","locations":[{"start":{"line":82,"column":2},"end":{"line":96,"column":null}},{"start":{"line":92,"column":9},"end":{"line":96,"column":null}}],"line":82},"8":{"loc":{"start":{"line":87,"column":4},"end":{"line":91,"column":null}},"type":"if","locations":[{"start":{"line":87,"column":4},"end":{"line":91,"column":null}},{"start":{},"end":{}}],"line":87},"9":{"loc":{"start":{"line":110,"column":2},"end":{"line":112,"column":null}},"type":"if","locations":[{"start":{"line":110,"column":2},"end":{"line":112,"column":null}},{"start":{},"end":{}}],"line":110},"10":{"loc":{"start":{"line":115,"column":4},"end":{"line":117,"column":null}},"type":"cond-expr","locations":[{"start":{"line":116,"column":8},"end":{"line":116,"column":null}},{"start":{"line":117,"column":8},"end":{"line":117,"column":null}}],"line":115},"11":{"loc":{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},"type":"if","locations":[{"start":{"line":126,"column":2},"end":{"line":126,"column":null}},{"start":{},"end":{}}],"line":126},"12":{"loc":{"start":{"line":138,"column":2},"end":{"line":138,"column":null}},"type":"if","locations":[{"start":{"line":138,"column":2},"end":{"line":138,"column":null}},{"start":{},"end":{}}],"line":138},"13":{"loc":{"start":{"line":141,"column":21},"end":{"line":143,"column":null}},"type":"cond-expr","locations":[{"start":{"line":142,"column":6},"end":{"line":142,"column":null}},{"start":{"line":143,"column":6},"end":{"line":143,"column":null}}],"line":141},"14":{"loc":{"start":{"line":150,"column":2},"end":{"line":152,"column":null}},"type":"if","locations":[{"start":{"line":150,"column":2},"end":{"line":152,"column":null}},{"start":{},"end":{}}],"line":150},"15":{"loc":{"start":{"line":158,"column":6},"end":{"line":158,"column":null}},"type":"cond-expr","locations":[{"start":{"line":158,"column":28},"end":{"line":158,"column":52}},{"start":{"line":158,"column":52},"end":{"line":158,"column":null}}],"line":158},"16":{"loc":{"start":{"line":170,"column":2},"end":{"line":170,"column":null}},"type":"if","locations":[{"start":{"line":170,"column":2},"end":{"line":170,"column":null}},{"start":{},"end":{}}],"line":170},"17":{"loc":{"start":{"line":170,"column":6},"end":{"line":170,"column":49}},"type":"binary-expr","locations":[{"start":{"line":170,"column":6},"end":{"line":170,"column":19}},{"start":{"line":170,"column":19},"end":{"line":170,"column":49}}],"line":170},"18":{"loc":{"start":{"line":172,"column":2},"end":{"line":172,"column":null}},"type":"if","locations":[{"start":{"line":172,"column":2},"end":{"line":172,"column":null}},{"start":{},"end":{}}],"line":172},"19":{"loc":{"start":{"line":174,"column":4},"end":{"line":174,"column":null}},"type":"if","locations":[{"start":{"line":174,"column":4},"end":{"line":174,"column":null}},{"start":{},"end":{}}],"line":174},"20":{"loc":{"start":{"line":175,"column":4},"end":{"line":178,"column":null}},"type":"if","locations":[{"start":{"line":175,"column":4},"end":{"line":178,"column":null}},{"start":{},"end":{}}],"line":175},"21":{"loc":{"start":{"line":175,"column":8},"end":{"line":175,"column":45}},"type":"binary-expr","locations":[{"start":{"line":175,"column":8},"end":{"line":175,"column":33}},{"start":{"line":175,"column":33},"end":{"line":175,"column":45}}],"line":175},"22":{"loc":{"start":{"line":177,"column":13},"end":{"line":177,"column":null}},"type":"binary-expr","locations":[{"start":{"line":177,"column":13},"end":{"line":177,"column":43}},{"start":{"line":177,"column":43},"end":{"line":177,"column":null}}],"line":177}},"s":{"0":1,"1":1,"2":46,"3":0,"4":46,"5":46,"6":46,"7":46,"8":12,"9":12,"10":12,"11":12,"12":12,"13":12,"14":10,"15":2,"16":2,"17":10,"18":12,"19":10,"20":12,"21":0,"22":0,"23":10,"24":0,"25":0,"26":0,"27":0,"28":0,"29":10,"30":10,"31":10,"32":10,"33":10,"34":70,"35":10,"36":0,"37":10,"38":10,"39":10,"40":10,"41":1,"42":9,"43":45,"44":9,"45":42,"46":9,"47":0,"48":9,"49":9,"50":10,"51":9,"52":1,"53":8,"54":8,"55":8,"56":8,"57":10,"58":8,"59":8,"60":0,"61":0,"62":8,"63":92,"64":91,"65":1,"66":1,"67":1,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0},"f":{"0":46,"1":46,"2":12,"3":10,"4":70,"5":45,"6":42,"7":92,"8":0},"b":{"0":[0,46],"1":[46,46],"2":[11,1],"3":[9,1],"4":[1,9],"5":[10,10,1],"6":[0,12],"7":[0,10],"8":[0,0],"9":[0,10],"10":[9,1],"11":[1,9],"12":[0,9],"13":[1,8],"14":[1,8],"15":[7,1],"16":[91,1],"17":[92,1],"18":[1,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0]},"meta":{"lastBranch":23,"lastFunction":9,"lastStatement":75,"seen":{"s:11:20:11:Infinity":0,"s:12:25:12:Infinity":1,"f:23:16:23:27":0,"b:24:2:24:Infinity:undefined:undefined:undefined:undefined":0,"s:24:2:24:Infinity":2,"b:24:6:24:23:24:23:24:37":1,"s:24:37:24:Infinity":3,"s:25:2:25:Infinity":4,"f:28:22:28:Infinity":1,"s:33:26:33:Infinity":5,"s:34:25:37:Infinity":6,"s:39:2:42:Infinity":7,"f:47:22:47:29":2,"s:48:61:48:Infinity":8,"s:49:12:49:Infinity":9,"s:52:4:52:Infinity":10,"b:52:26:52:59:52:59:52:Infinity":2,"s:54:2:54:Infinity":11,"s:55:2:61:Infinity":12,"s:56:4:56:Infinity":13,"s:57:4:57:Infinity":14,"s:59:4:59:Infinity":15,"s:60:4:60:Infinity":16,"s:64:4:66:Infinity":17,"b:65:8:65:Infinity:66:8:66:Infinity":3,"s:68:14:68:Infinity":18,"s:70:4:72:Infinity":19,"b:71:9:71:Infinity:72:8:72:Infinity":4,"b:70:4:70:31:70:31:70:47:70:47:70:Infinity":5,"b:74:2:80:Infinity:undefined:undefined:undefined:undefined":6,"s:74:2:80:Infinity":20,"s:75:4:78:Infinity":21,"s:79:4:79:Infinity":22,"b:82:2:96:Infinity:92:9:96:Infinity":7,"s:82:2:96:Infinity":23,"s:83:24:86:Infinity":24,"b:87:4:91:Infinity:undefined:undefined:undefined:undefined":8,"s:87:4:91:Infinity":25,"s:88:6:88:Infinity":26,"s:89:6:89:Infinity":27,"s:90:6:90:Infinity":28,"s:93:4:93:Infinity":29,"s:94:4:94:Infinity":30,"s:95:4:95:Infinity":31,"f:99:22:99:34":3,"s:106:51:106:Infinity":32,"s:108:8:108:Infinity":33,"f:108:32:108:40":4,"s:108:46:108:73":34,"b:110:2:112:Infinity:undefined:undefined:undefined:undefined":9,"s:110:2:112:Infinity":35,"s:111:4:111:Infinity":36,"s:115:4:117:Infinity":37,"b:116:8:116:Infinity:117:8:117:Infinity":10,"s:119:2:119:Infinity":38,"s:121:26:124:Infinity":39,"b:126:2:126:Infinity:undefined:undefined:undefined:undefined":11,"s:126:2:126:Infinity":40,"s:126:24:126:Infinity":41,"s:128:28:135:Infinity":42,"f:130:20:130:25":5,"s:130:36:134:6":43,"s:137:16:137:Infinity":44,"f:137:23:137:29":6,"s:137:35:137:70":45,"b:138:2:138:Infinity:undefined:undefined:undefined:undefined":12,"s:138:2:138:Infinity":46,"s:138:14:138:Infinity":47,"s:140:23:140:Infinity":48,"s:141:21:143:Infinity":49,"b:142:6:142:Infinity:143:6:143:Infinity":13,"s:145:22:148:Infinity":50,"b:150:2:152:Infinity:undefined:undefined:undefined:undefined":14,"s:150:2:152:Infinity":51,"s:151:4:151:Infinity":52,"s:154:12:154:Infinity":53,"s:155:2:155:Infinity":54,"s:156:2:165:Infinity":55,"s:158:6:158:Infinity":56,"b:158:28:158:52:158:52:158:Infinity":15,"s:159:4:159:Infinity":57,"s:160:4:160:Infinity":58,"s:161:4:161:Infinity":59,"s:163:4:163:Infinity":60,"s:164:4:164:Infinity":61,"s:166:2:166:Infinity":62,"f:169:9:169:33":7,"b:170:2:170:Infinity:undefined:undefined:undefined:undefined":16,"s:170:2:170:Infinity":63,"b:170:6:170:19:170:19:170:49":17,"s:170:49:170:Infinity":64,"s:171:20:171:Infinity":65,"b:172:2:172:Infinity:undefined:undefined:undefined:undefined":18,"s:172:2:172:Infinity":66,"s:172:32:172:Infinity":67,"s:173:2:180:Infinity":68,"f:173:18:173:24":8,"b:174:4:174:Infinity:undefined:undefined:undefined:undefined":19,"s:174:4:174:Infinity":69,"s:174:31:174:Infinity":70,"b:175:4:178:Infinity:undefined:undefined:undefined:undefined":20,"s:175:4:178:Infinity":71,"b:175:8:175:33:175:33:175:45":21,"s:176:22:176:Infinity":72,"s:177:6:177:Infinity":73,"b:177:13:177:43:177:43:177:Infinity":22,"s:179:4:179:Infinity":74}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/tool-check.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/tool-check.ts","statementMap":{"0":{"start":{"line":19,"column":68},"end":{"line":32,"column":null}},"1":{"start":{"line":38,"column":20},"end":{"line":38,"column":null}},"2":{"start":{"line":39,"column":15},"end":{"line":39,"column":null}},"3":{"start":{"line":41,"column":2},"end":{"line":47,"column":null}},"4":{"start":{"line":54,"column":18},"end":{"line":54,"column":null}},"5":{"start":{"line":55,"column":2},"end":{"line":55,"column":null}},"6":{"start":{"line":57,"column":17},"end":{"line":64,"column":null}},"7":{"start":{"line":66,"column":2},"end":{"line":66,"column":null}},"8":{"start":{"line":70,"column":2},"end":{"line":74,"column":null}},"9":{"start":{"line":71,"column":4},"end":{"line":73,"column":null}},"10":{"start":{"line":75,"column":2},"end":{"line":77,"column":null}}},"fnMap":{"0":{"name":"checkTool","decl":{"start":{"line":34,"column":22},"end":{"line":34,"column":null}},"loc":{"start":{"line":37,"column":28},"end":{"line":48,"column":null}},"line":37},"1":{"name":"promptForMissingTool","decl":{"start":{"line":50,"column":22},"end":{"line":50,"column":null}},"loc":{"start":{"line":53,"column":42},"end":{"line":67,"column":null}},"line":53},"2":{"name":"getInstallCommand","decl":{"start":{"line":69,"column":9},"end":{"line":69,"column":27}},"loc":{"start":{"line":69,"column":78},"end":{"line":78,"column":null}},"line":69}},"branchMap":{"0":{"loc":{"start":{"line":70,"column":2},"end":{"line":74,"column":null}},"type":"if","locations":[{"start":{"line":70,"column":2},"end":{"line":74,"column":null}},{"start":{},"end":{}}],"line":70},"1":{"loc":{"start":{"line":71,"column":11},"end":{"line":73,"column":null}},"type":"cond-expr","locations":[{"start":{"line":72,"column":8},"end":{"line":72,"column":null}},{"start":{"line":73,"column":8},"end":{"line":73,"column":null}}],"line":71},"2":{"loc":{"start":{"line":75,"column":9},"end":{"line":77,"column":null}},"type":"cond-expr","locations":[{"start":{"line":76,"column":6},"end":{"line":76,"column":null}},{"start":{"line":77,"column":6},"end":{"line":77,"column":null}}],"line":75}},"s":{"0":1,"1":50,"2":48,"3":48,"4":11,"5":11,"6":11,"7":11,"8":48,"9":0,"10":48},"f":{"0":50,"1":11,"2":48},"b":{"0":[0,48],"1":[0,0],"2":[33,15]},"meta":{"lastBranch":3,"lastFunction":3,"lastStatement":11,"seen":{"s:19:68:32:Infinity":0,"f:34:22:34:Infinity":0,"s:38:20:38:Infinity":1,"s:39:15:39:Infinity":2,"s:41:2:47:Infinity":3,"f:50:22:50:Infinity":1,"s:54:18:54:Infinity":4,"s:55:2:55:Infinity":5,"s:57:17:64:Infinity":6,"s:66:2:66:Infinity":7,"f:69:9:69:27":2,"b:70:2:74:Infinity:undefined:undefined:undefined:undefined":0,"s:70:2:74:Infinity":8,"s:71:4:73:Infinity":9,"b:72:8:72:Infinity:73:8:73:Infinity":1,"s:75:2:77:Infinity":10,"b:76:6:76:Infinity:77:6:77:Infinity":2}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/utils.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/utils.ts","statementMap":{"0":{"start":{"line":4,"column":18},"end":{"line":4,"column":null}},"1":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"2":{"start":{"line":5,"column":16},"end":{"line":5,"column":null}},"3":{"start":{"line":6,"column":2},"end":{"line":14,"column":null}},"4":{"start":{"line":7,"column":4},"end":{"line":7,"column":null}},"5":{"start":{"line":9,"column":4},"end":{"line":13,"column":null}},"6":{"start":{"line":10,"column":6},"end":{"line":10,"column":null}},"7":{"start":{"line":12,"column":6},"end":{"line":12,"column":null}},"8":{"start":{"line":18,"column":2},"end":{"line":18,"column":null}},"9":{"start":{"line":19,"column":2},"end":{"line":19,"column":null}},"10":{"start":{"line":20,"column":2},"end":{"line":20,"column":null}},"11":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}}},"fnMap":{"0":{"name":"readJsonMaybe","decl":{"start":{"line":3,"column":22},"end":{"line":3,"column":36}},"loc":{"start":{"line":3,"column":97},"end":{"line":15,"column":null}},"line":3},"1":{"name":"stripJsoncComments","decl":{"start":{"line":17,"column":16},"end":{"line":17,"column":35}},"loc":{"start":{"line":17,"column":60},"end":{"line":21,"column":null}},"line":17},"2":{"name":"writeJsonFile","decl":{"start":{"line":23,"column":22},"end":{"line":23,"column":null}},"loc":{"start":{"line":27,"column":17},"end":{"line":29,"column":null}},"line":27}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"type":"if","locations":[{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},{"start":{},"end":{}}],"line":5}},"s":{"0":286,"1":286,"2":280,"3":6,"4":6,"5":1,"6":1,"7":0,"8":1,"9":1,"10":1,"11":10},"f":{"0":286,"1":1,"2":10},"b":{"0":[280,6]},"meta":{"lastBranch":1,"lastFunction":3,"lastStatement":12,"seen":{"f:3:22:3:36":0,"s:4:18:4:Infinity":0,"b:5:2:5:Infinity:undefined:undefined:undefined:undefined":0,"s:5:2:5:Infinity":1,"s:5:16:5:Infinity":2,"s:6:2:14:Infinity":3,"s:7:4:7:Infinity":4,"s:9:4:13:Infinity":5,"s:10:6:10:Infinity":6,"s:12:6:12:Infinity":7,"f:17:16:17:35":1,"s:18:2:18:Infinity":8,"s:19:2:19:Infinity":9,"s:20:2:20:Infinity":10,"f:23:22:23:Infinity":2,"s:28:2:28:Infinity":11}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-api-key-service.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-api-key-service.ts","statementMap":{"0":{"start":{"line":9,"column":4},"end":{"line":9,"column":null}},"1":{"start":{"line":10,"column":4},"end":{"line":10,"column":null}},"2":{"start":{"line":11,"column":4},"end":{"line":11,"column":null}},"3":{"start":{"line":15,"column":4},"end":{"line":17,"column":null}},"4":{"start":{"line":16,"column":6},"end":{"line":16,"column":null}},"5":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":8,"column":2},"end":{"line":8,"column":14}},"loc":{"start":{"line":8,"column":89},"end":{"line":12,"column":null}},"line":8},"1":{"name":"create","decl":{"start":{"line":14,"column":8},"end":{"line":14,"column":15}},"loc":{"start":{"line":14,"column":91},"end":{"line":19,"column":null}},"line":14}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":27},"end":{"line":8,"column":47}},"type":"default-arg","locations":[{"start":{"line":8,"column":40},"end":{"line":8,"column":47}}],"line":8},"1":{"loc":{"start":{"line":8,"column":47},"end":{"line":8,"column":89}},"type":"default-arg","locations":[{"start":{"line":8,"column":62},"end":{"line":8,"column":89}}],"line":8},"2":{"loc":{"start":{"line":15,"column":4},"end":{"line":17,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":17,"column":null}},{"start":{},"end":{}}],"line":15}},"s":{"0":46,"1":46,"2":46,"3":1,"4":0,"5":1},"f":{"0":46,"1":1},"b":{"0":[46],"1":[46],"2":[0,1]},"meta":{"lastBranch":3,"lastFunction":2,"lastStatement":6,"seen":{"f:8:2:8:14":0,"b:8:40:8:47":0,"b:8:62:8:89":1,"s:9:4:9:Infinity":0,"s:10:4:10:Infinity":1,"s:11:4:11:Infinity":2,"f:14:8:14:15":1,"b:15:4:17:Infinity:undefined:undefined:undefined:undefined":2,"s:15:4:17:Infinity":3,"s:16:6:16:Infinity":4,"s:18:4:18:Infinity":5}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-auth-service.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-auth-service.ts","statementMap":{"0":{"start":{"line":4,"column":19},"end":{"line":4,"column":null}},"1":{"start":{"line":5,"column":30},"end":{"line":5,"column":null}},"2":{"start":{"line":8,"column":21},"end":{"line":8,"column":null}},"3":{"start":{"line":9,"column":21},"end":{"line":9,"column":41}},"4":{"start":{"line":10,"column":21},"end":{"line":10,"column":44}},"5":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"6":{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},"7":{"start":{"line":21,"column":4},"end":{"line":21,"column":null}},"8":{"start":{"line":22,"column":4},"end":{"line":24,"column":null}},"9":{"start":{"line":23,"column":6},"end":{"line":23,"column":null}},"10":{"start":{"line":26,"column":22},"end":{"line":26,"column":null}},"11":{"start":{"line":28,"column":24},"end":{"line":33,"column":null}},"12":{"start":{"line":35,"column":4},"end":{"line":40,"column":null}},"13":{"start":{"line":45,"column":2},"end":{"line":45,"column":null}},"14":{"start":{"line":49,"column":17},"end":{"line":49,"column":null}},"15":{"start":{"line":50,"column":15},"end":{"line":50,"column":null}},"16":{"start":{"line":51,"column":2},"end":{"line":51,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"loc":{"start":{"line":11,"column":4},"end":{"line":11,"column":null}},"line":11},"1":{"name":"login","decl":{"start":{"line":13,"column":8},"end":{"line":13,"column":34}},"loc":{"start":{"line":13,"column":34},"end":{"line":16,"column":null}},"line":13},"2":{"name":"loginInteractive","decl":{"start":{"line":18,"column":2},"end":{"line":18,"column":19}},"loc":{"start":{"line":20,"column":54},"end":{"line":41,"column":null}},"line":20},"3":{"name":"base64urlEncode","decl":{"start":{"line":44,"column":9},"end":{"line":44,"column":25}},"loc":{"start":{"line":44,"column":47},"end":{"line":46,"column":null}},"line":44},"4":{"name":"makeJwt","decl":{"start":{"line":48,"column":9},"end":{"line":48,"column":17}},"loc":{"start":{"line":48,"column":59},"end":{"line":52,"column":null}},"line":48}},"branchMap":{"0":{"loc":{"start":{"line":9,"column":4},"end":{"line":9,"column":null}},"type":"default-arg","locations":[{"start":{"line":9,"column":41},"end":{"line":9,"column":null}}],"line":9},"1":{"loc":{"start":{"line":10,"column":4},"end":{"line":10,"column":null}},"type":"default-arg","locations":[{"start":{"line":10,"column":44},"end":{"line":10,"column":null}}],"line":10},"2":{"loc":{"start":{"line":22,"column":4},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":4},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":22},"3":{"loc":{"start":{"line":28,"column":24},"end":{"line":33,"column":null}},"type":"cond-expr","locations":[{"start":{"line":29,"column":8},"end":{"line":32,"column":null}},{"start":{"line":33,"column":8},"end":{"line":33,"column":null}}],"line":28},"4":{"loc":{"start":{"line":31,"column":33},"end":{"line":31,"column":97}},"type":"cond-expr","locations":[{"start":{"line":31,"column":49},"end":{"line":31,"column":72}},{"start":{"line":31,"column":72},"end":{"line":31,"column":97}}],"line":31}},"s":{"0":46,"1":46,"2":46,"3":46,"4":46,"5":0,"6":0,"7":44,"8":44,"9":43,"10":1,"11":1,"12":44,"13":2,"14":1,"15":1,"16":1},"f":{"0":46,"1":0,"2":44,"3":2,"4":1},"b":{"0":[46],"1":[46],"2":[43,1],"3":[1,0],"4":[0,1]},"meta":{"lastBranch":5,"lastFunction":5,"lastStatement":17,"seen":{"s:4:19:4:Infinity":0,"s:5:30:5:Infinity":1,"f:7:2:7:Infinity":0,"b:9:41:9:Infinity":0,"b:10:44:10:Infinity":1,"s:8:21:8:Infinity":2,"s:9:21:9:41":3,"s:10:21:10:44":4,"f:13:8:13:34":1,"s:14:4:14:Infinity":5,"s:15:4:15:Infinity":6,"f:18:2:18:19":2,"s:21:4:21:Infinity":7,"b:22:4:24:Infinity:undefined:undefined:undefined:undefined":2,"s:22:4:24:Infinity":8,"s:23:6:23:Infinity":9,"s:26:22:26:Infinity":10,"s:28:24:33:Infinity":11,"b:29:8:32:Infinity:33:8:33:Infinity":3,"b:31:49:31:72:31:72:31:97":4,"s:35:4:40:Infinity":12,"f:44:9:44:25":3,"s:45:2:45:Infinity":13,"f:48:9:48:17":4,"s:49:17:49:Infinity":14,"s:50:15:50:Infinity":15,"s:51:2:51:Infinity":16}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-command-runner.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-command-runner.ts","statementMap":{"0":{"start":{"line":12,"column":91},"end":{"line":12,"column":null}},"1":{"start":{"line":14,"column":32},"end":{"line":14,"column":null}},"2":{"start":{"line":10,"column":4},"end":{"line":10,"column":null}},"3":{"start":{"line":17,"column":4},"end":{"line":17,"column":null}},"4":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"5":{"start":{"line":18,"column":53},"end":{"line":18,"column":83}},"6":{"start":{"line":22,"column":4},"end":{"line":29,"column":null}},"7":{"start":{"line":24,"column":21},"end":{"line":24,"column":null}},"8":{"start":{"line":25,"column":8},"end":{"line":25,"column":null}},"9":{"start":{"line":25,"column":39},"end":{"line":25,"column":null}},"10":{"start":{"line":26,"column":8},"end":{"line":26,"column":null}},"11":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"12":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"13":{"start":{"line":39,"column":20},"end":{"line":39,"column":null}},"14":{"start":{"line":39,"column":46},"end":{"line":39,"column":74}},"15":{"start":{"line":40,"column":4},"end":{"line":40,"column":null}},"16":{"start":{"line":40,"column":18},"end":{"line":40,"column":null}},"17":{"start":{"line":43,"column":6},"end":{"line":45,"column":null}},"18":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"19":{"start":{"line":47,"column":33},"end":{"line":47,"column":null}},"20":{"start":{"line":48,"column":4},"end":{"line":48,"column":null}}},"fnMap":{"0":{"name":"calls","decl":{"start":{"line":9,"column":6},"end":{"line":9,"column":14}},"loc":{"start":{"line":9,"column":14},"end":{"line":11,"column":null}},"line":9},"1":{"name":"checkInstalled","decl":{"start":{"line":16,"column":2},"end":{"line":16,"column":17}},"loc":{"start":{"line":16,"column":51},"end":{"line":19,"column":null}},"line":16},"2":{"name":"(anonymous_2)","decl":{"start":{"line":18,"column":41},"end":{"line":18,"column":47}},"loc":{"start":{"line":18,"column":53},"end":{"line":18,"column":83}},"line":18},"3":{"name":"handle","decl":{"start":{"line":21,"column":2},"end":{"line":21,"column":9}},"loc":{"start":{"line":21,"column":65},"end":{"line":31,"column":null}},"line":21},"4":{"name":"(anonymous_4)","decl":{"start":{"line":23,"column":6},"end":{"line":23,"column":14}},"loc":{"start":{"line":23,"column":34},"end":{"line":27,"column":null}},"line":23},"5":{"name":"run","decl":{"start":{"line":33,"column":8},"end":{"line":33,"column":null}},"loc":{"start":{"line":37,"column":21},"end":{"line":49,"column":null}},"line":37},"6":{"name":"(anonymous_6)","decl":{"start":{"line":39,"column":34},"end":{"line":39,"column":40}},"loc":{"start":{"line":39,"column":46},"end":{"line":39,"column":74}},"line":39}},"branchMap":{"0":{"loc":{"start":{"line":18,"column":27},"end":{"line":18,"column":93}},"type":"binary-expr","locations":[{"start":{"line":18,"column":27},"end":{"line":18,"column":88}},{"start":{"line":18,"column":88},"end":{"line":18,"column":93}}],"line":18},"1":{"loc":{"start":{"line":25,"column":8},"end":{"line":25,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":8},"end":{"line":25,"column":null}},{"start":{},"end":{}}],"line":25},"2":{"loc":{"start":{"line":40,"column":4},"end":{"line":40,"column":null}},"type":"if","locations":[{"start":{"line":40,"column":4},"end":{"line":40,"column":null}},{"start":{},"end":{}}],"line":40},"3":{"loc":{"start":{"line":43,"column":6},"end":{"line":45,"column":null}},"type":"cond-expr","locations":[{"start":{"line":44,"column":10},"end":{"line":44,"column":null}},{"start":{"line":45,"column":10},"end":{"line":45,"column":null}}],"line":43},"4":{"loc":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},{"start":{},"end":{}}],"line":47}},"s":{"0":36,"1":36,"2":3,"3":34,"4":34,"5":29,"6":61,"7":53,"8":53,"9":53,"10":0,"11":61,"12":12,"13":12,"14":24,"15":12,"16":0,"17":12,"18":12,"19":2,"20":10},"f":{"0":3,"1":34,"2":29,"3":61,"4":53,"5":12,"6":24},"b":{"0":[34,5],"1":[53,0],"2":[0,12],"3":[0,12],"4":[2,10]},"meta":{"lastBranch":5,"lastFunction":7,"lastStatement":21,"seen":{"s:12:91:12:Infinity":0,"s:14:32:14:Infinity":1,"f:9:6:9:14":0,"s:10:4:10:Infinity":2,"f:16:2:16:17":1,"s:17:4:17:Infinity":3,"s:18:4:18:Infinity":4,"b:18:27:18:88:18:88:18:93":0,"f:18:41:18:47":2,"s:18:53:18:83":5,"f:21:2:21:9":3,"s:22:4:29:Infinity":6,"f:23:6:23:14":4,"s:24:21:24:Infinity":7,"b:25:8:25:Infinity:undefined:undefined:undefined:undefined":1,"s:25:8:25:Infinity":8,"s:25:39:25:Infinity":9,"s:26:8:26:Infinity":10,"s:30:4:30:Infinity":11,"f:33:8:33:Infinity":5,"s:38:4:38:Infinity":12,"s:39:20:39:Infinity":13,"f:39:34:39:40":6,"s:39:46:39:74":14,"b:40:4:40:Infinity:undefined:undefined:undefined:undefined":2,"s:40:4:40:Infinity":15,"s:40:18:40:Infinity":16,"s:43:6:45:Infinity":17,"b:44:10:44:Infinity:45:10:45:Infinity":3,"b:47:4:47:Infinity:undefined:undefined:undefined:undefined":4,"s:47:4:47:Infinity":18,"s:47:33:47:Infinity":19,"s:48:4:48:Infinity":20}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-file-store.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-file-store.ts","statementMap":{"0":{"start":{"line":9,"column":63},"end":{"line":9,"column":null}},"1":{"start":{"line":10,"column":30},"end":{"line":10,"column":null}},"2":{"start":{"line":11,"column":39},"end":{"line":11,"column":null}},"3":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"4":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"5":{"start":{"line":22,"column":4},"end":{"line":22,"column":null}},"6":{"start":{"line":26,"column":4},"end":{"line":26,"column":null}},"7":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"8":{"start":{"line":34,"column":4},"end":{"line":34,"column":null}},"9":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"10":{"start":{"line":42,"column":4},"end":{"line":42,"column":null}}},"fnMap":{"0":{"name":"chmod","decl":{"start":{"line":13,"column":8},"end":{"line":13,"column":14}},"loc":{"start":{"line":13,"column":57},"end":{"line":15,"column":null}},"line":13},"1":{"name":"exists","decl":{"start":{"line":17,"column":8},"end":{"line":17,"column":15}},"loc":{"start":{"line":17,"column":47},"end":{"line":19,"column":null}},"line":17},"2":{"name":"getChmodCalls","decl":{"start":{"line":21,"column":2},"end":{"line":21,"column":57}},"loc":{"start":{"line":21,"column":57},"end":{"line":23,"column":null}},"line":21},"3":{"name":"getWrittenFiles","decl":{"start":{"line":25,"column":2},"end":{"line":25,"column":41}},"loc":{"start":{"line":25,"column":41},"end":{"line":27,"column":null}},"line":25},"4":{"name":"mkdir","decl":{"start":{"line":29,"column":8},"end":{"line":29,"column":14}},"loc":{"start":{"line":29,"column":43},"end":{"line":31,"column":null}},"line":29},"5":{"name":"readFile","decl":{"start":{"line":33,"column":8},"end":{"line":33,"column":17}},"loc":{"start":{"line":33,"column":55},"end":{"line":35,"column":null}},"line":33},"6":{"name":"seed","decl":{"start":{"line":37,"column":2},"end":{"line":37,"column":7}},"loc":{"start":{"line":37,"column":44},"end":{"line":39,"column":null}},"line":37},"7":{"name":"writeFile","decl":{"start":{"line":41,"column":8},"end":{"line":41,"column":18}},"loc":{"start":{"line":41,"column":64},"end":{"line":43,"column":null}},"line":41}},"branchMap":{"0":{"loc":{"start":{"line":18,"column":11},"end":{"line":18,"column":null}},"type":"binary-expr","locations":[{"start":{"line":18,"column":11},"end":{"line":18,"column":35}},{"start":{"line":18,"column":35},"end":{"line":18,"column":null}}],"line":18},"1":{"loc":{"start":{"line":34,"column":11},"end":{"line":34,"column":null}},"type":"binary-expr","locations":[{"start":{"line":34,"column":11},"end":{"line":34,"column":35}},{"start":{"line":34,"column":35},"end":{"line":34,"column":null}}],"line":34}},"s":{"0":45,"1":45,"2":45,"3":3,"4":145,"5":0,"6":24,"7":12,"8":390,"9":8,"10":44},"f":{"0":3,"1":145,"2":0,"3":24,"4":12,"5":390,"6":8,"7":44},"b":{"0":[145,136],"1":[390,377]},"meta":{"lastBranch":2,"lastFunction":8,"lastStatement":11,"seen":{"s:9:63:9:Infinity":0,"s:10:30:10:Infinity":1,"s:11:39:11:Infinity":2,"f:13:8:13:14":0,"s:14:4:14:Infinity":3,"f:17:8:17:15":1,"s:18:4:18:Infinity":4,"b:18:11:18:35:18:35:18:Infinity":0,"f:21:2:21:57":2,"s:22:4:22:Infinity":5,"f:25:2:25:41":3,"s:26:4:26:Infinity":6,"f:29:8:29:14":4,"s:30:4:30:Infinity":7,"f:33:8:33:17":5,"s:34:4:34:Infinity":8,"b:34:11:34:35:34:35:34:Infinity":1,"f:37:2:37:7":6,"s:38:4:38:Infinity":9,"f:41:8:41:18":7,"s:42:4:42:Infinity":10}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-prompter.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/__tests__/fake-prompter.ts","statementMap":{"0":{"start":{"line":5,"column":22},"end":{"line":5,"column":null}},"1":{"start":{"line":13,"column":13},"end":{"line":17,"column":null}},"2":{"start":{"line":13,"column":87},"end":{"line":17,"column":null}},"3":{"start":{"line":19,"column":13},"end":{"line":23,"column":null}},"4":{"start":{"line":19,"column":87},"end":{"line":23,"column":null}},"5":{"start":{"line":25,"column":13},"end":{"line":29,"column":null}},"6":{"start":{"line":25,"column":91},"end":{"line":29,"column":null}},"7":{"start":{"line":31,"column":13},"end":{"line":35,"column":null}},"8":{"start":{"line":31,"column":95},"end":{"line":35,"column":null}},"9":{"start":{"line":41,"column":61},"end":{"line":41,"column":null}},"10":{"start":{"line":43,"column":20},"end":{"line":43,"column":null}},"11":{"start":{"line":39,"column":4},"end":{"line":39,"column":null}},"12":{"start":{"line":45,"column":31},"end":{"line":45,"column":55}},"13":{"start":{"line":47,"column":4},"end":{"line":49,"column":null}},"14":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"15":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"16":{"start":{"line":55,"column":4},"end":{"line":55,"column":null}},"17":{"start":{"line":56,"column":18},"end":{"line":56,"column":null}},"18":{"start":{"line":57,"column":4},"end":{"line":58,"column":null}},"19":{"start":{"line":58,"column":6},"end":{"line":58,"column":null}},"20":{"start":{"line":59,"column":4},"end":{"line":60,"column":null}},"21":{"start":{"line":60,"column":6},"end":{"line":60,"column":null}},"22":{"start":{"line":61,"column":4},"end":{"line":62,"column":null}},"23":{"start":{"line":62,"column":6},"end":{"line":62,"column":null}},"24":{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},"25":{"start":{"line":63,"column":35},"end":{"line":63,"column":null}},"26":{"start":{"line":64,"column":4},"end":{"line":64,"column":null}},"27":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"28":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"29":{"start":{"line":75,"column":4},"end":{"line":75,"column":null}},"30":{"start":{"line":76,"column":18},"end":{"line":76,"column":null}},"31":{"start":{"line":77,"column":4},"end":{"line":78,"column":null}},"32":{"start":{"line":78,"column":6},"end":{"line":78,"column":null}},"33":{"start":{"line":79,"column":4},"end":{"line":80,"column":null}},"34":{"start":{"line":80,"column":6},"end":{"line":80,"column":null}},"35":{"start":{"line":81,"column":4},"end":{"line":82,"column":null}},"36":{"start":{"line":82,"column":6},"end":{"line":82,"column":null}},"37":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"38":{"start":{"line":83,"column":41},"end":{"line":83,"column":null}},"39":{"start":{"line":84,"column":4},"end":{"line":84,"column":null}},"40":{"start":{"line":88,"column":4},"end":{"line":88,"column":null}},"41":{"start":{"line":92,"column":4},"end":{"line":92,"column":null}},"42":{"start":{"line":96,"column":4},"end":{"line":96,"column":null}},"43":{"start":{"line":97,"column":18},"end":{"line":97,"column":null}},"44":{"start":{"line":98,"column":4},"end":{"line":98,"column":null}},"45":{"start":{"line":98,"column":16},"end":{"line":98,"column":null}},"46":{"start":{"line":99,"column":4},"end":{"line":100,"column":null}},"47":{"start":{"line":100,"column":6},"end":{"line":100,"column":null}},"48":{"start":{"line":101,"column":4},"end":{"line":102,"column":null}},"49":{"start":{"line":102,"column":6},"end":{"line":102,"column":null}},"50":{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},"51":{"start":{"line":103,"column":35},"end":{"line":103,"column":null}},"52":{"start":{"line":104,"column":4},"end":{"line":104,"column":null}},"53":{"start":{"line":108,"column":4},"end":{"line":115,"column":null}},"54":{"start":{"line":110,"column":8},"end":{"line":110,"column":null}},"55":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"56":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"57":{"start":{"line":119,"column":55},"end":{"line":119,"column":62}},"58":{"start":{"line":120,"column":4},"end":{"line":125,"column":null}},"59":{"start":{"line":121,"column":12},"end":{"line":123,"column":null}},"60":{"start":{"line":124,"column":6},"end":{"line":124,"column":null}},"61":{"start":{"line":129,"column":4},"end":{"line":129,"column":null}},"62":{"start":{"line":130,"column":18},"end":{"line":130,"column":null}},"63":{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},"64":{"start":{"line":131,"column":16},"end":{"line":131,"column":null}},"65":{"start":{"line":132,"column":4},"end":{"line":133,"column":null}},"66":{"start":{"line":133,"column":6},"end":{"line":133,"column":null}},"67":{"start":{"line":134,"column":4},"end":{"line":135,"column":null}},"68":{"start":{"line":135,"column":6},"end":{"line":135,"column":null}},"69":{"start":{"line":136,"column":4},"end":{"line":136,"column":null}},"70":{"start":{"line":136,"column":35},"end":{"line":136,"column":null}},"71":{"start":{"line":137,"column":4},"end":{"line":137,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":13,"column":13},"end":{"line":13,"column":26}},"loc":{"start":{"line":13,"column":87},"end":{"line":17,"column":null}},"line":13},"1":{"name":"(anonymous_1)","decl":{"start":{"line":19,"column":13},"end":{"line":19,"column":21}},"loc":{"start":{"line":19,"column":87},"end":{"line":23,"column":null}},"line":19},"2":{"name":"(anonymous_2)","decl":{"start":{"line":25,"column":13},"end":{"line":25,"column":24}},"loc":{"start":{"line":25,"column":91},"end":{"line":29,"column":null}},"line":25},"3":{"name":"(anonymous_3)","decl":{"start":{"line":31,"column":13},"end":{"line":31,"column":31}},"loc":{"start":{"line":31,"column":95},"end":{"line":35,"column":null}},"line":31},"4":{"name":"calls","decl":{"start":{"line":38,"column":6},"end":{"line":38,"column":14}},"loc":{"start":{"line":38,"column":14},"end":{"line":40,"column":null}},"line":38},"5":{"name":"constructor","decl":{"start":{"line":45,"column":2},"end":{"line":45,"column":14}},"loc":{"start":{"line":45,"column":55},"end":{"line":45,"column":null}},"line":45},"6":{"name":"assertExhausted","decl":{"start":{"line":46,"column":2},"end":{"line":46,"column":20}},"loc":{"start":{"line":46,"column":20},"end":{"line":50,"column":null}},"line":46},"7":{"name":"cancel","decl":{"start":{"line":51,"column":2},"end":{"line":51,"column":9}},"loc":{"start":{"line":51,"column":32},"end":{"line":53,"column":null}},"line":51},"8":{"name":"confirm","decl":{"start":{"line":54,"column":8},"end":{"line":54,"column":16}},"loc":{"start":{"line":54,"column":64},"end":{"line":65,"column":null}},"line":54},"9":{"name":"intro","decl":{"start":{"line":66,"column":2},"end":{"line":66,"column":8}},"loc":{"start":{"line":66,"column":31},"end":{"line":68,"column":null}},"line":66},"10":{"name":"log","decl":{"start":{"line":70,"column":2},"end":{"line":70,"column":6}},"loc":{"start":{"line":70,"column":43},"end":{"line":72,"column":null}},"line":70},"11":{"name":"multiselect","decl":{"start":{"line":74,"column":8},"end":{"line":74,"column":23}},"loc":{"start":{"line":74,"column":67},"end":{"line":85,"column":null}},"line":74},"12":{"name":"note","decl":{"start":{"line":87,"column":2},"end":{"line":87,"column":7}},"loc":{"start":{"line":87,"column":46},"end":{"line":89,"column":null}},"line":87},"13":{"name":"outro","decl":{"start":{"line":91,"column":2},"end":{"line":91,"column":8}},"loc":{"start":{"line":91,"column":31},"end":{"line":93,"column":null}},"line":91},"14":{"name":"select","decl":{"start":{"line":95,"column":8},"end":{"line":95,"column":18}},"loc":{"start":{"line":95,"column":78},"end":{"line":105,"column":null}},"line":95},"15":{"name":"spinner","decl":{"start":{"line":107,"column":2},"end":{"line":107,"column":21}},"loc":{"start":{"line":107,"column":21},"end":{"line":116,"column":null}},"line":107},"16":{"name":"(anonymous_16)","decl":{"start":{"line":109,"column":6},"end":{"line":109,"column":14}},"loc":{"start":{"line":109,"column":34},"end":{"line":111,"column":null}},"line":109},"17":{"name":"(anonymous_17)","decl":{"start":{"line":112,"column":6},"end":{"line":112,"column":13}},"loc":{"start":{"line":112,"column":33},"end":{"line":114,"column":null}},"line":112},"18":{"name":"tasks","decl":{"start":{"line":118,"column":8},"end":{"line":118,"column":14}},"loc":{"start":{"line":118,"column":61},"end":{"line":126,"column":null}},"line":118},"19":{"name":"(anonymous_19)","decl":{"start":{"line":119,"column":44},"end":{"line":119,"column":49}},"loc":{"start":{"line":119,"column":55},"end":{"line":119,"column":62}},"line":119},"20":{"name":"(anonymous_20)","decl":{"start":{"line":121,"column":12},"end":{"line":121,"column":20}},"loc":{"start":{"line":121,"column":37},"end":{"line":123,"column":null}},"line":121},"21":{"name":"text","decl":{"start":{"line":128,"column":8},"end":{"line":128,"column":13}},"loc":{"start":{"line":128,"column":60},"end":{"line":138,"column":null}},"line":128}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":9},"end":{"line":15,"column":null}},"type":"cond-expr","locations":[{"start":{"line":15,"column":37},"end":{"line":15,"column":57}},{"start":{"line":15,"column":57},"end":{"line":15,"column":null}}],"line":15},"1":{"loc":{"start":{"line":16,"column":12},"end":{"line":16,"column":null}},"type":"cond-expr","locations":[{"start":{"line":16,"column":40},"end":{"line":16,"column":48}},{"start":{"line":16,"column":48},"end":{"line":16,"column":null}}],"line":16},"2":{"loc":{"start":{"line":21,"column":9},"end":{"line":21,"column":null}},"type":"cond-expr","locations":[{"start":{"line":21,"column":37},"end":{"line":21,"column":57}},{"start":{"line":21,"column":57},"end":{"line":21,"column":null}}],"line":21},"3":{"loc":{"start":{"line":27,"column":9},"end":{"line":27,"column":null}},"type":"cond-expr","locations":[{"start":{"line":27,"column":37},"end":{"line":27,"column":57}},{"start":{"line":27,"column":57},"end":{"line":27,"column":null}}],"line":27},"4":{"loc":{"start":{"line":33,"column":9},"end":{"line":33,"column":null}},"type":"cond-expr","locations":[{"start":{"line":33,"column":37},"end":{"line":33,"column":57}},{"start":{"line":33,"column":57},"end":{"line":33,"column":null}}],"line":33},"5":{"loc":{"start":{"line":34,"column":12},"end":{"line":34,"column":null}},"type":"cond-expr","locations":[{"start":{"line":34,"column":32},"end":{"line":34,"column":45}},{"start":{"line":34,"column":45},"end":{"line":34,"column":null}}],"line":34},"6":{"loc":{"start":{"line":47,"column":4},"end":{"line":49,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":4},"end":{"line":49,"column":null}},{"start":{},"end":{}}],"line":47},"7":{"loc":{"start":{"line":57,"column":4},"end":{"line":58,"column":null}},"type":"if","locations":[{"start":{"line":57,"column":4},"end":{"line":58,"column":null}},{"start":{},"end":{}}],"line":57},"8":{"loc":{"start":{"line":59,"column":4},"end":{"line":60,"column":null}},"type":"if","locations":[{"start":{"line":59,"column":4},"end":{"line":60,"column":null}},{"start":{},"end":{}}],"line":59},"9":{"loc":{"start":{"line":61,"column":4},"end":{"line":62,"column":null}},"type":"if","locations":[{"start":{"line":61,"column":4},"end":{"line":62,"column":null}},{"start":{},"end":{}}],"line":61},"10":{"loc":{"start":{"line":61,"column":8},"end":{"line":61,"column":null}},"type":"binary-expr","locations":[{"start":{"line":61,"column":8},"end":{"line":61,"column":23}},{"start":{"line":61,"column":23},"end":{"line":61,"column":null}}],"line":61},"11":{"loc":{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},"type":"if","locations":[{"start":{"line":63,"column":4},"end":{"line":63,"column":null}},{"start":{},"end":{}}],"line":63},"12":{"loc":{"start":{"line":77,"column":4},"end":{"line":78,"column":null}},"type":"if","locations":[{"start":{"line":77,"column":4},"end":{"line":78,"column":null}},{"start":{},"end":{}}],"line":77},"13":{"loc":{"start":{"line":79,"column":4},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":79,"column":4},"end":{"line":80,"column":null}},{"start":{},"end":{}}],"line":79},"14":{"loc":{"start":{"line":81,"column":4},"end":{"line":82,"column":null}},"type":"if","locations":[{"start":{"line":81,"column":4},"end":{"line":82,"column":null}},{"start":{},"end":{}}],"line":81},"15":{"loc":{"start":{"line":81,"column":8},"end":{"line":81,"column":null}},"type":"binary-expr","locations":[{"start":{"line":81,"column":8},"end":{"line":81,"column":23}},{"start":{"line":81,"column":23},"end":{"line":81,"column":null}}],"line":81},"16":{"loc":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"type":"if","locations":[{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},{"start":{},"end":{}}],"line":83},"17":{"loc":{"start":{"line":98,"column":4},"end":{"line":98,"column":null}},"type":"if","locations":[{"start":{"line":98,"column":4},"end":{"line":98,"column":null}},{"start":{},"end":{}}],"line":98},"18":{"loc":{"start":{"line":99,"column":4},"end":{"line":100,"column":null}},"type":"if","locations":[{"start":{"line":99,"column":4},"end":{"line":100,"column":null}},{"start":{},"end":{}}],"line":99},"19":{"loc":{"start":{"line":101,"column":4},"end":{"line":102,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":4},"end":{"line":102,"column":null}},{"start":{},"end":{}}],"line":101},"20":{"loc":{"start":{"line":101,"column":8},"end":{"line":101,"column":null}},"type":"binary-expr","locations":[{"start":{"line":101,"column":8},"end":{"line":101,"column":23}},{"start":{"line":101,"column":23},"end":{"line":101,"column":null}}],"line":101},"21":{"loc":{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},"type":"if","locations":[{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},{"start":{},"end":{}}],"line":103},"22":{"loc":{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},"type":"if","locations":[{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},{"start":{},"end":{}}],"line":131},"23":{"loc":{"start":{"line":132,"column":4},"end":{"line":133,"column":null}},"type":"if","locations":[{"start":{"line":132,"column":4},"end":{"line":133,"column":null}},{"start":{},"end":{}}],"line":132},"24":{"loc":{"start":{"line":134,"column":4},"end":{"line":135,"column":null}},"type":"if","locations":[{"start":{"line":134,"column":4},"end":{"line":135,"column":null}},{"start":{},"end":{}}],"line":134},"25":{"loc":{"start":{"line":134,"column":8},"end":{"line":134,"column":null}},"type":"binary-expr","locations":[{"start":{"line":134,"column":8},"end":{"line":134,"column":23}},{"start":{"line":134,"column":23},"end":{"line":134,"column":null}}],"line":134},"26":{"loc":{"start":{"line":136,"column":4},"end":{"line":136,"column":null}},"type":"if","locations":[{"start":{"line":136,"column":4},"end":{"line":136,"column":null}},{"start":{},"end":{}}],"line":136}},"s":{"0":1,"1":1,"2":105,"3":1,"4":0,"5":1,"6":42,"7":1,"8":18,"9":46,"10":46,"11":5,"12":46,"13":0,"14":0,"15":0,"16":42,"17":42,"18":42,"19":0,"20":42,"21":0,"22":42,"23":0,"24":42,"25":0,"26":42,"27":46,"28":36,"29":18,"30":18,"31":18,"32":0,"33":18,"34":0,"35":18,"36":0,"37":18,"38":0,"39":18,"40":238,"41":31,"42":105,"43":105,"44":105,"45":0,"46":105,"47":0,"48":105,"49":0,"50":105,"51":2,"52":103,"53":87,"54":87,"55":87,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0},"f":{"0":105,"1":0,"2":42,"3":18,"4":5,"5":46,"6":0,"7":0,"8":42,"9":46,"10":36,"11":18,"12":238,"13":31,"14":105,"15":87,"16":87,"17":87,"18":0,"19":0,"20":0,"21":0},"b":{"0":[0,105],"1":[2,103],"2":[0,0],"3":[40,2],"4":[0,18],"5":[0,18],"6":[0,0],"7":[0,42],"8":[0,42],"9":[0,42],"10":[42,41],"11":[0,42],"12":[0,18],"13":[0,18],"14":[0,18],"15":[18,0],"16":[0,18],"17":[0,105],"18":[0,105],"19":[0,105],"20":[105,0],"21":[2,103],"22":[0,0],"23":[0,0],"24":[0,0],"25":[0,0],"26":[0,0]},"meta":{"lastBranch":27,"lastFunction":22,"lastStatement":72,"seen":{"s:5:22:5:Infinity":0,"s:13:13:17:Infinity":1,"f:13:13:13:26":0,"s:13:87:17:Infinity":2,"b:15:37:15:57:15:57:15:Infinity":0,"b:16:40:16:48:16:48:16:Infinity":1,"s:19:13:23:Infinity":3,"f:19:13:19:21":1,"s:19:87:23:Infinity":4,"b:21:37:21:57:21:57:21:Infinity":2,"s:25:13:29:Infinity":5,"f:25:13:25:24":2,"s:25:91:29:Infinity":6,"b:27:37:27:57:27:57:27:Infinity":3,"s:31:13:35:Infinity":7,"f:31:13:31:31":3,"s:31:95:35:Infinity":8,"b:33:37:33:57:33:57:33:Infinity":4,"b:34:32:34:45:34:45:34:Infinity":5,"s:41:61:41:Infinity":9,"s:43:20:43:Infinity":10,"f:38:6:38:14":4,"s:39:4:39:Infinity":11,"f:45:2:45:14":5,"s:45:31:45:55":12,"f:46:2:46:20":6,"b:47:4:49:Infinity:undefined:undefined:undefined:undefined":6,"s:47:4:49:Infinity":13,"s:48:6:48:Infinity":14,"f:51:2:51:9":7,"s:52:4:52:Infinity":15,"f:54:8:54:16":8,"s:55:4:55:Infinity":16,"s:56:18:56:Infinity":17,"b:57:4:58:Infinity:undefined:undefined:undefined:undefined":7,"s:57:4:58:Infinity":18,"s:58:6:58:Infinity":19,"b:59:4:60:Infinity:undefined:undefined:undefined:undefined":8,"s:59:4:60:Infinity":20,"s:60:6:60:Infinity":21,"b:61:4:62:Infinity:undefined:undefined:undefined:undefined":9,"s:61:4:62:Infinity":22,"b:61:8:61:23:61:23:61:Infinity":10,"s:62:6:62:Infinity":23,"b:63:4:63:Infinity:undefined:undefined:undefined:undefined":11,"s:63:4:63:Infinity":24,"s:63:35:63:Infinity":25,"s:64:4:64:Infinity":26,"f:66:2:66:8":9,"s:67:4:67:Infinity":27,"f:70:2:70:6":10,"s:71:4:71:Infinity":28,"f:74:8:74:23":11,"s:75:4:75:Infinity":29,"s:76:18:76:Infinity":30,"b:77:4:78:Infinity:undefined:undefined:undefined:undefined":12,"s:77:4:78:Infinity":31,"s:78:6:78:Infinity":32,"b:79:4:80:Infinity:undefined:undefined:undefined:undefined":13,"s:79:4:80:Infinity":33,"s:80:6:80:Infinity":34,"b:81:4:82:Infinity:undefined:undefined:undefined:undefined":14,"s:81:4:82:Infinity":35,"b:81:8:81:23:81:23:81:Infinity":15,"s:82:6:82:Infinity":36,"b:83:4:83:Infinity:undefined:undefined:undefined:undefined":16,"s:83:4:83:Infinity":37,"s:83:41:83:Infinity":38,"s:84:4:84:Infinity":39,"f:87:2:87:7":12,"s:88:4:88:Infinity":40,"f:91:2:91:8":13,"s:92:4:92:Infinity":41,"f:95:8:95:18":14,"s:96:4:96:Infinity":42,"s:97:18:97:Infinity":43,"b:98:4:98:Infinity:undefined:undefined:undefined:undefined":17,"s:98:4:98:Infinity":44,"s:98:16:98:Infinity":45,"b:99:4:100:Infinity:undefined:undefined:undefined:undefined":18,"s:99:4:100:Infinity":46,"s:100:6:100:Infinity":47,"b:101:4:102:Infinity:undefined:undefined:undefined:undefined":19,"s:101:4:102:Infinity":48,"b:101:8:101:23:101:23:101:Infinity":20,"s:102:6:102:Infinity":49,"b:103:4:103:Infinity:undefined:undefined:undefined:undefined":21,"s:103:4:103:Infinity":50,"s:103:35:103:Infinity":51,"s:104:4:104:Infinity":52,"f:107:2:107:21":15,"s:108:4:115:Infinity":53,"f:109:6:109:14":16,"s:110:8:110:Infinity":54,"f:112:6:112:13":17,"s:113:8:113:Infinity":55,"f:118:8:118:14":18,"s:119:4:119:Infinity":56,"f:119:44:119:49":19,"s:119:55:119:62":57,"s:120:4:125:Infinity":58,"s:121:12:123:Infinity":59,"f:121:12:121:20":20,"s:124:6:124:Infinity":60,"f:128:8:128:13":21,"s:129:4:129:Infinity":61,"s:130:18:130:Infinity":62,"b:131:4:131:Infinity:undefined:undefined:undefined:undefined":22,"s:131:4:131:Infinity":63,"s:131:16:131:Infinity":64,"b:132:4:133:Infinity:undefined:undefined:undefined:undefined":23,"s:132:4:133:Infinity":65,"s:133:6:133:Infinity":66,"b:134:4:135:Infinity:undefined:undefined:undefined:undefined":24,"s:134:4:135:Infinity":67,"b:134:8:134:23:134:23:134:Infinity":25,"s:135:6:135:Infinity":68,"b:136:4:136:Infinity:undefined:undefined:undefined:undefined":26,"s:136:4:136:Infinity":69,"s:136:35:136:Infinity":70,"s:137:4:137:Infinity":71}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/clack-prompter.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/clack-prompter.ts","statementMap":{"0":{"start":{"line":7,"column":6},"end":{"line":10,"column":null}},"1":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"2":{"start":{"line":8,"column":21},"end":{"line":8,"column":null}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"4":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"5":{"start":{"line":17,"column":4},"end":{"line":17,"column":null}},"6":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"7":{"start":{"line":23,"column":4},"end":{"line":23,"column":null}},"8":{"start":{"line":33,"column":4},"end":{"line":33,"column":null}},"9":{"start":{"line":36,"column":4},"end":{"line":36,"column":null}},"10":{"start":{"line":39,"column":4},"end":{"line":39,"column":null}},"11":{"start":{"line":51,"column":4},"end":{"line":51,"column":null}},"12":{"start":{"line":55,"column":14},"end":{"line":55,"column":null}},"13":{"start":{"line":56,"column":4},"end":{"line":59,"column":null}},"14":{"start":{"line":57,"column":34},"end":{"line":57,"column":null}},"15":{"start":{"line":58,"column":33},"end":{"line":58,"column":null}},"16":{"start":{"line":63,"column":4},"end":{"line":71,"column":null}},"17":{"start":{"line":64,"column":27},"end":{"line":70,"column":8}},"18":{"start":{"line":66,"column":25},"end":{"line":66,"column":null}},"19":{"start":{"line":67,"column":10},"end":{"line":67,"column":null}},"20":{"start":{"line":75,"column":4},"end":{"line":75,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":6},"end":{"line":7,"column":19}},"loc":{"start":{"line":7,"column":40},"end":{"line":10,"column":null}},"line":7},"1":{"name":"cancel","decl":{"start":{"line":13,"column":2},"end":{"line":13,"column":9}},"loc":{"start":{"line":13,"column":32},"end":{"line":15,"column":null}},"line":13},"2":{"name":"confirm","decl":{"start":{"line":16,"column":8},"end":{"line":16,"column":16}},"loc":{"start":{"line":16,"column":88},"end":{"line":18,"column":null}},"line":16},"3":{"name":"intro","decl":{"start":{"line":19,"column":2},"end":{"line":19,"column":8}},"loc":{"start":{"line":19,"column":31},"end":{"line":21,"column":null}},"line":19},"4":{"name":"log","decl":{"start":{"line":22,"column":2},"end":{"line":22,"column":6}},"loc":{"start":{"line":22,"column":95},"end":{"line":24,"column":null}},"line":22},"5":{"name":"multiselect","decl":{"start":{"line":25,"column":8},"end":{"line":25,"column":23}},"loc":{"start":{"line":32,"column":19},"end":{"line":34,"column":null}},"line":32},"6":{"name":"note","decl":{"start":{"line":35,"column":2},"end":{"line":35,"column":7}},"loc":{"start":{"line":35,"column":46},"end":{"line":37,"column":null}},"line":35},"7":{"name":"outro","decl":{"start":{"line":38,"column":2},"end":{"line":38,"column":8}},"loc":{"start":{"line":38,"column":31},"end":{"line":40,"column":null}},"line":38},"8":{"name":"select","decl":{"start":{"line":42,"column":8},"end":{"line":42,"column":18}},"loc":{"start":{"line":50,"column":17},"end":{"line":52,"column":null}},"line":50},"9":{"name":"spinner","decl":{"start":{"line":54,"column":2},"end":{"line":54,"column":21}},"loc":{"start":{"line":54,"column":21},"end":{"line":60,"column":null}},"line":54},"10":{"name":"(anonymous_10)","decl":{"start":{"line":57,"column":6},"end":{"line":57,"column":14}},"loc":{"start":{"line":57,"column":34},"end":{"line":57,"column":null}},"line":57},"11":{"name":"(anonymous_11)","decl":{"start":{"line":58,"column":6},"end":{"line":58,"column":13}},"loc":{"start":{"line":58,"column":33},"end":{"line":58,"column":null}},"line":58},"12":{"name":"tasks","decl":{"start":{"line":62,"column":8},"end":{"line":62,"column":14}},"loc":{"start":{"line":62,"column":61},"end":{"line":72,"column":null}},"line":62},"13":{"name":"(anonymous_13)","decl":{"start":{"line":64,"column":12},"end":{"line":64,"column":17}},"loc":{"start":{"line":64,"column":27},"end":{"line":70,"column":8}},"line":64},"14":{"name":"(anonymous_14)","decl":{"start":{"line":65,"column":14},"end":{"line":65,"column":21}},"loc":{"start":{"line":65,"column":56},"end":{"line":68,"column":null}},"line":65},"15":{"name":"text","decl":{"start":{"line":74,"column":8},"end":{"line":74,"column":13}},"loc":{"start":{"line":74,"column":82},"end":{"line":76,"column":null}},"line":74}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},{"start":{},"end":{}}],"line":8},"1":{"loc":{"start":{"line":67,"column":17},"end":{"line":67,"column":null}},"type":"binary-expr","locations":[{"start":{"line":67,"column":17},"end":{"line":67,"column":27}},{"start":{"line":67,"column":27},"end":{"line":67,"column":null}}],"line":67}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0},"b":{"0":[0,0],"1":[0,0]},"meta":{"lastBranch":2,"lastFunction":16,"lastStatement":21,"seen":{"s:7:6:10:Infinity":0,"f:7:6:7:19":0,"b:8:2:8:Infinity:undefined:undefined:undefined:undefined":0,"s:8:2:8:Infinity":1,"s:8:21:8:Infinity":2,"s:9:2:9:Infinity":3,"f:13:2:13:9":1,"s:14:4:14:Infinity":4,"f:16:8:16:16":2,"s:17:4:17:Infinity":5,"f:19:2:19:8":3,"s:20:4:20:Infinity":6,"f:22:2:22:6":4,"s:23:4:23:Infinity":7,"f:25:8:25:23":5,"s:33:4:33:Infinity":8,"f:35:2:35:7":6,"s:36:4:36:Infinity":9,"f:38:2:38:8":7,"s:39:4:39:Infinity":10,"f:42:8:42:18":8,"s:51:4:51:Infinity":11,"f:54:2:54:21":9,"s:55:14:55:Infinity":12,"s:56:4:59:Infinity":13,"f:57:6:57:14":10,"s:57:34:57:Infinity":14,"f:58:6:58:13":11,"s:58:33:58:Infinity":15,"f:62:8:62:14":12,"s:63:4:71:Infinity":16,"f:64:12:64:17":13,"s:64:27:70:8":17,"f:65:14:65:21":14,"s:66:25:66:Infinity":18,"s:67:10:67:Infinity":19,"b:67:17:67:27:67:27:67:Infinity":1,"f:74:8:74:13":15,"s:75:4:75:Infinity":20}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/fs-file-store.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/fs-file-store.ts","statementMap":{"0":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"1":{"start":{"line":12,"column":4},"end":{"line":17,"column":null}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":null}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":null}},"4":{"start":{"line":16,"column":6},"end":{"line":16,"column":null}},"5":{"start":{"line":21,"column":4},"end":{"line":21,"column":null}},"6":{"start":{"line":25,"column":4},"end":{"line":30,"column":null}},"7":{"start":{"line":26,"column":6},"end":{"line":26,"column":null}},"8":{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},"9":{"start":{"line":28,"column":35},"end":{"line":28,"column":null}},"10":{"start":{"line":29,"column":6},"end":{"line":29,"column":null}},"11":{"start":{"line":34,"column":16},"end":{"line":34,"column":null}},"12":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"13":{"start":{"line":36,"column":4},"end":{"line":36,"column":null}}},"fnMap":{"0":{"name":"chmod","decl":{"start":{"line":7,"column":8},"end":{"line":7,"column":14}},"loc":{"start":{"line":7,"column":61},"end":{"line":9,"column":null}},"line":7},"1":{"name":"exists","decl":{"start":{"line":11,"column":8},"end":{"line":11,"column":15}},"loc":{"start":{"line":11,"column":51},"end":{"line":18,"column":null}},"line":11},"2":{"name":"mkdir","decl":{"start":{"line":20,"column":8},"end":{"line":20,"column":14}},"loc":{"start":{"line":20,"column":42},"end":{"line":22,"column":null}},"line":20},"3":{"name":"readFile","decl":{"start":{"line":24,"column":8},"end":{"line":24,"column":17}},"loc":{"start":{"line":24,"column":59},"end":{"line":31,"column":null}},"line":24},"4":{"name":"writeFile","decl":{"start":{"line":33,"column":8},"end":{"line":33,"column":18}},"loc":{"start":{"line":33,"column":68},"end":{"line":37,"column":null}},"line":33}},"branchMap":{"0":{"loc":{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},{"start":{},"end":{}}],"line":28}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0]},"meta":{"lastBranch":1,"lastFunction":5,"lastStatement":14,"seen":{"f:7:8:7:14":0,"s:8:4:8:Infinity":0,"f:11:8:11:15":1,"s:12:4:17:Infinity":1,"s:13:6:13:Infinity":2,"s:14:6:14:Infinity":3,"s:16:6:16:Infinity":4,"f:20:8:20:14":2,"s:21:4:21:Infinity":5,"f:24:8:24:17":3,"s:25:4:30:Infinity":6,"s:26:6:26:Infinity":7,"b:28:6:28:Infinity:undefined:undefined:undefined:undefined":0,"s:28:6:28:Infinity":8,"s:28:35:28:Infinity":9,"s:29:6:29:Infinity":10,"f:33:8:33:18":4,"s:34:16:34:Infinity":11,"s:35:4:35:Infinity":12,"s:36:4:36:Infinity":13}}} -,"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/spawn-command-runner.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/commands/code/adapters/spawn-command-runner.ts","statementMap":{"0":{"start":{"line":7,"column":4},"end":{"line":11,"column":null}},"1":{"start":{"line":8,"column":12},"end":{"line":8,"column":null}},"2":{"start":{"line":9,"column":6},"end":{"line":9,"column":null}},"3":{"start":{"line":9,"column":34},"end":{"line":9,"column":53}},"4":{"start":{"line":10,"column":6},"end":{"line":10,"column":null}},"5":{"start":{"line":10,"column":30},"end":{"line":10,"column":44}},"6":{"start":{"line":19,"column":4},"end":{"line":43,"column":null}},"7":{"start":{"line":20,"column":12},"end":{"line":23,"column":null}},"8":{"start":{"line":25,"column":19},"end":{"line":25,"column":null}},"9":{"start":{"line":26,"column":19},"end":{"line":26,"column":null}},"10":{"start":{"line":28,"column":6},"end":{"line":30,"column":null}},"11":{"start":{"line":29,"column":8},"end":{"line":29,"column":null}},"12":{"start":{"line":31,"column":6},"end":{"line":33,"column":null}},"13":{"start":{"line":32,"column":8},"end":{"line":32,"column":null}},"14":{"start":{"line":35,"column":6},"end":{"line":41,"column":null}},"15":{"start":{"line":36,"column":8},"end":{"line":40,"column":null}},"16":{"start":{"line":37,"column":10},"end":{"line":37,"column":null}},"17":{"start":{"line":39,"column":10},"end":{"line":39,"column":null}},"18":{"start":{"line":42,"column":6},"end":{"line":42,"column":null}},"19":{"start":{"line":42,"column":35},"end":{"line":42,"column":48}}},"fnMap":{"0":{"name":"checkInstalled","decl":{"start":{"line":6,"column":8},"end":{"line":6,"column":23}},"loc":{"start":{"line":6,"column":57},"end":{"line":12,"column":null}},"line":6},"1":{"name":"(anonymous_1)","decl":{"start":{"line":7,"column":15},"end":{"line":7,"column":24}},"loc":{"start":{"line":7,"column":36},"end":{"line":11,"column":5}},"line":7},"2":{"name":"(anonymous_2)","decl":{"start":{"line":9,"column":15},"end":{"line":9,"column":25}},"loc":{"start":{"line":9,"column":34},"end":{"line":9,"column":53}},"line":9},"3":{"name":"(anonymous_3)","decl":{"start":{"line":10,"column":15},"end":{"line":10,"column":30}},"loc":{"start":{"line":10,"column":30},"end":{"line":10,"column":44}},"line":10},"4":{"name":"run","decl":{"start":{"line":14,"column":8},"end":{"line":14,"column":null}},"loc":{"start":{"line":18,"column":21},"end":{"line":44,"column":null}},"line":18},"5":{"name":"(anonymous_5)","decl":{"start":{"line":19,"column":15},"end":{"line":19,"column":32}},"loc":{"start":{"line":19,"column":52},"end":{"line":43,"column":5}},"line":19},"6":{"name":"(anonymous_6)","decl":{"start":{"line":28,"column":23},"end":{"line":28,"column":32}},"loc":{"start":{"line":28,"column":38},"end":{"line":30,"column":7}},"line":28},"7":{"name":"(anonymous_7)","decl":{"start":{"line":31,"column":23},"end":{"line":31,"column":32}},"loc":{"start":{"line":31,"column":38},"end":{"line":33,"column":7}},"line":31},"8":{"name":"(anonymous_8)","decl":{"start":{"line":35,"column":15},"end":{"line":35,"column":25}},"loc":{"start":{"line":35,"column":34},"end":{"line":41,"column":7}},"line":35},"9":{"name":"(anonymous_9)","decl":{"start":{"line":42,"column":15},"end":{"line":42,"column":25}},"loc":{"start":{"line":42,"column":35},"end":{"line":42,"column":48}},"line":42}},"branchMap":{"0":{"loc":{"start":{"line":21,"column":13},"end":{"line":21,"column":null}},"type":"binary-expr","locations":[{"start":{"line":21,"column":13},"end":{"line":21,"column":29}},{"start":{"line":21,"column":29},"end":{"line":21,"column":null}}],"line":21},"1":{"loc":{"start":{"line":36,"column":8},"end":{"line":40,"column":null}},"type":"if","locations":[{"start":{"line":36,"column":8},"end":{"line":40,"column":null}},{"start":{"line":38,"column":15},"end":{"line":40,"column":null}}],"line":36},"2":{"loc":{"start":{"line":39,"column":27},"end":{"line":39,"column":83}},"type":"binary-expr","locations":[{"start":{"line":39,"column":27},"end":{"line":39,"column":44}},{"start":{"line":39,"column":44},"end":{"line":39,"column":83}}],"line":39}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0]},"meta":{"lastBranch":3,"lastFunction":10,"lastStatement":20,"seen":{"f:6:8:6:23":0,"s:7:4:11:Infinity":0,"f:7:15:7:24":1,"s:8:12:8:Infinity":1,"s:9:6:9:Infinity":2,"f:9:15:9:25":2,"s:9:34:9:53":3,"s:10:6:10:Infinity":4,"f:10:15:10:30":3,"s:10:30:10:44":5,"f:14:8:14:Infinity":4,"s:19:4:43:Infinity":6,"f:19:15:19:32":5,"s:20:12:23:Infinity":7,"b:21:13:21:29:21:29:21:Infinity":0,"s:25:19:25:Infinity":8,"s:26:19:26:Infinity":9,"s:28:6:30:Infinity":10,"f:28:23:28:32":6,"s:29:8:29:Infinity":11,"s:31:6:33:Infinity":12,"f:31:23:31:32":7,"s:32:8:32:Infinity":13,"s:35:6:41:Infinity":14,"f:35:15:35:25":8,"b:36:8:40:Infinity:38:15:40:Infinity":1,"s:36:8:40:Infinity":15,"s:37:10:37:Infinity":16,"s:39:10:39:Infinity":17,"b:39:27:39:44:39:44:39:83":2,"s:42:6:42:Infinity":18,"f:42:15:42:25":9,"s:42:35:42:48":19}}} -,"/Users/marcus/berget-monorepo/cli/src/constants/command-structure.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/constants/command-structure.ts","statementMap":{"0":{"start":{"line":7,"column":30},"end":{"line":20,"column":null}},"1":{"start":{"line":23,"column":27},"end":{"line":113,"column":null}},"2":{"start":{"line":116,"column":36},"end":{"line":210,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":3,"seen":{"s:7:30:20:Infinity":0,"s:23:27:113:Infinity":1,"s:116:36:210:Infinity":2}}} -,"/Users/marcus/berget-monorepo/cli/src/services/api-key-service.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/services/api-key-service.ts","statementMap":{"0":{"start":{"line":35,"column":41},"end":{"line":35,"column":null}},"1":{"start":{"line":37,"column":36},"end":{"line":37,"column":null}},"2":{"start":{"line":41,"column":10},"end":{"line":41,"column":null}},"3":{"start":{"line":46,"column":4},"end":{"line":48,"column":null}},"4":{"start":{"line":47,"column":6},"end":{"line":47,"column":null}},"5":{"start":{"line":49,"column":4},"end":{"line":49,"column":null}},"6":{"start":{"line":57,"column":4},"end":{"line":75,"column":null}},"7":{"start":{"line":58,"column":6},"end":{"line":58,"column":null}},"8":{"start":{"line":60,"column":30},"end":{"line":62,"column":null}},"9":{"start":{"line":64,"column":6},"end":{"line":66,"column":null}},"10":{"start":{"line":65,"column":8},"end":{"line":65,"column":null}},"11":{"start":{"line":68,"column":6},"end":{"line":70,"column":null}},"12":{"start":{"line":69,"column":8},"end":{"line":69,"column":null}},"13":{"start":{"line":72,"column":6},"end":{"line":72,"column":null}},"14":{"start":{"line":74,"column":6},"end":{"line":74,"column":null}},"15":{"start":{"line":83,"column":4},"end":{"line":92,"column":null}},"16":{"start":{"line":84,"column":24},"end":{"line":86,"column":null}},"17":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"18":{"start":{"line":87,"column":17},"end":{"line":87,"column":null}},"19":{"start":{"line":88,"column":6},"end":{"line":88,"column":null}},"20":{"start":{"line":90,"column":6},"end":{"line":90,"column":null}},"21":{"start":{"line":91,"column":6},"end":{"line":91,"column":null}},"22":{"start":{"line":100,"column":4},"end":{"line":109,"column":null}},"23":{"start":{"line":101,"column":30},"end":{"line":103,"column":null}},"24":{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},"25":{"start":{"line":104,"column":17},"end":{"line":104,"column":null}},"26":{"start":{"line":105,"column":6},"end":{"line":105,"column":null}},"27":{"start":{"line":107,"column":6},"end":{"line":107,"column":null}},"28":{"start":{"line":108,"column":6},"end":{"line":108,"column":null}},"29":{"start":{"line":117,"column":4},"end":{"line":124,"column":null}},"30":{"start":{"line":118,"column":30},"end":{"line":118,"column":null}},"31":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"32":{"start":{"line":119,"column":17},"end":{"line":119,"column":null}},"33":{"start":{"line":120,"column":6},"end":{"line":120,"column":null}},"34":{"start":{"line":122,"column":6},"end":{"line":122,"column":null}},"35":{"start":{"line":123,"column":6},"end":{"line":123,"column":null}},"36":{"start":{"line":132,"column":4},"end":{"line":141,"column":null}},"37":{"start":{"line":133,"column":30},"end":{"line":135,"column":null}},"38":{"start":{"line":136,"column":6},"end":{"line":136,"column":null}},"39":{"start":{"line":136,"column":17},"end":{"line":136,"column":null}},"40":{"start":{"line":137,"column":6},"end":{"line":137,"column":null}},"41":{"start":{"line":139,"column":6},"end":{"line":139,"column":null}},"42":{"start":{"line":140,"column":6},"end":{"line":140,"column":null}},"43":{"start":{"line":145,"column":4},"end":{"line":156,"column":null}},"44":{"start":{"line":161,"column":4},"end":{"line":163,"column":null}},"45":{"start":{"line":162,"column":6},"end":{"line":162,"column":null}},"46":{"start":{"line":165,"column":20},"end":{"line":165,"column":null}},"47":{"start":{"line":167,"column":4},"end":{"line":169,"column":null}},"48":{"start":{"line":168,"column":6},"end":{"line":168,"column":null}},"49":{"start":{"line":171,"column":4},"end":{"line":173,"column":null}},"50":{"start":{"line":172,"column":6},"end":{"line":172,"column":null}},"51":{"start":{"line":175,"column":4},"end":{"line":177,"column":null}},"52":{"start":{"line":176,"column":6},"end":{"line":176,"column":null}},"53":{"start":{"line":179,"column":4},"end":{"line":183,"column":null}},"54":{"start":{"line":180,"column":6},"end":{"line":182,"column":null}},"55":{"start":{"line":185,"column":4},"end":{"line":185,"column":null}},"56":{"start":{"line":189,"column":4},"end":{"line":191,"column":null}},"57":{"start":{"line":190,"column":6},"end":{"line":190,"column":null}},"58":{"start":{"line":193,"column":24},"end":{"line":193,"column":null}},"59":{"start":{"line":194,"column":17},"end":{"line":194,"column":null}},"60":{"start":{"line":196,"column":4},"end":{"line":223,"column":null}},"61":{"start":{"line":198,"column":8},"end":{"line":198,"column":null}},"62":{"start":{"line":201,"column":8},"end":{"line":203,"column":null}},"63":{"start":{"line":206,"column":8},"end":{"line":208,"column":null}},"64":{"start":{"line":211,"column":8},"end":{"line":213,"column":null}},"65":{"start":{"line":216,"column":8},"end":{"line":218,"column":null}},"66":{"start":{"line":221,"column":8},"end":{"line":221,"column":null}},"67":{"start":{"line":227,"column":4},"end":{"line":229,"column":null}},"68":{"start":{"line":228,"column":6},"end":{"line":228,"column":null}},"69":{"start":{"line":231,"column":4},"end":{"line":233,"column":null}},"70":{"start":{"line":232,"column":6},"end":{"line":232,"column":null}},"71":{"start":{"line":235,"column":4},"end":{"line":237,"column":null}},"72":{"start":{"line":236,"column":6},"end":{"line":236,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":43,"column":2},"end":{"line":43,"column":10}},"loc":{"start":{"line":43,"column":24},"end":{"line":43,"column":null}},"line":43},"1":{"name":"getInstance","decl":{"start":{"line":45,"column":16},"end":{"line":45,"column":45}},"loc":{"start":{"line":45,"column":45},"end":{"line":50,"column":null}},"line":45},"2":{"name":"create","decl":{"start":{"line":56,"column":15},"end":{"line":56,"column":22}},"loc":{"start":{"line":56,"column":77},"end":{"line":76,"column":null}},"line":56},"3":{"name":"delete","decl":{"start":{"line":82,"column":15},"end":{"line":82,"column":22}},"loc":{"start":{"line":82,"column":52},"end":{"line":93,"column":null}},"line":82},"4":{"name":"describe","decl":{"start":{"line":99,"column":15},"end":{"line":99,"column":24}},"loc":{"start":{"line":99,"column":50},"end":{"line":110,"column":null}},"line":99},"5":{"name":"list","decl":{"start":{"line":116,"column":15},"end":{"line":116,"column":41}},"loc":{"start":{"line":116,"column":41},"end":{"line":125,"column":null}},"line":116},"6":{"name":"rotate","decl":{"start":{"line":131,"column":15},"end":{"line":131,"column":22}},"loc":{"start":{"line":131,"column":59},"end":{"line":142,"column":null}},"line":131},"7":{"name":"buildCreationFailedMessage","decl":{"start":{"line":144,"column":2},"end":{"line":144,"column":10}},"loc":{"start":{"line":144,"column":47},"end":{"line":158,"column":null}},"line":144},"8":{"name":"enhanceNetworkError","decl":{"start":{"line":160,"column":2},"end":{"line":160,"column":10}},"loc":{"start":{"line":160,"column":53},"end":{"line":186,"column":null}},"line":160},"9":{"name":"mapCreateError","decl":{"start":{"line":188,"column":2},"end":{"line":188,"column":10}},"loc":{"start":{"line":188,"column":48},"end":{"line":224,"column":null}},"line":188},"10":{"name":"validateCreateOptions","decl":{"start":{"line":226,"column":2},"end":{"line":226,"column":10}},"loc":{"start":{"line":226,"column":68},"end":{"line":238,"column":null}},"line":226}},"branchMap":{"0":{"loc":{"start":{"line":46,"column":4},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":46,"column":4},"end":{"line":48,"column":null}},{"start":{},"end":{}}],"line":46},"1":{"loc":{"start":{"line":64,"column":6},"end":{"line":66,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":6},"end":{"line":66,"column":null}},{"start":{},"end":{}}],"line":64},"2":{"loc":{"start":{"line":68,"column":6},"end":{"line":70,"column":null}},"type":"if","locations":[{"start":{"line":68,"column":6},"end":{"line":70,"column":null}},{"start":{},"end":{}}],"line":68},"3":{"loc":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"type":"if","locations":[{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},{"start":{},"end":{}}],"line":87},"4":{"loc":{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},"type":"if","locations":[{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},{"start":{},"end":{}}],"line":104},"5":{"loc":{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},"type":"if","locations":[{"start":{"line":119,"column":6},"end":{"line":119,"column":null}},{"start":{},"end":{}}],"line":119},"6":{"loc":{"start":{"line":120,"column":13},"end":{"line":120,"column":null}},"type":"binary-expr","locations":[{"start":{"line":120,"column":13},"end":{"line":120,"column":21}},{"start":{"line":120,"column":21},"end":{"line":120,"column":null}}],"line":120},"7":{"loc":{"start":{"line":136,"column":6},"end":{"line":136,"column":null}},"type":"if","locations":[{"start":{"line":136,"column":6},"end":{"line":136,"column":null}},{"start":{},"end":{}}],"line":136},"8":{"loc":{"start":{"line":161,"column":4},"end":{"line":163,"column":null}},"type":"if","locations":[{"start":{"line":161,"column":4},"end":{"line":163,"column":null}},{"start":{},"end":{}}],"line":161},"9":{"loc":{"start":{"line":167,"column":4},"end":{"line":169,"column":null}},"type":"if","locations":[{"start":{"line":167,"column":4},"end":{"line":169,"column":null}},{"start":{},"end":{}}],"line":167},"10":{"loc":{"start":{"line":171,"column":4},"end":{"line":173,"column":null}},"type":"if","locations":[{"start":{"line":171,"column":4},"end":{"line":173,"column":null}},{"start":{},"end":{}}],"line":171},"11":{"loc":{"start":{"line":175,"column":4},"end":{"line":177,"column":null}},"type":"if","locations":[{"start":{"line":175,"column":4},"end":{"line":177,"column":null}},{"start":{},"end":{}}],"line":175},"12":{"loc":{"start":{"line":175,"column":8},"end":{"line":175,"column":69}},"type":"binary-expr","locations":[{"start":{"line":175,"column":8},"end":{"line":175,"column":35}},{"start":{"line":175,"column":35},"end":{"line":175,"column":69}}],"line":175},"13":{"loc":{"start":{"line":179,"column":4},"end":{"line":183,"column":null}},"type":"if","locations":[{"start":{"line":179,"column":4},"end":{"line":183,"column":null}},{"start":{},"end":{}}],"line":179},"14":{"loc":{"start":{"line":189,"column":4},"end":{"line":191,"column":null}},"type":"if","locations":[{"start":{"line":189,"column":4},"end":{"line":191,"column":null}},{"start":{},"end":{}}],"line":189},"15":{"loc":{"start":{"line":189,"column":8},"end":{"line":189,"column":53}},"type":"binary-expr","locations":[{"start":{"line":189,"column":8},"end":{"line":189,"column":37}},{"start":{"line":189,"column":37},"end":{"line":189,"column":53}}],"line":189},"16":{"loc":{"start":{"line":196,"column":4},"end":{"line":223,"column":null}},"type":"switch","locations":[{"start":{"line":197,"column":6},"end":{"line":199,"column":null}},{"start":{"line":200,"column":6},"end":{"line":204,"column":null}},{"start":{"line":205,"column":6},"end":{"line":209,"column":null}},{"start":{"line":210,"column":6},"end":{"line":214,"column":null}},{"start":{"line":215,"column":6},"end":{"line":219,"column":null}},{"start":{"line":220,"column":6},"end":{"line":222,"column":null}}],"line":196},"17":{"loc":{"start":{"line":227,"column":4},"end":{"line":229,"column":null}},"type":"if","locations":[{"start":{"line":227,"column":4},"end":{"line":229,"column":null}},{"start":{},"end":{}}],"line":227},"18":{"loc":{"start":{"line":227,"column":8},"end":{"line":227,"column":59}},"type":"binary-expr","locations":[{"start":{"line":227,"column":8},"end":{"line":227,"column":25}},{"start":{"line":227,"column":25},"end":{"line":227,"column":59}}],"line":227},"19":{"loc":{"start":{"line":231,"column":4},"end":{"line":233,"column":null}},"type":"if","locations":[{"start":{"line":231,"column":4},"end":{"line":233,"column":null}},{"start":{},"end":{}}],"line":231},"20":{"loc":{"start":{"line":235,"column":4},"end":{"line":237,"column":null}},"type":"if","locations":[{"start":{"line":235,"column":4},"end":{"line":237,"column":null}},{"start":{},"end":{}}],"line":235},"21":{"loc":{"start":{"line":235,"column":8},"end":{"line":235,"column":65}},"type":"binary-expr","locations":[{"start":{"line":235,"column":8},"end":{"line":235,"column":31}},{"start":{"line":235,"column":31},"end":{"line":235,"column":65}}],"line":235}},"s":{"0":1,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0},"f":{"0":0,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0,0,0,0,0],"17":[0,0],"18":[0,0],"19":[0,0],"20":[0,0],"21":[0,0]},"meta":{"lastBranch":22,"lastFunction":11,"lastStatement":73,"seen":{"s:35:41:35:Infinity":0,"s:37:36:37:Infinity":1,"s:41:10:41:Infinity":2,"f:43:2:43:10":0,"f:45:16:45:45":1,"b:46:4:48:Infinity:undefined:undefined:undefined:undefined":0,"s:46:4:48:Infinity":3,"s:47:6:47:Infinity":4,"s:49:4:49:Infinity":5,"f:56:15:56:22":2,"s:57:4:75:Infinity":6,"s:58:6:58:Infinity":7,"s:60:30:62:Infinity":8,"b:64:6:66:Infinity:undefined:undefined:undefined:undefined":1,"s:64:6:66:Infinity":9,"s:65:8:65:Infinity":10,"b:68:6:70:Infinity:undefined:undefined:undefined:undefined":2,"s:68:6:70:Infinity":11,"s:69:8:69:Infinity":12,"s:72:6:72:Infinity":13,"s:74:6:74:Infinity":14,"f:82:15:82:22":3,"s:83:4:92:Infinity":15,"s:84:24:86:Infinity":16,"b:87:6:87:Infinity:undefined:undefined:undefined:undefined":3,"s:87:6:87:Infinity":17,"s:87:17:87:Infinity":18,"s:88:6:88:Infinity":19,"s:90:6:90:Infinity":20,"s:91:6:91:Infinity":21,"f:99:15:99:24":4,"s:100:4:109:Infinity":22,"s:101:30:103:Infinity":23,"b:104:6:104:Infinity:undefined:undefined:undefined:undefined":4,"s:104:6:104:Infinity":24,"s:104:17:104:Infinity":25,"s:105:6:105:Infinity":26,"s:107:6:107:Infinity":27,"s:108:6:108:Infinity":28,"f:116:15:116:41":5,"s:117:4:124:Infinity":29,"s:118:30:118:Infinity":30,"b:119:6:119:Infinity:undefined:undefined:undefined:undefined":5,"s:119:6:119:Infinity":31,"s:119:17:119:Infinity":32,"s:120:6:120:Infinity":33,"b:120:13:120:21:120:21:120:Infinity":6,"s:122:6:122:Infinity":34,"s:123:6:123:Infinity":35,"f:131:15:131:22":6,"s:132:4:141:Infinity":36,"s:133:30:135:Infinity":37,"b:136:6:136:Infinity:undefined:undefined:undefined:undefined":7,"s:136:6:136:Infinity":38,"s:136:17:136:Infinity":39,"s:137:6:137:Infinity":40,"s:139:6:139:Infinity":41,"s:140:6:140:Infinity":42,"f:144:2:144:10":7,"s:145:4:156:Infinity":43,"f:160:2:160:10":8,"b:161:4:163:Infinity:undefined:undefined:undefined:undefined":8,"s:161:4:163:Infinity":44,"s:162:6:162:Infinity":45,"s:165:20:165:Infinity":46,"b:167:4:169:Infinity:undefined:undefined:undefined:undefined":9,"s:167:4:169:Infinity":47,"s:168:6:168:Infinity":48,"b:171:4:173:Infinity:undefined:undefined:undefined:undefined":10,"s:171:4:173:Infinity":49,"s:172:6:172:Infinity":50,"b:175:4:177:Infinity:undefined:undefined:undefined:undefined":11,"s:175:4:177:Infinity":51,"b:175:8:175:35:175:35:175:69":12,"s:176:6:176:Infinity":52,"b:179:4:183:Infinity:undefined:undefined:undefined:undefined":13,"s:179:4:183:Infinity":53,"s:180:6:182:Infinity":54,"s:185:4:185:Infinity":55,"f:188:2:188:10":9,"b:189:4:191:Infinity:undefined:undefined:undefined:undefined":14,"s:189:4:191:Infinity":56,"b:189:8:189:37:189:37:189:53":15,"s:190:6:190:Infinity":57,"s:193:24:193:Infinity":58,"s:194:17:194:Infinity":59,"b:197:6:199:Infinity:200:6:204:Infinity:205:6:209:Infinity:210:6:214:Infinity:215:6:219:Infinity:220:6:222:Infinity":16,"s:196:4:223:Infinity":60,"s:198:8:198:Infinity":61,"s:201:8:203:Infinity":62,"s:206:8:208:Infinity":63,"s:211:8:213:Infinity":64,"s:216:8:218:Infinity":65,"s:221:8:221:Infinity":66,"f:226:2:226:10":10,"b:227:4:229:Infinity:undefined:undefined:undefined:undefined":17,"s:227:4:229:Infinity":67,"b:227:8:227:25:227:25:227:59":18,"s:228:6:228:Infinity":68,"b:231:4:233:Infinity:undefined:undefined:undefined:undefined":19,"s:231:4:233:Infinity":69,"s:232:6:232:Infinity":70,"b:235:4:237:Infinity:undefined:undefined:undefined:undefined":20,"s:235:4:237:Infinity":71,"b:235:8:235:31:235:31:235:65":21,"s:236:6:236:Infinity":72}}} -,"/Users/marcus/berget-monorepo/cli/src/services/auth-service.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/services/auth-service.ts","statementMap":{"0":{"start":{"line":18,"column":41},"end":{"line":18,"column":null}},"1":{"start":{"line":21,"column":36},"end":{"line":21,"column":null}},"2":{"start":{"line":28,"column":4},"end":{"line":30,"column":null}},"3":{"start":{"line":29,"column":6},"end":{"line":29,"column":null}},"4":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"5":{"start":{"line":40,"column":4},"end":{"line":67,"column":null}},"6":{"start":{"line":41,"column":21},"end":{"line":41,"column":null}},"7":{"start":{"line":43,"column":6},"end":{"line":46,"column":null}},"8":{"start":{"line":44,"column":8},"end":{"line":44,"column":null}},"9":{"start":{"line":45,"column":8},"end":{"line":45,"column":null}},"10":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"11":{"start":{"line":50,"column":6},"end":{"line":57,"column":null}},"12":{"start":{"line":51,"column":24},"end":{"line":51,"column":null}},"13":{"start":{"line":52,"column":8},"end":{"line":54,"column":null}},"14":{"start":{"line":53,"column":10},"end":{"line":53,"column":null}},"15":{"start":{"line":59,"column":6},"end":{"line":59,"column":null}},"16":{"start":{"line":60,"column":6},"end":{"line":60,"column":null}},"17":{"start":{"line":61,"column":6},"end":{"line":61,"column":null}},"18":{"start":{"line":63,"column":6},"end":{"line":63,"column":null}},"19":{"start":{"line":65,"column":6},"end":{"line":65,"column":null}},"20":{"start":{"line":66,"column":6},"end":{"line":66,"column":null}},"21":{"start":{"line":82,"column":4},"end":{"line":105,"column":null}},"22":{"start":{"line":83,"column":12},"end":{"line":83,"column":null}},"23":{"start":{"line":84,"column":28},"end":{"line":84,"column":null}},"24":{"start":{"line":85,"column":21},"end":{"line":85,"column":null}},"25":{"start":{"line":87,"column":6},"end":{"line":97,"column":null}},"26":{"start":{"line":88,"column":27},"end":{"line":88,"column":null}},"27":{"start":{"line":89,"column":14},"end":{"line":89,"column":null}},"28":{"start":{"line":91,"column":10},"end":{"line":91,"column":null}},"29":{"start":{"line":92,"column":8},"end":{"line":96,"column":null}},"30":{"start":{"line":99,"column":6},"end":{"line":99,"column":null}},"31":{"start":{"line":101,"column":6},"end":{"line":104,"column":null}},"32":{"start":{"line":109,"column":4},"end":{"line":118,"column":null}},"33":{"start":{"line":110,"column":12},"end":{"line":110,"column":null}},"34":{"start":{"line":111,"column":39},"end":{"line":111,"column":null}},"35":{"start":{"line":112,"column":6},"end":{"line":114,"column":null}},"36":{"start":{"line":113,"column":8},"end":{"line":113,"column":null}},"37":{"start":{"line":115,"column":6},"end":{"line":115,"column":null}},"38":{"start":{"line":117,"column":6},"end":{"line":117,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":25,"column":2},"end":{"line":25,"column":10}},"loc":{"start":{"line":25,"column":24},"end":{"line":25,"column":null}},"line":25},"1":{"name":"getInstance","decl":{"start":{"line":27,"column":16},"end":{"line":27,"column":43}},"loc":{"start":{"line":27,"column":43},"end":{"line":32,"column":null}},"line":27},"2":{"name":"login","decl":{"start":{"line":39,"column":15},"end":{"line":39,"column":21}},"loc":{"start":{"line":39,"column":87},"end":{"line":68,"column":null}},"line":39},"3":{"name":"loginInteractive","decl":{"start":{"line":75,"column":15},"end":{"line":75,"column":32}},"loc":{"start":{"line":81,"column":5},"end":{"line":106,"column":null}},"line":81},"4":{"name":"whoami","decl":{"start":{"line":108,"column":15},"end":{"line":108,"column":38}},"loc":{"start":{"line":108,"column":38},"end":{"line":119,"column":null}},"line":108}},"branchMap":{"0":{"loc":{"start":{"line":28,"column":4},"end":{"line":30,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":4},"end":{"line":30,"column":null}},{"start":{},"end":{}}],"line":28},"1":{"loc":{"start":{"line":43,"column":6},"end":{"line":46,"column":null}},"type":"if","locations":[{"start":{"line":43,"column":6},"end":{"line":46,"column":null}},{"start":{},"end":{}}],"line":43},"2":{"loc":{"start":{"line":44,"column":58},"end":{"line":44,"column":91}},"type":"binary-expr","locations":[{"start":{"line":44,"column":58},"end":{"line":44,"column":74}},{"start":{"line":44,"column":74},"end":{"line":44,"column":91}}],"line":44},"3":{"loc":{"start":{"line":52,"column":8},"end":{"line":54,"column":null}},"type":"if","locations":[{"start":{"line":52,"column":8},"end":{"line":54,"column":null}},{"start":{},"end":{}}],"line":52},"4":{"loc":{"start":{"line":53,"column":50},"end":{"line":53,"column":81}},"type":"binary-expr","locations":[{"start":{"line":53,"column":50},"end":{"line":53,"column":66}},{"start":{"line":53,"column":66},"end":{"line":53,"column":81}}],"line":53},"5":{"loc":{"start":{"line":87,"column":6},"end":{"line":97,"column":null}},"type":"if","locations":[{"start":{"line":87,"column":6},"end":{"line":97,"column":null}},{"start":{},"end":{}}],"line":87},"6":{"loc":{"start":{"line":87,"column":10},"end":{"line":87,"column":71}},"type":"binary-expr","locations":[{"start":{"line":87,"column":10},"end":{"line":87,"column":28}},{"start":{"line":87,"column":28},"end":{"line":87,"column":50}},{"start":{"line":87,"column":50},"end":{"line":87,"column":71}}],"line":87},"7":{"loc":{"start":{"line":91,"column":10},"end":{"line":91,"column":null}},"type":"cond-expr","locations":[{"start":{"line":91,"column":29},"end":{"line":91,"column":44}},{"start":{"line":91,"column":44},"end":{"line":91,"column":null}}],"line":91},"8":{"loc":{"start":{"line":91,"column":58},"end":{"line":91,"column":86}},"type":"binary-expr","locations":[{"start":{"line":91,"column":58},"end":{"line":91,"column":78}},{"start":{"line":91,"column":78},"end":{"line":91,"column":86}}],"line":91},"9":{"loc":{"start":{"line":102,"column":15},"end":{"line":102,"column":null}},"type":"cond-expr","locations":[{"start":{"line":102,"column":40},"end":{"line":102,"column":56}},{"start":{"line":102,"column":56},"end":{"line":102,"column":null}}],"line":102},"10":{"loc":{"start":{"line":112,"column":6},"end":{"line":114,"column":null}},"type":"if","locations":[{"start":{"line":112,"column":6},"end":{"line":114,"column":null}},{"start":{},"end":{}}],"line":112}},"s":{"0":1,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0},"f":{"0":0,"1":1,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0]},"meta":{"lastBranch":11,"lastFunction":5,"lastStatement":39,"seen":{"s:18:41:18:Infinity":0,"s:21:36:21:Infinity":1,"f:25:2:25:10":0,"f:27:16:27:43":1,"b:28:4:30:Infinity:undefined:undefined:undefined:undefined":0,"s:28:4:30:Infinity":2,"s:29:6:29:Infinity":3,"s:31:4:31:Infinity":4,"f:39:15:39:21":2,"s:40:4:67:Infinity":5,"s:41:21:41:Infinity":6,"b:43:6:46:Infinity:undefined:undefined:undefined:undefined":1,"s:43:6:46:Infinity":7,"s:44:8:44:Infinity":8,"b:44:58:44:74:44:74:44:91":2,"s:45:8:45:Infinity":9,"s:48:6:48:Infinity":10,"s:50:6:57:Infinity":11,"s:51:24:51:Infinity":12,"b:52:8:54:Infinity:undefined:undefined:undefined:undefined":3,"s:52:8:54:Infinity":13,"s:53:10:53:Infinity":14,"b:53:50:53:66:53:66:53:81":4,"s:59:6:59:Infinity":15,"s:60:6:60:Infinity":16,"s:61:6:61:Infinity":17,"s:63:6:63:Infinity":18,"s:65:6:65:Infinity":19,"s:66:6:66:Infinity":20,"f:75:15:75:32":3,"s:82:4:105:Infinity":21,"s:83:12:83:Infinity":22,"s:84:28:84:Infinity":23,"s:85:21:85:Infinity":24,"b:87:6:97:Infinity:undefined:undefined:undefined:undefined":5,"s:87:6:97:Infinity":25,"b:87:10:87:28:87:28:87:50:87:50:87:71":6,"s:88:27:88:Infinity":26,"s:89:14:89:Infinity":27,"s:91:10:91:Infinity":28,"b:91:29:91:44:91:44:91:Infinity":7,"b:91:58:91:78:91:78:91:86":8,"s:92:8:96:Infinity":29,"s:99:6:99:Infinity":30,"s:101:6:104:Infinity":31,"b:102:40:102:56:102:56:102:Infinity":9,"f:108:15:108:38":4,"s:109:4:118:Infinity":32,"s:110:12:110:Infinity":33,"s:111:39:111:Infinity":34,"b:112:6:114:Infinity:undefined:undefined:undefined:undefined":10,"s:112:6:114:Infinity":35,"s:113:8:113:Infinity":36,"s:115:6:115:Infinity":37,"s:117:6:117:Infinity":38}}} -,"/Users/marcus/berget-monorepo/cli/src/utils/error-handler.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/utils/error-handler.ts","statementMap":{"0":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"1":{"start":{"line":9,"column":21},"end":{"line":9,"column":null}},"2":{"start":{"line":10,"column":18},"end":{"line":10,"column":null}},"3":{"start":{"line":11,"column":18},"end":{"line":11,"column":null}},"4":{"start":{"line":14,"column":2},"end":{"line":34,"column":null}},"5":{"start":{"line":15,"column":4},"end":{"line":28,"column":null}},"6":{"start":{"line":17,"column":26},"end":{"line":17,"column":null}},"7":{"start":{"line":18,"column":6},"end":{"line":24,"column":null}},"8":{"start":{"line":19,"column":8},"end":{"line":19,"column":null}},"9":{"start":{"line":20,"column":8},"end":{"line":20,"column":null}},"10":{"start":{"line":21,"column":8},"end":{"line":21,"column":null}},"11":{"start":{"line":23,"column":8},"end":{"line":23,"column":null}},"12":{"start":{"line":27,"column":6},"end":{"line":27,"column":null}},"13":{"start":{"line":29,"column":9},"end":{"line":34,"column":null}},"14":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"15":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"16":{"start":{"line":33,"column":4},"end":{"line":33,"column":null}},"17":{"start":{"line":37,"column":2},"end":{"line":39,"column":null}},"18":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"19":{"start":{"line":40,"column":2},"end":{"line":42,"column":null}},"20":{"start":{"line":41,"column":4},"end":{"line":41,"column":null}},"21":{"start":{"line":45,"column":2},"end":{"line":45,"column":null}},"22":{"start":{"line":56,"column":2},"end":{"line":56,"column":null}},"23":{"start":{"line":59,"column":2},"end":{"line":69,"column":null}},"24":{"start":{"line":65,"column":4},"end":{"line":65,"column":null}},"25":{"start":{"line":66,"column":4},"end":{"line":66,"column":null}},"26":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"27":{"start":{"line":68,"column":4},"end":{"line":68,"column":null}},"28":{"start":{"line":72,"column":2},"end":{"line":83,"column":null}},"29":{"start":{"line":78,"column":4},"end":{"line":78,"column":null}},"30":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"31":{"start":{"line":80,"column":4},"end":{"line":80,"column":null}},"32":{"start":{"line":81,"column":4},"end":{"line":81,"column":null}},"33":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"34":{"start":{"line":86,"column":2},"end":{"line":98,"column":null}},"35":{"start":{"line":91,"column":4},"end":{"line":91,"column":null}},"36":{"start":{"line":92,"column":4},"end":{"line":92,"column":null}},"37":{"start":{"line":93,"column":4},"end":{"line":95,"column":null}},"38":{"start":{"line":96,"column":4},"end":{"line":96,"column":null}},"39":{"start":{"line":97,"column":4},"end":{"line":97,"column":null}},"40":{"start":{"line":101,"column":2},"end":{"line":110,"column":null}},"41":{"start":{"line":106,"column":4},"end":{"line":106,"column":null}},"42":{"start":{"line":107,"column":4},"end":{"line":107,"column":null}},"43":{"start":{"line":108,"column":4},"end":{"line":108,"column":null}},"44":{"start":{"line":109,"column":4},"end":{"line":109,"column":null}},"45":{"start":{"line":113,"column":2},"end":{"line":123,"column":null}},"46":{"start":{"line":118,"column":4},"end":{"line":118,"column":null}},"47":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"48":{"start":{"line":120,"column":4},"end":{"line":120,"column":null}},"49":{"start":{"line":121,"column":4},"end":{"line":121,"column":null}},"50":{"start":{"line":122,"column":4},"end":{"line":122,"column":null}},"51":{"start":{"line":126,"column":2},"end":{"line":131,"column":null}},"52":{"start":{"line":127,"column":4},"end":{"line":127,"column":null}},"53":{"start":{"line":128,"column":4},"end":{"line":128,"column":null}},"54":{"start":{"line":129,"column":4},"end":{"line":129,"column":null}},"55":{"start":{"line":130,"column":4},"end":{"line":130,"column":null}},"56":{"start":{"line":134,"column":2},"end":{"line":146,"column":null}},"57":{"start":{"line":142,"column":4},"end":{"line":142,"column":null}},"58":{"start":{"line":143,"column":4},"end":{"line":143,"column":null}},"59":{"start":{"line":144,"column":4},"end":{"line":144,"column":null}},"60":{"start":{"line":145,"column":4},"end":{"line":145,"column":null}},"61":{"start":{"line":148,"column":2},"end":{"line":150,"column":null}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":28}},"loc":{"start":{"line":6,"column":63},"end":{"line":46,"column":null}},"line":6},"1":{"name":"provideTroubleshootingTips","decl":{"start":{"line":51,"column":9},"end":{"line":51,"column":null}},"loc":{"start":{"line":55,"column":8},"end":{"line":151,"column":null}},"line":55}},"branchMap":{"0":{"loc":{"start":{"line":14,"column":2},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":14,"column":2},"end":{"line":34,"column":null}},{"start":{"line":29,"column":9},"end":{"line":34,"column":null}}],"line":14},"1":{"loc":{"start":{"line":18,"column":6},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":18,"column":6},"end":{"line":24,"column":null}},{"start":{"line":22,"column":13},"end":{"line":24,"column":null}}],"line":18},"2":{"loc":{"start":{"line":19,"column":23},"end":{"line":19,"column":null}},"type":"binary-expr","locations":[{"start":{"line":19,"column":23},"end":{"line":19,"column":52}},{"start":{"line":19,"column":52},"end":{"line":19,"column":null}}],"line":19},"3":{"loc":{"start":{"line":20,"column":20},"end":{"line":20,"column":null}},"type":"binary-expr","locations":[{"start":{"line":20,"column":20},"end":{"line":20,"column":46}},{"start":{"line":20,"column":46},"end":{"line":20,"column":null}}],"line":20},"4":{"loc":{"start":{"line":21,"column":20},"end":{"line":21,"column":null}},"type":"binary-expr","locations":[{"start":{"line":21,"column":20},"end":{"line":21,"column":46}},{"start":{"line":21,"column":46},"end":{"line":21,"column":null}}],"line":21},"5":{"loc":{"start":{"line":29,"column":9},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":29,"column":9},"end":{"line":34,"column":null}},{"start":{},"end":{}}],"line":29},"6":{"loc":{"start":{"line":29,"column":13},"end":{"line":29,"column":37}},"type":"binary-expr","locations":[{"start":{"line":29,"column":13},"end":{"line":29,"column":22}},{"start":{"line":29,"column":22},"end":{"line":29,"column":37}}],"line":29},"7":{"loc":{"start":{"line":37,"column":2},"end":{"line":39,"column":null}},"type":"if","locations":[{"start":{"line":37,"column":2},"end":{"line":39,"column":null}},{"start":{},"end":{}}],"line":37},"8":{"loc":{"start":{"line":40,"column":2},"end":{"line":42,"column":null}},"type":"if","locations":[{"start":{"line":40,"column":2},"end":{"line":42,"column":null}},{"start":{},"end":{}}],"line":40},"9":{"loc":{"start":{"line":59,"column":2},"end":{"line":69,"column":null}},"type":"if","locations":[{"start":{"line":59,"column":2},"end":{"line":69,"column":null}},{"start":{},"end":{}}],"line":59},"10":{"loc":{"start":{"line":60,"column":4},"end":{"line":63,"column":null}},"type":"binary-expr","locations":[{"start":{"line":60,"column":4},"end":{"line":60,"column":null}},{"start":{"line":61,"column":4},"end":{"line":61,"column":null}},{"start":{"line":62,"column":4},"end":{"line":62,"column":null}},{"start":{"line":63,"column":4},"end":{"line":63,"column":null}}],"line":60},"11":{"loc":{"start":{"line":72,"column":2},"end":{"line":83,"column":null}},"type":"if","locations":[{"start":{"line":72,"column":2},"end":{"line":83,"column":null}},{"start":{},"end":{}}],"line":72},"12":{"loc":{"start":{"line":73,"column":4},"end":{"line":76,"column":null}},"type":"binary-expr","locations":[{"start":{"line":73,"column":4},"end":{"line":73,"column":null}},{"start":{"line":74,"column":4},"end":{"line":74,"column":null}},{"start":{"line":75,"column":4},"end":{"line":75,"column":null}},{"start":{"line":76,"column":4},"end":{"line":76,"column":null}}],"line":73},"13":{"loc":{"start":{"line":86,"column":2},"end":{"line":98,"column":null}},"type":"if","locations":[{"start":{"line":86,"column":2},"end":{"line":98,"column":null}},{"start":{},"end":{}}],"line":86},"14":{"loc":{"start":{"line":87,"column":4},"end":{"line":89,"column":null}},"type":"binary-expr","locations":[{"start":{"line":87,"column":4},"end":{"line":87,"column":null}},{"start":{"line":88,"column":4},"end":{"line":88,"column":null}},{"start":{"line":89,"column":4},"end":{"line":89,"column":null}}],"line":87},"15":{"loc":{"start":{"line":101,"column":2},"end":{"line":110,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":2},"end":{"line":110,"column":null}},{"start":{},"end":{}}],"line":101},"16":{"loc":{"start":{"line":102,"column":4},"end":{"line":104,"column":null}},"type":"binary-expr","locations":[{"start":{"line":102,"column":4},"end":{"line":102,"column":null}},{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},{"start":{"line":104,"column":4},"end":{"line":104,"column":null}}],"line":102},"17":{"loc":{"start":{"line":113,"column":2},"end":{"line":123,"column":null}},"type":"if","locations":[{"start":{"line":113,"column":2},"end":{"line":123,"column":null}},{"start":{},"end":{}}],"line":113},"18":{"loc":{"start":{"line":114,"column":4},"end":{"line":116,"column":null}},"type":"binary-expr","locations":[{"start":{"line":114,"column":4},"end":{"line":114,"column":null}},{"start":{"line":115,"column":4},"end":{"line":115,"column":null}},{"start":{"line":116,"column":5},"end":{"line":116,"column":18}},{"start":{"line":116,"column":18},"end":{"line":116,"column":null}}],"line":114},"19":{"loc":{"start":{"line":126,"column":2},"end":{"line":131,"column":null}},"type":"if","locations":[{"start":{"line":126,"column":2},"end":{"line":131,"column":null}},{"start":{},"end":{}}],"line":126},"20":{"loc":{"start":{"line":126,"column":6},"end":{"line":126,"column":76}},"type":"binary-expr","locations":[{"start":{"line":126,"column":6},"end":{"line":126,"column":41}},{"start":{"line":126,"column":41},"end":{"line":126,"column":76}}],"line":126},"21":{"loc":{"start":{"line":134,"column":2},"end":{"line":146,"column":null}},"type":"if","locations":[{"start":{"line":134,"column":2},"end":{"line":146,"column":null}},{"start":{},"end":{}}],"line":134},"22":{"loc":{"start":{"line":135,"column":4},"end":{"line":140,"column":null}},"type":"binary-expr","locations":[{"start":{"line":135,"column":4},"end":{"line":135,"column":null}},{"start":{"line":136,"column":4},"end":{"line":136,"column":null}},{"start":{"line":137,"column":4},"end":{"line":137,"column":null}},{"start":{"line":138,"column":4},"end":{"line":138,"column":null}},{"start":{"line":139,"column":4},"end":{"line":139,"column":null}},{"start":{"line":140,"column":4},"end":{"line":140,"column":null}}],"line":135}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0},"f":{"0":0,"1":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0,0,0],"11":[0,0],"12":[0,0,0,0],"13":[0,0],"14":[0,0,0],"15":[0,0],"16":[0,0,0],"17":[0,0],"18":[0,0,0,0],"19":[0,0],"20":[0,0],"21":[0,0],"22":[0,0,0,0,0,0]},"meta":{"lastBranch":23,"lastFunction":2,"lastStatement":62,"seen":{"f:6:16:6:28":0,"s:7:2:7:Infinity":0,"s:9:21:9:Infinity":1,"s:10:18:10:Infinity":2,"s:11:18:11:Infinity":3,"b:14:2:34:Infinity:29:9:34:Infinity":0,"s:14:2:34:Infinity":4,"s:15:4:28:Infinity":5,"s:17:26:17:Infinity":6,"b:18:6:24:Infinity:22:13:24:Infinity":1,"s:18:6:24:Infinity":7,"s:19:8:19:Infinity":8,"b:19:23:19:52:19:52:19:Infinity":2,"s:20:8:20:Infinity":9,"b:20:20:20:46:20:46:20:Infinity":3,"s:21:8:21:Infinity":10,"b:21:20:21:46:21:46:21:Infinity":4,"s:23:8:23:Infinity":11,"s:27:6:27:Infinity":12,"b:29:9:34:Infinity:undefined:undefined:undefined:undefined":5,"s:29:9:34:Infinity":13,"b:29:13:29:22:29:22:29:37":6,"s:31:4:31:Infinity":14,"s:32:4:32:Infinity":15,"s:33:4:33:Infinity":16,"b:37:2:39:Infinity:undefined:undefined:undefined:undefined":7,"s:37:2:39:Infinity":17,"s:38:4:38:Infinity":18,"b:40:2:42:Infinity:undefined:undefined:undefined:undefined":8,"s:40:2:42:Infinity":19,"s:41:4:41:Infinity":20,"s:45:2:45:Infinity":21,"f:51:9:51:Infinity":1,"s:56:2:56:Infinity":22,"b:59:2:69:Infinity:undefined:undefined:undefined:undefined":9,"s:59:2:69:Infinity":23,"b:60:4:60:Infinity:61:4:61:Infinity:62:4:62:Infinity:63:4:63:Infinity":10,"s:65:4:65:Infinity":24,"s:66:4:66:Infinity":25,"s:67:4:67:Infinity":26,"s:68:4:68:Infinity":27,"b:72:2:83:Infinity:undefined:undefined:undefined:undefined":11,"s:72:2:83:Infinity":28,"b:73:4:73:Infinity:74:4:74:Infinity:75:4:75:Infinity:76:4:76:Infinity":12,"s:78:4:78:Infinity":29,"s:79:4:79:Infinity":30,"s:80:4:80:Infinity":31,"s:81:4:81:Infinity":32,"s:82:4:82:Infinity":33,"b:86:2:98:Infinity:undefined:undefined:undefined:undefined":13,"s:86:2:98:Infinity":34,"b:87:4:87:Infinity:88:4:88:Infinity:89:4:89:Infinity":14,"s:91:4:91:Infinity":35,"s:92:4:92:Infinity":36,"s:93:4:95:Infinity":37,"s:96:4:96:Infinity":38,"s:97:4:97:Infinity":39,"b:101:2:110:Infinity:undefined:undefined:undefined:undefined":15,"s:101:2:110:Infinity":40,"b:102:4:102:Infinity:103:4:103:Infinity:104:4:104:Infinity":16,"s:106:4:106:Infinity":41,"s:107:4:107:Infinity":42,"s:108:4:108:Infinity":43,"s:109:4:109:Infinity":44,"b:113:2:123:Infinity:undefined:undefined:undefined:undefined":17,"s:113:2:123:Infinity":45,"b:114:4:114:Infinity:115:4:115:Infinity:116:5:116:18:116:18:116:Infinity":18,"s:118:4:118:Infinity":46,"s:119:4:119:Infinity":47,"s:120:4:120:Infinity":48,"s:121:4:121:Infinity":49,"s:122:4:122:Infinity":50,"b:126:2:131:Infinity:undefined:undefined:undefined:undefined":19,"s:126:2:131:Infinity":51,"b:126:6:126:41:126:41:126:76":20,"s:127:4:127:Infinity":52,"s:128:4:128:Infinity":53,"s:129:4:129:Infinity":54,"s:130:4:130:Infinity":55,"b:134:2:146:Infinity:undefined:undefined:undefined:undefined":21,"s:134:2:146:Infinity":56,"b:135:4:135:Infinity:136:4:136:Infinity:137:4:137:Infinity:138:4:138:Infinity:139:4:139:Infinity:140:4:140:Infinity":22,"s:142:4:142:Infinity":57,"s:143:4:143:Infinity":58,"s:144:4:144:Infinity":59,"s:145:4:145:Infinity":60,"s:148:2:150:Infinity":61}}} -,"/Users/marcus/berget-monorepo/cli/src/utils/logger.ts": {"path":"/Users/marcus/berget-monorepo/cli/src/utils/logger.ts","statementMap":{"0":{"start":{"line":6,"column":7},"end":{"line":12,"column":null}},"1":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"2":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"4":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"5":{"start":{"line":11,"column":2},"end":{"line":11,"column":null}},"6":{"start":{"line":14,"column":18},"end":{"line":14,"column":null}},"7":{"start":{"line":21,"column":10},"end":{"line":21,"column":null}},"8":{"start":{"line":25,"column":4},"end":{"line":31,"column":null}},"9":{"start":{"line":26,"column":6},"end":{"line":26,"column":null}},"10":{"start":{"line":27,"column":11},"end":{"line":31,"column":null}},"11":{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},"12":{"start":{"line":29,"column":11},"end":{"line":31,"column":null}},"13":{"start":{"line":30,"column":6},"end":{"line":30,"column":null}},"14":{"start":{"line":35,"column":4},"end":{"line":37,"column":null}},"15":{"start":{"line":36,"column":6},"end":{"line":36,"column":null}},"16":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"17":{"start":{"line":46,"column":4},"end":{"line":56,"column":null}},"18":{"start":{"line":47,"column":30},"end":{"line":47,"column":null}},"19":{"start":{"line":48,"column":27},"end":{"line":50,"column":null}},"20":{"start":{"line":49,"column":8},"end":{"line":49,"column":null}},"21":{"start":{"line":51,"column":6},"end":{"line":55,"column":null}},"22":{"start":{"line":52,"column":8},"end":{"line":52,"column":null}},"23":{"start":{"line":54,"column":8},"end":{"line":54,"column":null}},"24":{"start":{"line":63,"column":4},"end":{"line":69,"column":null}},"25":{"start":{"line":64,"column":6},"end":{"line":68,"column":null}},"26":{"start":{"line":65,"column":8},"end":{"line":65,"column":null}},"27":{"start":{"line":67,"column":8},"end":{"line":67,"column":null}},"28":{"start":{"line":76,"column":4},"end":{"line":76,"column":null}},"29":{"start":{"line":83,"column":4},"end":{"line":89,"column":null}},"30":{"start":{"line":84,"column":6},"end":{"line":88,"column":null}},"31":{"start":{"line":85,"column":8},"end":{"line":85,"column":null}},"32":{"start":{"line":87,"column":8},"end":{"line":87,"column":null}},"33":{"start":{"line":96,"column":4},"end":{"line":102,"column":null}},"34":{"start":{"line":97,"column":6},"end":{"line":101,"column":null}},"35":{"start":{"line":98,"column":8},"end":{"line":98,"column":null}},"36":{"start":{"line":100,"column":8},"end":{"line":100,"column":null}},"37":{"start":{"line":109,"column":4},"end":{"line":109,"column":null}},"38":{"start":{"line":116,"column":4},"end":{"line":122,"column":null}},"39":{"start":{"line":117,"column":6},"end":{"line":121,"column":null}},"40":{"start":{"line":118,"column":8},"end":{"line":118,"column":null}},"41":{"start":{"line":120,"column":8},"end":{"line":120,"column":null}},"42":{"start":{"line":129,"column":4},"end":{"line":135,"column":null}},"43":{"start":{"line":130,"column":6},"end":{"line":134,"column":null}},"44":{"start":{"line":131,"column":8},"end":{"line":131,"column":null}},"45":{"start":{"line":133,"column":8},"end":{"line":133,"column":null}},"46":{"start":{"line":142,"column":4},"end":{"line":167,"column":null}},"47":{"start":{"line":144,"column":8},"end":{"line":144,"column":null}},"48":{"start":{"line":145,"column":8},"end":{"line":145,"column":null}},"49":{"start":{"line":148,"column":8},"end":{"line":148,"column":null}},"50":{"start":{"line":149,"column":8},"end":{"line":149,"column":null}},"51":{"start":{"line":152,"column":8},"end":{"line":152,"column":null}},"52":{"start":{"line":153,"column":8},"end":{"line":153,"column":null}},"53":{"start":{"line":156,"column":8},"end":{"line":156,"column":null}},"54":{"start":{"line":157,"column":8},"end":{"line":157,"column":null}},"55":{"start":{"line":160,"column":8},"end":{"line":160,"column":null}},"56":{"start":{"line":161,"column":8},"end":{"line":161,"column":null}},"57":{"start":{"line":165,"column":8},"end":{"line":165,"column":null}},"58":{"start":{"line":177,"column":15},"end":{"line":177,"column":null}},"59":{"start":{"line":180,"column":2},"end":{"line":180,"column":null}},"60":{"start":{"line":183,"column":2},"end":{"line":183,"column":null}},"61":{"start":{"line":186,"column":2},"end":{"line":186,"column":null}},"62":{"start":{"line":189,"column":2},"end":{"line":189,"column":null}},"63":{"start":{"line":191,"column":2},"end":{"line":191,"column":null}},"64":{"start":{"line":195,"column":22},"end":{"line":195,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":6,"column":7},"end":{"line":6,"column":12}},"loc":{"start":{"line":6,"column":7},"end":{"line":12,"column":null}},"line":6},"1":{"name":"constructor","decl":{"start":{"line":23,"column":2},"end":{"line":23,"column":10}},"loc":{"start":{"line":23,"column":24},"end":{"line":32,"column":null}},"line":23},"2":{"name":"getInstance","decl":{"start":{"line":34,"column":16},"end":{"line":34,"column":38}},"loc":{"start":{"line":34,"column":38},"end":{"line":39,"column":null}},"line":34},"3":{"name":"debug","decl":{"start":{"line":45,"column":2},"end":{"line":45,"column":9}},"loc":{"start":{"line":45,"column":60},"end":{"line":57,"column":null}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":48,"column":38},"end":{"line":48,"column":43}},"loc":{"start":{"line":49,"column":8},"end":{"line":49,"column":null}},"line":49},"5":{"name":"error","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":9}},"loc":{"start":{"line":62,"column":60},"end":{"line":70,"column":null}},"line":62},"6":{"name":"getLogLevel","decl":{"start":{"line":75,"column":2},"end":{"line":75,"column":9}},"loc":{"start":{"line":75,"column":33},"end":{"line":77,"column":null}},"line":75},"7":{"name":"info","decl":{"start":{"line":82,"column":2},"end":{"line":82,"column":9}},"loc":{"start":{"line":82,"column":59},"end":{"line":90,"column":null}},"line":82},"8":{"name":"log","decl":{"start":{"line":95,"column":2},"end":{"line":95,"column":9}},"loc":{"start":{"line":95,"column":58},"end":{"line":103,"column":null}},"line":95},"9":{"name":"setLogLevel","decl":{"start":{"line":108,"column":2},"end":{"line":108,"column":9}},"loc":{"start":{"line":108,"column":44},"end":{"line":110,"column":null}},"line":108},"10":{"name":"success","decl":{"start":{"line":115,"column":2},"end":{"line":115,"column":9}},"loc":{"start":{"line":115,"column":62},"end":{"line":123,"column":null}},"line":115},"11":{"name":"warn","decl":{"start":{"line":128,"column":2},"end":{"line":128,"column":9}},"loc":{"start":{"line":128,"column":59},"end":{"line":136,"column":null}},"line":128},"12":{"name":"setLogLevelFromString","decl":{"start":{"line":141,"column":2},"end":{"line":141,"column":10}},"loc":{"start":{"line":141,"column":53},"end":{"line":168,"column":null}},"line":141},"13":{"name":"redactSecrets","decl":{"start":{"line":176,"column":9},"end":{"line":176,"column":23}},"loc":{"start":{"line":176,"column":46},"end":{"line":192,"column":null}},"line":176}},"branchMap":{"0":{"loc":{"start":{"line":25,"column":4},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":4},"end":{"line":31,"column":null}},{"start":{"line":27,"column":11},"end":{"line":31,"column":null}}],"line":25},"1":{"loc":{"start":{"line":27,"column":11},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":27,"column":11},"end":{"line":31,"column":null}},{"start":{"line":29,"column":11},"end":{"line":31,"column":null}}],"line":27},"2":{"loc":{"start":{"line":29,"column":11},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":29,"column":11},"end":{"line":31,"column":null}},{"start":{},"end":{}}],"line":29},"3":{"loc":{"start":{"line":35,"column":4},"end":{"line":37,"column":null}},"type":"if","locations":[{"start":{"line":35,"column":4},"end":{"line":37,"column":null}},{"start":{},"end":{}}],"line":35},"4":{"loc":{"start":{"line":46,"column":4},"end":{"line":56,"column":null}},"type":"if","locations":[{"start":{"line":46,"column":4},"end":{"line":56,"column":null}},{"start":{},"end":{}}],"line":46},"5":{"loc":{"start":{"line":49,"column":8},"end":{"line":49,"column":null}},"type":"cond-expr","locations":[{"start":{"line":49,"column":34},"end":{"line":49,"column":55}},{"start":{"line":49,"column":55},"end":{"line":49,"column":null}}],"line":49},"6":{"loc":{"start":{"line":51,"column":6},"end":{"line":55,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":6},"end":{"line":55,"column":null}},{"start":{"line":53,"column":13},"end":{"line":55,"column":null}}],"line":51},"7":{"loc":{"start":{"line":63,"column":4},"end":{"line":69,"column":null}},"type":"if","locations":[{"start":{"line":63,"column":4},"end":{"line":69,"column":null}},{"start":{},"end":{}}],"line":63},"8":{"loc":{"start":{"line":64,"column":6},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":6},"end":{"line":68,"column":null}},{"start":{"line":66,"column":13},"end":{"line":68,"column":null}}],"line":64},"9":{"loc":{"start":{"line":83,"column":4},"end":{"line":89,"column":null}},"type":"if","locations":[{"start":{"line":83,"column":4},"end":{"line":89,"column":null}},{"start":{},"end":{}}],"line":83},"10":{"loc":{"start":{"line":84,"column":6},"end":{"line":88,"column":null}},"type":"if","locations":[{"start":{"line":84,"column":6},"end":{"line":88,"column":null}},{"start":{"line":86,"column":13},"end":{"line":88,"column":null}}],"line":84},"11":{"loc":{"start":{"line":96,"column":4},"end":{"line":102,"column":null}},"type":"if","locations":[{"start":{"line":96,"column":4},"end":{"line":102,"column":null}},{"start":{},"end":{}}],"line":96},"12":{"loc":{"start":{"line":97,"column":6},"end":{"line":101,"column":null}},"type":"if","locations":[{"start":{"line":97,"column":6},"end":{"line":101,"column":null}},{"start":{"line":99,"column":13},"end":{"line":101,"column":null}}],"line":97},"13":{"loc":{"start":{"line":116,"column":4},"end":{"line":122,"column":null}},"type":"if","locations":[{"start":{"line":116,"column":4},"end":{"line":122,"column":null}},{"start":{},"end":{}}],"line":116},"14":{"loc":{"start":{"line":117,"column":6},"end":{"line":121,"column":null}},"type":"if","locations":[{"start":{"line":117,"column":6},"end":{"line":121,"column":null}},{"start":{"line":119,"column":13},"end":{"line":121,"column":null}}],"line":117},"15":{"loc":{"start":{"line":129,"column":4},"end":{"line":135,"column":null}},"type":"if","locations":[{"start":{"line":129,"column":4},"end":{"line":135,"column":null}},{"start":{},"end":{}}],"line":129},"16":{"loc":{"start":{"line":130,"column":6},"end":{"line":134,"column":null}},"type":"if","locations":[{"start":{"line":130,"column":6},"end":{"line":134,"column":null}},{"start":{"line":132,"column":13},"end":{"line":134,"column":null}}],"line":130},"17":{"loc":{"start":{"line":142,"column":4},"end":{"line":167,"column":null}},"type":"switch","locations":[{"start":{"line":143,"column":6},"end":{"line":146,"column":null}},{"start":{"line":147,"column":6},"end":{"line":150,"column":null}},{"start":{"line":151,"column":6},"end":{"line":154,"column":null}},{"start":{"line":155,"column":6},"end":{"line":158,"column":null}},{"start":{"line":159,"column":6},"end":{"line":162,"column":null}},{"start":{"line":163,"column":6},"end":{"line":166,"column":null}}],"line":142}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":0,"10":1,"11":0,"12":1,"13":0,"14":1,"15":1,"16":1,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":1},"f":{"0":1,"1":1,"2":1,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0},"b":{"0":[0,1],"1":[0,1],"2":[0,1],"3":[1,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0,0,0,0,0]},"meta":{"lastBranch":18,"lastFunction":14,"lastStatement":65,"seen":{"s:6:7:12:Infinity":0,"f:6:7:6:12":0,"s:7:2:7:Infinity":1,"s:8:2:8:Infinity":2,"s:9:2:9:Infinity":3,"s:10:2:10:Infinity":4,"s:11:2:11:Infinity":5,"s:14:18:14:Infinity":6,"s:21:10:21:Infinity":7,"f:23:2:23:10":1,"b:25:4:31:Infinity:27:11:31:Infinity":0,"s:25:4:31:Infinity":8,"s:26:6:26:Infinity":9,"b:27:11:31:Infinity:29:11:31:Infinity":1,"s:27:11:31:Infinity":10,"s:28:6:28:Infinity":11,"b:29:11:31:Infinity:undefined:undefined:undefined:undefined":2,"s:29:11:31:Infinity":12,"s:30:6:30:Infinity":13,"f:34:16:34:38":2,"b:35:4:37:Infinity:undefined:undefined:undefined:undefined":3,"s:35:4:37:Infinity":14,"s:36:6:36:Infinity":15,"s:38:4:38:Infinity":16,"f:45:2:45:9":3,"b:46:4:56:Infinity:undefined:undefined:undefined:undefined":4,"s:46:4:56:Infinity":17,"s:47:30:47:Infinity":18,"s:48:27:50:Infinity":19,"f:48:38:48:43":4,"s:49:8:49:Infinity":20,"b:49:34:49:55:49:55:49:Infinity":5,"b:51:6:55:Infinity:53:13:55:Infinity":6,"s:51:6:55:Infinity":21,"s:52:8:52:Infinity":22,"s:54:8:54:Infinity":23,"f:62:2:62:9":5,"b:63:4:69:Infinity:undefined:undefined:undefined:undefined":7,"s:63:4:69:Infinity":24,"b:64:6:68:Infinity:66:13:68:Infinity":8,"s:64:6:68:Infinity":25,"s:65:8:65:Infinity":26,"s:67:8:67:Infinity":27,"f:75:2:75:9":6,"s:76:4:76:Infinity":28,"f:82:2:82:9":7,"b:83:4:89:Infinity:undefined:undefined:undefined:undefined":9,"s:83:4:89:Infinity":29,"b:84:6:88:Infinity:86:13:88:Infinity":10,"s:84:6:88:Infinity":30,"s:85:8:85:Infinity":31,"s:87:8:87:Infinity":32,"f:95:2:95:9":8,"b:96:4:102:Infinity:undefined:undefined:undefined:undefined":11,"s:96:4:102:Infinity":33,"b:97:6:101:Infinity:99:13:101:Infinity":12,"s:97:6:101:Infinity":34,"s:98:8:98:Infinity":35,"s:100:8:100:Infinity":36,"f:108:2:108:9":9,"s:109:4:109:Infinity":37,"f:115:2:115:9":10,"b:116:4:122:Infinity:undefined:undefined:undefined:undefined":13,"s:116:4:122:Infinity":38,"b:117:6:121:Infinity:119:13:121:Infinity":14,"s:117:6:121:Infinity":39,"s:118:8:118:Infinity":40,"s:120:8:120:Infinity":41,"f:128:2:128:9":11,"b:129:4:135:Infinity:undefined:undefined:undefined:undefined":15,"s:129:4:135:Infinity":42,"b:130:6:134:Infinity:132:13:134:Infinity":16,"s:130:6:134:Infinity":43,"s:131:8:131:Infinity":44,"s:133:8:133:Infinity":45,"f:141:2:141:10":12,"b:143:6:146:Infinity:147:6:150:Infinity:151:6:154:Infinity:155:6:158:Infinity:159:6:162:Infinity:163:6:166:Infinity":17,"s:142:4:167:Infinity":46,"s:144:8:144:Infinity":47,"s:145:8:145:Infinity":48,"s:148:8:148:Infinity":49,"s:149:8:149:Infinity":50,"s:152:8:152:Infinity":51,"s:153:8:153:Infinity":52,"s:156:8:156:Infinity":53,"s:157:8:157:Infinity":54,"s:160:8:160:Infinity":55,"s:161:8:161:Infinity":56,"s:165:8:165:Infinity":57,"f:176:9:176:23":13,"s:177:15:177:Infinity":58,"s:180:2:180:Infinity":59,"s:183:2:183:Infinity":60,"s:186:2:186:Infinity":61,"s:189:2:189:Infinity":62,"s:191:2:191:Infinity":63,"s:195:22:195:Infinity":64}}} -} +{} diff --git a/coverage/index.html b/coverage/index.html index 503d920..30510a0 100644 --- a/coverage/index.html +++ b/coverage/index.html @@ -23,30 +23,30 @@

All files

- 44.54% + Unknown% Statements - 506/1136 + 0/0
- 37.76% + Unknown% Branches - 253/670 + 0/0
- 45.54% + Unknown% Functions - 92/202 + 0/0
- 44.45% + Unknown% Lines - 473/1064 + 0/0
@@ -61,7 +61,7 @@

All files

-
+
@@ -78,187 +78,7 @@

All files

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
src -
-
0%0/110%0/20%0/30%0/11
src/agents -
-
72%18/2550%4/860%3/572%18/25
src/auth -
-
40.38%21/5225%7/2862.5%5/844.68%21/47
src/auth/middleware -
-
0%0/170%0/160%0/40%0/17
src/auth/oauth -
-
3.75%6/1600%0/910%0/243.94%6/152
src/auth/storage -
-
0%0/240%0/110%0/50%0/24
src/commands/code -
-
82.26%348/42376.67%194/25395.65%44/4683.03%323/389
src/commands/code/__tests__ -
-
70.86%90/12755%44/8079.54%35/4473.87%82/111
src/commands/code/adapters -
-
1.81%1/550%0/120%0/312%1/50
src/constants -
-
100%3/3100%0/0100%0/0100%3/3
src/services -
-
3.57%4/1120%0/7112.5%2/163.7%4/108
src/utils -
-
11.81%15/1274.08%4/9818.75%3/1611.81%15/127
@@ -266,7 +86,7 @@

All files

- - - - - - \ No newline at end of file diff --git a/coverage/src/agents/backend.ts.html b/coverage/src/agents/backend.ts.html deleted file mode 100644 index 6632f0f..0000000 --- a/coverage/src/agents/backend.ts.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - Code coverage report for src/agents/backend.ts - - - - - - - - - -
-
-

All files / src/agents backend.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { Agent } from './types.js';
- 
-export const agent: Agent = {
-  config: {
-    description: 'Functional, modular Koa + TypeScript services',
-    mode: 'primary',
-    name: 'backend',
-  },
-  systemPrompt: `# Backend Agent
- 
-Functional, modular Koa + TypeScript services with schema-first approach and code quality focus.
- 
-**Use when:**
- 
-- Working with Koa routers and services
-- Backend development in /services
-- API development and database work
- 
-**Key features:**
- 
-- Zod validation and OpenAPI generation
-- Code quality and refactoring principles
-- PR workflow integration`,
-};
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/agents/devops.ts.html b/coverage/src/agents/devops.ts.html deleted file mode 100644 index fe08861..0000000 --- a/coverage/src/agents/devops.ts.html +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - Code coverage report for src/agents/devops.ts - - - - - - - - - -
-
-

All files / src/agents devops.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { Agent } from './types.js';
- 
-export const agent: Agent = {
-  config: {
-    description: 'Declarative GitOps infra with FluxCD, Kustomize, Helm, operators.',
-    mode: 'primary',
-    name: 'devops',
-    permission: {
-      bash: 'allow',
-      edit: 'allow',
-      webfetch: 'allow',
-    },
-    temperature: 0.3,
-    top_p: 0.8,
-  },
-  systemPrompt: `You are Berget Code DevOps agent. Voice: Scandinavian calm—precise, concise, confident. Start simple: k8s/{deployment,service,ingress}. Add FluxCD sync to repo and image automation. Use Kustomize bases/overlays (staging, production). Add dependencies via Helm from upstream sources; prefer native operators when available (CloudNativePG, cert-manager, external-dns). SemVer with -rc tags keeps CI environments current. Observability with Prometheus/Grafana. No manual kubectl in production—Git is the source of truth.
- 
-GIT WORKFLOW RULES (CRITICAL):
-- NEVER push directly to main branch - ALWAYS use pull requests
-- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
-- ALWAYS clean up test files, documentation files, and temporary artifacts before committing
-- ALWAYS ensure git history maintains production quality - no test commits, no debugging code
-- ALWAYS create descriptive commit messages following project conventions
-- ALWAYS run tests and build before creating PR
- 
-Helm Values Configuration Process:
-1. Documentation First Approach: Always fetch official documentation from Artifact Hub/GitHub for the specific chart version before writing values. Search Artifact Hub for exact chart version documentation, check the chart's GitHub repository for official docs and examples, verify the exact version being used in the deployment.
-2. Validation Requirements: Check for available validation schemas before committing YAML files. Use Helm's built-in validation tools (helm lint, helm template). Validate against JSON schema if available for the chart. Ensure YAML syntax correctness with linters.
-3. Standard Workflow: Identify chart name and exact version. Fetch official documentation from Artifact Hub/GitHub. Check for available schemas and validation tools. Write values according to official documentation. Validate against schema (if available). Test with helm template or helm lint. Commit validated YAML files.
-4. Quality Assurance: Never commit unvalidated Helm values. Use helm dependency update when adding new charts. Test rendering with helm template --dry-run before deployment. Document any custom values with comments referencing official docs.
- 
-CRITICAL: When all devops implementation tasks are complete and ready for merge, ALWAYS invoke @quality subagent to handle testing, building, and complete PR management including URL provision.`,
-};
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/agents/frontend.ts.html b/coverage/src/agents/frontend.ts.html deleted file mode 100644 index 61f2e67..0000000 --- a/coverage/src/agents/frontend.ts.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - Code coverage report for src/agents/frontend.ts - - - - - - - - - -
-
-

All files / src/agents frontend.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { Agent } from './types.js';
- 
-export const agent: Agent = {
-  config: {
-    description: 'Scandinavian, type-safe UIs with React, Tailwind, and Shadcn',
-    mode: 'primary',
-    name: 'frontend',
-  },
-  systemPrompt: `# Frontend Agent
- 
-Builds Scandinavian, type-safe UIs with React, Tailwind, and Shadcn.
- 
-**Use when:**
- 
-- Working with React components (.tsx files)
-- Frontend development in /apps/frontend
-- UI/UX implementation
- 
-**Key features:**
- 
-- Design system integration
-- Semantic tokens and accessibility
-- Props-first component architecture`,
-};
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/agents/fullstack.ts.html b/coverage/src/agents/fullstack.ts.html deleted file mode 100644 index 472ca26..0000000 --- a/coverage/src/agents/fullstack.ts.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - Code coverage report for src/agents/fullstack.ts - - - - - - - - - -
-
-

All files / src/agents fullstack.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { Agent } from './types.js';
- 
-export const agent: Agent = {
-  config: {
-    description: 'Router/coordinator agent for full-stack development',
-    mode: 'primary',
-    name: 'fullstack',
-  },
-  systemPrompt: `# Fullstack Agent
- 
-Router/coordinator agent for full-stack development with schema-driven architecture. Handles routing between different personas based on file paths and task requirements.
- 
-**Use when:**
- 
-- Working across multiple parts of a monorepo
-- Need to coordinate between frontend, backend, devops, and app
-- Starting new projects and need to determine tech stack
- 
-**Key features:**
- 
-- Schema-driven development (database → OpenAPI → types)
-- Automatic routing to appropriate persona
-- Tech stack discovery and recommendations`,
-};
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/agents/index.html b/coverage/src/agents/index.html deleted file mode 100644 index a7eeeb9..0000000 --- a/coverage/src/agents/index.html +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - Code coverage report for src/agents - - - - - - - - - -
-
-

All files src/agents

-
- -
- 72% - Statements - 18/25 -
- - -
- 50% - Branches - 4/8 -
- - -
- 60% - Functions - 3/5 -
- - -
- 72% - Lines - 18/25 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
app.ts -
-
100%1/1100%0/0100%0/0100%1/1
backend.ts -
-
100%1/1100%0/0100%0/0100%1/1
devops.ts -
-
100%1/1100%0/0100%0/0100%1/1
frontend.ts -
-
100%1/1100%0/0100%0/0100%1/1
fullstack.ts -
-
100%1/1100%0/0100%0/0100%1/1
index.ts -
-
61.11%11/1850%4/860%3/561.11%11/18
quality.ts -
-
100%1/1100%0/0100%0/0100%1/1
security.ts -
-
100%1/1100%0/0100%0/0100%1/1
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/agents/index.ts.html b/coverage/src/agents/index.ts.html deleted file mode 100644 index d5be0a4..0000000 --- a/coverage/src/agents/index.ts.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - - - Code coverage report for src/agents/index.ts - - - - - - - - - -
-
-

All files / src/agents index.ts

-
- -
- 61.11% - Statements - 11/18 -
- - -
- 50% - Branches - 4/8 -
- - -
- 60% - Functions - 3/5 -
- - -
- 61.11% - Lines - 11/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -28x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -7x -7x -  -7x -7x -  -  -7x -  -  -  -7x -  -  -  -7x -  -  -  -  -  -  -7x -  -  -  -8x -  -  -  - 
import type { Agent } from './types.js';
- 
-import { agent as app } from './app.js';
-import { agent as backend } from './backend.js';
-import { agent as devops } from './devops.js';
-import { agent as frontend } from './frontend.js';
-import { agent as fullstack } from './fullstack.js';
-import { agent as quality } from './quality.js';
-import { agent as security } from './security.js';
- 
-const agents: Record<string, Agent> = {
-  app,
-  backend,
-  devops,
-  frontend,
-  fullstack,
-  quality,
-  security,
-};
- 
-export { agents };
- 
-export function getAgent(name: string): Agent | undefined {
-  return agents[name];
-}
- 
-export function getAllAgents(): Agent[] {
-  return Object.values(agents);
-}
- 
-export function toAgentTemplate(agent: Agent): {
-  content: string;
-  description: string;
-  name: string;
-} {
-  return {
-    content: agent.systemPrompt,
-    description: agent.config.description,
-    name: agent.config.name,
-  };
-}
- 
-export function toMarkdown(agent: Agent): string {
-  const { config, systemPrompt } = agent;
-  let frontmatter = `---\nname: ${config.name}\ndescription: ${config.description}\n`;
- 
-  Eif (config.mode) {
-    frontmatter += `mode: ${config.mode}\n`;
-  }
- 
-  Iif (config.temperature) {
-    frontmatter += `temperature: ${config.temperature}\n`;
-  }
- 
-  Iif (config.top_p) {
-    frontmatter += `top_p: ${config.top_p}\n`;
-  }
- 
-  Iif (config.permission) {
-    frontmatter += `permission:\n`;
-    for (const [key, value] of Object.entries(config.permission)) {
-      frontmatter += `  ${key}: ${value}\n`;
-    }
-  }
- 
-  return `${frontmatter}---\n\n${systemPrompt}`;
-}
- 
-export function toPiPrompt(agent: Agent): string {
-  return agent.systemPrompt;
-}
- 
-export { type Agent, type AgentConfig } from './types.js';
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/agents/quality.ts.html b/coverage/src/agents/quality.ts.html deleted file mode 100644 index b964d1e..0000000 --- a/coverage/src/agents/quality.ts.html +++ /dev/null @@ -1,292 +0,0 @@ - - - - - - Code coverage report for src/agents/quality.ts - - - - - - - - - -
-
-

All files / src/agents quality.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { Agent } from './types.js';
- 
-export const agent: Agent = {
-  config: {
-    description: 'Quality assurance specialist for testing, building, and complete PR management.',
-    mode: 'subagent',
-    name: 'quality',
-    permission: {
-      bash: 'allow',
-      edit: 'allow',
-      webfetch: 'allow',
-    },
-    temperature: 0.1,
-    top_p: 0.9,
-  },
-  systemPrompt: `Voice: Scandinavian calm—precise, concise, confident. You are Berget Code Quality agent. Specialist in code quality assurance, testing, building, and pull request lifecycle management.
- 
-Core responsibilities:
-  - Run comprehensive test suites (npm test, npm run test, jest, vitest)
-  - Execute build processes (npm run build, webpack, vite, tsc)
-  - Create and manage pull requests with proper descriptions
-  - Handle merge conflicts and keep main updated
-  - Monitor GitHub for reviewer comments and address them
-  - Ensure code quality standards are met
-  - Validate linting and formatting (npm run lint, prettier)
-  - Check test coverage and performance benchmarks
-  - Handle CI/CD pipeline validation
- 
-Complete PR Workflow:
-   1. Ensure all tests pass: npm test
-   2. Build successfully: npm run build
-   3. Commit all changes with proper message
-   4. Push to feature branch
-   5. Update main branch and handle merge conflicts
-   6. Create or update PR with comprehensive description
-   7. Monitor for reviewer comments
-   8. Address feedback and push updates
-   9. Always provide PR URL for user review
- 
-Essential CLI commands:
-   - npm test or npm run test (run test suite)
-   - npm run build (build project)
-   - npm run lint (run linting)
-   - npm run format (format code)
-   - npm run test:coverage (check coverage)
-   - git add <specific-files> && git commit -m "message" && git push (commit and push)
-   - git checkout main && git pull origin main (update main)
-   - git checkout feature-branch && git merge main (handle conflicts)
-   - gh pr create --title "title" --body "body" (create PR)
-   - gh pr view --comments (check PR comments)
-   - gh pr edit --title "title" --body "body" (update PR)
- 
-PR Creation Process:
-   - Always include clear summary of changes
-   - List technical details and improvements
-   - Include testing and validation results
-   - Add any breaking changes or migration notes
-   - Provide PR URL immediately after creation
- 
-GIT WORKFLOW RULES (CRITICAL - ENFORCE STRICTLY):
-   - NEVER push directly to main branch - ALWAYS use pull requests
-   - NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
-   - ALWAYS clean up test files, documentation files, and temporary artifacts before committing
-   - ALWAYS ensure git history maintains production quality - no test commits, no debugging code
-   - ALWAYS create descriptive commit messages following project conventions
-   - ALWAYS run tests and build before creating PR
- 
-Always provide specific command examples and wait for processes to complete before proceeding.`,
-};
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/agents/security.ts.html b/coverage/src/agents/security.ts.html deleted file mode 100644 index 4e9925e..0000000 --- a/coverage/src/agents/security.ts.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - Code coverage report for src/agents/security.ts - - - - - - - - - -
-
-

All files / src/agents security.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { Agent } from './types.js';
- 
-export const agent: Agent = {
-  config: {
-    description:
-      'Security specialist for pentesting, OWASP compliance, and vulnerability assessments.',
-    mode: 'subagent',
-    name: 'security',
-    permission: {
-      bash: 'allow',
-      edit: 'deny',
-      webfetch: 'allow',
-    },
-    temperature: 0.2,
-    top_p: 0.8,
-  },
-  systemPrompt: `Voice: Scandinavian calm—precise, concise, confident. You are Berget Code Security agent. Expert in application security, penetration testing, and OWASP standards. Core responsibilities: Conduct security assessments and penetration tests, Validate OWASP Top 10 compliance, Review code for security vulnerabilities, Implement security headers and Content Security Policy (CSP), Audit API security, Check for sensitive data exposure, Validate input sanitization and output encoding, Assess dependency security and supply chain risks. Tools and techniques: OWASP ZAP, Burp Suite, security linters, dependency scanners, manual code review. Always provide specific, actionable security recommendations with priority levels.
- 
-GIT WORKFLOW RULES (CRITICAL):
-- NEVER push directly to main branch - ALWAYS use pull requests
-- NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
-- ALWAYS clean up test files, documentation files, and temporary artifacts before committing
-- ALWAYS ensure git history maintains production quality - no test commits, no debugging code
-- ALWAYS create descriptive commit messages following project conventions
-- ALWAYS run tests and build before creating PR`,
-};
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/config.ts.html b/coverage/src/auth/config.ts.html deleted file mode 100644 index d2c8a86..0000000 --- a/coverage/src/auth/config.ts.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - Code coverage report for src/auth/config.ts - - - - - - - - - -
-
-

All files / src/auth config.ts

-
- -
- 0% - Statements - 0/17 -
- - -
- 0% - Branches - 0/14 -
- - -
- 0% - Functions - 0/1 -
- - -
- 0% - Lines - 0/17 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import type { AuthConfig } from './types.js';
- 
-export function getAuthConfig(options?: { local?: boolean; stage?: boolean }): AuthConfig {
-  // Allow explicit override of Keycloak URL
-  if (process.env.BERGET_KEYCLOAK_URL) {
-    const apiBaseUrl = process.env.BERGET_API_URL || 'https://api.berget.ai';
-    return {
-      apiBaseUrl,
-      clientId: 'berget-code',
-      keycloakUrl: process.env.BERGET_KEYCLOAK_URL,
-      realm: 'berget',
-    };
-  }
- 
-  let apiBaseUrl: string;
-  let keycloakUrl: string;
- 
-  // Environment variable always takes precedence
-  if (process.env.BERGET_API_URL) {
-    apiBaseUrl = process.env.BERGET_API_URL;
-    // Infer keycloak from API URL for custom endpoints
-    if (apiBaseUrl.includes('localhost') || apiBaseUrl.includes('stage.')) {
-      keycloakUrl = 'https://keycloak.stage.berget.ai';
-    } else {
-      keycloakUrl = 'https://keycloak.berget.ai';
-    }
-  } else if (options?.local) {
-    apiBaseUrl = 'http://localhost:3000';
-    keycloakUrl = 'https://keycloak.stage.berget.ai';
-  } else if (options?.stage) {
-    apiBaseUrl = 'https://api.stage.berget.ai';
-    keycloakUrl = 'https://keycloak.stage.berget.ai';
-  } else {
-    apiBaseUrl = 'https://api.berget.ai';
-    keycloakUrl = 'https://keycloak.berget.ai';
-  }
- 
-  return {
-    apiBaseUrl,
-    clientId: 'berget-code',
-    keycloakUrl,
-    realm: 'berget',
-  };
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/index.html b/coverage/src/auth/index.html deleted file mode 100644 index 8d78a30..0000000 --- a/coverage/src/auth/index.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - Code coverage report for src/auth - - - - - - - - - -
-
-

All files src/auth

-
- -
- 40.38% - Statements - 21/52 -
- - -
- 25% - Branches - 7/28 -
- - -
- 62.5% - Functions - 5/8 -
- - -
- 44.68% - Lines - 21/47 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
config.ts -
-
0%0/170%0/140%0/10%0/17
issuer.ts -
-
11.11%1/90%0/20%0/212.5%1/8
jwt.ts -
-
76.92%20/2658.33%7/12100%5/590.9%20/22
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/issuer.ts.html b/coverage/src/auth/issuer.ts.html deleted file mode 100644 index aecd27c..0000000 --- a/coverage/src/auth/issuer.ts.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - Code coverage report for src/auth/issuer.ts - - - - - - - - - -
-
-

All files / src/auth issuer.ts

-
- -
- 11.11% - Statements - 1/9 -
- - -
- 0% - Branches - 0/2 -
- - -
- 0% - Functions - 0/2 -
- - -
- 12.5% - Lines - 1/8 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
// openid-client@^6 API surface verified:
-// discovery(url: URL, clientId: string, clientMetadata?: object, clientAuth?: ClientAuth): Promise<Configuration>
-// randomPKCECodeVerifier(): string
-// calculatePKCECodeChallenge(codeVerifier: string): string
-// buildAuthorizationUrl(configuration: Configuration, parameters?: Record<string, string>): URL
-// authorizationCodeGrant(configuration: Configuration, url: URL, checkState?: boolean, options?: object): Promise<{ access_token: string, refresh_token?: string, expires_in?: number, ... }>
-// refreshTokenGrant(configuration: Configuration, refreshToken: string, options?: object): Promise<{ access_token: string, refresh_token?: string, expires_in?: number, ... }>
- 
-import { type Configuration, discovery } from 'openid-client';
- 
-import type { AuthConfig } from './types.js';
- 
-const cache = new Map<string, Configuration>();
- 
-export function clearConfigurationCache(): void {
-  cache.clear();
-}
- 
-export async function getConfiguration(config: AuthConfig): Promise<Configuration> {
-  const issuerUrl = new URL(`${config.keycloakUrl}/realms/${config.realm}`).toString();
- 
-  const cached = cache.get(issuerUrl);
-  if (cached) return cached;
- 
-  const configuration = await discovery(
-    new URL(issuerUrl),
-    config.clientId,
-    {}, // no additional client metadata needed for public PKCE client
-    // 4th arg (clientAuth) omitted — public PKCE client has no auth
-  );
- 
-  cache.set(issuerUrl, configuration);
-  return configuration;
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/jwt.ts.html b/coverage/src/auth/jwt.ts.html deleted file mode 100644 index 434c6d3..0000000 --- a/coverage/src/auth/jwt.ts.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - Code coverage report for src/auth/jwt.ts - - - - - - - - - -
-
-

All files / src/auth jwt.ts

-
- -
- 76.92% - Statements - 20/26 -
- - -
- 58.33% - Branches - 7/12 -
- - -
- 100% - Functions - 5/5 -
- - -
- 90.9% - Lines - 20/22 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64  -  -  -  -  -  -3x -  -  -  -  -  -  -  -  -5x -5x -5x -  -  -  -  -  -  -  -  -  -  -3x -3x -3x -3x -3x -3x -3x -  -  -  -  -  -  -  -  -  -2x -2x -2x -2x -  -  -  -  -  -  -11x -11x -11x -11x -11x -  -  -  -  - 
/**
- * Decode the payload of a JWT token without verification.
- * @param token The JWT token string
- * @returns The decoded payload, or null if the token is invalid
- */
-export function decodeJwtPayload(token: string): null | unknown {
-  return parseJwtBody(token);
-}
- 
-/**
- * Extract the expiration timestamp (in milliseconds) from a JWT token.
- * @param accessToken The JWT access token
- * @returns The expiration timestamp in milliseconds, or 0 if invalid
- */
-export function extractJwtExpiresAt(accessToken: string): number {
-  const decoded = parseJwtBody(accessToken);
-  Eif (decoded && typeof decoded.exp === 'number') {
-    return decoded.exp * 1000; // JWT exp is in seconds, convert to milliseconds
-  }
-  return 0;
-}
- 
-/**
- * Check if the JWT token has the `berget_code_seat` role.
- * @param accessToken The JWT access token
- * @returns true if the token has the `berget_code_seat` role, false otherwise
- */
-export function hasBergetCodeSeat(accessToken: string): boolean {
-  const decoded = parseJwtBody(accessToken);
-  Iif (!decoded) return false;
-  const realmAccess = decoded.realm_access as Record<string, unknown> | undefined;
-  Iif (!realmAccess) return false;
-  const roles = realmAccess.roles as string[] | undefined;
-  Iif (!Array.isArray(roles)) return false;
-  return roles.includes('berget_code_seat');
-}
- 
-/**
- * Check if a token is expired with a configurable buffer.
- * Uses 10% of remaining lifetime or 30 seconds, whichever is smaller.
- * @param expiresAt The expiration timestamp in milliseconds
- * @returns true if expired or about to expire, false otherwise
- */
-export function isTokenExpired(expiresAt: number): boolean {
-  const now = Date.now();
-  const timeUntilExpiry = expiresAt - now;
-  const buffer = Math.min(30 * 1000, timeUntilExpiry * 0.1);
-  return now + buffer >= expiresAt;
-}
- 
-/**
- * Internal: split a JWT into its three parts and parse the payload JSON.
- */
-function parseJwtBody(token: string): null | Record<string, unknown> {
-  try {
-    const parts = token.split('.');
-    Iif (parts.length !== 3) return null;
-    const payload = Buffer.from(parts[1], 'base64url').toString('utf8');
-    return JSON.parse(payload);
-  } catch {
-    return null;
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/middleware/auth-middleware.ts.html b/coverage/src/auth/middleware/auth-middleware.ts.html deleted file mode 100644 index 12ff78e..0000000 --- a/coverage/src/auth/middleware/auth-middleware.ts.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - Code coverage report for src/auth/middleware/auth-middleware.ts - - - - - - - - - -
-
-

All files / src/auth/middleware auth-middleware.ts

-
- -
- 0% - Statements - 0/17 -
- - -
- 0% - Branches - 0/16 -
- - -
- 0% - Functions - 0/4 -
- - -
- 0% - Lines - 0/17 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import type { Middleware } from 'openapi-fetch';
- 
-import { FileTokenStore } from '../storage/token-store.js';
- 
-export function authMiddleware(options: {
-  getToken?: () => Promise<null | string>;
-  refresh?: () => Promise<boolean>;
-}): Middleware {
-  const getToken =
-    options.getToken ||
-    (async () => {
-      const store = new FileTokenStore();
-      const data = await store.get();
-      return data?.access_token || null;
-    });
- 
-  return {
-    async onRequest(req) {
-      const token = await getToken();
-      if (token && !req.headers.get('Authorization')) {
-        req.headers.set('Authorization', `Bearer ${token}`);
-      }
-      return req;
-    },
-    async onResponse(res, _options, req) {
-      if (res.status === 401 && options.refresh) {
-        const ok = await options.refresh();
-        if (ok) {
-          const newToken = await getToken();
-          if (newToken) {
-            req.headers.set('Authorization', `Bearer ${newToken}`);
-            return fetch(req);
-          }
-        }
-      }
-      return undefined; // no modification
-    },
-  };
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/middleware/index.html b/coverage/src/auth/middleware/index.html deleted file mode 100644 index b69284a..0000000 --- a/coverage/src/auth/middleware/index.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - Code coverage report for src/auth/middleware - - - - - - - - - -
-
-

All files src/auth/middleware

-
- -
- 0% - Statements - 0/17 -
- - -
- 0% - Branches - 0/16 -
- - -
- 0% - Functions - 0/4 -
- - -
- 0% - Lines - 0/17 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
auth-middleware.ts -
-
0%0/170%0/160%0/40%0/17
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/oauth/callback-pages.ts.html b/coverage/src/auth/oauth/callback-pages.ts.html deleted file mode 100644 index 2e5fb22..0000000 --- a/coverage/src/auth/oauth/callback-pages.ts.html +++ /dev/null @@ -1,472 +0,0 @@ - - - - - - Code coverage report for src/auth/oauth/callback-pages.ts - - - - - - - - - -
-
-

All files / src/auth/oauth callback-pages.ts

-
- -
- 0% - Statements - 0/5 -
- - -
- 100% - Branches - 0/0 -
- - -
- 0% - Functions - 0/3 -
- - -
- 0% - Lines - 0/5 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
/**
- * HTML callback pages for the OAuth PKCE browser flow.
- * Kept separate from pkce-flow.ts to keep the flow logic focused.
- */
- 
-export function getErrorPage(title: string, message: string): string {
-  const safeTitle = escapeHtml(title);
-  const safeMessage = escapeHtml(message);
-  return `<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Berget - Authentication Failed</title>
-    <style>
-      * { margin: 0; padding: 0; box-sizing: border-box; }
-      body {
-        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        min-height: 100vh;
-        background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%);
-        color: #fff;
-      }
-      .container {
-        text-align: center;
-        padding: 3rem;
-        max-width: 400px;
-      }
-      .icon {
-        width: 80px;
-        height: 80px;
-        background: linear-gradient(135deg, #f87171 0%, #ef4444 100%);
-        border-radius: 50%;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        margin: 0 auto 1.5rem;
-        box-shadow: 0 4px 20px rgba(248, 113, 113, 0.3);
-      }
-      .icon svg { width: 40px; height: 40px; stroke: #fff; stroke-width: 3; }
-      h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.75rem; color: #fff; }
-      p { color: #94a3b8; font-size: 0.95rem; line-height: 1.5; }
-      .brand { margin-top: 2rem; opacity: 0.5; font-size: 0.8rem; letter-spacing: 0.05em; }
-    </style>
-  </head>
-  <body>
-    <div class="container">
-      <div class="icon">
-        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
-          <line x1="18" y1="6" x2="6" y2="18"></line>
-          <line x1="6" y1="6" x2="18" y2="18"></line>
-        </svg>
-      </div>
-      <h1>${safeTitle}</h1>
-      <p>${safeMessage}</p>
-      <div class="brand">BERGET</div>
-    </div>
-  </body>
-</html>`;
-}
- 
-export function getSuccessPage(): string {
-  return `<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Berget - Authentication Successful</title>
-    <style>
-      * { margin: 0; padding: 0; box-sizing: border-box; }
-      body {
-        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        min-height: 100vh;
-        background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%);
-        color: #fff;
-      }
-      .container {
-        text-align: center;
-        padding: 3rem;
-        max-width: 400px;
-      }
-      .icon {
-        width: 80px;
-        height: 80px;
-        background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
-        border-radius: 50%;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        margin: 0 auto 1.5rem;
-        box-shadow: 0 4px 20px rgba(74, 222, 128, 0.3);
-      }
-      .icon svg { width: 40px; height: 40px; stroke: #fff; stroke-width: 3; }
-      h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.75rem; color: #fff; }
-      p { color: #94a3b8; font-size: 0.95rem; line-height: 1.5; }
-      .brand { margin-top: 2rem; opacity: 0.5; font-size: 0.8rem; letter-spacing: 0.05em; }
-    </style>
-  </head>
-  <body>
-    <div class="container">
-      <div class="icon">
-        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
-          <polyline points="20 6 9 17 4 12"></polyline>
-        </svg>
-      </div>
-      <h1>Authentication Successful</h1>
-      <p>You can close this window and return to your terminal.</p>
-      <div class="brand">BERGET</div>
-    </div>
-  </body>
-</html>`;
-}
- 
-/**
- * Escape HTML special characters to prevent XSS.
- */
-function escapeHtml(text: string): string {
-  return text
-    .replace(/&/g, '&amp;')
-    .replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;')
-    .replace(/"/g, '&quot;')
-    .replace(/'/g, '&#x27;');
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/oauth/index.html b/coverage/src/auth/oauth/index.html deleted file mode 100644 index fb8a7c9..0000000 --- a/coverage/src/auth/oauth/index.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - Code coverage report for src/auth/oauth - - - - - - - - - -
-
-

All files src/auth/oauth

-
- -
- 3.75% - Statements - 6/160 -
- - -
- 0% - Branches - 0/91 -
- - -
- 0% - Functions - 0/24 -
- - -
- 3.94% - Lines - 6/152 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
callback-pages.ts -
-
0%0/5100%0/00%0/30%0/5
pkce-flow.ts -
-
1.9%2/1050%0/560%0/151.98%2/101
token-refresh.ts -
-
8%4/500%0/350%0/68.69%4/46
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/oauth/pkce-flow.ts.html b/coverage/src/auth/oauth/pkce-flow.ts.html deleted file mode 100644 index 453b805..0000000 --- a/coverage/src/auth/oauth/pkce-flow.ts.html +++ /dev/null @@ -1,826 +0,0 @@ - - - - - - Code coverage report for src/auth/oauth/pkce-flow.ts - - - - - - - - - -
-
-

All files / src/auth/oauth pkce-flow.ts

-
- -
- 1.9% - Statements - 2/105 -
- - -
- 0% - Branches - 0/56 -
- - -
- 0% - Functions - 0/15 -
- - -
- 1.98% - Lines - 2/101 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import * as crypto from 'node:crypto';
-import * as http from 'node:http';
-import * as net from 'node:net';
-import {
-  authorizationCodeGrant,
-  buildAuthorizationUrl,
-  calculatePKCECodeChallenge,
-  type Configuration,
-  randomPKCECodeVerifier,
-  ResponseBodyError,
-} from 'openid-client';
- 
-import type { BrowserAuthResult } from '../types.js';
- 
-import { logger, LogLevel } from '../../utils/logger.js';
-import { getErrorPage, getSuccessPage } from './callback-pages.js';
- 
-const FALLBACK_CALLBACK_PORT = 8787;
-const AUTH_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
- 
-export interface PkceFlowOptions {
-  config: Configuration;
-  /** Injected http.createServer for testability */
-  createServer?: typeof http.createServer;
-  debug?: boolean;
-}
- 
-/**
- * Start the PKCE browser flow: spin up a callback server, open the browser,
- * and exchange the authorization code for tokens.
- */
-export async function startPkceFlow(options: PkceFlowOptions): Promise<BrowserAuthResult> {
-  const {
-    config,
-    createServer: createServerFactory = http.createServer,
-    debug: debugOption,
-  } = options;
-  const debug = debugOption || logger.getLogLevel() >= LogLevel.DEBUG;
- 
-  const codeVerifier = randomPKCECodeVerifier();
-  const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
-  const state = crypto.randomUUID();
- 
-  try {
-    const { port, server } = await startCallbackServer(createServerFactory);
-    const redirectUri = `http://127.0.0.1:${port}/callback`;
- 
-    if (debug) {
-      console.log(`Callback server listening on port ${port}`);
-    }
- 
-    // Build authorization URL using openid-client
-    const authorizationUrl = buildAuthorizationUrl(config, {
-      code_challenge: codeChallenge,
-      code_challenge_method: 'S256',
-      redirect_uri: redirectUri,
-      scope: 'openid email profile offline_access',
-      state,
-    });
- 
-    if (debug) {
-      logger.debug('Built authorization URL:', authorizationUrl.toString().split('?')[0] + '?...');
-    }
- 
-    // Create the callback handler promise
-    const authResult = await new Promise<{
-      callbackUrl?: string;
-      code?: string;
-      error?: string;
-      success: boolean;
-    }>((resolve) => {
-      let resolved = false;
-      const sockets = new Set<net.Socket>();
- 
-      const safeResolve = (result: {
-        callbackUrl?: string;
-        code?: string;
-        error?: string;
-        success: boolean;
-      }) => {
-        if (resolved) return;
-        resolved = true;
-        clearTimeout(timeoutHandle);
-        server.close();
-        for (const socket of sockets) {
-          socket.destroy();
-        }
-        sockets.clear();
-        resolve(result);
-      };
- 
-      server.on('request', (request, res) => {
-        const requestUrl = new URL(request.url || '', `http://127.0.0.1:${port}`);
- 
-        if (requestUrl.pathname !== '/callback') {
-          res.writeHead(404, { Connection: 'close' });
-          res.end();
-          return;
-        }
- 
-        const receivedState = requestUrl.searchParams.get('state') || '';
-        const code = requestUrl.searchParams.get('code') || '';
-        const error = requestUrl.searchParams.get('error') || '';
- 
-        if (error) {
-          const description = requestUrl.searchParams.get('error_description') || error;
-          if (debug) {
-            logger.debug(`Callback returned OAuth error: ${error} — ${description}`);
-          }
-          res.writeHead(400, { Connection: 'close', 'Content-Type': 'text/html; charset=utf-8' });
-          res.end(getErrorPage('Authentication Failed', description));
-          safeResolve({ error, success: false });
-          return;
-        }
- 
-        if (receivedState !== state) {
-          if (debug) {
-            logger.debug(`State mismatch: expected ${state}, got ${receivedState}`);
-          }
-          res.writeHead(403, { Connection: 'close', 'Content-Type': 'text/html; charset=utf-8' });
-          res.end(
-            getErrorPage('Authentication Failed', 'Invalid state parameter. Please try again.'),
-          );
-          safeResolve({ error: 'Invalid state parameter', success: false });
-          return;
-        }
- 
-        if (!code) {
-          res.writeHead(400, { Connection: 'close', 'Content-Type': 'text/html; charset=utf-8' });
-          res.end(getErrorPage('Authentication Failed', 'Missing authorization code.'));
-          safeResolve({ error: 'Missing authorization code', success: false });
-          return;
-        }
- 
-        res.writeHead(200, { Connection: 'close', 'Content-Type': 'text/html; charset=utf-8' });
-        res.end(getSuccessPage());
-        safeResolve({ callbackUrl: requestUrl.toString(), code, success: true });
-      });
- 
-      server.on('connection', (socket: net.Socket) => {
-        sockets.add(socket);
-        socket.on('close', () => sockets.delete(socket));
-      });
- 
-      const timeoutHandle = setTimeout(
-        () => safeResolve({ error: 'Authentication timed out', success: false }),
-        AUTH_TIMEOUT_MS,
-      );
- 
-      // Open browser
-      (async () => {
-        try {
-          const open = await import('open').then((m) => m.default);
-          await open(authorizationUrl.toString());
-        } catch (error) {
-          logger.debug('Failed to open browser:', error);
-          logger.info(`Please open this URL in your browser: ${authorizationUrl.toString()}`);
-        }
-      })();
-    });
- 
-    if (!authResult.success || !authResult.code || !authResult.callbackUrl) {
-      return {
-        error: authResult.error || 'Unknown error',
-        success: false,
-      };
-    }
- 
-    // Exchange code for tokens using the FULL callback URL (preserves iss, session_state, etc.)
-    const callbackUrl = new URL(authResult.callbackUrl);
- 
-    if (debug) {
-      logger.debug('Exchanging code for tokens at token endpoint');
-      logger.debug('Callback URL used for exchange:', callbackUrl.toString());
-    }
- 
-    try {
-      const tokenResult = await authorizationCodeGrant(config, callbackUrl, {
-        expectedState: state,
-        pkceCodeVerifier: codeVerifier,
-      });
- 
-      if (debug) {
-        logger.debug('Token exchange succeeded. Expires in:', tokenResult.expires_in);
-      }
- 
-      return {
-        accessToken: tokenResult.access_token,
-        expiresIn: tokenResult.expires_in,
-        refreshToken: tokenResult.refresh_token,
-        success: true,
-      };
-    } catch (tokenError) {
-      if (debug) {
-        logger.debug('Token exchange failed:', tokenError);
-        if (tokenError instanceof ResponseBodyError) {
-          logger.debug('ResponseBodyError details — status:', (tokenError as any).status);
-          logger.debug('ResponseBodyError details — response:', (tokenError as any).response);
-        }
-      }
-      throw tokenError;
-    }
-  } catch (error) {
-    return {
-      error: error instanceof Error ? error.message : String(error),
-      success: false,
-    };
-  }
-}
- 
-/**
- * Start a local HTTP callback server with port fallback.
- * Returns the bound port.
- */
-function startCallbackServer(
-  createServerFactory: typeof http.createServer,
-): Promise<{ port: number; server: http.Server }> {
-  return new Promise((resolve, reject) => {
-    // Do not pass a request handler here — the caller will attach it via
-    // server.on('request'). Passing a handler would cause double writes
-    // if the caller also uses server.on('request').
-    const server = createServerFactory();
- 
-    function attemptListen(port: number) {
-      server.once('error', (error: NodeJS.ErrnoException) => {
-        if (error.code === 'EADDRINUSE' && port === FALLBACK_CALLBACK_PORT) {
-          server.close(() => attemptListen(0));
-        } else {
-          reject(error);
-        }
-      });
- 
-      server.once('listening', () => {
-        const address = server.address();
-        if (address && typeof address === 'object') {
-          resolve({ port: address.port, server });
-        } else {
-          reject(new Error('Server address is not available'));
-        }
-      });
- 
-      server.listen(port, '127.0.0.1');
-    }
- 
-    attemptListen(FALLBACK_CALLBACK_PORT);
-  });
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/oauth/token-refresh.ts.html b/coverage/src/auth/oauth/token-refresh.ts.html deleted file mode 100644 index 3b15b51..0000000 --- a/coverage/src/auth/oauth/token-refresh.ts.html +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - Code coverage report for src/auth/oauth/token-refresh.ts - - - - - - - - - -
-
-

All files / src/auth/oauth token-refresh.ts

-
- -
- 8% - Statements - 4/50 -
- - -
- 0% - Branches - 0/35 -
- - -
- 0% - Functions - 0/6 -
- - -
- 8.69% - Lines - 4/46 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import type { Configuration } from 'openid-client';
- 
-import { refreshTokenGrant } from 'openid-client';
-import { ResponseBodyError } from 'openid-client';
- 
-import type { TokenStore } from '../storage/token-store.js';
-import type { TokenData } from '../types.js';
- 
-import { extractJwtExpiresAt } from '../jwt.js';
- 
-// Well-known transient network error codes. Retrying these is safe and
-// common, e.g. brief DNS failure, port temporarily unavailable.
-const TRANSIENT_ERROR_CODES = new Set([
-  'EAI_AGAIN',
-  'ECONNREFUSED',
-  'ECONNRESET',
-  'ENETUNREACH',
-  'ENOTFOUND',
-  'ETIMEDOUT',
-]);
- 
-const MAX_RETRIES = 3;
-const INITIAL_BACKOFF_MS = 200;
- 
-function isTransientError(error: unknown): boolean {
-  if (!(error instanceof Error)) return false;
-  const code = (error as NodeJS.ErrnoException).code;
-  if (code && TRANSIENT_ERROR_CODES.has(code)) return true;
-  return false;
-}
- 
-// In-flight refresh promises keyed by config, then by store.
-// This prevents two calls with the SAME config+store from duplicating,
-// while ensuring different stores don't share promises.
-const inFlightByConfig = new WeakMap<Configuration, Map<TokenStore, Promise<boolean>>>();
- 
-export async function refreshAccessToken(
-  config: Configuration,
-  tokenStore: TokenStore,
-): Promise<boolean> {
-  let storeMap = inFlightByConfig.get(config);
-  if (!storeMap) {
-    storeMap = new Map<TokenStore, Promise<boolean>>();
-    inFlightByConfig.set(config, storeMap);
-  }
- 
-  const existing = storeMap.get(tokenStore);
-  if (existing) {
-    return existing;
-  }
- 
-  const promise = doRefresh(config, tokenStore).finally(() => {
-    storeMap!.delete(tokenStore);
-  });
- 
-  storeMap.set(tokenStore, promise);
-  return promise;
-}
- 
-/**
- * Try to refresh the access token with exponential backoff on transient
- * network failures. Permanent auth errors clear stored tokens; transient
- * errors are retried up to MAX_RETRIES and never delete tokens.
- */
-async function doRefresh(config: Configuration, tokenStore: TokenStore): Promise<boolean> {
-  const tokenData = await tokenStore.get();
-  if (!tokenData?.refresh_token) return false;
- 
-  let attempt = 0;
- 
-  while (true) {
-    try {
-      const result = await refreshTokenGrant(config, tokenData.refresh_token);
- 
-      // Extract tokens from response
-      const accessToken = result.access_token;
-      const refreshToken = result.refresh_token || tokenData.refresh_token;
-      const expiresIn = result.expires_in || 3600;
- 
-      // Calculate expiration from JWT or fallback
-      const jwtExpiresAt = extractJwtExpiresAt(accessToken);
-      const expiresAt = jwtExpiresAt > 0 ? jwtExpiresAt : Date.now() + expiresIn * 1000;
- 
-      const newTokenData: TokenData = {
-        access_token: accessToken,
-        expires_at: expiresAt,
-        refresh_token: refreshToken,
-      };
- 
-      await tokenStore.set(newTokenData);
-      return true;
-    } catch (error) {
-      // On invalid/expired refresh token (401/403 from Keycloak), clear tokens.
-      // ResponseBodyError from openid-client carries structured error info.
-      if (error instanceof ResponseBodyError) {
-        if (error.error === 'invalid_grant' || error.status === 401 || error.status === 403) {
-          await tokenStore.clear();
-        }
-        return false;
-      }
- 
-      if (
-        error instanceof Error &&
-        (error.message.includes('401') ||
-          error.message.includes('403') ||
-          error.message.includes('invalid_grant'))
-      ) {
-        // Fallback for non-standard error shapes (e.g. network-level failures)
-        await tokenStore.clear();
-        return false;
-      }
- 
-      if (isTransientError(error) && attempt < MAX_RETRIES - 1) {
-        await sleep(INITIAL_BACKOFF_MS * 2 ** attempt);
-        attempt++;
-        continue;
-      }
- 
-      return false;
-    }
-  }
-}
- 
-function sleep(ms: number): Promise<void> {
-  return new Promise((resolve) => setTimeout(resolve, ms));
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/storage/index.html b/coverage/src/auth/storage/index.html deleted file mode 100644 index 5085700..0000000 --- a/coverage/src/auth/storage/index.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - Code coverage report for src/auth/storage - - - - - - - - - -
-
-

All files src/auth/storage

-
- -
- 0% - Statements - 0/24 -
- - -
- 0% - Branches - 0/11 -
- - -
- 0% - Functions - 0/5 -
- - -
- 0% - Lines - 0/24 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
token-store.ts -
-
0%0/240%0/110%0/50%0/24
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/auth/storage/token-store.ts.html b/coverage/src/auth/storage/token-store.ts.html deleted file mode 100644 index 4232d5b..0000000 --- a/coverage/src/auth/storage/token-store.ts.html +++ /dev/null @@ -1,328 +0,0 @@ - - - - - - Code coverage report for src/auth/storage/token-store.ts - - - - - - - - - -
-
-

All files / src/auth/storage token-store.ts

-
- -
- 0% - Statements - 0/24 -
- - -
- 0% - Branches - 0/11 -
- - -
- 0% - Functions - 0/5 -
- - -
- 0% - Lines - 0/24 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import * as fs from 'node:fs/promises';
-import * as os from 'node:os';
-import * as path from 'node:path';
- 
-import type { TokenData } from '../types.js';
- 
-import { logger } from '../../utils/logger.js';
- 
-export interface TokenStore {
-  clear(): Promise<void>;
-  get(): Promise<null | TokenData>;
-  set(data: TokenData): Promise<void>;
-}
- 
-export class FileTokenStore implements TokenStore {
-  private tokenFilePath: string;
- 
-  constructor(filePath?: string) {
-    this.tokenFilePath = filePath || getDefaultTokenFilePath();
-  }
- 
-  async clear(): Promise<void> {
-    try {
-      await fs.unlink(this.tokenFilePath);
-    } catch {
-      // ignore if file doesn't exist
-    }
-  }
- 
-  async get(): Promise<null | TokenData> {
-    let data: string | undefined;
-    try {
-      data = await fs.readFile(this.tokenFilePath, 'utf8');
-    } catch (error) {
-      const code = (error as NodeJS.ErrnoException).code;
-      if (code === 'ENOENT') {
-        return null; // Not logged in — expected
-      }
-      logger.warn(
-        `Could not read auth file (${code || 'unknown error'}). Run \`berget auth login\` to re-authenticate.`,
-        String(error),
-      );
-      return null;
-    }
- 
-    try {
-      const parsed = JSON.parse(data) as TokenData;
-      // Validate shape
-      if (
-        typeof parsed.access_token === 'string' &&
-        typeof parsed.refresh_token === 'string' &&
-        typeof parsed.expires_at === 'number'
-      ) {
-        return parsed;
-      }
-      return null;
-    } catch (error) {
-      logger.warn(
-        `Auth file appears corrupted. Run \`berget auth login\` to re-authenticate.`,
-        String(error),
-      );
-      return null;
-    }
-  }
- 
-  async set(data: TokenData): Promise<void> {
-    const bergetDir = path.dirname(this.tokenFilePath);
-    try {
-      await fs.mkdir(bergetDir, { recursive: true });
-    } catch {
-      // ignore
-    }
-    await fs.writeFile(this.tokenFilePath, JSON.stringify(data, null, 2));
-    await fs.chmod(this.tokenFilePath, 0o600);
-  }
-}
- 
-function getDefaultTokenFilePath(): string {
-  const bergetDir = path.join(os.homedir(), '.berget');
-  return path.join(bergetDir, 'auth.json');
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/client.ts.html b/coverage/src/client.ts.html deleted file mode 100644 index 0b94f5d..0000000 --- a/coverage/src/client.ts.html +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - Code coverage report for src/client.ts - - - - - - - - - -
-
-

All files / src client.ts

-
- -
- 0% - Statements - 0/11 -
- - -
- 0% - Branches - 0/2 -
- - -
- 0% - Functions - 0/3 -
- - -
- 0% - Lines - 0/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import createClient from 'openapi-fetch';
- 
-import type { paths } from './types/api.js';
- 
-import { getAuthConfig } from './auth/config.js';
-import { getConfiguration } from './auth/issuer.js';
-import { authMiddleware } from './auth/middleware/auth-middleware.js';
-import { refreshAccessToken } from './auth/oauth/token-refresh.js';
-import { FileTokenStore } from './auth/storage/token-store.js';
- 
-export function createAuthenticatedClient(options?: { local?: boolean; stage?: boolean }) {
-  const config = getAuthConfig(options);
-  const client = createClient<paths>({
-    baseUrl: config.apiBaseUrl,
-    headers: {
-      Accept: 'application/json',
-      'Content-Type': 'application/json',
-    },
-  });
- 
-  const tokenStore = new FileTokenStore();
- 
-  client.use(
-    authMiddleware({
-      getToken: async () => {
-        const data = await tokenStore.get();
-        return data?.access_token || null;
-      },
-      refresh: async () => {
-        try {
-          const configuration = await getConfiguration(config);
-          return await refreshAccessToken(configuration, tokenStore);
-        } catch {
-          return false;
-        }
-      },
-    }),
-  );
- 
-  return client;
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-api-key-service.ts.html b/coverage/src/commands/code/__tests__/fake-api-key-service.ts.html deleted file mode 100644 index 1b653f7..0000000 --- a/coverage/src/commands/code/__tests__/fake-api-key-service.ts.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - Code coverage report for src/commands/code/__tests__/fake-api-key-service.ts - - - - - - - - - -
-
-

All files / src/commands/code/__tests__ fake-api-key-service.ts

-
- -
- 83.33% - Statements - 5/6 -
- - -
- 75% - Branches - 3/4 -
- - -
- 100% - Functions - 2/2 -
- - -
- 83.33% - Lines - 5/6 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21  -  -  -  -  -  -  -  -46x -46x -46x -  -  -  -1x -  -  -1x -  -  - 
import type { ApiKeyServicePort } from '../ports/auth-services.js';
- 
-export class FakeApiKeyService implements ApiKeyServicePort {
-  private readonly _errorMessage: string;
-  private readonly _key: string;
-  private readonly _shouldFail: boolean;
- 
-  constructor(key: string, shouldFail = false, errorMessage = 'API key creation failed') {
-    this._key = key;
-    this._shouldFail = shouldFail;
-    this._errorMessage = errorMessage;
-  }
- 
-  async create(_options: { description?: string; name: string }): Promise<{ key: string }> {
-    Iif (this._shouldFail) {
-      throw new Error(this._errorMessage);
-    }
-    return { key: this._key };
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-auth-service.ts.html b/coverage/src/commands/code/__tests__/fake-auth-service.ts.html deleted file mode 100644 index 9cb1bee..0000000 --- a/coverage/src/commands/code/__tests__/fake-auth-service.ts.html +++ /dev/null @@ -1,241 +0,0 @@ - - - - - - Code coverage report for src/commands/code/__tests__/fake-auth-service.ts - - - - - - - - - -
-
-

All files / src/commands/code/__tests__ fake-auth-service.ts

-
- -
- 88.23% - Statements - 15/17 -
- - -
- 75% - Branches - 6/8 -
- - -
- 80% - Functions - 4/5 -
- - -
- 88.23% - Lines - 15/17 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53  -  -  -46x -46x -  -  -46x -46x -46x -  -  -  -  -  -  -  -  -  -  -44x -44x -43x -  -  -1x -  -1x -  -  -  -  -  -  -44x -  -  -  -  -  -  -  -  -  -2x -  -  -  -1x -1x -1x -  - 
import type { AuthServicePort } from '../ports/auth-services.js';
- 
-export class FakeAuthService implements AuthServicePort {
-  loginCallCount = 0;
-  loginInteractiveCallCount = 0;
- 
-  constructor(
-    private readonly _shouldSucceed: boolean,
-    private readonly _hasSeat: boolean = true,
-    private readonly _validToken: boolean = true,
-  ) {}
- 
-  async login(): Promise<boolean> {
-    this.loginCallCount++;
-    return this._shouldSucceed;
-  }
- 
-  loginInteractive(_options?: {
-    debug?: boolean;
-  }): ReturnType<AuthServicePort['loginInteractive']> {
-    this.loginInteractiveCallCount++;
-    if (!this._shouldSucceed) {
-      return Promise.resolve({ error: 'Login failed', success: false });
-    }
- 
-    const farFuture = Math.floor(Date.now() / 1000) + 3600 * 24 * 365; // 1 year from now in seconds
- 
-    const accessToken = this._validToken
-      ? makeJwt({
-          exp: farFuture,
-          realm_access: { roles: this._hasSeat ? ['berget_code_seat'] : ['default-roles-berget'] },
-        })
-      : 'invalid.token.here';
- 
-    return Promise.resolve({
-      accessToken,
-      expiresIn: 3600,
-      refreshToken: 'refresh',
-      success: true,
-    });
-  }
-}
- 
-function base64urlEncode(data: string): string {
-  return Buffer.from(data).toString('base64url');
-}
- 
-function makeJwt(payload: Record<string, unknown>): string {
-  const header = base64urlEncode(JSON.stringify({ alg: 'none', typ: 'JWT' }));
-  const body = base64urlEncode(JSON.stringify(payload));
-  return `${header}.${body}.signature`;
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-command-runner.ts.html b/coverage/src/commands/code/__tests__/fake-command-runner.ts.html deleted file mode 100644 index 548d376..0000000 --- a/coverage/src/commands/code/__tests__/fake-command-runner.ts.html +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - Code coverage report for src/commands/code/__tests__/fake-command-runner.ts - - - - - - - - - -
-
-

All files / src/commands/code/__tests__ fake-command-runner.ts

-
- -
- 90.47% - Statements - 19/21 -
- - -
- 70% - Branches - 7/10 -
- - -
- 100% - Functions - 7/7 -
- - -
- 93.75% - Lines - 15/16 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51  -  -  -  -  -  -  -  -  -3x -  -36x -  -36x -  -  -34x -34x -  -  -  -61x -  -53x -53x -  -  -  -  -61x -  -  -  -  -  -  -  -12x -24x -12x -  -  -12x -  -  -  -12x -10x -  -  - 
import type { CommandRunner } from '../ports/command-runner.js';
- 
-type Handler = {
-  match: (command: string, arguments_: readonly string[]) => boolean;
-  response: ((command: string, arguments_: readonly string[]) => Error | string) | Error | string;
-};
- 
-export class FakeCommandRunner implements CommandRunner {
-  get calls() {
-    return this._calls;
-  }
-  private _calls: Array<{ args: string[]; command: string; options?: { cwd?: string } }> = [];
- 
-  private handlers: Handler[] = [];
- 
-  checkInstalled(binary: string): Promise<boolean> {
-    this._calls.push({ args: [], command: `check:${binary}` });
-    return Promise.resolve(this.handlers.some((h) => h.match(binary, ['--version'])) || false);
-  }
- 
-  handle(match: RegExp | string, response: Error | string): this {
-    this.handlers.push({
-      match: (cmd, arguments_) => {
-        const full = `${cmd} ${arguments_.join(' ')}`;
-        Eif (typeof match === 'string') return full.startsWith(match);
-        return match.test(full);
-      },
-      response,
-    });
-    return this;
-  }
- 
-  async run(
-    command: string,
-    arguments_: readonly string[],
-    options?: { cwd?: string },
-  ): Promise<string> {
-    this._calls.push({ args: [...arguments_], command, options });
-    const handler = this.handlers.find((h) => h.match(command, arguments_));
-    Iif (!handler) throw new Error(`Unexpected command: ${command} ${arguments_.join(' ')}`);
- 
-    const result =
-      typeof handler.response === 'function'
-        ? handler.response(command, arguments_)
-        : handler.response;
- 
-    if (result instanceof Error) throw result;
-    return result;
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-file-store.ts.html b/coverage/src/commands/code/__tests__/fake-file-store.ts.html deleted file mode 100644 index c3d925b..0000000 --- a/coverage/src/commands/code/__tests__/fake-file-store.ts.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - Code coverage report for src/commands/code/__tests__/fake-file-store.ts - - - - - - - - - -
-
-

All files / src/commands/code/__tests__ fake-file-store.ts

-
- -
- 90.9% - Statements - 10/11 -
- - -
- 100% - Branches - 4/4 -
- - -
- 87.5% - Functions - 7/8 -
- - -
- 90.9% - Lines - 10/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45  -  -  -  -  -  -  -  -45x -45x -45x -  -  -3x -  -  -  -145x -  -  -  -  -  -  -  -24x -  -  -  -12x -  -  -  -390x -  -  -  -8x -  -  -  -44x -  -  - 
import type { FileStore } from '../ports/file-store.js';
- 
-export interface FileEntry {
-  content: string;
-  isDirectory?: boolean;
-}
- 
-export class FakeFileStore implements FileStore {
-  private _chmodCalls: Array<{ mode: number; path: string }> = [];
-  private dirs: Set<string> = new Set();
-  private files: Map<string, string> = new Map();
- 
-  async chmod(path: string, mode: number): Promise<void> {
-    this._chmodCalls.push({ mode, path });
-  }
- 
-  async exists(path: string): Promise<boolean> {
-    return this.files.has(path) || this.dirs.has(path);
-  }
- 
-  getChmodCalls(): Array<{ mode: number; path: string }> {
-    return this._chmodCalls;
-  }
- 
-  getWrittenFiles(): Map<string, string> {
-    return new Map(this.files);
-  }
- 
-  async mkdir(path: string): Promise<void> {
-    this.dirs.add(path);
-  }
- 
-  async readFile(path: string): Promise<null | string> {
-    return this.files.get(path) ?? null;
-  }
- 
-  seed(path: string, content: string): void {
-    this.files.set(path, content);
-  }
- 
-  async writeFile(path: string, content: string): Promise<void> {
-    this.files.set(path, content);
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/fake-prompter.ts.html b/coverage/src/commands/code/__tests__/fake-prompter.ts.html deleted file mode 100644 index 5323dfa..0000000 --- a/coverage/src/commands/code/__tests__/fake-prompter.ts.html +++ /dev/null @@ -1,502 +0,0 @@ - - - - - - Code coverage report for src/commands/code/__tests__/fake-prompter.ts - - - - - - - - - -
-
-

All files / src/commands/code/__tests__ fake-prompter.ts

-
- -
- 56.94% - Statements - 41/72 -
- - -
- 44.44% - Branches - 24/54 -
- - -
- 68.18% - Functions - 15/22 -
- - -
- 60.65% - Lines - 37/61 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140  -  -  -  -1x -  -  -  -  -  -  -  -105x -  -  -  -  -  -1x -  -  -  -  -  -42x -  -  -  -  -  -18x -  -  -  -  -  -  -  -5x -  -46x -  -46x -  -46x -  -  -  -  -  -  -  -  -  -42x -42x -42x -  -42x -  -42x -  -42x -42x -  -  -46x -  -  -  -36x -  -  -  -18x -18x -18x -  -18x -  -18x -  -18x -18x -  -  -  -238x -  -  -  -31x -  -  -  -105x -105x -105x -105x -  -105x -  -105x -103x -  -  -  -87x -  -87x -  -  -87x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import type { Prompter, Spinner, TaskItem } from '../ports/prompter.js';
- 
-import { CancelledError } from '../errors.js';
- 
-export const CANCEL = Symbol('cancel');
- 
-type PromptEntry =
-  | { kind: 'confirm'; match?: RegExp; response: boolean | symbol }
-  | { kind: 'multiselect'; match?: RegExp; response: (string | symbol)[] }
-  | { kind: 'select'; match?: RegExp; response: string | symbol }
-  | { kind: 'text'; match?: RegExp; response: string | symbol };
- 
-export const select = <T>(value: symbol | T, match?: RegExp | string): PromptEntry => ({
-  kind: 'select',
-  match: typeof match === 'string' ? new RegExp(match) : match,
-  response: typeof value === 'symbol' ? value : String(value),
-});
- 
-export const text = (value: string | symbol, match?: RegExp | string): PromptEntry => ({
-  kind: 'text',
-  match: typeof match === 'string' ? new RegExp(match) : match,
-  response: value,
-});
- 
-export const confirm = (value: boolean | symbol, match?: RegExp | string): PromptEntry => ({
-  kind: 'confirm',
-  match: typeof match === 'string' ? new RegExp(match) : match,
-  response: value,
-});
- 
-export const multiselect = <T>(values: symbol | T[], match?: RegExp | string): PromptEntry => ({
-  kind: 'multiselect',
-  match: typeof match === 'string' ? new RegExp(match) : match,
-  response: values === CANCEL ? [CANCEL] : ((values as T[]).map(String) as (string | symbol)[]),
-});
- 
-export class FakePrompter implements Prompter {
-  get calls() {
-    return this._calls;
-  }
-  private _calls: Array<{ args: unknown; method: string }> = [];
- 
-  private _cursor = 0;
- 
-  constructor(private readonly _script: PromptEntry[]) {}
-  assertExhausted() {
-    if (this._cursor !== this._script.length) {
-      throw new Error(`Script not exhausted: ${this._script.length - this._cursor} entries left`);
-    }
-  }
-  cancel(message: string): void {
-    this._calls.push({ args: { message }, method: 'cancel' });
-  }
-  async confirm(options: { message: string }): Promise<boolean> {
-    this._calls.push({ args: options, method: 'confirm' });
-    const entry = this._script[this._cursor++];
-    Iif (!entry)
-      throw new Error(`No script entry for confirm #${this._cursor} (${options.message})`);
-    Iif (entry.kind !== 'confirm')
-      throw new Error(`Expected confirm, got ${entry.kind} for ${options.message}`);
-    Iif (entry.match && !entry.match.test(options.message))
-      throw new Error(`Message mismatch: got "${options.message}"`);
-    Iif (entry.response === CANCEL) throw new CancelledError();
-    return entry.response as boolean;
-  }
-  intro(message: string): void {
-    this._calls.push({ args: { message }, method: 'intro' });
-  }
- 
-  log(type: string, message: string): void {
-    this._calls.push({ args: { message, type }, method: 'log' });
-  }
- 
-  async multiselect<T>(options: { message: string }): Promise<T[]> {
-    this._calls.push({ args: options, method: 'multiselect' });
-    const entry = this._script[this._cursor++];
-    Iif (!entry)
-      throw new Error(`No script entry for multiselect #${this._cursor} (${options.message})`);
-    Iif (entry.kind !== 'multiselect')
-      throw new Error(`Expected multiselect, got ${entry.kind} for ${options.message}`);
-    Iif (entry.match && !entry.match.test(options.message))
-      throw new Error(`Message mismatch: got "${options.message}"`);
-    Iif (entry.response.includes(CANCEL)) throw new CancelledError();
-    return entry.response as T[];
-  }
- 
-  note(message: string, title?: string): void {
-    this._calls.push({ args: { message, title }, method: 'note' });
-  }
- 
-  outro(message: string): void {
-    this._calls.push({ args: { message }, method: 'outro' });
-  }
- 
-  async select<T>(options: { initialValue?: T; message: string }): Promise<T> {
-    this._calls.push({ args: options, method: 'select' });
-    const entry = this._script[this._cursor++];
-    Iif (!entry) throw new Error(`No script entry for select #${this._cursor} (${options.message})`);
-    Iif (entry.kind !== 'select')
-      throw new Error(`Expected select, got ${entry.kind} for ${options.message}`);
-    Iif (entry.match && !entry.match.test(options.message))
-      throw new Error(`Message mismatch: got "${options.message}"`);
-    if (entry.response === CANCEL) throw new CancelledError();
-    return entry.response as T;
-  }
- 
-  spinner(): Spinner {
-    return {
-      start: (message: string) => {
-        this._calls.push({ args: { message: message }, method: 'spinner.start' });
-      },
-      stop: (message: string) => {
-        this._calls.push({ args: { message: message }, method: 'spinner.stop' });
-      },
-    };
-  }
- 
-  async tasks(items: ReadonlyArray<TaskItem>): Promise<void> {
-    this._calls.push({ args: { items: items.map((i) => i.title) }, method: 'tasks' });
-    for (const item of items) {
-      const noop = (_msg: string) => {
-        // no-op in tests
-      };
-      await item.task(noop);
-    }
-  }
- 
-  async text(options: { message: string }): Promise<string> {
-    this._calls.push({ args: options, method: 'text' });
-    const entry = this._script[this._cursor++];
-    if (!entry) throw new Error(`No script entry for text #${this._cursor} (${options.message})`);
-    if (entry.kind !== 'text')
-      throw new Error(`Expected text, got ${entry.kind} for ${options.message}`);
-    if (entry.match && !entry.match.test(options.message))
-      throw new Error(`Message mismatch: got "${options.message}"`);
-    if (entry.response === CANCEL) throw new CancelledError();
-    return entry.response as string;
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/__tests__/index.html b/coverage/src/commands/code/__tests__/index.html deleted file mode 100644 index f655719..0000000 --- a/coverage/src/commands/code/__tests__/index.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - Code coverage report for src/commands/code/__tests__ - - - - - - - - - -
-
-

All files src/commands/code/__tests__

-
- -
- 70.86% - Statements - 90/127 -
- - -
- 55% - Branches - 44/80 -
- - -
- 79.54% - Functions - 35/44 -
- - -
- 73.87% - Lines - 82/111 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
fake-api-key-service.ts -
-
83.33%5/675%3/4100%2/283.33%5/6
fake-auth-service.ts -
-
88.23%15/1775%6/880%4/588.23%15/17
fake-command-runner.ts -
-
90.47%19/2170%7/10100%7/793.75%15/16
fake-file-store.ts -
-
90.9%10/11100%4/487.5%7/890.9%10/11
fake-prompter.ts -
-
56.94%41/7244.44%24/5468.18%15/2260.65%37/61
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/adapters/clack-prompter.ts.html b/coverage/src/commands/code/adapters/clack-prompter.ts.html deleted file mode 100644 index a5d97cd..0000000 --- a/coverage/src/commands/code/adapters/clack-prompter.ts.html +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - Code coverage report for src/commands/code/adapters/clack-prompter.ts - - - - - - - - - -
-
-

All files / src/commands/code/adapters clack-prompter.ts

-
- -
- 4.76% - Statements - 1/21 -
- - -
- 0% - Branches - 0/4 -
- - -
- 0% - Functions - 0/16 -
- - -
- 5% - Lines - 1/20 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import * as p from '@clack/prompts';
- 
-import type { Prompter, Spinner, TaskItem } from '../ports/prompter.js';
- 
-import { CancelledError } from '../errors.js';
- 
-const unwrap = <T>(v: symbol | T): T => {
-  if (p.isCancel(v)) throw new CancelledError();
-  return v as T;
-};
- 
-export class ClackPrompter implements Prompter {
-  cancel(message: string): void {
-    p.cancel(message);
-  }
-  async confirm(options: { initialValue?: boolean; message: string }): Promise<boolean> {
-    return unwrap(await p.confirm(options));
-  }
-  intro(message: string): void {
-    p.intro(message);
-  }
-  log(type: 'error' | 'info' | 'message' | 'step' | 'success' | 'warn', message: string): void {
-    p.log[type](message);
-  }
-  async multiselect<T>(options: {
-    message: string;
-    options: ReadonlyArray<{
-      hint?: string;
-      label: string;
-      value: T;
-    }>;
-  }): Promise<T[]> {
-    return unwrap(await p.multiselect(options as any));
-  }
-  note(message: string, title?: string): void {
-    p.note(message, title);
-  }
-  outro(message: string): void {
-    p.outro(message);
-  }
- 
-  async select<T>(options: {
-    initialValue?: T;
-    message: string;
-    options: ReadonlyArray<{
-      hint?: string;
-      label: string;
-      value: T;
-    }>;
-  }): Promise<T> {
-    return unwrap(await p.select(options as any));
-  }
- 
-  spinner(): Spinner {
-    const s = p.spinner();
-    return {
-      start: (message: string) => s.start(message),
-      stop: (message: string) => s.stop(message),
-    };
-  }
- 
-  async tasks(items: ReadonlyArray<TaskItem>): Promise<void> {
-    await p.tasks(
-      items.map((item) => ({
-        task: async (message: (msg: string) => void) => {
-          const result = await item.task(message);
-          return result ?? item.title;
-        },
-        title: item.title,
-      })),
-    );
-  }
- 
-  async text(options: { message: string; placeholder?: string }): Promise<string> {
-    return unwrap(await p.text(options));
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/adapters/fs-file-store.ts.html b/coverage/src/commands/code/adapters/fs-file-store.ts.html deleted file mode 100644 index 2b5eb30..0000000 --- a/coverage/src/commands/code/adapters/fs-file-store.ts.html +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - Code coverage report for src/commands/code/adapters/fs-file-store.ts - - - - - - - - - -
-
-

All files / src/commands/code/adapters fs-file-store.ts

-
- -
- 0% - Statements - 0/14 -
- - -
- 0% - Branches - 0/2 -
- - -
- 0% - Functions - 0/5 -
- - -
- 0% - Lines - 0/13 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { promises as fs } from 'node:fs';
-import * as path from 'node:path';
- 
-import type { FileStore } from '../ports/file-store.js';
- 
-export class FsFileStore implements FileStore {
-  async chmod(filePath: string, mode: number): Promise<void> {
-    await fs.chmod(filePath, mode);
-  }
- 
-  async exists(filePath: string): Promise<boolean> {
-    try {
-      await fs.access(filePath);
-      return true;
-    } catch {
-      return false;
-    }
-  }
- 
-  async mkdir(dir: string): Promise<void> {
-    await fs.mkdir(dir, { recursive: true });
-  }
- 
-  async readFile(filePath: string): Promise<null | string> {
-    try {
-      return await fs.readFile(filePath, 'utf8');
-    } catch (error: any) {
-      if (error.code === 'ENOENT') return null;
-      throw error;
-    }
-  }
- 
-  async writeFile(filePath: string, content: string): Promise<void> {
-    const dir = path.dirname(filePath);
-    await fs.mkdir(dir, { recursive: true });
-    await fs.writeFile(filePath, content, 'utf8');
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/adapters/index.html b/coverage/src/commands/code/adapters/index.html deleted file mode 100644 index 04f712b..0000000 --- a/coverage/src/commands/code/adapters/index.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - Code coverage report for src/commands/code/adapters - - - - - - - - - -
-
-

All files src/commands/code/adapters

-
- -
- 1.81% - Statements - 1/55 -
- - -
- 0% - Branches - 0/12 -
- - -
- 0% - Functions - 0/31 -
- - -
- 2% - Lines - 1/50 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
clack-prompter.ts -
-
4.76%1/210%0/40%0/165%1/20
fs-file-store.ts -
-
0%0/140%0/20%0/50%0/13
spawn-command-runner.ts -
-
0%0/200%0/60%0/100%0/17
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/adapters/spawn-command-runner.ts.html b/coverage/src/commands/code/adapters/spawn-command-runner.ts.html deleted file mode 100644 index d40d221..0000000 --- a/coverage/src/commands/code/adapters/spawn-command-runner.ts.html +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - Code coverage report for src/commands/code/adapters/spawn-command-runner.ts - - - - - - - - - -
-
-

All files / src/commands/code/adapters spawn-command-runner.ts

-
- -
- 0% - Statements - 0/20 -
- - -
- 0% - Branches - 0/6 -
- - -
- 0% - Functions - 0/10 -
- - -
- 0% - Lines - 0/17 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { spawn } from 'node:child_process';
- 
-import type { CommandRunner } from '../ports/command-runner.js';
- 
-export class SpawnCommandRunner implements CommandRunner {
-  async checkInstalled(binary: string): Promise<boolean> {
-    return new Promise((resolve) => {
-      const child = spawn('which', [binary], { stdio: 'pipe' });
-      child.on('close', (code) => resolve(code === 0));
-      child.on('error', () => resolve(false));
-    });
-  }
- 
-  async run(
-    command: string,
-    arguments_: readonly string[],
-    options?: { cwd?: string },
-  ): Promise<string> {
-    return new Promise<string>((resolve, reject) => {
-      const child = spawn(command, arguments_ as string[], {
-        cwd: options?.cwd || process.cwd(),
-        stdio: 'pipe',
-      });
- 
-      let stdout = '';
-      let stderr = '';
- 
-      child.stdout?.on('data', (d) => {
-        stdout += d.toString();
-      });
-      child.stderr?.on('data', (d) => {
-        stderr += d.toString();
-      });
- 
-      child.on('close', (code) => {
-        if (code === 0) {
-          resolve(stdout);
-        } else {
-          reject(new Error(stderr.trim() || `Command failed with exit code ${code}`));
-        }
-      });
-      child.on('error', (error) => reject(error));
-    });
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/auth-sync.ts.html b/coverage/src/commands/code/auth-sync.ts.html deleted file mode 100644 index 0f9686a..0000000 --- a/coverage/src/commands/code/auth-sync.ts.html +++ /dev/null @@ -1,1066 +0,0 @@ - - - - - - Code coverage report for src/commands/code/auth-sync.ts - - - - - - - - - -
-
-

All files / src/commands/code auth-sync.ts

-
- -
- 68.59% - Statements - 83/121 -
- - -
- 65.38% - Branches - 34/52 -
- - -
- 100% - Functions - 9/9 -
- - -
- 67.79% - Lines - 80/118 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -46x -  -1x -24x -15x -  -  -1x -  -  -  -  -  -  -  -  -  -36x -  -36x -  -36x -1x -  -  -  -  -  -  -  -1x -1x -  -  -35x -3x -  -  -35x -32x -  -  -  -3x -  -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -  -3x -  -2x -  -  -  -  -  -  -  -2x -2x -2x -2x -2x -2x -  -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -1x -1x -1x -1x -1x -  -  -  -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -46x -  -46x -  -46x -2x -  -  -44x -  -44x -44x -  -44x -  -  -44x -43x -43x -  -  -  -43x -  -  -1x -  -1x -1x -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -36x -36x -1x -1x -1x -  -  -  -  -  -  -46x -46x -  -2x -2x -  -  -  -  -  -  -  -2x -  -2x -2x -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -  -1x -1x -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -2x -2x -  -2x -2x -  -  -  -  -  -  -  -  -2x -  -2x -  -  -  -  -  -  -  -  -  -2x -2x -  - 
import type { ApiKeyServicePort, AuthServicePort } from './ports/auth-services.js';
-import type { FileStore } from './ports/file-store.js';
-import type { Prompter } from './ports/prompter.js';
- 
-import {
-  decodeJwtPayload,
-  extractJwtExpiresAt,
-  hasBergetCodeSeat,
-  isTokenExpired,
-} from '../../auth/jwt.js';
-import { logger } from '../../utils/logger.js';
-import { FatalError } from './errors.js';
- 
-export interface AuthDeps {
-  apiKeyService: ApiKeyServicePort;
-  authService: AuthServicePort;
-  files: FileStore;
-  homeDir: string;
-  prompter: Prompter;
-}
- 
-export interface AuthResult {
-  authenticated: boolean;
-}
- 
-export interface CliAuth {
-  access_token: string;
-  expires_at: number;
-  refresh_token: string;
-}
- 
-const CLI_AUTH_PATH = (homeDir: string) => homeDir + '/.berget/auth.json';
- 
-const TOOL_AUTH_PATHS = {
-  opencode: (homeDir: string) => homeDir + '/.local/share/opencode/auth.json',
-  pi: (homeDir: string) => homeDir + '/.pi/agent/auth.json',
-} as const;
- 
-const TOOL_API_KEY_TYPES: Record<'opencode' | 'pi', string> = {
-  opencode: 'api',
-  pi: 'api_key',
-};
- 
-export async function configureAuth(
-  deps: Pick<AuthDeps, 'apiKeyService' | 'files' | 'homeDir' | 'prompter'>,
-  tool: 'opencode' | 'pi',
-  cliAuth: CliAuth | null,
-): Promise<AuthResult> {
-  const { apiKeyService, files, homeDir, prompter } = deps;
- 
-  const alreadyAuth = await isToolAuthenticated(files, homeDir, tool);
- 
-  if (alreadyAuth) {
-    const choice = await prompter.select<'keep' | 'reconfigure'>({
-      message: `Account is already connected to Berget AI (${tool === 'opencode' ? 'OpenCode' : 'Pi'}). How do you want to proceed?`,
-      options: [
-        { label: 'Keep existing authentication', value: 'keep' },
-        { label: 'Reconfigure — choose a different method', value: 'reconfigure' },
-      ],
-    });
- 
-    Eif (choice === 'keep') {
-      return { authenticated: true };
-    }
-    // Fall through to reconfigure
-  } else if (cliAuth !== null) {
-    prompter.note('Authentication required to use Berget AI.', 'Connect your account');
-  }
- 
-  if (cliAuth === null) {
-    return { authenticated: false };
-  }
- 
-  // Check Berget Code seat
-  const jwtPayload = decodeJwtPayload(cliAuth.access_token);
- 
-  // If we can't decode the JWT, sync OAuth anyway — the tokens are valid even if
-  // we can't verify the subscription role. Let the tool handle authorization.
-  Iif (!jwtPayload) {
-    const s = prompter.spinner();
-    s.start('Authenticating with Berget AI...');
-    try {
-      await syncOAuthToTool(files, homeDir, tool, cliAuth);
-      s.stop('Authenticated.');
-    } catch (error) {
-      s.stop('Authentication failed.');
-      throw error;
-    }
-    prompter.note(
-      'Warning: Could not verify Berget Code subscription status.\nIf you do not have a subscription, the tool may show an authorization error.',
-      'Authentication',
-    );
-    return { authenticated: true };
-  }
- 
-  // JWT decoded successfully — check subscription seat
-  const hasSeat = hasBergetCodeSeat(cliAuth.access_token);
- 
-  if (hasSeat) {
-    // Case B: Has seat — ask how to authenticate
-    const method = await prompter.select<'api_key' | 'subscription'>({
-      message: 'You have a Berget Code subscription. How do you want to authenticate?',
-      options: [
-        { label: 'Use my Berget Code subscription', value: 'subscription' },
-        { label: 'Use an API key instead', value: 'api_key' },
-      ],
-    });
- 
-    Eif (method === 'subscription') {
-      const s = prompter.spinner();
-      s.start('Authenticating with Berget AI via subscription...');
-      try {
-        await syncOAuthToTool(files, homeDir, tool, cliAuth);
-        s.stop('Authenticated.');
-      } catch (error) {
-        s.stop('Authentication failed.');
-        throw error;
-      }
-      return { authenticated: true };
-    }
- 
-    // Create API key instead
-    const s = prompter.spinner();
-    s.start('Creating API key...');
-    try {
-      const { key } = await apiKeyService.create({
-        description: 'Created by berget code init',
-        name: `${tool === 'opencode' ? 'OpenCode' : 'Pi'} (created by berget CLI)`,
-      });
-      await syncApiKeyToTool(files, homeDir, tool, key);
-      s.stop('API key created and saved.');
-      return { authenticated: true };
-    } catch (error: any) {
-      s.stop('API key creation failed.');
-      throw new FatalError(
-        error?.message ||
-          'Could not create API key. Please create one manually with `berget api-keys create`.',
-      );
-    }
-  }
- 
-  // No Berget Code seat — prompt for API key creation
-  const shouldCreate = await prompter.confirm({
-    initialValue: true,
-    message: 'You do not have a Berget Code subscription. Would you like to create a new API key?',
-  });
- 
-  Eif (shouldCreate) {
-    const s = prompter.spinner();
-    s.start('Creating API key...');
-    try {
-      const { key } = await apiKeyService.create({
-        description: 'Created by berget code init',
-        name: `${tool === 'opencode' ? 'OpenCode' : 'Pi'} (created by berget CLI)`,
-      });
-      await syncApiKeyToTool(files, homeDir, tool, key);
-      s.stop('API key created and saved.');
-      return { authenticated: true };
-    } catch (error: any) {
-      s.stop('API key creation failed.');
-      throw new FatalError(
-        error?.message ||
-          'Could not create API key. Please create one manually with `berget api-keys create`.',
-      );
-    }
-  }
- 
-  // Case D: Declined
-  prompter.note(
-    'Authentication skipped. You\'ll need to set up authentication manually:\n1. Run: berget api-keys create --name "My Key"\n2. Set BERGET_API_KEY environment variable, or\n3. Run `berget auth login` and try again',
-    'Authentication',
-  );
-  return { authenticated: false };
-}
- 
-export async function ensureCliAuth(
-  deps: Pick<AuthDeps, 'authService' | 'files' | 'homeDir' | 'prompter'>,
-): Promise<CliAuth | null> {
-  const { authService, files, homeDir, prompter } = deps;
- 
-  const cliAuth: CliAuth | null = await readCliAuth(files, homeDir);
- 
-  if (cliAuth && !isTokenExpired(cliAuth.expires_at)) {
-    return cliAuth;
-  }
- 
-  prompter.note('Authentication required to use Berget AI.', 'Connect your account');
- 
-  const s = prompter.spinner();
-  s.start('Waiting for browser login...');
- 
-  const loginResult = await authService.loginInteractive({
-    debug: process.env.LOG_LEVEL === 'debug',
-  });
-  if (!loginResult.success) {
-    s.stop('Login failed.');
-    prompter.note(
-      `${loginResult.error || 'Login timed out or was cancelled.'}\n\nPlease run \`berget auth login\` manually, then run \`berget code init\` again.`,
-      'Authentication Failed',
-    );
-    return null;
-  }
- 
-  s.stop('Successfully logged in to Berget.');
- 
-  const jwtExpiresAt = extractJwtExpiresAt(loginResult.accessToken!);
-  Iif (jwtExpiresAt === 0) {
-    s.stop('Login succeeded but received invalid token.');
-    prompter.note('Please try logging in again or contact support.', 'Authentication Error');
-    return null;
-  }
- 
-  return {
-    access_token: loginResult.accessToken!,
-    expires_at: jwtExpiresAt,
-    refresh_token: loginResult.refreshToken!,
-  };
-}
- 
-export async function isToolAuthenticated(
-  files: FileStore,
-  homeDir: string,
-  tool: 'opencode' | 'pi',
-): Promise<boolean> {
-  const content = await files.readFile(TOOL_AUTH_PATHS[tool](homeDir));
-  if (!content) return false;
-  try {
-    const parsed = JSON.parse(content);
-    return typeof parsed.berget === 'object' && parsed.berget !== null;
-  } catch {
-    return false;
-  }
-}
- 
-export async function readCliAuth(files: FileStore, homeDir: string): Promise<CliAuth | null> {
-  const content = await files.readFile(CLI_AUTH_PATH(homeDir));
-  if (!content) return null;
-  let parsed: any;
-  try {
-    parsed = JSON.parse(content);
-  } catch (error) {
-    logger.warn(
-      `CLI auth file appears corrupted. Run \`berget auth login\` to re-authenticate.`,
-      String(error),
-    );
-    return null;
-  }
-  Eif (parsed.access_token && parsed.refresh_token) {
-    // Extract the actual expiry time from the JWT token instead of using the stored expires_at
-    const jwtExpiresAt = extractJwtExpiresAt(parsed.access_token);
-    Iif (jwtExpiresAt === 0) {
-      // Invalid token, return null
-      return null;
-    }
-    return {
-      access_token: parsed.access_token,
-      expires_at: jwtExpiresAt,
-      refresh_token: parsed.refresh_token,
-    };
-  }
-  return null;
-}
- 
-export async function syncApiKeyToTool(
-  files: FileStore,
-  homeDir: string,
-  tool: 'opencode' | 'pi',
-  apiKey: string,
-): Promise<void> {
-  const authPath = TOOL_AUTH_PATHS[tool](homeDir);
-  let existing: Record<string, unknown> = {};
- 
-  const content = await files.readFile(authPath);
-  Iif (content) {
-    try {
-      existing = JSON.parse(content) as Record<string, unknown>;
-    } catch {
-      existing = {};
-    }
-  }
- 
-  const updated = {
-    ...existing,
-    berget: {
-      key: apiKey,
-      type: TOOL_API_KEY_TYPES[tool],
-    },
-  };
- 
-  await files.writeFile(authPath, JSON.stringify(updated, null, 2) + '\n');
-  await files.chmod(authPath, 0o600);
-}
- 
-export async function syncOAuthToTool(
-  files: FileStore,
-  homeDir: string,
-  tool: 'opencode' | 'pi',
-  cliAuth: CliAuth,
-): Promise<void> {
-  const authPath = TOOL_AUTH_PATHS[tool](homeDir);
-  let existing: Record<string, unknown> = {};
- 
-  const content = await files.readFile(authPath);
-  Iif (content) {
-    try {
-      existing = JSON.parse(content) as Record<string, unknown>;
-    } catch {
-      existing = {};
-    }
-  }
- 
-  // Use the JWT's actual expiry time for consistency
-  const jwtExpiresAt = extractJwtExpiresAt(cliAuth.access_token);
- 
-  const updated = {
-    ...existing,
-    berget: {
-      access: cliAuth.access_token,
-      expires: jwtExpiresAt,
-      refresh: cliAuth.refresh_token,
-      type: 'oauth',
-    },
-  };
- 
-  await files.writeFile(authPath, JSON.stringify(updated, null, 2) + '\n');
-  await files.chmod(authPath, 0o600);
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/errors.ts.html b/coverage/src/commands/code/errors.ts.html deleted file mode 100644 index 7017a2e..0000000 --- a/coverage/src/commands/code/errors.ts.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - Code coverage report for src/commands/code/errors.ts - - - - - - - - - -
-
-

All files / src/commands/code errors.ts

-
- -
- 100% - Statements - 11/11 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 4/4 -
- - -
- 100% - Lines - 11/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31  -  -6x -6x -  -  -  -  -  -2x -2x -  -2x -2x -  -  -  -  -  -5x -5x -  -  -  -  -1x -1x -1x -  -  - 
export class CancelledError extends Error {
-  constructor() {
-    super('Wizard cancelled');
-    this.name = 'CancelledError';
-  }
-}
- 
-export class CommandFailedError extends Error {
-  constructor(
-    public readonly command: string,
-    public readonly exitCode: number,
-  ) {
-    super(`Command "${command}" failed with exit code ${exitCode}`);
-    this.name = 'CommandFailedError';
-  }
-}
- 
-export class FatalError extends Error {
-  constructor(message: string) {
-    super(message);
-    this.name = 'FatalError';
-  }
-}
- 
-export class PrerequisiteError extends Error {
-  constructor(public readonly binary: string) {
-    super(`Required binary not found: ${binary}`);
-    this.name = 'PrerequisiteError';
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/index.html b/coverage/src/commands/code/index.html deleted file mode 100644 index c66003a..0000000 --- a/coverage/src/commands/code/index.html +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - Code coverage report for src/commands/code - - - - - - - - - -
-
-

All files src/commands/code

-
- -
- 82.26% - Statements - 348/423 -
- - -
- 76.67% - Branches - 194/253 -
- - -
- 95.65% - Functions - 44/46 -
- - -
- 83.03% - Lines - 323/389 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
auth-sync.ts -
-
68.59%83/12165.38%34/52100%9/967.79%80/118
errors.ts -
-
100%11/11100%0/0100%4/4100%11/11
init.ts -
-
91.52%54/5987.09%54/6266.66%2/394.33%50/53
opencode.ts -
-
91.79%123/13483.33%70/84100%15/1594.06%111/118
pi.ts -
-
74.66%56/7565.95%31/4788.88%8/976.11%51/67
tool-check.ts -
-
90.9%10/1150%3/6100%3/390.9%10/11
utils.ts -
-
91.66%11/12100%2/2100%3/390.9%10/11
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/init.ts.html b/coverage/src/commands/code/init.ts.html deleted file mode 100644 index 0537cd6..0000000 --- a/coverage/src/commands/code/init.ts.html +++ /dev/null @@ -1,748 +0,0 @@ - - - - - - Code coverage report for src/commands/code/init.ts - - - - - - - - - -
-
-

All files / src/commands/code init.ts

-
- -
- 91.52% - Statements - 54/59 -
- - -
- 87.09% - Branches - 54/62 -
- - -
- 66.66% - Functions - 2/3 -
- - -
- 94.33% - Lines - 50/53 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -8x -8x -1x -  -7x -6x -3x -1x -2x -1x -  -  -  -  -46x -  -46x -46x -  -  -  -  -46x -  -46x -46x -  -46x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -44x -42x -  -42x -  -  -13x -5x -  -  -  -  -8x -  -8x -1x -  -  -7x -  -4x -4x -1x -  -3x -3x -3x -3x -  -2x -2x -  -  -  -  -7x -3x -  -  -  -36x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -36x -  -36x -  -  -  -  -  -  -36x -31x -19x -18x -  -12x -10x -  -  -  -31x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -46x -  -46x -  -  -  -46x -  -  -  -  -46x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import chalk from 'chalk';
-import * as os from 'node:os';
- 
-import type { ApiKeyServicePort, AuthServicePort } from './ports/auth-services.js';
-import type { CommandRunner } from './ports/command-runner.js';
-import type { FileStore } from './ports/file-store.js';
-import type { Prompter } from './ports/prompter.js';
- 
-import { ApiKeyService } from '../../services/api-key-service.js';
-import { AuthService } from '../../services/auth-service.js';
-import { ClackPrompter } from './adapters/clack-prompter.js';
-import { FsFileStore } from './adapters/fs-file-store.js';
-import { SpawnCommandRunner } from './adapters/spawn-command-runner.js';
-import { configureAuth, ensureCliAuth } from './auth-sync.js';
-import { CancelledError, CommandFailedError, FatalError, PrerequisiteError } from './errors.js';
-import {
-  getOpencodeLabel,
-  getOpencodeState,
-  initOpenCode,
-  initOpenCodeAgents,
-} from './opencode.js';
-import { getPiLabel, getPiState, initPi, initPiAgent } from './pi.js';
-import { checkTool, promptForMissingTool } from './tool-check.js';
- 
-export interface InitCommandResult {
-  exitCode: number;
-  stderr?: string;
-}
- 
-export interface WizardDeps {
-  apiKeyService: ApiKeyServicePort;
-  authService: AuthServicePort;
-  commands: CommandRunner;
-  cwd: string;
-  files: FileStore;
-  homeDir: string;
-  isTty?: boolean;
-  prompter: Prompter;
-}
- 
-export async function executeInitCommand(deps: WizardDeps): Promise<InitCommandResult> {
-  try {
-    await runInit(deps);
-    return { exitCode: 0 };
-  } catch (error) {
-    if (error instanceof CancelledError) return { exitCode: 130 };
-    if (error instanceof FatalError) return { exitCode: 1, stderr: error.message };
-    if (error instanceof PrerequisiteError)
-      return { exitCode: 2, stderr: `Missing required binary: ${error.binary}` };
-    if (error instanceof CommandFailedError) return { exitCode: 5, stderr: error.message };
-    throw error;
-  }
-}
- 
-export async function runInit(deps: WizardDeps): Promise<void> {
-  const { apiKeyService, authService, commands, cwd, files, homeDir, isTty, prompter } = deps;
- 
-  prompter.intro(`${chalk.bgGreen.black(' berget code ')}`);
-  prompter.note(
-    `Ask questions and report bugs on our GitHub repository:\n\n${chalk.cyan.underline('https://github.com/berget-ai/cli')}`,
-    'Need help?',
-  );
- 
-  const cliAuth = await ensureCliAuth({ authService, files, homeDir, prompter });
- 
-  const ocState = await getOpencodeState(files, homeDir, cwd);
-  const piState = await getPiState(files, homeDir, cwd);
- 
-  const tool = await prompter.select<'opencode' | 'pi'>({
-    initialValue: 'opencode',
-    message: 'How do you want to use Berget AI?',
-    options: [
-      {
-        hint: 'Open source AI coding agent',
-        label: `OpenCode${getOpencodeLabel(ocState)}`,
-        value: 'opencode',
-      },
-      {
-        hint: 'Minimal terminal coding harness',
-        label: `Pi${getPiLabel(piState)}`,
-        value: 'pi',
-      },
-    ],
-  });
- 
-  // Check if the selected tool is installed
-  const toolCheck = await checkTool(commands, tool);
-  let toolConfigured = toolCheck.installed;
- 
-  if (!toolCheck.installed) {
-    // Non-TTY guard: throw instead of exit so callers (including tests)
-    // can decide how to handle the failure.
-    if (isTty === false) {
-      throw new FatalError(
-        `${toolCheck.name} is not installed.\nInstall it first:\n  ${toolCheck.installCommand}\nDocs: ${toolCheck.docsUrl}`,
-      );
-    }
- 
-    const action = await promptForMissingTool(prompter, toolCheck);
- 
-    if (action === 'exit') {
-      throw new CancelledError();
-    }
- 
-    if (action === 'retry') {
-      // Re-check once. If still missing, show prompt again.
-      const recheck = await checkTool(commands, tool);
-      if (recheck.installed) {
-        toolConfigured = true;
-      } else {
-        const secondAction = await promptForMissingTool(prompter, recheck);
-        Iif (secondAction === 'exit') throw new CancelledError();
-        if (secondAction === 'continue') toolConfigured = false;
-        if (secondAction === 'retry') {
-          // One more check, then give up and treat as "continue"
-          const finalCheck = await checkTool(commands, tool);
-          toolConfigured = finalCheck.installed;
-        }
-      }
-    }
- 
-    if (action === 'continue') {
-      toolConfigured = false;
-    }
-  }
- 
-  const scope = await prompter.select<'global' | 'project'>({
-    initialValue: 'project',
-    message: 'Where should the configuration apply?',
-    options: [
-      {
-        hint:
-          tool === 'opencode'
-            ? ocState.project
-              ? 'Already configured'
-              : 'opencode.json in current directory'
-            : piState.project
-              ? 'Already configured'
-              : '.pi/settings.json in current directory',
-        label: 'This project only',
-        value: 'project',
-      },
-      {
-        hint:
-          tool === 'opencode'
-            ? ocState.global
-              ? 'Already configured'
-              : '~/.config/opencode/opencode.json'
-            : piState.global
-              ? 'Already configured'
-              : '~/.pi/agent/settings.json',
-        label: 'Globally for all projects',
-        value: 'global',
-      },
-    ],
-  });
- 
-  prompter.log('step', 'Configuring authentication...');
- 
-  const authResult = await configureAuth(
-    { apiKeyService, files, homeDir, prompter },
-    tool,
-    cliAuth,
-  );
- 
-  // Only configure the tool if it's installed (or user chose retry and it was found)
-  if (toolConfigured) {
-    if (tool === 'opencode') {
-      await initOpenCode({ commands, cwd, files, homeDir, prompter, scope });
-      await initOpenCodeAgents({ cwd, files, homeDir, prompter, scope });
-    } else {
-      await initPi({ commands, cwd, files, homeDir, prompter, scope });
-      await initPiAgent({ cwd, files, homeDir, prompter, scope });
-    }
-  }
- 
-  const nextSteps = toolConfigured
-    ? authResult.authenticated
-      ? tool === 'opencode'
-        ? "You're all set!\n\n1. Run: opencode\n2. Select model: /models"
-        : "You're all set!\n\n1. Restart Pi or run /reload\n2. Select model: /model"
-      : tool === 'opencode'
-        ? 'Next steps:\n\n1. Run: opencode\n2. Type: /connect\n3. Choose your auth method:\n   • "Login with Berget" — Berget Code plan\n   • "Enter Berget API Key manually"\n   • (or set BERGET_API_KEY env var)\n4. Select model: /models'
-        : 'Next steps:\n\n1. Restart Pi or run /reload\n2. Type: /login\n3. Choose your auth method:\n   • "Use a subscription" → Berget AI\n   • (or set BERGET_API_KEY env var)\n4. Select model: /model'
-    : authResult.authenticated
-      ? tool === 'opencode'
-        ? `Auth is configured. Next steps:\n\n1. Install OpenCode:\n   ${toolCheck.installCommand}\n2. Run: opencode\n3. Select model: /models`
-        : `Auth is configured. Next steps:\n\n1. Install Pi:\n   ${toolCheck.installCommand}\n2. Run: pi\n3. Select model: /model`
-      : tool === 'opencode'
-        ? `Next steps:\n\n1. Install OpenCode:\n   ${toolCheck.installCommand}\n2. Run: opencode\n3. Authenticate with Berget AI`
-        : `Next steps:\n\n1. Install Pi:\n   ${toolCheck.installCommand}\n2. Run: pi\n3. Authenticate with Berget AI`;
- 
-  const toolName = tool === 'opencode' ? 'OpenCode' : 'Pi';
-  const docsUrl =
-    tool === 'opencode'
-      ? 'https://github.com/berget-ai/opencode-berget-auth'
-      : 'https://github.com/berget-ai/pi-provider';
- 
-  prompter.note(
-    `${nextSteps}\n\nFor more information, see official docs:\n\n${docsUrl}`,
-    `Successfully configured Berget AI for ${toolName}`,
-  );
- 
-  prompter.outro('Initialization complete!');
-}
- 
-export async function runInitCommand(): Promise<void> {
-  const result = await executeInitCommand({
-    apiKeyService: ApiKeyService.getInstance(),
-    authService: AuthService.getInstance(),
-    commands: new SpawnCommandRunner(),
-    cwd: process.cwd(),
-    files: new FsFileStore(),
-    homeDir: os.homedir(),
-    isTty: process.stdin.isTTY,
-    prompter: new ClackPrompter(),
-  });
- 
-  if (result.stderr) console.error(result.stderr);
-  process.exitCode = result.exitCode;
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/opencode.ts.html b/coverage/src/commands/code/opencode.ts.html deleted file mode 100644 index ce5e7a6..0000000 --- a/coverage/src/commands/code/opencode.ts.html +++ /dev/null @@ -1,931 +0,0 @@ - - - - - - Code coverage report for src/commands/code/opencode.ts - - - - - - - - - -
-
-

All files / src/commands/code opencode.ts

-
- -
- 91.79% - Statements - 123/134 -
- - -
- 83.33% - Branches - 70/84 -
- - -
- 100% - Functions - 15/15 -
- - -
- 94.06% - Lines - 111/118 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283  -  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -46x -44x -  -  -  -  -  -  -  -46x -46x -46x -  -  -  -46x -  -  -  -  -46x -  -  -  -  -  -  -  -  -19x -  -19x -19x -19x -  -19x -2x -  -  -17x -2x -  -15x -  -  -17x -  -  -  -17x -  -16x -16x -16x -16x -16x -  -  -  -  -  -  -  -  -  -  -  -  -  -18x -  -126x -  -18x -  -  -  -  -18x -  -  -  -18x -  -18x -  -90x -90x -90x -  -  -  -  -  -  -  -18x -  -  -  -  -  -18x -13x -  -  -5x -5x -5x -  -9x -9x -9x -  -  -  -5x -5x -5x -5x -5x -5x -  -  -  -  -5x -  -  -  -  -5x -1x -  -  -4x -  -4x -4x -4x -4x -23x -7x -  -7x -7x -7x -  -4x -  -  -  -  -4x -  -  -  -19x -1x -1x -1x -  -  -  -  -1x -  -1x -  -  -  -  -1x -1x -  -  -1x -1x -1x -1x -  -1x -1x -1x -  -  -1x -  -1x -1x -  -  -  -  -  -  -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -18x -18x -3x -3x -  -  -  -  -  -18x -19x -19x -19x -19x -19x -  -19x -  -  -  -184x -  -4x -184x -4x -  -  -  -  -  -  -  -  -19x -16x -16x -16x -15x -12x -  -  -3x -3x -3x -3x -3x -3x -  - 
import { applyEdits, modify, parse } from 'jsonc-parser';
-import path from 'node:path';
- 
-import type { CommandRunner } from './ports/command-runner.js';
-import type { FileStore } from './ports/file-store.js';
-import type { Prompter } from './ports/prompter.js';
- 
-import { getAllAgents, toMarkdown } from '../../agents/index.js';
-import { CancelledError } from './errors.js';
-import { readJsonMaybe } from './utils.js';
- 
-const OPENCODE_PLUGIN = '@bergetai/opencode-auth@1.0.24';
-const OPENCODE_PLUGIN_NAME = '@bergetai/opencode-auth';
- 
-export interface InitOpenCodeDeps {
-  commands: CommandRunner;
-  cwd: string;
-  files: FileStore;
-  homeDir: string;
-  prompter: Prompter;
-  scope: 'global' | 'project';
-}
- 
-export function getOpencodeLabel(state: { global: boolean; project: boolean }): string {
-  if (state.project || state.global) return ' (already configured)';
-  return '';
-}
- 
-export async function getOpencodeState(
-  files: FileStore,
-  homeDir: string,
-  cwd: string,
-): Promise<{ global: boolean; project: boolean }> {
-  const projectJsonc = await readJsonMaybe(files, path.join(cwd, 'opencode.jsonc'));
-  const projectJson = await readJsonMaybe(files, path.join(cwd, 'opencode.json'));
-  const globalJsonc = await readJsonMaybe(
-    files,
-    path.join(homeDir, '.config', 'opencode', 'opencode.jsonc'),
-  );
-  const globalJson = await readJsonMaybe(
-    files,
-    path.join(homeDir, '.config', 'opencode', 'opencode.json'),
-  );
- 
-  return {
-    global: hasPluginInConfig(globalJsonc) || hasPluginInConfig(globalJson),
-    project: hasPluginInConfig(projectJsonc) || hasPluginInConfig(projectJson),
-  };
-}
- 
-/* ─── State helpers ─────────────────────────────────────────────────────── */
- 
-export async function initOpenCode(deps: InitOpenCodeDeps): Promise<void> {
-  const { commands: _commands, cwd, files, homeDir, prompter, scope } = deps;
- 
-  const configPath = await resolveOpencodeConfigPath(files, homeDir, cwd, scope);
-  const existingContent = await files.readFile(configPath);
-  const newContent = generateModifiedContent(existingContent, configPath);
- 
-  if (existingContent && existingContent === newContent) {
-    return;
-  }
- 
-  if (existingContent) {
-    prompter.note(`OpenCode config will be updated at:\n  ${configPath}`, 'Config update');
-  } else {
-    prompter.note(`OpenCode config will be created at:\n  ${configPath}`, 'Config update');
-  }
- 
-  const shouldWrite = await prompter.confirm({
-    initialValue: true,
-    message: existingContent ? `Write these changes to ${configPath}?` : `Create ${configPath}?`,
-  });
-  if (!shouldWrite) throw new CancelledError();
- 
-  const s = prompter.spinner();
-  s.start('Writing OpenCode configuration...');
-  try {
-    await files.writeFile(configPath, newContent);
-    s.stop(`Wrote configuration to ${configPath}.`);
-  } catch (error) {
-    s.stop('Failed to write configuration.');
-    throw error;
-  }
-}
- 
-export async function initOpenCodeAgents(deps: {
-  cwd: string;
-  files: FileStore;
-  homeDir: string;
-  prompter: Prompter;
-  scope: 'global' | 'project';
-}): Promise<boolean> {
-  const { cwd, files, homeDir, prompter, scope } = deps;
- 
-  const agents = getAllAgents().filter((a) => a.config.mode === 'primary');
- 
-  Iif (agents.length === 0) {
-    return false;
-  }
- 
-  const agentsDir =
-    scope === 'project'
-      ? path.join(cwd, '.opencode', 'agents')
-      : path.join(homeDir, '.config', 'opencode', 'agents');
- 
-  prompter.note('Space to toggle, Enter to confirm.', 'Agent Setup');
- 
-  const agentOptions = await Promise.all(
-    agents.map(async (agent) => {
-      const agentPath = path.join(agentsDir, `${agent.config.name}.md`);
-      const exists = await files.exists(agentPath);
-      return {
-        hint: exists ? 'already configured' : agent.config.description,
-        label: agent.config.name,
-        value: agent.config.name,
-      };
-    }),
-  );
- 
-  const selectedAgents = await prompter.multiselect({
-    message: 'Select agents to set up:',
-    options: agentOptions,
-    required: false,
-  });
- 
-  if (selectedAgents.length === 0) {
-    return false;
-  }
- 
-  const newAgents: string[] = [];
-  const existingAgents: string[] = [];
-  await Promise.all(
-    selectedAgents.map(async (agentName: string) => {
-      const agentPath = path.join(agentsDir, `${agentName}.md`);
-      const exists = await files.exists(agentPath);
-      (exists ? existingAgents : newAgents).push(agentName);
-    }),
-  );
- 
-  const summaryParts: string[] = [];
-  if (newAgents.length > 0) summaryParts.push(`New: ${newAgents.join(', ')}`);
-  if (existingAgents.length > 0) summaryParts.push(`Replaced: ${existingAgents.join(', ')}`);
-  Eif (summaryParts.length > 0) {
-    prompter.note(
-      `  Agent Setup Summary:\n${summaryParts.map((part) => `  ${part}`).join('\n')}`,
-      'Agent Setup',
-    );
-  }
- 
-  const shouldWrite = await prompter.confirm({
-    initialValue: true,
-    message: 'Write agent configuration files?',
-  });
- 
-  if (!shouldWrite) {
-    throw new CancelledError();
-  }
- 
-  await files.mkdir(agentsDir);
- 
-  const s = prompter.spinner();
-  s.start('Writing agent configurations...');
-  try {
-    for (const agentName of selectedAgents) {
-      const agent = agents.find((a) => a.config.name === agentName);
-      Iif (!agent) continue;
- 
-      const agentPath = path.join(agentsDir, `${agentName}.md`);
-      const content = toMarkdown(agent);
-      await files.writeFile(agentPath, content);
-    }
-    s.stop(`Wrote ${selectedAgents.length} agent(s) to ${agentsDir}`);
-  } catch (error) {
-    s.stop('Failed to write agent configurations.');
-    throw error;
-  }
-  return true;
-}
- 
-function generateModifiedContent(existingContent: null | string, configPath: string): string {
-  if (configPath.endsWith('.jsonc')) {
-    const content = existingContent || '{}';
-    const parseErrors: any[] = [];
-    const parsed = parse(content, parseErrors, {
-      allowTrailingComma: true,
-      disallowComments: false,
-    });
- 
-    let jsConfig: Record<string, unknown> = {};
-    const canModifyText =
-      parsed !== undefined &&
-      typeof parsed === 'object' &&
-      parsed !== null &&
-      !Array.isArray(parsed);
- 
-    Eif (canModifyText) {
-      jsConfig = parsed as Record<string, unknown>;
-    }
- 
-    const pluginsKey = jsConfig.plugins === undefined ? 'plugin' : 'plugins';
-    const existingPlugins: string[] = (jsConfig[pluginsKey] as string[]) || [];
-    const filtered = existingPlugins.filter((p: string) => !p.includes(OPENCODE_PLUGIN_NAME));
-    filtered.push(OPENCODE_PLUGIN);
- 
-    Eif (canModifyText) {
-      let modifiedContent = content;
-      const pluginEdits = modify(modifiedContent, [pluginsKey], filtered, {
-        formattingOptions: { insertSpaces: true, tabSize: 2 },
-      });
-      modifiedContent = applyEdits(modifiedContent, pluginEdits);
- 
-      Eif (!jsConfig.$schema) {
-        const schemaEdits = modify(
-          modifiedContent,
-          ['$schema'],
-          'https://opencode.ai/config.json',
-          {
-            formattingOptions: { insertSpaces: true, tabSize: 2 },
-          },
-        );
-        modifiedContent = applyEdits(modifiedContent, schemaEdits);
-      }
- 
-      return modifiedContent;
-    }
- 
-    const config: Record<string, unknown> = {
-      $schema: 'https://opencode.ai/config.json',
-      [pluginsKey]: filtered,
-    };
-    return JSON.stringify(config, null, 2) + '\n';
-  }
- 
-  let config: Record<string, unknown> = {};
-  if (existingContent) {
-    try {
-      config = JSON.parse(existingContent);
-    } catch {
-      // ignore malformed, overwrite
-    }
-  }
- 
-  const pluginsKey = config.plugins === undefined ? 'plugin' : 'plugins';
-  const existingPlugins: string[] = (config[pluginsKey] as string[]) || [];
-  const filtered = existingPlugins.filter((p: string) => !p.includes(OPENCODE_PLUGIN_NAME));
-  filtered.push(OPENCODE_PLUGIN);
-  config[pluginsKey] = filtered;
-  config.$schema = config.$schema || 'https://opencode.ai/config.json';
- 
-  return JSON.stringify(config, null, 2) + '\n';
-}
- 
-function hasPluginInConfig(config: unknown): boolean {
-  if (!config || typeof config !== 'object') return false;
-  const plugins =
-    (config as Record<string, unknown>).plugin || (config as Record<string, unknown>).plugins;
-  Iif (!Array.isArray(plugins)) return false;
-  return plugins.some((p: unknown) => typeof p === 'string' && p.includes(OPENCODE_PLUGIN_NAME));
-}
- 
-async function resolveOpencodeConfigPath(
-  files: FileStore,
-  homeDir: string,
-  cwd: string,
-  scope: 'global' | 'project',
-): Promise<string> {
-  if (scope === 'project') {
-    const jsoncPath = path.join(cwd, 'opencode.jsonc');
-    const jsonPath = path.join(cwd, 'opencode.json');
-    if (await files.exists(jsoncPath)) return jsoncPath;
-    if (await files.exists(jsonPath)) return jsonPath;
-    return jsonPath;
-  }
- 
-  const globalDir = path.join(homeDir, '.config', 'opencode');
-  const jsoncPath = path.join(globalDir, 'opencode.jsonc');
-  const jsonPath = path.join(globalDir, 'opencode.json');
-  Iif (await files.exists(jsoncPath)) return jsoncPath;
-  Iif (await files.exists(jsonPath)) return jsonPath;
-  return jsonPath;
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/pi.ts.html b/coverage/src/commands/code/pi.ts.html deleted file mode 100644 index 9ab2045..0000000 --- a/coverage/src/commands/code/pi.ts.html +++ /dev/null @@ -1,628 +0,0 @@ - - - - - - Code coverage report for src/commands/code/pi.ts - - - - - - - - - -
-
-

All files / src/commands/code pi.ts

-
- -
- 74.66% - Statements - 56/75 -
- - -
- 65.95% - Branches - 31/47 -
- - -
- 88.88% - Functions - 8/9 -
- - -
- 76.11% - Lines - 51/67 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182  -  -  -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -  -  -46x -46x -  -  -  -  -  -  -  -46x -46x -  -  -  -  -46x -  -  -  -  -  -  -  -  -12x -12x -  -  -12x -  -12x -12x -12x -10x -  -2x -2x -  -  -  -10x -  -  -  -12x -  -10x -  -  -  -12x -  -  -  -  -  -  -  -10x -  -  -  -  -  -  -  -  -  -  -10x -10x -10x -  -  -  -  -  -  -  -  -  -  -10x -  -70x -  -10x -  -  -  -  -10x -  -  -  -10x -  -10x -  -  -  -  -10x -  -9x -  -45x -  -  -  -  -  -  -42x -9x -  -9x -9x -  -  -  -10x -  -  -  -  -9x -1x -  -  -8x -8x -8x -  -8x -10x -8x -8x -  -  -  -  -8x -  -  -  -92x -1x -1x -  -  -  -  -  -  -  -  -  - 
import path from 'node:path';
- 
-import type { CommandRunner } from './ports/command-runner.js';
-import type { FileStore } from './ports/file-store.js';
-import type { Prompter } from './ports/prompter.js';
- 
-import { getAllAgents, toPiPrompt } from '../../agents/index.js';
-import { CancelledError, CommandFailedError } from './errors.js';
-import { readJsonMaybe, writeJsonFile } from './utils.js';
- 
-const PI_PROVIDER = 'npm:@bergetai/pi-provider';
-const PI_PROVIDER_NAME = '@bergetai/pi-provider';
- 
-export interface InitPiDeps {
-  commands: CommandRunner;
-  cwd: string;
-  files: FileStore;
-  homeDir: string;
-  prompter: Prompter;
-  scope: 'global' | 'project';
-}
- 
-export function getPiLabel(state: { global: boolean; project: boolean }): string {
-  Iif (state.project || state.global) return ' (already configured)';
-  return '';
-}
- 
-export async function getPiState(
-  files: FileStore,
-  homeDir: string,
-  cwd: string,
-): Promise<{ global: boolean; project: boolean }> {
-  const projectSettings = await readJsonMaybe(files, path.join(cwd, '.pi', 'settings.json'));
-  const globalSettings = await readJsonMaybe(
-    files,
-    path.join(homeDir, '.pi', 'agent', 'settings.json'),
-  );
- 
-  return {
-    global: hasPiProviderInSettings(globalSettings),
-    project: hasPiProviderInSettings(projectSettings),
-  };
-}
- 
-/* ─── State helpers ─────────────────────────────────────────────────────── */
- 
-export async function initPi(deps: InitPiDeps): Promise<void> {
-  const { commands, cwd, files, homeDir, prompter, scope } = deps;
-  const s = prompter.spinner();
- 
-  const installArguments =
-    scope === 'project' ? ['install', '-l', PI_PROVIDER] : ['install', PI_PROVIDER];
- 
-  s.start('Installing Berget AI provider for Pi...');
-  try {
-    await commands.run('pi', installArguments);
-    s.stop('Installed Pi provider.');
-  } catch {
-    s.stop('Pi provider installation failed. Please try again or install manually.');
-    throw new CommandFailedError(`pi ${installArguments.join(' ')}`, 1);
-  }
- 
-  const settingsPath =
-    scope === 'project'
-      ? path.join(cwd, '.pi', 'settings.json')
-      : path.join(homeDir, '.pi', 'agent', 'settings.json');
- 
-  const raw = await readJsonMaybe(files, settingsPath);
-  const settings: Record<string, unknown> =
-    typeof raw === 'object' && raw !== null && !Array.isArray(raw)
-      ? (raw as Record<string, unknown>)
-      : {};
- 
-  Iif (settings.defaultProvider === 'berget') {
-    prompter.note(
-      'Berget AI is already set as your default provider.',
-      'Default provider already set',
-    );
-    return;
-  }
- 
-  Iif (settings.defaultProvider) {
-    const makeDefault = await prompter.confirm({
-      initialValue: false,
-      message: `Your default provider is ${settings.defaultProvider}. Switch to Berget AI instead?`,
-    });
-    if (makeDefault) {
-      settings.defaultProvider = 'berget';
-      await writeJsonFile(files, settingsPath, settings);
-      prompter.note('Berget AI is now your default provider.', 'Updated default provider');
-    }
-  } else {
-    settings.defaultProvider = 'berget';
-    await writeJsonFile(files, settingsPath, settings);
-    prompter.note('Berget AI is now your default provider.', 'Updated default provider');
-  }
-}
- 
-export async function initPiAgent(deps: {
-  cwd: string;
-  files: FileStore;
-  homeDir: string;
-  prompter: Prompter;
-  scope: 'global' | 'project';
-}): Promise<boolean> {
-  const { cwd, files, homeDir, prompter, scope } = deps;
- 
-  const agents = getAllAgents().filter((a) => a.config.mode === 'primary');
- 
-  Iif (agents.length === 0) {
-    return false;
-  }
- 
-  const systemPath =
-    scope === 'project'
-      ? path.join(cwd, '.pi', 'SYSTEM.md')
-      : path.join(homeDir, '.pi', 'agent', 'SYSTEM.md');
- 
-  prompter.note('Pi uses a single system prompt.', 'Agent Setup');
- 
-  const shouldInitAgent = await prompter.confirm({
-    initialValue: false,
-    message: 'Set up an agent for Pi?',
-  });
- 
-  if (!shouldInitAgent) return false;
- 
-  const selectedAgentName = await prompter.select({
-    message: 'Choose an agent:',
-    options: agents.map((agent) => ({
-      hint: agent.config.description,
-      label: agent.config.name,
-      value: agent.config.name,
-    })),
-  });
- 
-  const agent = agents.find((a) => a.config.name === selectedAgentName);
-  Iif (!agent) return false;
- 
-  const systemExists = await files.exists(systemPath);
-  const confirmMsg = systemExists
-    ? `SYSTEM.md already exists. Replace with ${agent.config.name}?`
-    : 'Create agent configuration?';
- 
-  const shouldWrite = await prompter.confirm({
-    initialValue: true,
-    message: confirmMsg,
-  });
- 
-  if (!shouldWrite) {
-    throw new CancelledError();
-  }
- 
-  const s = prompter.spinner();
-  s.start('Writing agent configuration...');
-  try {
-    const systemDir =
-      scope === 'project' ? path.join(cwd, '.pi') : path.join(homeDir, '.pi', 'agent');
-    await files.mkdir(systemDir);
-    await files.writeFile(systemPath, toPiPrompt(agent));
-    s.stop(`Wrote agent configuration to ${systemPath}`);
-  } catch (error) {
-    s.stop('Failed to write agent configuration.');
-    throw error;
-  }
-  return true;
-}
- 
-function hasPiProviderInSettings(settings: unknown): boolean {
-  if (!settings || typeof settings !== 'object') return false;
-  const packages = (settings as Record<string, unknown>).packages;
-  Eif (!Array.isArray(packages)) return false;
-  return packages.some((p: unknown) => {
-    if (typeof p === 'string') return p.includes(PI_PROVIDER_NAME);
-    if (typeof p === 'object' && p !== null) {
-      const source = (p as Record<string, unknown>).source;
-      return typeof source === 'string' && source.includes(PI_PROVIDER_NAME);
-    }
-    return false;
-  });
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/tool-check.ts.html b/coverage/src/commands/code/tool-check.ts.html deleted file mode 100644 index a71c4fb..0000000 --- a/coverage/src/commands/code/tool-check.ts.html +++ /dev/null @@ -1,319 +0,0 @@ - - - - - - Code coverage report for src/commands/code/tool-check.ts - - - - - - - - - -
-
-

All files / src/commands/code tool-check.ts

-
- -
- 90.9% - Statements - 10/11 -
- - -
- 50% - Branches - 3/6 -
- - -
- 100% - Functions - 3/3 -
- - -
- 90.9% - Lines - 10/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -50x -48x -  -48x -  -  -  -  -  -  -  -  -  -  -  -  -11x -11x -  -11x -  -  -  -  -  -  -  -  -11x -  -  -  -48x -  -  -  -  -48x -  -  -  - 
import type { CommandRunner } from './ports/command-runner.js';
-import type { Prompter } from './ports/prompter.js';
- 
-export interface ToolCheckResult {
-  description: string;
-  docsUrl: string;
-  installCommand: string;
-  installed: boolean;
-  name: string;
-}
- 
-interface ToolInfo {
-  description: string;
-  docsUrl: string;
-  installCommand: string;
-  name: string;
-}
- 
-const TOOL_INFO: Record<string, Omit<ToolInfo, 'installCommand'>> = {
-  opencode: {
-    description:
-      'OpenCode is an open source AI coding agent. Install it to start coding with AI in your terminal.',
-    docsUrl: 'https://opencode.ai/docs',
-    name: 'OpenCode',
-  },
-  pi: {
-    description:
-      'Pi is a minimal terminal coding harness. Install it to start coding with AI in your terminal.',
-    docsUrl: 'https://pi.dev/docs/latest',
-    name: 'Pi',
-  },
-};
- 
-export async function checkTool(
-  commands: CommandRunner,
-  tool: 'opencode' | 'pi',
-): Promise<ToolCheckResult> {
-  const installed = await commands.checkInstalled(tool);
-  const info = TOOL_INFO[tool];
- 
-  return {
-    description: info.description,
-    docsUrl: info.docsUrl,
-    installCommand: getInstallCommand(tool, process.platform),
-    installed,
-    name: info.name,
-  };
-}
- 
-export async function promptForMissingTool(
-  prompter: Prompter,
-  tool: ToolCheckResult,
-): Promise<'continue' | 'exit' | 'retry'> {
-  const message = `${tool.description}\n\nInstall:\n  ${tool.installCommand}\n\nDocs: ${tool.docsUrl}`;
-  prompter.note(message, `${tool.name} not installed`);
- 
-  const action = await prompter.select<'continue' | 'exit' | 'retry'>({
-    message: 'What would you like to do?',
-    options: [
-      { label: "I've installed it — check again", value: 'retry' },
-      { label: 'Continue without installing (auth only)', value: 'continue' },
-      { label: 'Exit', value: 'exit' },
-    ],
-  });
- 
-  return action;
-}
- 
-function getInstallCommand(tool: 'opencode' | 'pi', platform: string): string {
-  Iif (platform === 'win32') {
-    return tool === 'opencode'
-      ? 'npm install -g opencode-ai'
-      : 'npm install -g @earendil-works/pi-coding-agent';
-  }
-  return tool === 'opencode'
-    ? 'curl -fsSL https://opencode.ai/install | bash'
-    : 'curl -fsSL https://pi.dev/install.sh | sh';
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/commands/code/utils.ts.html b/coverage/src/commands/code/utils.ts.html deleted file mode 100644 index 79c3841..0000000 --- a/coverage/src/commands/code/utils.ts.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - Code coverage report for src/commands/code/utils.ts - - - - - - - - - -
-
-

All files / src/commands/code utils.ts

-
- -
- 91.66% - Statements - 11/12 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 3/3 -
- - -
- 90.9% - Lines - 10/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30  -  -  -286x -286x -6x -6x -  -1x -1x -  -  -  -  -  -  -  -1x -1x -1x -  -  -  -  -  -  -  -10x -  - 
import type { FileStore } from './ports/file-store.js';
- 
-export async function readJsonMaybe(files: FileStore, filePath: string): Promise<null | unknown> {
-  const content = await files.readFile(filePath);
-  if (!content) return null;
-  try {
-    return JSON.parse(content);
-  } catch {
-    try {
-      return JSON.parse(stripJsoncComments(content));
-    } catch {
-      return null;
-    }
-  }
-}
- 
-export function stripJsoncComments(content: string): string {
-  content = content.replaceAll(/\/\/.*$/gm, '');
-  content = content.replaceAll(/\/\*[\s\S]*?\*\//g, '');
-  return content;
-}
- 
-export async function writeJsonFile(
-  files: FileStore,
-  filePath: string,
-  data: Record<string, unknown>,
-): Promise<void> {
-  await files.writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`);
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/constants/command-structure.ts.html b/coverage/src/constants/command-structure.ts.html deleted file mode 100644 index 476de2d..0000000 --- a/coverage/src/constants/command-structure.ts.html +++ /dev/null @@ -1,715 +0,0 @@ - - - - - - Code coverage report for src/constants/command-structure.ts - - - - - - - - - -
-
-

All files / src/constants command-structure.ts

-
- -
- 100% - Statements - 3/3 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 3/3 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
/**
- * Command structure constants for the CLI
- * Following patterns from AWS CLI and Google Cloud CLI
- */
- 
-// Main command groups
-export const COMMAND_GROUPS = {
-  API_KEYS: 'api-keys',
-  APPS: 'apps',
-  AUTH: 'auth',
-  BILLING: 'billing',
-  CHAT: 'chat',
-  CLUSTERS: 'clusters',
-  CODE: 'code',
-  FLUX: 'flux',
-  HELM: 'helm',
-  KUBECTL: 'kubectl',
-  MODELS: 'models',
-  USERS: 'users',
-};
- 
-// Subcommands for each group
-export const SUBCOMMANDS = {
-  // API Keys commands
-  API_KEYS: {
-    CREATE: 'create',
-    DELETE: 'delete',
-    DESCRIBE: 'describe',
-    GET_DEFAULT: 'get-default',
-    LIST: 'list',
-    ROTATE: 'rotate',
-    SET_DEFAULT: 'set-default',
-  },
- 
-  // Apps commands
-  APPS: {
-    DESCRIBE_INSTALLATION: 'describe-installation',
-    DESCRIBE_TEMPLATE: 'describe-template',
-    INSTALL: 'install',
-    LIST_INSTALLATIONS: 'list-installations',
-    LIST_TEMPLATES: 'list-templates',
-    UNINSTALL: 'uninstall',
-  },
- 
-  // Auth commands
-  AUTH: {
-    LOGIN: 'login',
-    LOGOUT: 'logout',
-    WHOAMI: 'whoami',
-  },
- 
-  // Billing commands
-  BILLING: {
-    ADD_PAYMENT_METHOD: 'add-payment-method',
-    DESCRIBE_INVOICE: 'describe-invoice',
-    GET_USAGE: 'get-usage',
-    LIST_INVOICES: 'list-invoices',
-    LIST_PAYMENT_METHODS: 'list-payment-methods',
-    REMOVE_PAYMENT_METHOD: 'remove-payment-method',
-    UPDATE_SUBSCRIPTION: 'update-subscription',
-  },
- 
-  // Chat commands
-  CHAT: {
-    LIST: 'list',
-    RUN: 'run',
-  },
- 
-  // Clusters commands
-  CLUSTERS: {
-    DESCRIBE: 'describe',
-    GET_USAGE: 'get-usage',
-    LIST: 'list',
-  },
- 
-  // Code commands
-  CODE: {
-    INIT: 'init',
-  },
- 
-  // Flux commands
-  FLUX: {
-    BOOTSTRAP: 'bootstrap',
-    INSTALL: 'install',
-  },
- 
-  // Helm commands
-  HELM: {
-    ADD_REPO: 'add-repo',
-    INSTALL: 'install',
-  },
- 
-  // Kubectl commands
-  KUBECTL: {
-    APPLY: 'apply',
-    CREATE_NAMESPACE: 'create-namespace',
-    GET: 'get',
-  },
- 
-  // Models commands
-  MODELS: {
-    DESCRIBE: 'describe',
-    LIST: 'list',
-  },
- 
-  // Users commands
-  USERS: {
-    DESCRIBE: 'describe',
-    INVITE: 'invite',
-    LIST: 'list',
-    UPDATE: 'update',
-  },
-};
- 
-// Command descriptions
-export const COMMAND_DESCRIPTIONS = {
-  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.CREATE}`]: 'Create a new API key',
-  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.DELETE}`]: 'Delete an API key',
-  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.DESCRIBE}`]:
-    'Get usage statistics for an API key',
-  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.GET_DEFAULT}`]:
-    'Show the current default API key',
- 
-  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.LIST}`]: 'List all API keys',
-  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.ROTATE}`]: 'Rotate an API key',
-  [`${COMMAND_GROUPS.API_KEYS} ${SUBCOMMANDS.API_KEYS.SET_DEFAULT}`]:
-    'Set an API key as the default for chat commands',
-  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.DESCRIBE_INSTALLATION}`]:
-    'Get detailed information about an installed application',
-  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.DESCRIBE_TEMPLATE}`]:
-    'Get detailed information about an application template',
-  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.INSTALL}`]: 'Install an application',
-  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.LIST_INSTALLATIONS}`]: 'List installed applications',
-  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.LIST_TEMPLATES}`]:
-    'List available application templates',
- 
-  [`${COMMAND_GROUPS.APPS} ${SUBCOMMANDS.APPS.UNINSTALL}`]: 'Uninstall an application',
-  [`${COMMAND_GROUPS.AUTH} ${SUBCOMMANDS.AUTH.LOGIN}`]: 'Log in to Berget AI',
-  [`${COMMAND_GROUPS.AUTH} ${SUBCOMMANDS.AUTH.LOGOUT}`]: 'Log out from Berget AI',
-  [`${COMMAND_GROUPS.AUTH} ${SUBCOMMANDS.AUTH.WHOAMI}`]: 'Display current user information',
- 
-  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.ADD_PAYMENT_METHOD}`]:
-    'Add a new payment method',
-  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.DESCRIBE_INVOICE}`]:
-    'Get detailed information about an invoice',
-  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.GET_USAGE}`]: 'Get current usage metrics',
-  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.LIST_INVOICES}`]: 'List all invoices',
-  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.LIST_PAYMENT_METHODS}`]:
-    'List all payment methods',
-  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.REMOVE_PAYMENT_METHOD}`]:
-    'Remove a payment method',
-  [`${COMMAND_GROUPS.BILLING} ${SUBCOMMANDS.BILLING.UPDATE_SUBSCRIPTION}`]:
-    'Update subscription plan',
- 
-  [`${COMMAND_GROUPS.CHAT} ${SUBCOMMANDS.CHAT.LIST}`]: 'List available chat models',
-  [`${COMMAND_GROUPS.CHAT} ${SUBCOMMANDS.CHAT.RUN}`]: 'Run a chat session with a specified model',
-  [`${COMMAND_GROUPS.CLUSTERS} ${SUBCOMMANDS.CLUSTERS.DESCRIBE}`]:
-    'Get detailed information about a cluster',
- 
-  [`${COMMAND_GROUPS.CLUSTERS} ${SUBCOMMANDS.CLUSTERS.GET_USAGE}`]:
-    'Get resource usage for a cluster',
-  [`${COMMAND_GROUPS.CLUSTERS} ${SUBCOMMANDS.CLUSTERS.LIST}`]: 'List all clusters',
-  [`${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`]:
-    'Interactive setup for Berget AI coding tools',
- 
-  [`${COMMAND_GROUPS.FLUX} ${SUBCOMMANDS.FLUX.BOOTSTRAP}`]: 'Bootstrap Flux CD',
-  [`${COMMAND_GROUPS.FLUX} ${SUBCOMMANDS.FLUX.INSTALL}`]: 'Install Flux CD',
-  [`${COMMAND_GROUPS.HELM} ${SUBCOMMANDS.HELM.ADD_REPO}`]: 'Add a Helm repository',
- 
-  [`${COMMAND_GROUPS.HELM} ${SUBCOMMANDS.HELM.INSTALL}`]: 'Install a Helm chart',
-  [`${COMMAND_GROUPS.KUBECTL} ${SUBCOMMANDS.KUBECTL.APPLY}`]: 'Apply a Kubernetes configuration',
-  [`${COMMAND_GROUPS.KUBECTL} ${SUBCOMMANDS.KUBECTL.CREATE_NAMESPACE}`]:
-    'Create a Kubernetes namespace',
-  [`${COMMAND_GROUPS.KUBECTL} ${SUBCOMMANDS.KUBECTL.GET}`]: 'Get Kubernetes resources',
-  [`${COMMAND_GROUPS.MODELS} ${SUBCOMMANDS.MODELS.DESCRIBE}`]:
-    'Get detailed information about an AI model',
- 
-  [`${COMMAND_GROUPS.MODELS} ${SUBCOMMANDS.MODELS.LIST}`]: 'List available AI models',
-  [`${COMMAND_GROUPS.USERS} ${SUBCOMMANDS.USERS.DESCRIBE}`]:
-    'Get detailed information about a user',
-  [`${COMMAND_GROUPS.USERS} ${SUBCOMMANDS.USERS.INVITE}`]: 'Invite a new user to your organization',
-  [`${COMMAND_GROUPS.USERS} ${SUBCOMMANDS.USERS.LIST}`]: 'List all users in your organization',
-  [`${COMMAND_GROUPS.USERS} ${SUBCOMMANDS.USERS.UPDATE}`]: 'Update user information',
-  // API Keys group
-  [COMMAND_GROUPS.API_KEYS]: 'Manage API keys',
-  // Apps group
-  [COMMAND_GROUPS.APPS]: 'Manage applications',
-  // Auth group
-  [COMMAND_GROUPS.AUTH]: 'Manage authentication and authorization',
- 
-  // Billing group
-  [COMMAND_GROUPS.BILLING]: 'Manage billing and usage',
-  // Chat group
-  [COMMAND_GROUPS.CHAT]: 'Interact with AI chat models',
-  // Clusters group
-  [COMMAND_GROUPS.CLUSTERS]: 'Manage Kubernetes clusters',
- 
-  // Code group
-  [COMMAND_GROUPS.CODE]: 'Configure Berget AI coding tools',
-  // Flux group
-  [COMMAND_GROUPS.FLUX]: 'Manage Flux CD',
-  // Helm group
-  [COMMAND_GROUPS.HELM]: 'Manage Helm charts',
-  // Kubectl group
-  [COMMAND_GROUPS.KUBECTL]: 'Manage Kubernetes resources',
-  // Models group
-  [COMMAND_GROUPS.MODELS]: 'Manage AI models',
-  // Users group
-  [COMMAND_GROUPS.USERS]: 'Manage users',
-};
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/constants/index.html b/coverage/src/constants/index.html deleted file mode 100644 index 067a533..0000000 --- a/coverage/src/constants/index.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - Code coverage report for src/constants - - - - - - - - - -
-
-

All files src/constants

-
- -
- 100% - Statements - 3/3 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 3/3 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
command-structure.ts -
-
100%3/3100%0/0100%0/0100%3/3
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/index.html b/coverage/src/index.html deleted file mode 100644 index 65bdd7d..0000000 --- a/coverage/src/index.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - Code coverage report for src - - - - - - - - - -
-
-

All files src

-
- -
- 0% - Statements - 0/11 -
- - -
- 0% - Branches - 0/2 -
- - -
- 0% - Functions - 0/3 -
- - -
- 0% - Lines - 0/11 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
client.ts -
-
0%0/110%0/20%0/30%0/11
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/services/api-key-service.ts.html b/coverage/src/services/api-key-service.ts.html deleted file mode 100644 index a4c3ee5..0000000 --- a/coverage/src/services/api-key-service.ts.html +++ /dev/null @@ -1,802 +0,0 @@ - - - - - - Code coverage report for src/services/api-key-service.ts - - - - - - - - - -
-
-

All files / src/services api-key-service.ts

-
- -
- 2.73% - Statements - 2/73 -
- - -
- 0% - Branches - 0/48 -
- - -
- 9.09% - Functions - 1/11 -
- - -
- 2.89% - Lines - 2/69 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { createAuthenticatedClient } from '../client.js';
-import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure.js';
-import { handleError } from '../utils/error-handler.js';
- 
-export interface ApiKey {
-  active: boolean;
-  created: string;
-  description: null | string;
-  id: number;
-  lastUsed: null | string;
-  modified: string;
-  name: string;
-  prefix: string;
-}
- 
-export interface ApiKeyResponse {
-  created: string;
-  description: null | string;
-  id: number;
-  key: string;
-  name: string;
-}
- 
-export interface CreateApiKeyOptions {
-  description?: string;
-  name: string;
-}
- 
-/**
- * Service for managing API keys
- * Command group: api-keys
- */
-export class ApiKeyService {
-  // Command group name for this service
-  public static readonly COMMAND_GROUP = COMMAND_GROUPS.API_KEYS;
-  // Subcommands for this service
-  public static readonly COMMANDS = SUBCOMMANDS.API_KEYS;
- 
-  private static instance: ApiKeyService;
- 
-  private client = createAuthenticatedClient();
- 
-  private constructor() {}
- 
-  public static getInstance(): ApiKeyService {
-    if (!ApiKeyService.instance) {
-      ApiKeyService.instance = new ApiKeyService();
-    }
-    return ApiKeyService.instance;
-  }
- 
-  /**
-   * Create a new API key
-   * Command: berget api-keys create
-   */
-  public async create(options: CreateApiKeyOptions): Promise<ApiKeyResponse> {
-    try {
-      this.validateCreateOptions(options);
- 
-      const { data, error } = await this.client.POST('/v1/api-keys', {
-        body: options,
-      });
- 
-      if (error) {
-        throw this.mapCreateError(error);
-      }
- 
-      if (!data) {
-        throw new Error('No data received from server');
-      }
- 
-      return data;
-    } catch (error) {
-      throw this.enhanceNetworkError(error);
-    }
-  }
- 
-  /**
-   * Delete an API key
-   * Command: berget api-keys delete
-   */
-  public async delete(id: string): Promise<boolean> {
-    try {
-      const { error } = await this.client.DELETE('/v1/api-keys/{id}', {
-        params: { path: { id } },
-      });
-      if (error) throw new Error(JSON.stringify(error));
-      return true;
-    } catch (error) {
-      console.error('Failed to delete API key:', error);
-      throw error;
-    }
-  }
- 
-  /**
-   * Get usage statistics for an API key
-   * Command: berget api-keys describe
-   */
-  public async describe(id: string): Promise<any> {
-    try {
-      const { data, error } = await this.client.GET('/v1/api-keys/{id}/usage', {
-        params: { path: { id } },
-      });
-      if (error) throw new Error(JSON.stringify(error));
-      return data;
-    } catch (error) {
-      console.error('Failed to get API key usage:', error);
-      throw error;
-    }
-  }
- 
-  /**
-   * List all API keys
-   * Command: berget api-keys list
-   */
-  public async list(): Promise<ApiKey[]> {
-    try {
-      const { data, error } = await this.client.GET('/v1/api-keys');
-      if (error) throw error;
-      return data || [];
-    } catch (error) {
-      handleError('Failed to list API keys', error);
-      throw error;
-    }
-  }
- 
-  /**
-   * Rotate an API key
-   * Command: berget api-keys rotate
-   */
-  public async rotate(id: string): Promise<ApiKeyResponse> {
-    try {
-      const { data, error } = await this.client.PUT('/v1/api-keys/{id}/rotate', {
-        params: { path: { id } },
-      });
-      if (error) throw new Error(JSON.stringify(error));
-      return data!;
-    } catch (error) {
-      console.error('Failed to rotate API key:', error);
-      throw error;
-    }
-  }
- 
-  private buildCreationFailedMessage(): string {
-    return (
-      'Failed to create API key. This could be due to:\n' +
-      '• Account limits or quota restrictions\n' +
-      '• Insufficient permissions for API key creation\n' +
-      '• Temporary server issues\n' +
-      '• Billing or subscription issues\n\n' +
-      'Troubleshooting steps:\n' +
-      '1. Check if you have reached your API key limit\n' +
-      '2. Verify your account has API key creation permissions\n' +
-      '3. Check your billing status and subscription\n' +
-      '4. Try again in a few minutes if this is a temporary issue\n' +
-      '5. Contact support if the problem persists'
-    );
-  }
- 
-  private enhanceNetworkError(error: unknown): Error {
-    if (!(error instanceof Error)) {
-      throw error;
-    }
- 
-    const message = error.message;
- 
-    if (message.includes('ECONNREFUSED')) {
-      return new Error('Cannot connect to Berget API. Please check your internet connection.');
-    }
- 
-    if (message.includes('ENOTFOUND')) {
-      return new Error('Cannot resolve Berget API hostname. Please check your DNS settings.');
-    }
- 
-    if (message.includes('401') || message.includes('Unauthorized')) {
-      return new Error('Authentication failed. Please run `berget auth login` to log in again.');
-    }
- 
-    if (message.includes('403')) {
-      return new Error(
-        'Access forbidden. Your account may not have permission to create API keys.',
-      );
-    }
- 
-    throw error;
-  }
- 
-  private mapCreateError(error: unknown): Error {
-    if (typeof error !== 'object' || error === null) {
-      return new Error(JSON.stringify(error));
-    }
- 
-    const errorObject = error as any;
-    const code = errorObject.error?.code;
- 
-    switch (code) {
-      case 'API_KEY_CREATION_FAILED': {
-        return new Error(this.buildCreationFailedMessage());
-      }
-      case 'BILLING_REQUIRED': {
-        return new Error(
-          'A valid billing method is required to create API keys. Please add a payment method.',
-        );
-      }
-      case 'INSUFFICIENT_PERMISSIONS': {
-        return new Error(
-          'Your account does not have permission to create API keys. Please contact your administrator.',
-        );
-      }
-      case 'QUOTA_EXCEEDED': {
-        return new Error(
-          'You have reached your API key limit. Please delete existing keys or contact support to increase your quota.',
-        );
-      }
-      case 'USER_NOT_FOUND': {
-        return new Error(
-          'Before you can create API keys, you need to finish setting up your account.\n\nCheck your inbox for a verification email from Berget AI and complete the account setup.',
-        );
-      }
-      default: {
-        return new Error(JSON.stringify(error));
-      }
-    }
-  }
- 
-  private validateCreateOptions(options: CreateApiKeyOptions): void {
-    if (!options.name || options.name.trim().length === 0) {
-      throw new Error('API key name is required and cannot be empty');
-    }
- 
-    if (options.name.length > 100) {
-      throw new Error('API key name must be 100 characters or less');
-    }
- 
-    if (options.description && options.description.length > 500) {
-      throw new Error('API key description must be 500 characters or less');
-    }
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/services/auth-service.ts.html b/coverage/src/services/auth-service.ts.html deleted file mode 100644 index 478a33b..0000000 --- a/coverage/src/services/auth-service.ts.html +++ /dev/null @@ -1,445 +0,0 @@ - - - - - - Code coverage report for src/services/auth-service.ts - - - - - - - - - -
-
-

All files / src/services auth-service.ts

-
- -
- 5.12% - Statements - 2/39 -
- - -
- 0% - Branches - 0/23 -
- - -
- 20% - Functions - 1/5 -
- - -
- 5.12% - Lines - 2/39 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import chalk from 'chalk';
- 
-import { getAuthConfig } from '../auth/config.js';
-import { getConfiguration } from '../auth/issuer.js';
-import { extractJwtExpiresAt } from '../auth/jwt.js';
-import { startPkceFlow } from '../auth/oauth/pkce-flow.js';
-import { FileTokenStore } from '../auth/storage/token-store.js';
-import { createAuthenticatedClient } from '../client.js';
-import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure.js';
-import { handleError } from '../utils/error-handler.js';
- 
-/**
- * Service for authentication operations
- * Command group: auth
- */
-export class AuthService {
-  // Command group name for this service
-  public static readonly COMMAND_GROUP = COMMAND_GROUPS.AUTH;
- 
-  // Subcommands for this service
-  public static readonly COMMANDS = SUBCOMMANDS.AUTH;
- 
-  private static instance: AuthService;
- 
-  private constructor() {}
- 
-  public static getInstance(): AuthService {
-    if (!AuthService.instance) {
-      AuthService.instance = new AuthService();
-    }
-    return AuthService.instance;
-  }
- 
-  /**
-   * Browser-based PKCE login for interactive CLI use.
-   * Prints status to stdout/stderr. Use loginInteractive() when you need
-   * a silent, UI-agnostic result (e.g. inside the setup wizard).
-   */
-  public async login(options?: { debug?: boolean; stage?: boolean }): Promise<boolean> {
-    try {
-      const result = await this.loginInteractive(options);
- 
-      if (!result.success) {
-        console.log(chalk.red(`\nAuthentication failed: ${result.error || 'Unknown error'}`));
-        return false;
-      }
- 
-      console.log(chalk.green('\n✓ Successfully logged in to Berget'));
- 
-      try {
-        const profile = await this.whoami();
-        if (profile?.email) {
-          console.log(chalk.green(`Logged in as ${profile.name || profile.email}`));
-        }
-      } catch {
-        // Ignore errors fetching profile
-      }
- 
-      console.log(chalk.cyan('\nNext steps:'));
-      console.log(chalk.cyan('  • Create an API key: berget api-keys create'));
-      console.log(chalk.cyan('  • Initialize OpenCode: berget code init'));
- 
-      return true;
-    } catch (error) {
-      handleError('Login failed', error);
-      return false;
-    }
-  }
- 
-  /**
-   * Browser-based PKCE login for wizard / programmatic use.
-   * Does NOT print to stdout — returns tokens so callers can display
-   * their own UI (e.g. via clack/prompts).
-   */
-  public async loginInteractive(options?: { debug?: boolean; stage?: boolean }): Promise<{
-    accessToken?: string;
-    error?: string;
-    expiresIn?: number;
-    refreshToken?: string;
-    success: boolean;
-  }> {
-    try {
-      const config = getAuthConfig(options);
-      const configuration = await getConfiguration(config);
-      const result = await startPkceFlow({ config: configuration, debug: options?.debug });
- 
-      if (result.success && result.accessToken && result.refreshToken) {
-        const tokenStore = new FileTokenStore();
-        const jwtExpiresAt = extractJwtExpiresAt(result.accessToken);
-        const expiresAt =
-          jwtExpiresAt > 0 ? jwtExpiresAt : Date.now() + (result.expiresIn || 3600) * 1000;
-        await tokenStore.set({
-          access_token: result.accessToken,
-          expires_at: expiresAt,
-          refresh_token: result.refreshToken,
-        });
-      }
- 
-      return result;
-    } catch (error) {
-      return {
-        error: error instanceof Error ? error.message : String(error),
-        success: false,
-      };
-    }
-  }
- 
-  public async whoami(): Promise<any> {
-    try {
-      const client = createAuthenticatedClient();
-      const { data: profile, error } = await client.GET('/v1/users/me');
-      if (error) {
-        return null;
-      }
-      return profile;
-    } catch {
-      return null;
-    }
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/services/index.html b/coverage/src/services/index.html deleted file mode 100644 index 522877f..0000000 --- a/coverage/src/services/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for src/services - - - - - - - - - -
-
-

All files src/services

-
- -
- 3.57% - Statements - 4/112 -
- - -
- 0% - Branches - 0/71 -
- - -
- 12.5% - Functions - 2/16 -
- - -
- 3.7% - Lines - 4/108 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
api-key-service.ts -
-
2.73%2/730%0/489.09%1/112.89%2/69
auth-service.ts -
-
5.12%2/390%0/2320%1/55.12%2/39
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/utils/error-handler.ts.html b/coverage/src/utils/error-handler.ts.html deleted file mode 100644 index b623a81..0000000 --- a/coverage/src/utils/error-handler.ts.html +++ /dev/null @@ -1,538 +0,0 @@ - - - - - - Code coverage report for src/utils/error-handler.ts - - - - - - - - - -
-
-

All files / src/utils error-handler.ts

-
- -
- 0% - Statements - 0/62 -
- - -
- 0% - Branches - 0/58 -
- - -
- 0% - Functions - 0/2 -
- - -
- 0% - Lines - 0/62 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import chalk from 'chalk';
- 
-/**
- * Formats and prints error messages in a consistent way
- */
-export function handleError(message: string, error: any): void {
-  console.error(chalk.red(`❌ Error: ${message}`));
- 
-  let errorDetails = '';
-  let errorCode = '';
-  let errorType = '';
- 
-  // If the error is a string (like JSON.stringify(error))
-  if (typeof error === 'string') {
-    try {
-      // Try to parse it as JSON
-      const parsedError = JSON.parse(error);
-      if (parsedError.error) {
-        errorDetails = parsedError.error.message || parsedError.error;
-        errorCode = parsedError.error.code || parsedError.code;
-        errorType = parsedError.error.type || '';
-      } else {
-        errorDetails = error;
-      }
-    } catch {
-      // If it's not valid JSON, just print the string
-      errorDetails = error;
-    }
-  } else if (error && error.message) {
-    // If it's an Error object
-    errorDetails = error.message;
-    errorCode = error.code;
-    errorType = error.type;
-  }
- 
-  // Print error details
-  if (errorDetails) {
-    console.error(chalk.dim(`📝 Details: ${errorDetails}`));
-  }
-  if (errorCode) {
-    console.error(chalk.dim(`🔢 Code: ${errorCode}`));
-  }
- 
-  // Provide helpful troubleshooting based on error type
-  provideTroubleshootingTips(errorType, errorCode, errorDetails);
-}
- 
-/**
- * Provides helpful troubleshooting tips based on error type
- */
-function provideTroubleshootingTips(
-  errorType: string,
-  errorCode: string,
-  errorDetails: string,
-): void {
-  console.error(chalk.blue('\n💡 Troubleshooting tips:'));
- 
-  // Authentication errors
-  if (
-    errorType === 'authentication_error' ||
-    errorCode === 'AUTH_FAILED' ||
-    errorDetails?.includes('Unauthorized') ||
-    errorDetails?.includes('Authentication failed')
-  ) {
-    console.error(chalk.yellow('   🔐 Authentication issue detected:'));
-    console.error(chalk.white('   • Run `berget auth login` to log in'));
-    console.error(chalk.white('   • Check if your session has expired'));
-    console.error(chalk.white('   • Verify you have the correct permissions'));
-  }
- 
-  // Network/connection errors
-  if (
-    errorDetails?.includes('fetch failed') ||
-    errorDetails?.includes('ECONNREFUSED') ||
-    errorDetails?.includes('ENOTFOUND') ||
-    errorDetails?.includes('network')
-  ) {
-    console.error(chalk.yellow('   🌐 Network issue detected:'));
-    console.error(chalk.white('   • Check your internet connection'));
-    console.error(chalk.white('   • Verify you can reach api.berget.ai'));
-    console.error(chalk.white('   • Try again in a few minutes'));
-    console.error(chalk.white('   • Check if any firewall is blocking the request'));
-  }
- 
-  // API key errors
-  if (
-    errorCode?.includes('API_KEY') ||
-    errorDetails?.includes('API key') ||
-    errorType === 'invalid_request_error'
-  ) {
-    console.error(chalk.yellow('   🔑 API key issue detected:'));
-    console.error(chalk.white('   • Run `berget api-keys list` to check your keys'));
-    console.error(
-      chalk.white('   • Create a new key with `berget api-keys create --name "My Key"`'),
-    );
-    console.error(chalk.white('   • Set a default key with `berget api-keys set-default <id>`'));
-    console.error(chalk.white('   • Check if your API key has expired'));
-  }
- 
-  // Rate limiting
-  if (
-    errorCode === 'RATE_LIMIT_EXCEEDED' ||
-    errorDetails?.includes('rate limit') ||
-    errorDetails?.includes('too many requests')
-  ) {
-    console.error(chalk.yellow('   ⏱️  Rate limit exceeded:'));
-    console.error(chalk.white('   • Wait a few minutes before trying again'));
-    console.error(chalk.white('   • Consider upgrading your plan for higher limits'));
-    console.error(chalk.white('   • Use `berget billing get-usage` to check your usage'));
-  }
- 
-  // Server errors
-  if (
-    errorCode?.includes('SERVER_ERROR') ||
-    errorType === 'server_error' ||
-    (errorCode && Number.parseInt(errorCode) >= 500)
-  ) {
-    console.error(chalk.yellow('   🖥️  Server issue detected:'));
-    console.error(chalk.white('   • This is a temporary problem on our end'));
-    console.error(chalk.white('   • Try again in a few minutes'));
-    console.error(chalk.white('   • Check status.berget.ai for service status'));
-    console.error(chalk.white('   • Contact support if the problem persists'));
-  }
- 
-  // Cluster errors
-  if (errorCode?.includes('CLUSTERS') || errorDetails?.includes('cluster')) {
-    console.error(chalk.yellow('   🏗️  Cluster issue detected:'));
-    console.error(chalk.white('   • Clusters may be temporarily unavailable'));
-    console.error(chalk.white('   • Try again later or contact support'));
-    console.error(chalk.white('   • Check your cluster permissions'));
-  }
- 
-  // Generic fallback
-  if (
-    !errorType?.includes('authentication') &&
-    !errorDetails?.includes('fetch failed') &&
-    !errorCode?.includes('API_KEY') &&
-    !errorCode?.includes('RATE_LIMIT') &&
-    !errorCode?.includes('SERVER_ERROR') &&
-    !errorCode?.includes('CLUSTERS')
-  ) {
-    console.error(chalk.yellow('   ❓ General issue:'));
-    console.error(chalk.white('   • Try running the command with --debug for more info'));
-    console.error(chalk.white('   • Check your configuration with `berget auth whoami`'));
-    console.error(chalk.white('   • Contact support if the problem persists'));
-  }
- 
-  console.error(
-    chalk.dim('\nNeed more help? Visit https://docs.berget.ai or contact support@berget.ai'),
-  );
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/utils/index.html b/coverage/src/utils/index.html deleted file mode 100644 index d8a1690..0000000 --- a/coverage/src/utils/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for src/utils - - - - - - - - - -
-
-

All files src/utils

-
- -
- 11.81% - Statements - 15/127 -
- - -
- 4.08% - Branches - 4/98 -
- - -
- 18.75% - Functions - 3/16 -
- - -
- 11.81% - Lines - 15/127 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
error-handler.ts -
-
0%0/620%0/580%0/20%0/62
logger.ts -
-
23.07%15/6510%4/4021.42%3/1423.07%15/65
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/utils/logger.ts.html b/coverage/src/utils/logger.ts.html deleted file mode 100644 index d76d5fc..0000000 --- a/coverage/src/utils/logger.ts.html +++ /dev/null @@ -1,670 +0,0 @@ - - - - - - Code coverage report for src/utils/logger.ts - - - - - - - - - -
-
-

All files / src/utils logger.ts

-
- -
- 23.07% - Statements - 15/65 -
- - -
- 10% - Branches - 4/40 -
- - -
- 21.42% - Functions - 3/14 -
- - -
- 23.07% - Lines - 15/65 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196  -  -  -  -  -1x -1x -1x -1x -1x -1x -  -  -1x -  -  -  -  -  -  -1x -  -  -  -1x -  -1x -  -1x -  -  -  -  -  -1x -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x - 
import chalk from 'chalk';
- 
-/**
- * Log levels in order of increasing verbosity
- */
-export enum LogLevel {
-  NONE = 0,
-  ERROR = 1,
-  WARN = 2,
-  INFO = 3,
-  DEBUG = 4,
-}
- 
-const REDACTION = '[REDACTED]';
- 
-/**
- * Logger class for centralized logging with configurable log levels
- */
-export class Logger {
-  private static instance: Logger;
-  private logLevel: LogLevel = LogLevel.INFO; // Default log level
- 
-  private constructor() {
-    // Set log level from environment variable or command line argument
-    Iif (process.env.LOG_LEVEL) {
-      this.setLogLevelFromString(process.env.LOG_LEVEL);
-    } else Iif (process.argv.includes('--debug')) {
-      this.logLevel = LogLevel.DEBUG;
-    } else Iif (process.argv.includes('--quiet')) {
-      this.logLevel = LogLevel.ERROR;
-    }
-  }
- 
-  public static getInstance(): Logger {
-    Eif (!Logger.instance) {
-      Logger.instance = new Logger();
-    }
-    return Logger.instance;
-  }
- 
-  /**
-   * Log a debug message (only shown at DEBUG level).
-   * Automatically redacts known secrets from string arguments.
-   */
-  public debug(message: string, ...arguments_: any[]): void {
-    if (this.logLevel >= LogLevel.DEBUG) {
-      const redactedMessage = redactSecrets(message);
-      const redactedArgs = arguments_.map((arg) =>
-        typeof arg === 'string' ? redactSecrets(arg) : arg,
-      );
-      if (redactedArgs.length > 0) {
-        console.log(chalk.yellow(`DEBUG: ${redactedMessage}`), ...redactedArgs);
-      } else {
-        console.log(chalk.yellow(`DEBUG: ${redactedMessage}`));
-      }
-    }
-  }
- 
-  /**
-   * Log an error message (shown at ERROR level and above)
-   */
-  public error(message: string, ...arguments_: any[]): void {
-    if (this.logLevel >= LogLevel.ERROR) {
-      if (arguments_.length > 0) {
-        console.error(chalk.red(message), ...arguments_);
-      } else {
-        console.error(chalk.red(message));
-      }
-    }
-  }
- 
-  /**
-   * Get the current log level
-   */
-  public getLogLevel(): LogLevel {
-    return this.logLevel;
-  }
- 
-  /**
-   * Log an info message (shown at INFO level and above)
-   */
-  public info(message: string, ...arguments_: any[]): void {
-    if (this.logLevel >= LogLevel.INFO) {
-      if (arguments_.length > 0) {
-        console.log(chalk.blue(message), ...arguments_);
-      } else {
-        console.log(chalk.blue(message));
-      }
-    }
-  }
- 
-  /**
-   * Log a plain message without color (shown at INFO level and above)
-   */
-  public log(message: string, ...arguments_: any[]): void {
-    if (this.logLevel >= LogLevel.INFO) {
-      if (arguments_.length > 0) {
-        console.log(message, ...arguments_);
-      } else {
-        console.log(message);
-      }
-    }
-  }
- 
-  /**
-   * Set the log level
-   */
-  public setLogLevel(level: LogLevel): void {
-    this.logLevel = level;
-  }
- 
-  /**
-   * Log a success message (shown at INFO level and above)
-   */
-  public success(message: string, ...arguments_: any[]): void {
-    if (this.logLevel >= LogLevel.INFO) {
-      if (arguments_.length > 0) {
-        console.log(chalk.green(message), ...arguments_);
-      } else {
-        console.log(chalk.green(message));
-      }
-    }
-  }
- 
-  /**
-   * Log a warning message (shown at WARN level and above)
-   */
-  public warn(message: string, ...arguments_: any[]): void {
-    if (this.logLevel >= LogLevel.WARN) {
-      if (arguments_.length > 0) {
-        console.log(chalk.yellow(message), ...arguments_);
-      } else {
-        console.log(chalk.yellow(message));
-      }
-    }
-  }
- 
-  /**
-   * Set the log level from a string
-   */
-  private setLogLevelFromString(level: string): void {
-    switch (level.toLowerCase()) {
-      case 'debug': {
-        this.logLevel = LogLevel.DEBUG;
-        break;
-      }
-      case 'error': {
-        this.logLevel = LogLevel.ERROR;
-        break;
-      }
-      case 'info': {
-        this.logLevel = LogLevel.INFO;
-        break;
-      }
-      case 'none': {
-        this.logLevel = LogLevel.NONE;
-        break;
-      }
-      case 'warn': {
-        this.logLevel = LogLevel.WARN;
-        break;
-      }
-      default: {
-        // Invalid log level, keep default
-        console.warn(`Invalid log level: ${level}. Using default (INFO).`);
-      }
-    }
-  }
-}
- 
-/**
- * Redact known secret patterns from log strings.
- * Handles Bearer tokens, URL query parameters (code, access_token,
- * refresh_token), Berget API keys, and JWT-like strings.
- */
-function redactSecrets(value: string): string {
-  let result = value;
- 
-  // Bearer tokens
-  result = result.replace(/Bearer\s+\S+/gi, `Bearer ${REDACTION}`);
- 
-  // URL query parameters: code=..., access_token=..., refresh_token=...
-  result = result.replace(/\b(code|access_token|refresh_token)=[^&\s]*/gi, `$1=${REDACTION}`);
- 
-  // Berget API keys (sk_ber_*)
-  result = result.replace(/sk_ber_\w+/g, REDACTION);
- 
-  // JWT-like strings (3 base64url segments separated by dots)
-  result = result.replace(/ey[A-Za-z0-9_-]*(?:\.[A-Za-z0-9_-]*){2,}/g, REDACTION);
- 
-  return result;
-}
- 
-// Export a singleton instance for easy import
-export const logger = Logger.getInstance();
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/src/services/chat-service.ts b/src/services/chat-service.ts index 5855e18..e794104 100644 --- a/src/services/chat-service.ts +++ b/src/services/chat-service.ts @@ -66,24 +66,7 @@ export class ChatService { optionsCopy.messages = []; } - logger.debug('Starting createCompletion with options:'); - try { - logger.debug( - JSON.stringify( - { - ...optionsCopy, - apiKey: optionsCopy.apiKey ? '***' : undefined, - messages: optionsCopy.messages - ? `${optionsCopy.messages.length} messages` - : '0 messages', - }, - null, - 2, - ), - ); - } catch (error) { - logger.error('Failed to stringify options:', error); - } + this.logCompletionOptions(optionsCopy); const headers: Record = {}; @@ -91,41 +74,16 @@ export class ChatService { headers['Authorization'] = optionsCopy.apiKey; } - // Set default model if not provided if (!optionsCopy.model) { logger.debug('No model specified, using default: google/gemma-3-27b-it'); optionsCopy.model = 'google/gemma-3-27b-it'; } - logger.debug('Chat completion options:'); - logger.debug( - JSON.stringify( - { - ...optionsCopy, - apiKey: optionsCopy.apiKey ? '***' : undefined, - }, - null, - 2, - ), - ); + this.logCompletionOptions(optionsCopy); return this.executeCompletion(optionsCopy, headers); } catch (error) { - let errorMessage = 'Failed to create chat completion'; - - if (error instanceof Error) { - try { - const parsedError = JSON.parse(error.message); - if (parsedError.error && parsedError.error.message) { - errorMessage = `Chat error: ${parsedError.error.message}`; - } - } catch { - errorMessage = `Chat error: ${error.message}`; - } - } - - logger.error(errorMessage); - throw new Error(errorMessage); + throw this.formatCompletionError(error); } } @@ -135,37 +93,23 @@ export class ChatService { */ public async listModels(apiKey?: string): Promise { try { - const headers = apiKey ? { Authorization: apiKey } : {}; + let data: any; + let error: any; if (apiKey) { - const { data, error } = await this.client.GET('/v1/models', { headers }); - if (error) throw new Error(JSON.stringify(error)); - return data; + const result = await this.client.GET('/v1/models', { headers: { Authorization: apiKey } }); + data = result.data; + error = result.error; } else { - const { data, error } = await this.client.GET('/v1/models'); - if (error) throw new Error(JSON.stringify(error)); - return data; - } - } catch (error) { - let errorMessage = 'Failed to list models'; - - if (error instanceof Error) { - try { - const parsedError = JSON.parse(error.message); - if (parsedError.error) { - errorMessage = `Models error: ${ - typeof parsedError.error === 'string' - ? parsedError.error - : parsedError.error.message || JSON.stringify(parsedError.error) - }`; - } - } catch { - errorMessage = `Models error: ${error.message}`; - } + const result = await this.client.GET('/v1/models'); + data = result.data; + error = result.error; } - logger.error(errorMessage); - throw new Error(errorMessage); + if (error) throw new Error(JSON.stringify(error)); + return data; + } catch (error) { + throw this.formatListModelsError(error); } } @@ -272,6 +216,46 @@ export class ChatService { } } + private formatCompletionError(error: unknown): Error { + let errorMessage = 'Failed to create chat completion'; + + if (error instanceof Error) { + try { + const parsedError = JSON.parse(error.message); + if (parsedError.error && parsedError.error.message) { + errorMessage = `Chat error: ${parsedError.error.message}`; + } + } catch { + errorMessage = `Chat error: ${error.message}`; + } + } + + logger.error(errorMessage); + return new Error(errorMessage); + } + + private formatListModelsError(error: unknown): Error { + let errorMessage = 'Failed to list models'; + + if (error instanceof Error) { + try { + const parsedError = JSON.parse(error.message); + if (parsedError.error) { + errorMessage = `Models error: ${ + typeof parsedError.error === 'string' + ? parsedError.error + : parsedError.error.message || JSON.stringify(parsedError.error) + }`; + } + } catch { + errorMessage = `Models error: ${error.message}`; + } + } + + logger.error(errorMessage); + return new Error(errorMessage); + } + /** * Handle streaming response from the API * @param options Request options @@ -325,6 +309,26 @@ export class ChatService { return braceCount === 0; } + private logCompletionOptions(optionsCopy: ChatCompletionOptions): void { + try { + logger.debug( + JSON.stringify( + { + ...optionsCopy, + apiKey: optionsCopy.apiKey ? '***' : undefined, + messages: optionsCopy.messages + ? `${optionsCopy.messages.length} messages` + : '0 messages', + }, + null, + 2, + ), + ); + } catch (error) { + logger.error('Failed to stringify options:', error); + } + } + private logParseError(error: unknown, jsonData: string): void { logger.error(`Error parsing chunk: ${error}`); const errorMsg = (error as any).message || ''; From 9ea963317e6a610c0dc75559b2f91d38a9d47b45 Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:17:37 +0200 Subject: [PATCH 6/8] =?UTF-8?q?refactor(commands/chat):=20reduce=20resolve?= =?UTF-8?q?ApiKey=20complexity=20to=20=E2=89=A415?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract resolveDefaultApiKey() for default API key resolution logic - Simplify early returns for env var and command-line API keys --- src/commands/chat.ts | 99 ++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/src/commands/chat.ts b/src/commands/chat.ts index b99ba74..4a16d15 100644 --- a/src/commands/chat.ts +++ b/src/commands/chat.ts @@ -221,19 +221,16 @@ async function handleStreamingCompletion( } async function resolveApiKey(options: any): Promise { - let apiKey = options.apiKey; - const environmentApiKey = process.env.BERGET_API_KEY; if (environmentApiKey) { console.log(chalk.dim('Using API key from BERGET_API_KEY environment variable')); - apiKey = environmentApiKey; if (process.argv.includes('--debug')) { console.log( chalk.yellow(`DEBUG: API key from env starts with: ${environmentApiKey.slice(0, 4)}...`), ); } - return apiKey; + return environmentApiKey; } if (options.apiKey) { @@ -241,53 +238,11 @@ async function resolveApiKey(options: any): Promise { return options.apiKey; } - if (!apiKey && !options.apiKeyId) { - try { - const defaultApiKeyManager = DefaultApiKeyManager.getInstance(); - const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData(); - - if (defaultApiKeyData) { - if (defaultApiKeyData.key) { - console.log(chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)); - return defaultApiKeyData.key; - } else { - console.log( - chalk.yellow( - `Default API key "${defaultApiKeyData.name}" exists but the key value is missing.`, - ), - ); - console.log( - chalk.yellow( - `Try rotating the key with: berget api-keys rotate ${defaultApiKeyData.id}`, - ), - ); - } - } else { - console.log(chalk.yellow('No default API key set.')); - apiKey = await defaultApiKeyManager.promptForDefaultApiKey(); - - if (!apiKey) { - console.log(chalk.red('Error: An API key is required to use the chat command.')); - console.log(chalk.yellow('You can:')); - console.log( - chalk.yellow('1. Create an API key with: berget api-keys create --name "My Key"'), - ); - console.log( - chalk.yellow('2. Set a default API key with: berget api-keys set-default '), - ); - console.log(chalk.yellow('3. Provide an API key with the --api-key option')); - return undefined; - } - } - } catch (error) { - if (process.argv.includes('--debug')) { - console.log(chalk.yellow('DEBUG: Error checking default API key:')); - console.log(chalk.yellow(String(error))); - } - } + if (!options.apiKeyId) { + return resolveDefaultApiKey(); } - return apiKey; + return undefined; } async function resolveApiKeyForList(options: any): Promise { @@ -360,6 +315,52 @@ async function resolveApiKeyFromId(apiKeyId: string): Promise { + try { + const defaultApiKeyManager = DefaultApiKeyManager.getInstance(); + const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData(); + + if (defaultApiKeyData) { + if (defaultApiKeyData.key) { + console.log(chalk.dim(`Using default API key: ${defaultApiKeyData.name}`)); + return defaultApiKeyData.key; + } + + console.log( + chalk.yellow( + `Default API key "${defaultApiKeyData.name}" exists but the key value is missing.`, + ), + ); + console.log( + chalk.yellow(`Try rotating the key with: berget api-keys rotate ${defaultApiKeyData.id}`), + ); + return undefined; + } + + console.log(chalk.yellow('No default API key set.')); + const apiKey = await defaultApiKeyManager.promptForDefaultApiKey(); + + if (!apiKey) { + console.log(chalk.red('Error: An API key is required to use the chat command.')); + console.log(chalk.yellow('You can:')); + console.log( + chalk.yellow('1. Create an API key with: berget api-keys create --name "My Key"'), + ); + console.log(chalk.yellow('2. Set a default API key with: berget api-keys set-default ')); + console.log(chalk.yellow('3. Provide an API key with the --api-key option')); + return undefined; + } + + return apiKey; + } catch (error) { + if (process.argv.includes('--debug')) { + console.log(chalk.yellow('DEBUG: Error checking default API key:')); + console.log(chalk.yellow(String(error))); + } + return undefined; + } +} + async function resolveInputMessage(message: string | undefined): Promise { let inputMessage = message; let stdinContent = ''; From 9126186d6b07767d190b527bbaba4f2c92493cf7 Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:19:30 +0200 Subject: [PATCH 7/8] =?UTF-8?q?refactor(token-refresh):=20reduce=20doRefre?= =?UTF-8?q?sh=20complexity=20from=2021=20to=20=E2=89=A415?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract classifyRefreshError() to determine error handling action - Extract storeNewTokens() for token persistence logic - Introduce RefreshErrorAction interface for structured error classification - All 12 existing tests pass --- src/auth/oauth/token-refresh.ts | 87 ++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 34 deletions(-) diff --git a/src/auth/oauth/token-refresh.ts b/src/auth/oauth/token-refresh.ts index d390db3..c568a9c 100644 --- a/src/auth/oauth/token-refresh.ts +++ b/src/auth/oauth/token-refresh.ts @@ -34,6 +34,11 @@ function isTransientError(error: unknown): boolean { // while ensuring different stores don't share promises. const inFlightByConfig = new WeakMap>>(); +interface RefreshErrorAction { + clearTokens: boolean; + retry: boolean; +} + export async function refreshAccessToken( config: Configuration, tokenStore: TokenStore, @@ -57,6 +62,29 @@ export async function refreshAccessToken( return promise; } +function classifyRefreshError(error: unknown, attempt: number): RefreshErrorAction { + if (error instanceof ResponseBodyError) { + const isPermanent = + error.error === 'invalid_grant' || error.status === 401 || error.status === 403; + return { clearTokens: isPermanent, retry: false }; + } + + if ( + error instanceof Error && + (error.message.includes('401') || + error.message.includes('403') || + error.message.includes('invalid_grant')) + ) { + return { clearTokens: true, retry: false }; + } + + if (isTransientError(error) && attempt < MAX_RETRIES - 1) { + return { clearTokens: false, retry: true }; + } + + return { clearTokens: false, retry: false }; +} + /** * Try to refresh the access token with exponential backoff on transient * network failures. Permanent auth errors clear stored tokens; transient @@ -71,46 +99,16 @@ async function doRefresh(config: Configuration, tokenStore: TokenStore): Promise while (true) { try { const result = await refreshTokenGrant(config, tokenData.refresh_token); - - // Extract tokens from response - const accessToken = result.access_token; - const refreshToken = result.refresh_token || tokenData.refresh_token; - const expiresIn = result.expires_in || 3600; - - // Calculate expiration from JWT or fallback - const jwtExpiresAt = extractJwtExpiresAt(accessToken); - const expiresAt = jwtExpiresAt > 0 ? jwtExpiresAt : Date.now() + expiresIn * 1000; - - const newTokenData: TokenData = { - access_token: accessToken, - expires_at: expiresAt, - refresh_token: refreshToken, - }; - - await tokenStore.set(newTokenData); + await storeNewTokens(tokenStore, tokenData.refresh_token, result); return true; } catch (error) { - // On invalid/expired refresh token (401/403 from Keycloak), clear tokens. - // ResponseBodyError from openid-client carries structured error info. - if (error instanceof ResponseBodyError) { - if (error.error === 'invalid_grant' || error.status === 401 || error.status === 403) { - await tokenStore.clear(); - } - return false; - } + const action = classifyRefreshError(error, attempt); - if ( - error instanceof Error && - (error.message.includes('401') || - error.message.includes('403') || - error.message.includes('invalid_grant')) - ) { - // Fallback for non-standard error shapes (e.g. network-level failures) + if (action.clearTokens) { await tokenStore.clear(); - return false; } - if (isTransientError(error) && attempt < MAX_RETRIES - 1) { + if (action.retry) { await sleep(INITIAL_BACKOFF_MS * 2 ** attempt); attempt++; continue; @@ -124,3 +122,24 @@ async function doRefresh(config: Configuration, tokenStore: TokenStore): Promise function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } + +async function storeNewTokens( + tokenStore: TokenStore, + oldRefreshToken: string, + result: any, +): Promise { + const accessToken = result.access_token; + const refreshToken = result.refresh_token || oldRefreshToken; + const expiresIn = result.expires_in || 3600; + + const jwtExpiresAt = extractJwtExpiresAt(accessToken); + const expiresAt = jwtExpiresAt > 0 ? jwtExpiresAt : Date.now() + expiresIn * 1000; + + const newTokenData: TokenData = { + access_token: accessToken, + expires_at: expiresAt, + refresh_token: refreshToken, + }; + + await tokenStore.set(newTokenData); +} From 882137229b2ce953deda868c3a1f52e0ed1a7abf Mon Sep 17 00:00:00 2001 From: Marcus Olsson <8396880+marcusolsson@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:21:47 +0200 Subject: [PATCH 8/8] =?UTF-8?q?refactor(auth-sync):=20reduce=20configureAu?= =?UTF-8?q?th=20complexity=20from=2025=20to=20=E2=89=A415?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract handleUndecodableJwt() for JWT decode failure path - Extract handleHasSeat() for subscription seat flow - Extract handleNoSeat() for no-subscription API key flow - Extract createAndSyncApiKey() for shared API key creation logic - All 40 existing tests pass --- src/commands/code/auth-sync.ts | 197 ++++++++++++++++++--------------- 1 file changed, 107 insertions(+), 90 deletions(-) diff --git a/src/commands/code/auth-sync.ts b/src/commands/code/auth-sync.ts index 0ed2231..b5acb84 100644 --- a/src/commands/code/auth-sync.ts +++ b/src/commands/code/auth-sync.ts @@ -71,106 +71,19 @@ export async function configureAuth( return { authenticated: false }; } - // Check Berget Code seat const jwtPayload = decodeJwtPayload(cliAuth.access_token); - // If we can't decode the JWT, sync OAuth anyway — the tokens are valid even if - // we can't verify the subscription role. Let the tool handle authorization. if (!jwtPayload) { - const s = prompter.spinner(); - s.start('Authenticating with Berget AI...'); - try { - await syncOAuthToTool(files, homeDir, tool, cliAuth); - s.stop('Authenticated.'); - } catch (error) { - s.stop('Authentication failed.'); - throw error; - } - prompter.note( - 'Warning: Could not verify Berget Code subscription status.\nIf you do not have a subscription, the tool may show an authorization error.', - 'Authentication', - ); - return { authenticated: true }; + return handleUndecodableJwt(prompter, files, homeDir, tool, cliAuth); } - // JWT decoded successfully — check subscription seat const hasSeat = hasBergetCodeSeat(cliAuth.access_token); if (hasSeat) { - // Case B: Has seat — ask how to authenticate - const method = await prompter.select<'api_key' | 'subscription'>({ - message: 'You have a Berget Code subscription. How do you want to authenticate?', - options: [ - { label: 'Use my Berget Code subscription', value: 'subscription' }, - { label: 'Use an API key instead', value: 'api_key' }, - ], - }); - - if (method === 'subscription') { - const s = prompter.spinner(); - s.start('Authenticating with Berget AI via subscription...'); - try { - await syncOAuthToTool(files, homeDir, tool, cliAuth); - s.stop('Authenticated.'); - } catch (error) { - s.stop('Authentication failed.'); - throw error; - } - return { authenticated: true }; - } - - // Create API key instead - const s = prompter.spinner(); - s.start('Creating API key...'); - try { - const { key } = await apiKeyService.create({ - description: 'Created by berget code init', - name: `${tool === 'opencode' ? 'OpenCode' : 'Pi'} (created by berget CLI)`, - }); - await syncApiKeyToTool(files, homeDir, tool, key); - s.stop('API key created and saved.'); - return { authenticated: true }; - } catch (error: any) { - s.stop('API key creation failed.'); - throw new FatalError( - error?.message || - 'Could not create API key. Please create one manually with `berget api-keys create`.', - ); - } - } - - // No Berget Code seat — prompt for API key creation - const shouldCreate = await prompter.confirm({ - initialValue: true, - message: 'You do not have a Berget Code subscription. Would you like to create a new API key?', - }); - - if (shouldCreate) { - const s = prompter.spinner(); - s.start('Creating API key...'); - try { - const { key } = await apiKeyService.create({ - description: 'Created by berget code init', - name: `${tool === 'opencode' ? 'OpenCode' : 'Pi'} (created by berget CLI)`, - }); - await syncApiKeyToTool(files, homeDir, tool, key); - s.stop('API key created and saved.'); - return { authenticated: true }; - } catch (error: any) { - s.stop('API key creation failed.'); - throw new FatalError( - error?.message || - 'Could not create API key. Please create one manually with `berget api-keys create`.', - ); - } + return handleHasSeat(prompter, apiKeyService, files, homeDir, tool, cliAuth); } - // Case D: Declined - prompter.note( - 'Authentication skipped. You\'ll need to set up authentication manually:\n1. Run: berget api-keys create --name "My Key"\n2. Set BERGET_API_KEY environment variable, or\n3. Run `berget auth login` and try again', - 'Authentication', - ); - return { authenticated: false }; + return handleNoSeat(prompter, apiKeyService, files, homeDir, tool); } export async function ensureCliAuth( @@ -325,3 +238,107 @@ export async function syncOAuthToTool( await files.writeFile(authPath, JSON.stringify(updated, null, 2) + '\n'); await files.chmod(authPath, 0o600); } + +async function createAndSyncApiKey( + prompter: Prompter, + apiKeyService: ApiKeyServicePort, + files: FileStore, + homeDir: string, + tool: 'opencode' | 'pi', +): Promise { + const s = prompter.spinner(); + s.start('Creating API key...'); + try { + const { key } = await apiKeyService.create({ + description: 'Created by berget code init', + name: `${tool === 'opencode' ? 'OpenCode' : 'Pi'} (created by berget CLI)`, + }); + await syncApiKeyToTool(files, homeDir, tool, key); + s.stop('API key created and saved.'); + return { authenticated: true }; + } catch (error: any) { + s.stop('API key creation failed.'); + throw new FatalError( + error?.message || + 'Could not create API key. Please create one manually with `berget api-keys create`.', + ); + } +} + +async function handleHasSeat( + prompter: Prompter, + apiKeyService: ApiKeyServicePort, + files: FileStore, + homeDir: string, + tool: 'opencode' | 'pi', + cliAuth: CliAuth, +): Promise { + const method = await prompter.select<'api_key' | 'subscription'>({ + message: 'You have a Berget Code subscription. How do you want to authenticate?', + options: [ + { label: 'Use my Berget Code subscription', value: 'subscription' }, + { label: 'Use an API key instead', value: 'api_key' }, + ], + }); + + if (method === 'subscription') { + const s = prompter.spinner(); + s.start('Authenticating with Berget AI via subscription...'); + try { + await syncOAuthToTool(files, homeDir, tool, cliAuth); + s.stop('Authenticated.'); + } catch (error) { + s.stop('Authentication failed.'); + throw error; + } + return { authenticated: true }; + } + + return createAndSyncApiKey(prompter, apiKeyService, files, homeDir, tool); +} + +async function handleNoSeat( + prompter: Prompter, + apiKeyService: ApiKeyServicePort, + files: FileStore, + homeDir: string, + tool: 'opencode' | 'pi', +): Promise { + const shouldCreate = await prompter.confirm({ + initialValue: true, + message: 'You do not have a Berget Code subscription. Would you like to create a new API key?', + }); + + if (shouldCreate) { + return createAndSyncApiKey(prompter, apiKeyService, files, homeDir, tool); + } + + prompter.note( + 'Authentication skipped. You\'ll need to set up authentication manually:\n1. Run: berget api-keys create --name "My Key"\n2. Set BERGET_API_KEY environment variable, or\n3. Run `berget auth login` and try again', + 'Authentication', + ); + return { authenticated: false }; +} + +async function handleUndecodableJwt( + prompter: Prompter, + files: FileStore, + homeDir: string, + tool: 'opencode' | 'pi', + cliAuth: CliAuth, +): Promise { + const s = prompter.spinner(); + s.start('Authenticating with Berget AI...'); + try { + await syncOAuthToTool(files, homeDir, tool, cliAuth); + s.stop('Authenticated.'); + } catch (error) { + s.stop('Authentication failed.'); + throw error; + } + prompter.note( + 'Warning: Could not verify Berget Code subscription status.\nIf you do not have a subscription, the tool may show an authorization error.', + 'Authentication', + ); + return { authenticated: true }; +}