@wispbit/local 1.0.75 → 1.0.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/cli-bundle.js +2 -2
  2. package/package.json +1 -1
package/cli-bundle.js CHANGED
@@ -279,8 +279,8 @@ ${ge}`)}else u.push(Y)}let E="";if(o&&(o.mode==="check"?E=o.filePath?` ${W.dim(`
279
279
  `;await OQ.promises.appendFile(o,a)}return{systemMessage:new gl({level:3}).dim.italic("wispbit will automatically review all changes in this session")}}async handlePostToolUse(e){Zt.log(`[ClaudeHookHandler] PostToolUse (${e.tool_name}) for file ${e.tool_input.file_path}`);let n=new ga;if(!await n.getSession("claude",e.session_id)){Zt.log("[ClaudeHookHandler] Session not initialized, skipping PostToolUse");return}let i=e.tool_input.file_path,o=dC.isAbsolute(i)?dC.relative(e.cwd,i):i,s,a;e.tool_name==="Write"?(a="",s=e.tool_input.content||""):(a=e.tool_input.old_string||"",s=e.tool_input.new_string||""),await n.addFileChange(o,a,s),Zt.log(`[ClaudeHookHandler] Added change for ${o}`)}async handleStop(e){Zt.log(`[ClaudeHookHandler] Stop for session ${e.session_id}`);let n=new ga,r=await n.getSession("claude",e.session_id);if(!r){Zt.log("[ClaudeHookHandler] Session not initialized, skipping Stop");return}Zt.log(`[ClaudeHookHandler] Wispbit session ID: ${r.wispbitSessionId}`);let i=n.getLastCheckpointTimestamp();if((i?n.getFileChanges(i):n.getFileChanges()).length===0){Zt.log("[ClaudeHookHandler] No file changes since last checkpoint, skipping");return}let s=n.getFileChanges();Zt.log(`[ClaudeHookHandler] Found ${s.length} files changed in session`);for(let M of s)Zt.log(`
280
280
  [ClaudeHookHandler] File: ${M.filename} (${M.status})`),Zt.log(`[ClaudeHookHandler] +${M.additions} -${M.deletions}`),Zt.log(`[ClaudeHookHandler] Diff:
281
281
  ${M.patch}`);let{results:a,rules:c}=await this.runPowerlint(e.cwd,s),u=a.flatMap(M=>M.matches.map(G=>({...G,ruleId:M.ruleId}))),l=n.getLastCheckpointMatches(),E=new Map;for(let M of u){let G=M.ruleId;E.has(G)||E.set(G,[]),E.get(G).push(M)}let d=new Map;for(let M of l)d.has(M.ruleId)||d.set(M.ruleId,[]),d.get(M.ruleId).push(M);let T=[];for(let[M,G]of E.entries()){let H=d.get(M)||[],re=G.map(j=>({file:j.file.path,startLine:j.range.start.line,endLine:j.range.end.line,fingerprint:j.fingerprint})),Z=H.map(j=>({file:j.file.path,startLine:j.range.start.line,endLine:j.range.end.line,fingerprint:j.fingerprint})),q=ph(re,Z),Y=G.filter((j,se)=>!q.has(se));T.push(...Y)}let S=new Map;for(let M of T){let G=M.ruleId;S.has(G)||S.set(G,[]),S.get(G).push(M)}let p=Array.from(S.entries()).map(([M,G])=>({ruleId:M,matches:G})),f=new Map;for(let M of u){let G=M.ruleId;f.has(G)||f.set(G,[]),f.get(G).push(M)}let h=Array.from(f.entries()).map(([M,G])=>({ruleId:M,matches:G})),O=T.length,N=u.length;Zt.log(`[ClaudeHookHandler] New: ${O}, Total: ${N}`),await n.createCheckpoint(T);let C=await this.buildStopMessage(p,h,c,e.cwd,O,N,s.length);if(Zt.log(`[ClaudeHookHandler] Built system message: ${C?"yes":"no"}`),!!C)return{systemMessage:C}}async handleSessionEnd(e){Zt.log(`[ClaudeHookHandler] SessionEnd (${e.reason}) for session ${e.session_id}`);let n=new ga;if(!await n.getSession("claude",e.session_id)){Zt.log("[ClaudeHookHandler] Session not initialized, skipping SessionEnd");return}await n.endSession()}async runPowerlint(e,n){let r=new Kr({repositoryUrl:void 0,workspaceRoot:e}),i=await EC(),o=await Yo.initialize(r,{apiKey:i||void 0});if("failed"in o)throw new Error(`Failed to initialize config: ${o.error}`);let s=o,a=new zr,c=new $o(s,r),u=await c.loadAllRules(),l=new Ma(s,r,a),E=await c.getDismissals([]),d=new Map;for(let S of E)d.has(S.ruleId)||d.set(S.ruleId,[]),d.get(S.ruleId).push(S.match);return{results:await l.execute(u,{mode:"session",customDiffOptions:{fileChanges:n},dismissedMatchesByRule:d}),rules:u}}async buildStopMessage(e,n,r,i,o,s,a){let c=e.filter(T=>T.matches.length>0),u=n.filter(T=>T.matches.length>0),l=new gl({level:3}),E;if(s===o)if(o>0)E=l.red("wispbit found ")+l.red.bold(`${o} new`)+l.red(` ${o===1?"issue":"issues"}`);else return null;else o>0?E=l.red("wispbit found ")+l.red.bold(`${o} new`)+l.red(` ${o===1?"issue":"issues"}`)+l.dim(` (${s} total)`):E=l.dim.italic(`wispbit found ${s} total ${s===1?"issue":"issues"} from ${a} ${a===1?"file edit":"file edits"} this session`);let d=[];if(c.length>0){let T=new Set;for(let p of u)for(let f of p.matches)T.add(f.file.path);let S=await Lh(c,r,i,l,{maxMatchesPerRule:1,maxDiffLines:10});d.push(S),d.push("",E),d.push(l.dim("Run ")+l.cyan("!wispbit")+l.dim(" to view, ")+l.cyan("!wispbit --fix")+l.dim(" to fix, ")+l.cyan("!wispbit --dismiss")+l.dim(" to dismiss (add ")+l.cyan("RULE-123")+l.dim(" for specific rules)"))}else u.length>0?d.push(E+l.dim.italic(". Run ")+l.cyan("!wispbit")+l.dim.italic(" to view and fix issues.")):d.push(E);return d.join(`
282
- `)}};function CQ(t){switch(t){case"claude":return new _C;default:throw new Error(`Unknown hook provider: ${t}`)}}import*as Hc from"fs/promises";import*as IQ from"os";import*as yh from"path";var TC=class{getStorageDir(){return yh.join(IQ.homedir(),".wispbit","hooks")}getStoragePath(e){return yh.join(this.getStorageDir(),`${e}.json`)}async load(e){let n=this.getStoragePath(e);try{let r=await Hc.readFile(n,"utf-8");return JSON.parse(r)}catch{return null}}async save(e,n){let r=this.getStoragePath(e);await Hc.mkdir(yh.dirname(r),{recursive:!0}),await Hc.writeFile(r,JSON.stringify(n,null,2))}async clear(e){let n=this.getStoragePath(e);try{await Hc.unlink(n)}catch{}}};async function MQ(t,e){let[n,r]=t.split(".");if(!n||!r)throw new Error(`Invalid providerEvent format: ${t}. Expected "provider.event"`);let i=CQ(n),o=new TC,s=i.eventSchemas[r];if(!s)throw new Error(`Unknown event: ${r} for provider: ${n}`);let a=s.parse(e),c=i.getConversationId(a);i._setContext(o,c);let u=await i.handleEvent(r,a);return i._clearContext(),u??{}}var yr=ue(Xne(),1);import{promises as ere}from"fs";import{join as HI,relative as tre}from"path";import{fileURLToPath as ys,pathToFileURL as but}from"url";var BI=class t{constructor(e,n,r,i){this._uri=e,this._languageId=n,this._version=r,this._content=i,this._lineOffsets=void 0}get uri(){return this._uri}get languageId(){return this._languageId}get version(){return this._version}getText(e){if(e){let n=this.offsetAt(e.start),r=this.offsetAt(e.end);return this._content.substring(n,r)}return this._content}update(e,n){for(let r of e)if(t.isIncremental(r)){let i=Qne(r.range),o=this.offsetAt(i.start),s=this.offsetAt(i.end);this._content=this._content.substring(0,o)+r.text+this._content.substring(s,this._content.length);let a=Math.max(i.start.line,0),c=Math.max(i.end.line,0),u=this._lineOffsets,l=qne(r.text,!1,o);if(c-a===l.length)for(let d=0,T=l.length;d<T;d++)u[d+a+1]=l[d];else l.length<1e4?u.splice(a+1,c-a,...l):this._lineOffsets=u=u.slice(0,a+1).concat(l,u.slice(c+1));let E=r.text.length-(s-o);if(E!==0)for(let d=a+1+l.length,T=u.length;d<T;d++)u[d]=u[d]+E}else if(t.isFull(r))this._content=r.text,this._lineOffsets=void 0;else throw new Error("Unknown change event received");this._version=n}getLineOffsets(){return this._lineOffsets===void 0&&(this._lineOffsets=qne(this._content,!0)),this._lineOffsets}positionAt(e){e=Math.max(Math.min(e,this._content.length),0);let n=this.getLineOffsets(),r=0,i=n.length;if(i===0)return{line:0,character:e};for(;r<i;){let s=Math.floor((r+i)/2);n[s]>e?i=s:r=s+1}let o=r-1;return e=this.ensureBeforeEOL(e,n[o]),{line:o,character:e-n[o]}}offsetAt(e){let n=this.getLineOffsets();if(e.line>=n.length)return this._content.length;if(e.line<0)return 0;let r=n[e.line];if(e.character<=0)return r;let i=e.line+1<n.length?n[e.line+1]:this._content.length,o=Math.min(r+e.character,i);return this.ensureBeforeEOL(o,r)}ensureBeforeEOL(e,n){for(;e>n&&Jne(this._content.charCodeAt(e-1));)e--;return e}get lineCount(){return this.getLineOffsets().length}static isIncremental(e){let n=e;return n!=null&&typeof n.text=="string"&&n.range!==void 0&&(n.rangeLength===void 0||typeof n.rangeLength=="number")}static isFull(e){let n=e;return n!=null&&typeof n.text=="string"&&n.range===void 0&&n.rangeLength===void 0}},em;(function(t){function e(i,o,s,a){return new BI(i,o,s,a)}t.create=e;function n(i,o,s){if(i instanceof BI)return i.update(o,s),i;throw new Error("TextDocument.update: document must be created by TextDocument.create")}t.update=n;function r(i,o){let s=i.getText(),a=TF(o.map(Lut),(l,E)=>{let d=l.range.start.line-E.range.start.line;return d===0?l.range.start.character-E.range.start.character:d}),c=0,u=[];for(let l of a){let E=i.offsetAt(l.range.start);if(E<c)throw new Error("Overlapping edit");E>c&&u.push(s.substring(c,E)),l.newText.length&&u.push(l.newText),c=i.offsetAt(l.range.end)}return u.push(s.substr(c)),u.join("")}t.applyEdits=r})(em||(em={}));function TF(t,e){if(t.length<=1)return t;let n=t.length/2|0,r=t.slice(0,n),i=t.slice(n);TF(r,e),TF(i,e);let o=0,s=0,a=0;for(;o<r.length&&s<i.length;)e(r[o],i[s])<=0?t[a++]=r[o++]:t[a++]=i[s++];for(;o<r.length;)t[a++]=r[o++];for(;s<i.length;)t[a++]=i[s++];return t}function qne(t,e,n=0){let r=e?[n]:[];for(let i=0;i<t.length;i++){let o=t.charCodeAt(i);Jne(o)&&(o===13&&i+1<t.length&&t.charCodeAt(i+1)===10&&i++,r.push(n+i+1))}return r}function Jne(t){return t===13||t===10}function Qne(t){let e=t.start,n=t.end;return e.line>n.line||e.line===n.line&&e.character>n.character?{start:n,end:e}:t}function Lut(t){let e=Qne(t.range);return e!==t.range?{newText:t.newText,range:e}:t}function Si(t){let e=decodeURIComponent(t);return e.startsWith("file:///")&&(e=e.replace(/\\/g,"/")),e=e.replace(/^file:\/\/\/([a-z]):/,(n,r)=>`file:///${r.toUpperCase()}:`),e}var FI=class{syncedDocuments=new Map;diagnosticsByFileAndRule=new Map;dismissalsByFile=new Map;fixesByFile=new Map;listen(e,n){e.onDidOpenTextDocument(r=>{let i=r.textDocument,o=Si(i.uri),s=em.create(o,i.languageId,i.version,i.text);this.syncedDocuments.set(o,s),n.onDidOpen?.(o,s)}),e.onDidChangeTextDocument(r=>{let i=r.textDocument,o=Si(i.uri),s=r.contentChanges;if(s.length===0)return;let a=i.version;if(a==null)return;let c=this.syncedDocuments.get(o);c&&(c=em.update(c,s,a),this.syncedDocuments.set(o,c),n.onDidChangeContent?.(o,c,s))}),e.onDidCloseTextDocument(r=>{let i=Si(r.textDocument.uri);this.syncedDocuments.delete(i),n.onDidClose?.(i)}),e.onDidSaveTextDocument(r=>{let i=Si(r.textDocument.uri),o=this.syncedDocuments.get(i);o&&n.onDidSave?.(i,o)})}getDocument(e){let n=Si(e);return this.syncedDocuments.get(n)}getAllDocumentUris(){return Array.from(this.syncedDocuments.values()).map(e=>e.uri)}getAllDiagnosticUris(){return Array.from(this.diagnosticsByFileAndRule.keys())}setDiagnosticsForRule(e,n,r){let i=Si(e);this.diagnosticsByFileAndRule.has(i)||this.diagnosticsByFileAndRule.set(i,new Map),this.diagnosticsByFileAndRule.get(i).set(n,r)}getDiagnostics(e){let n=Si(e),r=this.diagnosticsByFileAndRule.get(n);if(!r)return[];let i=[];for(let[o,s]of r.entries())i.push(...s);return i}clearDiagnostics(e){let n=Si(e);this.diagnosticsByFileAndRule.delete(n)}setDismissals(e,n){this.dismissalsByFile.set(e,n)}getDismissals(e){return this.dismissalsByFile.get(e)||[]}hasDismissals(e){return this.dismissalsByFile.has(e)}clearDismissals(e){this.dismissalsByFile.delete(e)}setFixes(e,n){this.fixesByFile.set(e,n)}getFixes(e){return this.fixesByFile.get(e)||[]}hasFixes(e){return this.fixesByFile.has(e)}clearFixes(e){this.fixesByFile.delete(e)}};import{sep as yut}from"path";var kI=class{contexts=new Map;workspacePath;apiKey;lspClient;RULES_CACHE_TTL_MS=300*1e3;constructor(e){this.workspacePath=e.workspacePath,this.apiKey=e.apiKey,this.lspClient=e.lspClient}async discoverAndInitialize(e,n){let r=await qN(this.workspacePath);for(let i of r){let o=await this.initializeContext(i).catch(s=>(n?.(i,s),null));o&&(this.contexts.set(i,o),e?.(i,o))}}async initializeContext(e){let n=new Kr({workspaceRoot:e}),r=await Yo.initialize(n,{apiKey:this.apiKey,lspClient:this.lspClient});if("failed"in r)throw new Error(`Config initialization failed for ${e}: ${r.error}`);let i=r,o=new $o(i,n),s=new zr,a=new Ma(i,n,s);return{repoRoot:e,environment:n,config:i,ruleProvider:o,eventEmitter:s,ruleExecutor:a,cachedRules:null,rulesById:new Map,rulesCacheTimestamp:0,rulesLoadingPromise:null,lastCommitSelector:null,currentExecutionRules:[],completedRulesCount:0,isExecuting:!1,currentExecutionPromise:null}}findContextForFile(e){return Array.from(this.contexts.entries()).filter(([r])=>e.startsWith(r+yut)||e===r).sort((r,i)=>i[0].length-r[0].length)[0]?.[1]||null}getAllContexts(){return Array.from(this.contexts.values())}getRepoCount(){return this.contexts.size}hasRepositories(){return this.contexts.size>0}getContext(e){return this.contexts.get(e)}shutdown(){for(let e of this.contexts.values())e.ruleExecutor.clearCache();this.contexts.clear()}};function vut(t,e,n){if(t.fingerprint)return`${e}:${t.fingerprint}`;let r=t.text?.slice(0,100)||"",i=`${t.range.start.line}:${t.range.start.column}-${t.range.end.line}:${t.range.end.column}`;return`${e}:${n}:${i}:${Uut(r)}`}function Uut(t){let e=0;for(let n=0;n<t.length;n++){let r=t.charCodeAt(n);e=(e<<5)-e+r,e=e&e}return e.toString(36)}var SF=class{connection;documentManager;repositoryContextManager;workspacePath;apiKey;lspClient;batchProgressReporter=null;batchProgressToken="wispbit-batch-lint";progressTokenCreated=!1;fixQueue=[];isProcessingFix=!1;branchCheckTimer=null;BRANCH_CHECK_DEBOUNCE_MS=1e3;branchCheckInterval=null;BRANCH_CHECK_INTERVAL_MS=3e4;executionDebounceTimer=null;EXECUTION_DEBOUNCE_MS=1e3;constructor(e){this.workspacePath=e.workspacePath,this.apiKey=e.apiKey,this.lspClient=e.lspClient,this.connection=(0,yr.createConnection)(yr.ProposedFeatures.all,process.stdin,process.stdout),this.documentManager=new FI,this.repositoryContextManager=new kI({workspacePath:this.workspacePath,apiKey:this.apiKey,lspClient:this.lspClient}),this.registerHandlers()}findContextForFile(e){let n=ys(e);return this.repositoryContextManager.findContextForFile(n)}pathToNormalizedUri(e){let n=but(e).toString();return decodeURIComponent(n)}getDiagnosticsForUri(e){let n=this.documentManager.getDiagnostics(e);if(n.length===0){let r=Si(e),i=this.documentManager.getAllDiagnosticUris();for(let o of i)if(Si(o)===r){n=this.documentManager.getDiagnostics(o);break}}return n}async updateDiagnosticsForRuleMatches(e,n,r,i){if(!e.currentExecutionRules.find(c=>c.internalId===n)){this.connection.console.log(`[${e.repoRoot}] Warning: Rule ${n} not found in current execution`);return}let s=new Map;for(let c of r){let u=c.file.path;s.has(u)||s.set(u,[]),s.get(u).push(c)}let a=new Set(s.keys());if(i){let c=this.documentManager.getAllDiagnosticUris();for(let u of c){let l=ys(u),E=this.toRelativePath(l,e);this.documentManager.getDiagnostics(u).some(S=>S.data?.rule?.id===n)&&a.add(E)}}for(let c of a){let u=s.get(c)||[],l=await this.createDiagnosticsForFile(e,c,n,u,e.currentExecutionRules),E=HI(e.repoRoot,c),d=this.pathToNormalizedUri(E);this.updateDiagnosticsForRule(d,n,l)}}async handleRulePartial(e,n,r,i){if(!e.isExecuting||e.currentExecutionRules.length===0)return;await this.updateDiagnosticsForRuleMatches(e,n,r,!1);let o=e.currentExecutionRules.find(s=>s.internalId===n);o&&this.connection.console.log(`[${e.repoRoot}] Partial results for rule ${o.id}: ${r.length} of ${i} matches ready`)}async handleRuleComplete(e,n,r){if(!e.isExecuting||e.currentExecutionRules.length===0)return;e.completedRulesCount++;let i=Math.round(e.completedRulesCount/e.currentExecutionRules.length*100);this.updateBatchProgress(i,n);let o=e.currentExecutionRules.find(s=>s.id===n);if(!o){this.connection.console.log(`[${e.repoRoot}] Warning: Rule ${n} not found in current execution`);return}r.length>0&&this.connection.console.log(`[${e.repoRoot}] Rule ${o.id} completed with ${r.length} match(es) in files: ${[...new Set(r.map(s=>s.file.path))].join(", ")}`),await this.updateDiagnosticsForRuleMatches(e,o.internalId,r,!0)}setupProgressListenersForContext(e){e.eventEmitter.on("rules:progress",n=>{this.updateBatchProgress(n.percentage,n.ruleId)}),e.eventEmitter.on("rules:rule-partial",async n=>{await this.handleRulePartial(e,n.ruleId,n.matches,n.totalMatches)}),e.eventEmitter.on("rules:rule-complete",async n=>{await this.handleRuleComplete(e,n.ruleId,n.matches)})}toRelativePath(e,n){if(!n){let r=this.pathToNormalizedUri(e);n=this.findContextForFile(r)||void 0}return n?tre(n.repoRoot,e):tre(this.workspacePath,e)}updateDiagnosticsForRule(e,n,r){this.documentManager.setDiagnosticsForRule(e,n,r);let i=this.documentManager.getDiagnostics(e);this.connection.sendDiagnostics({uri:e,diagnostics:i})}removeDiagnosticByMatchId(e,n){let r=this.documentManager.getDiagnostics(e),i=r.find(a=>a.data?.matchId===n);if(!i)return;let o=i.data?.rule?.id;if(!o)return;let s=r.filter(a=>a.data?.rule?.id===o&&a.data?.matchId!==n);this.updateDiagnosticsForRule(e,o,s)}clearAllDiagnostics(){let e=this.documentManager.getAllDiagnosticUris();for(let n of e)this.clearDiagnosticsForFile(n)}clearDiagnosticsForFile(e){this.documentManager.clearDiagnostics(e),this.connection.sendDiagnostics({uri:e,diagnostics:[]})}handleDocumentChangesWithRanges(e,n){let r=this.documentManager.getDiagnostics(e);if(r.length===0)return;this.connection.console.log(`Document changed: ${e}, ${n.length} change(s), ${r.length} diagnostic(s)`);let i=new Set;for(let o of n){if(!o.range){this.connection.console.log("Full document change detected - removing all diagnostics");for(let s of r)s.data?.matchId&&i.add(s.data.matchId);continue}for(let s of r)this.rangesOverlap(o.range,s.range)&&s.data?.matchId&&i.add(s.data.matchId)}for(let o of i)this.removeDiagnosticByMatchId(e,o);i.size>0&&this.connection.console.log(`Removed ${i.size} diagnostic(s) due to document edits`)}rangesOverlap(e,n){return e.end.line<n.start.line||e.start.line>n.end.line?!1:e.start.line<=n.end.line&&e.end.line>=n.start.line}async createDiagnosticsForFile(e,n,r,i,o){let s=i.length;this.documentManager.hasDismissals(n)||await this.loadDismissalsForFile(e,n),this.documentManager.hasFixes(n)||await this.loadFixesForFile(e,n);let a={ruleId:r,matches:i},c=this.filterDismissedResults([a],n),u=c[0]?.matches.length||0,l=s-u,E=await this.filterFixedResults(e,c,n),d=E[0]?.matches.length||0,T=u-d,S=HI(e.repoRoot,n),p=this.pathToNormalizedUri(S),f=await this.convertResultsToDiagnostics(e,E,o,p);if(s>0){let O=o.find(C=>C.internalId===r)?.id||r,N=[];l>0&&N.push(`${l} dismissed`),T>0&&N.push(`${T} fixed`),N.length>0?this.connection.console.log(`[${e.repoRoot}] ${n}: ${f.length} diagnostic(s) created, ${N.join(", ")} (rule: ${O})`):this.connection.console.log(`[${e.repoRoot}] ${n}: ${f.length} diagnostic(s) created (rule: ${O})`)}return f}async getFileContent(e){let n=this.pathToNormalizedUri(e),r=this.documentManager.getDocument(n);return r?r.getText():await ere.readFile(e,"utf-8").catch(()=>null)}async computeFixForMatch(e,n){let r=await Nd(e,n.repoRoot,o=>this.getFileContent(o));return r?{fileChanges:r.fileChanges.map(o=>({...o,fileUri:this.pathToNormalizedUri(o.filePath)})),diff:r.diff,diffs:r.diffs}:null}async loadRulesWithCache(e){let r=Date.now()-e.rulesCacheTimestamp;return e.cachedRules&&r<this.repositoryContextManager.RULES_CACHE_TTL_MS?(this.connection.console.log(`[${e.repoRoot}] Using cached rules (age: ${Math.round(r/1e3)}s / ${this.repositoryContextManager.RULES_CACHE_TTL_MS/1e3}s)`),e.cachedRules):e.rulesLoadingPromise?(this.connection.console.log(`[${e.repoRoot}] Rules are already being loaded, waiting for existing request...`),e.rulesLoadingPromise):(this.connection.console.log(`[${e.repoRoot}] Loading fresh rules from API...`),e.rulesLoadingPromise=e.ruleProvider.loadAllRules().then(i=>{e.cachedRules=i,e.rulesCacheTimestamp=Date.now(),e.rulesById.clear();for(let o of i)e.rulesById.set(o.id,o);if(this.connection.console.log(`[${e.repoRoot}] Loaded ${i.length} rules (cache valid for ${this.repositoryContextManager.RULES_CACHE_TTL_MS/1e3}s)`),i.length>0){this.connection.console.log(`[${e.repoRoot}] Fetched rules:`);for(let o of i){let s=o.autofix||!1,a="";s&&(a=" (autofix)"),this.connection.console.log(`[${e.repoRoot}] - ${o.id}: ${o.message}${a}`)}}return i}).finally(()=>{e.rulesLoadingPromise=null}),await e.rulesLoadingPromise)}async loadDismissalsForFile(e,n){if(this.documentManager.hasDismissals(n))return;let i=(await e.ruleProvider.getDismissals([n])).map(o=>({ruleId:o.ruleId,file:o.match.file.path,startLine:o.match.range.start.line,endLine:o.match.range.end.line,fingerprint:o.match.fingerprint,dismissedAt:o.createdAt,dismissalId:o.dismissalId}));this.documentManager.setDismissals(n,i)}async loadFixesForFile(e,n){if(this.documentManager.hasFixes(n))return;let r=await e.ruleProvider.getFixes([n]);this.documentManager.setFixes(n,r)}filterDismissedResults(e,n){let r=this.documentManager.getDismissals(n);return r.length===0?e:e.map(i=>{let o=r.filter(u=>u.ruleId===i.ruleId);if(o.length===0)return i;let s=i.matches.map(u=>({file:n,startLine:u.range.start.line,endLine:u.range.end.line,fingerprint:u.fingerprint})),c=hh(s,o).map(u=>i.matches.find(l=>l.range.start.line===u.startLine&&l.range.end.line===u.endLine&&l.fingerprint===u.fingerprint));return{...i,matches:c}})}async filterFixedResults(e,n,r){let i=this.documentManager.getFixes(r);if(i.length===0)return n;this.connection.console.log(`[${e.repoRoot}] Filtering fixes for ${r}: ${i.length} fix(es) loaded`);let o=HI(e.repoRoot,r),s=await this.getFileContent(o);return s===null?n:n.map(a=>{let c=i.filter(f=>f.ruleId===a.ruleId);if(c.length===0)return a;let u=new Set;for(let f of c)f.match?.edits?.some(O=>O.oldString&&a1(s,O.oldString))&&f.match.fingerprint&&u.add(f.match.fingerprint);let l=c.length-u.size;u.size>0&&this.connection.console.log(`[${e.repoRoot}] ${r}: ${u.size} fix(es) reverted, ${l} still active`);let E=a.matches.map(f=>({file:r,startLine:f.range.start.line,endLine:f.range.end.line,fingerprint:f.fingerprint})),d=c.filter(f=>!f.match.fingerprint||!u.has(f.match.fingerprint)).map(f=>({file:r,startLine:f.match.range.start.line,endLine:f.match.range.end.line,fingerprint:f.match.fingerprint})),S=hh(E,d).map(f=>a.matches.find(h=>h.range.start.line===f.startLine&&h.range.end.line===f.endLine&&h.fingerprint===f.fingerprint)),p=a.matches.length-S.length;return p>0&&this.connection.console.log(`[${e.repoRoot}] ${r}: Filtered out ${p} match(es) with active fixes`),{...a,matches:S}})}async convertResultsToDiagnostics(e,n,r,i){let o=[],s=new Set;for(let a of n){let c=r.find(u=>u.internalId===a.ruleId);if(!c){this.connection.console.log(`Warning: Could not find rule with internal ID ${a.ruleId}`);continue}for(let u of a.matches){let l=`${u.range.start.line}-${u.range.end.line}`;if(s.has(l))continue;s.add(l);let E=vut(u,c.internalId,i),d=null;u.edits&&u.edits.length>0&&(d=await this.computeFixForMatch(u,e).catch(S=>(this.connection.console.log(`Warning: Failed to compute fix for match: ${S}`),null)));let T={range:{start:{line:u.range.start.line-1,character:u.range.start.column-1},end:{line:u.range.end.line-1,character:u.range.end.column-1}},severity:yr.DiagnosticSeverity.Warning,message:u.description||c.message,code:c.id,codeDescription:{href:`https://app.wispbit.com/rules/${c.internalId}`},source:"wispbit",data:{uri:i,match:u,matchId:E,fix:d?{diff:d.diff,diffs:d.diffs,autofix:c.autofix||!1}:null,rule:{id:c.internalId,displayId:c.id,summary:c.summary||null}}};o.push(T)}}return o}triggerExecution(){this.executionDebounceTimer&&(clearTimeout(this.executionDebounceTimer),this.executionDebounceTimer=null),this.executionDebounceTimer=setTimeout(()=>{this.executionDebounceTimer=null,this.executeQueuedFiles()},this.EXECUTION_DEBOUNCE_MS)}lintDocument(e){if(!this.documentManager.getDocument(e)){this.connection.console.log(`Document not found: ${e}`);return}let r=ys(e),i=this.toRelativePath(r);this.connection.console.log(`File changed: ${i}`),this.triggerExecution()}async executeQueuedFiles(){let e=this.repositoryContextManager.getAllContexts();if(e.length===0){this.connection.console.log("No repositories found, skipping execution");return}this.connection.console.log(`Executing rules for ${e.length} repository(ies)`),this.cleanupProgress(),await this.startBatchProgress(0);try{for(let n of e)await this.executeForContext(n);this.cleanupProgress()}catch(n){this.connection.console.error(`Error executing rules: ${n.message}`),this.connection.console.error(n.stack),this.cleanupProgress()}}async executeForContext(e){e.isExecuting=!0,this.connection.console.log(`[${e.repoRoot}] Executing rules for changed files`);try{let n=await this.loadRulesWithCache(e);e.completedRulesCount=0,e.currentExecutionRules=n;let{commitSelector:r,include:i}=await ed(e.repoRoot);this.connection.console.log(`[${e.repoRoot}] Using diff mode with selector ${r} and includes [${i.join(", ")}]`),e.lastCommitSelector=r,await e.ruleExecutor.execute(n,{mode:"diff",diffOptions:{include:i,commitSelector:r,skipPreExistingViolations:!0}})}catch(n){this.connection.console.error(`[${e.repoRoot}] Error executing rules: ${n.message}`),this.connection.console.error(n.stack)}finally{e.isExecuting=!1}}async startBatchProgress(e){if(this.batchProgressReporter)this.batchProgressReporter.report(e,"Checking workspace");else try{this.progressTokenCreated||(await this.connection.sendRequest("window/workDoneProgress/create",{token:this.batchProgressToken}),this.progressTokenCreated=!0),this.batchProgressReporter=await this.connection.window.createWorkDoneProgress(),this.batchProgressReporter.begin("wispbit",e,"Checking workspace",!1)}catch(n){this.connection.console.log(`Failed to create batch progress: ${n}`)}}cleanupProgress(){this.batchProgressReporter&&(this.batchProgressReporter.done(),this.batchProgressReporter=null)}updateBatchProgress(e,n){if(!this.batchProgressReporter)return;let r=`Checking workspace (${n})`;this.batchProgressReporter.report(e,r)}async processFixQueue(){if(!this.isProcessingFix){for(this.isProcessingFix=!0;this.fixQueue.length>0;){let e=this.fixQueue.shift();e&&await e()}this.isProcessingFix=!1}}handleQuickfix(e){let{uri:n,matchId:r}=e[0];this.fixQueue.push(async()=>{await this.applyQuickfix(n,r)}),this.processFixQueue()}async applyQuickfix(e,n){let i=this.getDiagnosticsForUri(e).find(p=>p.data?.matchId===n);if(!i){this.connection.window.showErrorMessage("Could not apply fix"),this.connection.console.error(`Diagnostic not found for matchId: ${n}`);return}let o=i.data?.match,s=i.data?.rule;if(!o?.edits||o.edits.length===0){this.connection.window.showErrorMessage("No fix available"),this.connection.console.error(`No fix available for matchId ${n}, rule ${s?.id}`);return}let a=this.findContextForFile(e);if(!a){this.connection.window.showErrorMessage("File is not in any repository"),this.connection.console.error(`No repository context found for ${e}`);return}let c=ys(e),u=this.toRelativePath(c,a);this.connection.console.log(`[${a.repoRoot}] Applying fix for matchId ${n}, rule ${s?.id}`);let l=await this.computeFixForMatch(o,a);if(!l){this.connection.window.showErrorMessage("Failed to compute fix"),this.connection.console.error(`[${a.repoRoot}] Failed to compute fix for matchId ${n}, rule ${s?.id}`);return}let E=ys(e),d=[];for(let p of l.fileChanges){let h=p.filePath===E?e:p.fileUri,O=this.documentManager.getDocument(h),N=O?O.lineCount:p.oldContent.split(`
283
- `).length;O||p.oldContent.length>0||d.push(yr.CreateFile.create(h,{overwrite:!1,ignoreIfExists:!0}));let M={textDocument:{uri:h,version:O?.version??null},edits:[yr.TextEdit.replace({start:{line:0,character:0},end:{line:N,character:0}},p.newContent)]};d.push(M)}let T=await this.connection.workspace.applyEdit({documentChanges:d});T.applied?this.connection.console.log(`[${a.repoRoot}] Applied fix successfully`):this.connection.console.log(`[${a.repoRoot}] Could not apply fix. Reason: ${T.failureReason}, Change: ${T.failedChange}`),await a.ruleProvider.createFix(s?.id,o).catch(p=>{this.connection.console.log(`[${a.repoRoot}] Failed to track fix: ${p.message}`)}),this.removeDiagnosticByMatchId(e,n),this.documentManager.clearFixes(u);let S=this.getDiagnosticsForUri(e);this.connection.sendDiagnostics({uri:e,diagnostics:S})}async handleDismiss(e){let{uri:n,matchId:r}=e[0],i=this.findContextForFile(n);if(!i){this.connection.window.showErrorMessage("File is not in any repository"),this.connection.console.error(`No repository context found for ${n}`);return}let o=ys(n),s=this.toRelativePath(o,i),c=this.getDiagnosticsForUri(n).find(T=>T.data?.matchId===r);if(!c){this.connection.window.showErrorMessage("Could not dismiss violation"),this.connection.console.error(`[${i.repoRoot}] Diagnostic not found for matchId: ${r}`);return}let u=c.data?.match,l=c.data?.rule?.id;if(!u){this.connection.window.showErrorMessage("Could not dismiss violation"),this.connection.console.error(`[${i.repoRoot}] Match not found for matchId: ${r}`);return}await i.ruleProvider.createDismissal(l,u);let E=c.data?.rule?.displayId||l;this.connection.console.log(`[${i.repoRoot}] Dismissed violation: ${E} with matchId ${r}`),this.removeDiagnosticByMatchId(n,r);let d=this.getDiagnosticsForUri(n);this.connection.sendDiagnostics({uri:n,diagnostics:d}),this.documentManager.clearDismissals(s)}async handleGetDismissals(e){let{uri:n}=e[0];if(!n||typeof n!="string")return this.connection.console.log(`Invalid URI provided to getDismissals: ${n}`),[];if(!n.startsWith("file://"))return this.connection.console.log(`URI must be a file:// URL, got: ${n}`),[];let r=this.findContextForFile(n);if(!r)return this.connection.console.log(`No repository context found for ${n}`),[];let i=ys(n),o=this.toRelativePath(i,r);await this.loadDismissalsForFile(r,o);let s=this.documentManager.getDismissals(o),a=await this.loadRulesWithCache(r),c=this.documentManager.getDocument(n);if(!c){let u=Si(n),l=this.documentManager.getAllDocumentUris();for(let E of l)if(Si(E)===u){c=this.documentManager.getDocument(E);break}}return s.map(u=>{let l=a.find(T=>T.internalId===u.ruleId),E="";if(c){let T=c.getText({start:{line:u.startLine-1,character:0},end:{line:u.startLine-1,character:100}});E=T.trim().substring(0,60),T.trim().length>60&&(E+="...")}let d="";if(u.dismissedAt){let T=new Date,S=new Date(u.dismissedAt),p=T.getTime()-S.getTime(),f=Math.floor(p/6e4),h=Math.floor(f/60),O=Math.floor(h/24);f<1?d="just now":f<60?d=`${f} minute${f===1?"":"s"} ago`:h<24?d=`${h} hour${h===1?"":"s"} ago`:d=`${O} day${O===1?"":"s"} ago`}return{dismissalId:u.dismissalId,ruleId:u.ruleId,displayId:l?.id||u.ruleId,ruleName:l?.message||"Unknown rule",line:u.startLine,fingerprint:u.fingerprint,fileName:o,codeSnippet:E,timeAgo:d}})}async handleUndismiss(e){let{uri:n,dismissalId:r}=e[0],i=this.findContextForFile(n);if(!i){this.connection.window.showErrorMessage("File is not in any repository"),this.connection.console.error(`No repository context found for ${n}`);return}let o=ys(n),s=this.toRelativePath(o,i),c=this.documentManager.getDismissals(s).find(T=>T.dismissalId===r);if(!c){this.connection.window.showErrorMessage("Dismissal not found"),this.connection.console.error(`[${i.repoRoot}] Dismissal not found with ID ${r}`);return}await i.ruleProvider.deleteDismissal(c.ruleId,c.file,c.fingerprint);let l=(await this.loadRulesWithCache(i)).find(T=>T.internalId===c.ruleId),E=l?.id||c.ruleId,d=l?.message||"Unknown rule";this.connection.console.log(`Undismissed violation: ${E} at line ${c.startLine}`),this.connection.window.showInformationMessage(`Undismissed violation: ${E} at line ${c.startLine} - ${d}`),this.documentManager.clearDismissals(s),this.triggerExecution()}async handleRemember(e){let{uri:n,range:r,selectedText:i,note:o}=e[0],s=this.findContextForFile(n);if(!s){this.connection.window.showErrorMessage("File is not in any repository"),this.connection.console.error(`No repository context found for ${n}`);return}let a=ys(n),c=this.toRelativePath(a,s);if(!o||o.trim().length===0){this.connection.window.showErrorMessage("Note is required to remember a pattern");return}let l=this.getDiagnosticsForUri(n).filter(E=>E.source==="wispbit"&&E.data?.match).map(E=>({...E.data.match,ruleId:E.data.rule?.id}));this.connection.console.log(`[${s.repoRoot}] Remembering pattern with ${l.length} matches: ${i.substring(0,100)}...`),this.connection.console.log(`[${s.repoRoot}] Note: ${o}`);try{await s.ruleProvider.rememberPattern(c,i,{start:{line:r.start.line+1,column:r.start.character+1},end:{line:r.end.line+1,column:r.end.character+1}},o.trim(),l),this.connection.window.showInformationMessage(`Pattern remembered: ${o.trim()}`)}catch(E){this.connection.console.log(`Failed to remember: ${E.message}`),this.connection.window.showErrorMessage(`Failed to remember: ${E.message}`)}}truncateMessage(e,n=60){return e.length<=n?e:e.substring(0,n)+"..."}generateCodeActions(e,n){let r=[],i=n.filter(c=>c.source==="wispbit"),o=i.filter(c=>c.data?.fix),s=o.length>1&&o.some((c,u)=>o.slice(u+1).some(l=>c.range.start.line<=l.range.end.line&&c.range.end.line>=l.range.start.line)),a=!1;for(let c of i){let u=c.data?.fix,l=u?.autofix||!1,E=u&&(!s||!a);if(u){let T=this.truncateMessage(c.message);r.push({title:`Apply fix: ${T}`,kind:"quickfix",command:{title:"Apply Fix",command:"wispbit.quickfix",arguments:[{uri:e,matchId:c.data?.matchId}]},diagnostics:[c],isPreferred:E}),E&&(a=!0),l&&r.push({title:`Fix: ${T}`,kind:"source.fixAll",command:{title:"Apply Fix",command:"wispbit.quickfix",arguments:[{uri:e,matchId:c.data?.matchId}]},diagnostics:[c],isPreferred:!1})}let d=this.truncateMessage(c.message);r.push({title:`Dismiss: ${d}`,kind:"quickfix",command:{title:"Dismiss",command:"wispbit.dismiss",arguments:[{uri:e,matchId:c.data?.matchId}]},diagnostics:[c]})}return r}generateHover(e,n){let r=e.find(d=>n.line<d.range.start.line||n.line>d.range.end.line?!1:d.range.start.line===d.range.end.line?n.character>=d.range.start.character&&n.character<=d.range.end.character:n.line===d.range.start.line?n.character>=d.range.start.character:n.line===d.range.end.line?n.character<=d.range.end.character:!0);if(!r)return null;let i=String(r.code||""),o;for(let d of this.repositoryContextManager.getAllContexts())if(o=d.rulesById.get(i),o)break;let s=r.data?.fix,a=r.data?.match?.file?.path,c=r.data?.uri,l=(c?this.findContextForFile(c):null)?.repoRoot||this.workspacePath,E="";if(s?.diffs&&s.diffs.length>0)for(let{file:d,diff:T}of s.diffs){if(!(d.path===a)){let p=HI(l,d.path),f=this.pathToNormalizedUri(p);E+=`*[${d.path}](${f})*
282
+ `)}};function CQ(t){switch(t){case"claude":return new _C;default:throw new Error(`Unknown hook provider: ${t}`)}}import*as Hc from"fs/promises";import*as IQ from"os";import*as yh from"path";var TC=class{getStorageDir(){return yh.join(IQ.homedir(),".wispbit","hooks")}getStoragePath(e){return yh.join(this.getStorageDir(),`${e}.json`)}async load(e){let n=this.getStoragePath(e);try{let r=await Hc.readFile(n,"utf-8");return JSON.parse(r)}catch{return null}}async save(e,n){let r=this.getStoragePath(e);await Hc.mkdir(yh.dirname(r),{recursive:!0}),await Hc.writeFile(r,JSON.stringify(n,null,2))}async clear(e){let n=this.getStoragePath(e);try{await Hc.unlink(n)}catch{}}};async function MQ(t,e){let[n,r]=t.split(".");if(!n||!r)throw new Error(`Invalid providerEvent format: ${t}. Expected "provider.event"`);let i=CQ(n),o=new TC,s=i.eventSchemas[r];if(!s)throw new Error(`Unknown event: ${r} for provider: ${n}`);let a=s.parse(e),c=i.getConversationId(a);i._setContext(o,c);let u=await i.handleEvent(r,a);return i._clearContext(),u??{}}var yr=ue(Xne(),1);import{promises as ere}from"fs";import{join as HI,relative as tre}from"path";import{fileURLToPath as ys,pathToFileURL as but}from"url";var BI=class t{constructor(e,n,r,i){this._uri=e,this._languageId=n,this._version=r,this._content=i,this._lineOffsets=void 0}get uri(){return this._uri}get languageId(){return this._languageId}get version(){return this._version}getText(e){if(e){let n=this.offsetAt(e.start),r=this.offsetAt(e.end);return this._content.substring(n,r)}return this._content}update(e,n){for(let r of e)if(t.isIncremental(r)){let i=Qne(r.range),o=this.offsetAt(i.start),s=this.offsetAt(i.end);this._content=this._content.substring(0,o)+r.text+this._content.substring(s,this._content.length);let a=Math.max(i.start.line,0),c=Math.max(i.end.line,0),u=this._lineOffsets,l=qne(r.text,!1,o);if(c-a===l.length)for(let d=0,T=l.length;d<T;d++)u[d+a+1]=l[d];else l.length<1e4?u.splice(a+1,c-a,...l):this._lineOffsets=u=u.slice(0,a+1).concat(l,u.slice(c+1));let E=r.text.length-(s-o);if(E!==0)for(let d=a+1+l.length,T=u.length;d<T;d++)u[d]=u[d]+E}else if(t.isFull(r))this._content=r.text,this._lineOffsets=void 0;else throw new Error("Unknown change event received");this._version=n}getLineOffsets(){return this._lineOffsets===void 0&&(this._lineOffsets=qne(this._content,!0)),this._lineOffsets}positionAt(e){e=Math.max(Math.min(e,this._content.length),0);let n=this.getLineOffsets(),r=0,i=n.length;if(i===0)return{line:0,character:e};for(;r<i;){let s=Math.floor((r+i)/2);n[s]>e?i=s:r=s+1}let o=r-1;return e=this.ensureBeforeEOL(e,n[o]),{line:o,character:e-n[o]}}offsetAt(e){let n=this.getLineOffsets();if(e.line>=n.length)return this._content.length;if(e.line<0)return 0;let r=n[e.line];if(e.character<=0)return r;let i=e.line+1<n.length?n[e.line+1]:this._content.length,o=Math.min(r+e.character,i);return this.ensureBeforeEOL(o,r)}ensureBeforeEOL(e,n){for(;e>n&&Jne(this._content.charCodeAt(e-1));)e--;return e}get lineCount(){return this.getLineOffsets().length}static isIncremental(e){let n=e;return n!=null&&typeof n.text=="string"&&n.range!==void 0&&(n.rangeLength===void 0||typeof n.rangeLength=="number")}static isFull(e){let n=e;return n!=null&&typeof n.text=="string"&&n.range===void 0&&n.rangeLength===void 0}},em;(function(t){function e(i,o,s,a){return new BI(i,o,s,a)}t.create=e;function n(i,o,s){if(i instanceof BI)return i.update(o,s),i;throw new Error("TextDocument.update: document must be created by TextDocument.create")}t.update=n;function r(i,o){let s=i.getText(),a=TF(o.map(Lut),(l,E)=>{let d=l.range.start.line-E.range.start.line;return d===0?l.range.start.character-E.range.start.character:d}),c=0,u=[];for(let l of a){let E=i.offsetAt(l.range.start);if(E<c)throw new Error("Overlapping edit");E>c&&u.push(s.substring(c,E)),l.newText.length&&u.push(l.newText),c=i.offsetAt(l.range.end)}return u.push(s.substr(c)),u.join("")}t.applyEdits=r})(em||(em={}));function TF(t,e){if(t.length<=1)return t;let n=t.length/2|0,r=t.slice(0,n),i=t.slice(n);TF(r,e),TF(i,e);let o=0,s=0,a=0;for(;o<r.length&&s<i.length;)e(r[o],i[s])<=0?t[a++]=r[o++]:t[a++]=i[s++];for(;o<r.length;)t[a++]=r[o++];for(;s<i.length;)t[a++]=i[s++];return t}function qne(t,e,n=0){let r=e?[n]:[];for(let i=0;i<t.length;i++){let o=t.charCodeAt(i);Jne(o)&&(o===13&&i+1<t.length&&t.charCodeAt(i+1)===10&&i++,r.push(n+i+1))}return r}function Jne(t){return t===13||t===10}function Qne(t){let e=t.start,n=t.end;return e.line>n.line||e.line===n.line&&e.character>n.character?{start:n,end:e}:t}function Lut(t){let e=Qne(t.range);return e!==t.range?{newText:t.newText,range:e}:t}function Si(t){let e=decodeURIComponent(t);return e.startsWith("file:///")&&(e=e.replace(/\\/g,"/")),e=e.replace(/^file:\/\/\/([a-z]):/,(n,r)=>`file:///${r.toUpperCase()}:`),e}var FI=class{syncedDocuments=new Map;diagnosticsByFileAndRule=new Map;dismissalsByFile=new Map;fixesByFile=new Map;listen(e,n){e.onDidOpenTextDocument(r=>{let i=r.textDocument,o=Si(i.uri),s=em.create(o,i.languageId,i.version,i.text);this.syncedDocuments.set(o,s),n.onDidOpen?.(o,s)}),e.onDidChangeTextDocument(r=>{let i=r.textDocument,o=Si(i.uri),s=r.contentChanges;if(s.length===0)return;let a=i.version;if(a==null)return;let c=this.syncedDocuments.get(o);c&&(c=em.update(c,s,a),this.syncedDocuments.set(o,c),n.onDidChangeContent?.(o,c,s))}),e.onDidCloseTextDocument(r=>{let i=Si(r.textDocument.uri);this.syncedDocuments.delete(i),n.onDidClose?.(i)}),e.onDidSaveTextDocument(r=>{let i=Si(r.textDocument.uri),o=this.syncedDocuments.get(i);o&&n.onDidSave?.(i,o)})}getDocument(e){let n=Si(e);return this.syncedDocuments.get(n)}getAllDocumentUris(){return Array.from(this.syncedDocuments.values()).map(e=>e.uri)}getAllDiagnosticUris(){return Array.from(this.diagnosticsByFileAndRule.keys())}setDiagnosticsForRule(e,n,r){let i=Si(e);this.diagnosticsByFileAndRule.has(i)||this.diagnosticsByFileAndRule.set(i,new Map),this.diagnosticsByFileAndRule.get(i).set(n,r)}getDiagnostics(e){let n=Si(e),r=this.diagnosticsByFileAndRule.get(n);if(!r)return[];let i=[];for(let[o,s]of r.entries())i.push(...s);return i}clearDiagnostics(e){let n=Si(e);this.diagnosticsByFileAndRule.delete(n)}setDismissals(e,n){this.dismissalsByFile.set(e,n)}getDismissals(e){return this.dismissalsByFile.get(e)||[]}hasDismissals(e){return this.dismissalsByFile.has(e)}clearDismissals(e){this.dismissalsByFile.delete(e)}setFixes(e,n){this.fixesByFile.set(e,n)}getFixes(e){return this.fixesByFile.get(e)||[]}hasFixes(e){return this.fixesByFile.has(e)}clearFixes(e){this.fixesByFile.delete(e)}};import{sep as yut}from"path";var kI=class{contexts=new Map;workspacePath;apiKey;lspClient;RULES_CACHE_TTL_MS=300*1e3;constructor(e){this.workspacePath=e.workspacePath,this.apiKey=e.apiKey,this.lspClient=e.lspClient}async discoverAndInitialize(e,n){let r=await qN(this.workspacePath);for(let i of r){let o=await this.initializeContext(i).catch(s=>(n?.(i,s),null));o&&(this.contexts.set(i,o),e?.(i,o))}}async initializeContext(e){let n=new Kr({workspaceRoot:e}),r=await Yo.initialize(n,{apiKey:this.apiKey,lspClient:this.lspClient});if("failed"in r)throw new Error(`Config initialization failed for ${e}: ${r.error}`);let i=r,o=new $o(i,n),s=new zr,a=new Ma(i,n,s);return{repoRoot:e,environment:n,config:i,ruleProvider:o,eventEmitter:s,ruleExecutor:a,cachedRules:null,rulesById:new Map,rulesCacheTimestamp:0,rulesLoadingPromise:null,lastCommitSelector:null,currentExecutionRules:[],completedRulesCount:0,isExecuting:!1,currentExecutionPromise:null}}findContextForFile(e){return Array.from(this.contexts.entries()).filter(([r])=>e.startsWith(r+yut)||e===r).sort((r,i)=>i[0].length-r[0].length)[0]?.[1]||null}getAllContexts(){return Array.from(this.contexts.values())}getRepoCount(){return this.contexts.size}hasRepositories(){return this.contexts.size>0}getContext(e){return this.contexts.get(e)}shutdown(){for(let e of this.contexts.values())e.ruleExecutor.clearCache();this.contexts.clear()}};function vut(t,e,n){if(t.fingerprint)return`${e}:${t.fingerprint}`;let r=t.text?.slice(0,100)||"",i=`${t.range.start.line}:${t.range.start.column}-${t.range.end.line}:${t.range.end.column}`;return`${e}:${n}:${i}:${Uut(r)}`}function Uut(t){let e=0;for(let n=0;n<t.length;n++){let r=t.charCodeAt(n);e=(e<<5)-e+r,e=e&e}return e.toString(36)}var SF=class{connection;documentManager;repositoryContextManager;workspacePath;apiKey;lspClient;batchProgressReporter=null;batchProgressToken="wispbit-batch-lint";progressTokenCreated=!1;fixQueue=[];isProcessingFix=!1;branchCheckTimer=null;BRANCH_CHECK_DEBOUNCE_MS=1e3;branchCheckInterval=null;BRANCH_CHECK_INTERVAL_MS=3e4;executionDebounceTimer=null;EXECUTION_DEBOUNCE_MS=1e3;constructor(e){this.workspacePath=e.workspacePath,this.apiKey=e.apiKey,this.lspClient=e.lspClient,this.connection=(0,yr.createConnection)(yr.ProposedFeatures.all,process.stdin,process.stdout),this.documentManager=new FI,this.repositoryContextManager=new kI({workspacePath:this.workspacePath,apiKey:this.apiKey,lspClient:this.lspClient}),this.registerHandlers()}findContextForFile(e){let n=ys(e);return this.repositoryContextManager.findContextForFile(n)}pathToNormalizedUri(e){let n=but(e).toString();return decodeURIComponent(n)}getDiagnosticsForUri(e){let n=this.documentManager.getDiagnostics(e);if(n.length===0){let r=Si(e),i=this.documentManager.getAllDiagnosticUris();for(let o of i)if(Si(o)===r){n=this.documentManager.getDiagnostics(o);break}}return n}async updateDiagnosticsForRuleMatches(e,n,r,i){if(!e.currentExecutionRules.find(c=>c.internalId===n)){this.connection.console.log(`[${e.repoRoot}] Warning: Rule ${n} not found in current execution`);return}let s=new Map;for(let c of r){let u=c.file.path;s.has(u)||s.set(u,[]),s.get(u).push(c)}let a=new Set(s.keys());if(i){let c=this.documentManager.getAllDiagnosticUris();for(let u of c){let l=ys(u),E=this.toRelativePath(l,e);this.documentManager.getDiagnostics(u).some(S=>S.data?.rule?.id===n)&&a.add(E)}}for(let c of a){let u=s.get(c)||[],l=await this.createDiagnosticsForFile(e,c,n,u,e.currentExecutionRules),E=HI(e.repoRoot,c),d=this.pathToNormalizedUri(E);this.updateDiagnosticsForRule(d,n,l)}}async handleRulePartial(e,n,r,i){if(!e.isExecuting||e.currentExecutionRules.length===0)return;await this.updateDiagnosticsForRuleMatches(e,n,r,!1);let o=e.currentExecutionRules.find(s=>s.internalId===n);o&&this.connection.console.log(`[${e.repoRoot}] Partial results for rule ${o.id}: ${r.length} of ${i} matches ready`)}async handleRuleComplete(e,n,r){if(!e.isExecuting||e.currentExecutionRules.length===0)return;e.completedRulesCount++;let i=Math.round(e.completedRulesCount/e.currentExecutionRules.length*100);this.updateBatchProgress(i,n);let o=e.currentExecutionRules.find(s=>s.id===n);if(!o){this.connection.console.log(`[${e.repoRoot}] Warning: Rule ${n} not found in current execution`);return}r.length>0&&this.connection.console.log(`[${e.repoRoot}] Rule ${o.id} completed with ${r.length} match(es) in files: ${[...new Set(r.map(s=>s.file.path))].join(", ")}`),await this.updateDiagnosticsForRuleMatches(e,o.internalId,r,!0)}setupProgressListenersForContext(e){e.eventEmitter.on("rules:progress",n=>{this.updateBatchProgress(n.percentage,n.ruleId)}),e.eventEmitter.on("rules:rule-partial",async n=>{await this.handleRulePartial(e,n.ruleId,n.matches,n.totalMatches)}),e.eventEmitter.on("rules:rule-complete",async n=>{await this.handleRuleComplete(e,n.ruleId,n.matches)})}toRelativePath(e,n){if(!n){let r=this.pathToNormalizedUri(e);n=this.findContextForFile(r)||void 0}return n?tre(n.repoRoot,e):tre(this.workspacePath,e)}updateDiagnosticsForRule(e,n,r){this.documentManager.setDiagnosticsForRule(e,n,r);let i=this.documentManager.getDiagnostics(e);this.connection.sendDiagnostics({uri:e,diagnostics:i})}removeDiagnosticByMatchId(e,n){let r=this.documentManager.getDiagnostics(e),i=r.find(a=>a.data?.matchId===n);if(!i)return;let o=i.data?.rule?.id;if(!o)return;let s=r.filter(a=>a.data?.rule?.id===o&&a.data?.matchId!==n);this.updateDiagnosticsForRule(e,o,s)}clearAllDiagnostics(){let e=this.documentManager.getAllDiagnosticUris();for(let n of e)this.clearDiagnosticsForFile(n)}clearDiagnosticsForFile(e){this.documentManager.clearDiagnostics(e),this.connection.sendDiagnostics({uri:e,diagnostics:[]})}handleDocumentChangesWithRanges(e,n){let r=this.documentManager.getDiagnostics(e);if(r.length===0)return;this.connection.console.log(`Document changed: ${e}, ${n.length} change(s), ${r.length} diagnostic(s)`);let i=new Set;for(let o of n){if(!o.range){this.connection.console.log("Full document change detected - removing all diagnostics");for(let s of r)s.data?.matchId&&i.add(s.data.matchId);continue}for(let s of r)this.rangesOverlap(o.range,s.range)&&s.data?.matchId&&i.add(s.data.matchId)}for(let o of i)this.removeDiagnosticByMatchId(e,o);i.size>0&&this.connection.console.log(`Removed ${i.size} diagnostic(s) due to document edits`)}rangesOverlap(e,n){return e.end.line<n.start.line||e.start.line>n.end.line?!1:e.start.line<=n.end.line&&e.end.line>=n.start.line}async createDiagnosticsForFile(e,n,r,i,o){let s=i.length;this.documentManager.hasDismissals(n)||await this.loadDismissalsForFile(e,n),this.documentManager.hasFixes(n)||await this.loadFixesForFile(e,n);let a={ruleId:r,matches:i},c=this.filterDismissedResults([a],n),u=c[0]?.matches.length||0,l=s-u,E=await this.filterFixedResults(e,c,n),d=E[0]?.matches.length||0,T=u-d,S=HI(e.repoRoot,n),p=this.pathToNormalizedUri(S),f=await this.convertResultsToDiagnostics(e,E,o,p);if(s>0){let O=o.find(C=>C.internalId===r)?.id||r,N=[];l>0&&N.push(`${l} dismissed`),T>0&&N.push(`${T} fixed`),N.length>0?this.connection.console.log(`[${e.repoRoot}] ${n}: ${f.length} diagnostic(s) created, ${N.join(", ")} (rule: ${O})`):this.connection.console.log(`[${e.repoRoot}] ${n}: ${f.length} diagnostic(s) created (rule: ${O})`)}return f}async getFileContent(e){let n=this.pathToNormalizedUri(e),r=this.documentManager.getDocument(n);return r?r.getText():await ere.readFile(e,"utf-8").catch(()=>null)}async computeFixForMatch(e,n){let r=await Nd(e,n.repoRoot,o=>this.getFileContent(o));return r?{fileChanges:r.fileChanges.map(o=>({...o,fileUri:this.pathToNormalizedUri(o.filePath)})),diff:r.diff,diffs:r.diffs}:null}async loadRulesWithCache(e){let r=Date.now()-e.rulesCacheTimestamp;return e.cachedRules&&r<this.repositoryContextManager.RULES_CACHE_TTL_MS?(this.connection.console.log(`[${e.repoRoot}] Using cached rules (age: ${Math.round(r/1e3)}s / ${this.repositoryContextManager.RULES_CACHE_TTL_MS/1e3}s)`),e.cachedRules):e.rulesLoadingPromise?(this.connection.console.log(`[${e.repoRoot}] Rules are already being loaded, waiting for existing request...`),e.rulesLoadingPromise):(this.connection.console.log(`[${e.repoRoot}] Loading fresh rules from API...`),e.rulesLoadingPromise=e.ruleProvider.loadAllRules().then(i=>{e.cachedRules=i,e.rulesCacheTimestamp=Date.now(),e.rulesById.clear();for(let o of i)e.rulesById.set(o.id,o);if(this.connection.console.log(`[${e.repoRoot}] Loaded ${i.length} rules (cache valid for ${this.repositoryContextManager.RULES_CACHE_TTL_MS/1e3}s)`),i.length>0){this.connection.console.log(`[${e.repoRoot}] Fetched rules:`);for(let o of i){let s=o.autofix||!1,a="";s&&(a=" (autofix)"),this.connection.console.log(`[${e.repoRoot}] - ${o.id}: ${o.message}${a}`)}}return i}).finally(()=>{e.rulesLoadingPromise=null}),await e.rulesLoadingPromise)}async loadDismissalsForFile(e,n){if(this.documentManager.hasDismissals(n))return;let i=(await e.ruleProvider.getDismissals([n])).map(o=>({ruleId:o.ruleId,file:o.match.file.path,startLine:o.match.range.start.line,endLine:o.match.range.end.line,fingerprint:o.match.fingerprint,dismissedAt:o.createdAt,dismissalId:o.dismissalId}));this.documentManager.setDismissals(n,i)}async loadFixesForFile(e,n){if(this.documentManager.hasFixes(n))return;let r=await e.ruleProvider.getFixes([n]);this.documentManager.setFixes(n,r)}filterDismissedResults(e,n){let r=this.documentManager.getDismissals(n);return r.length===0?e:e.map(i=>{let o=r.filter(u=>u.ruleId===i.ruleId);if(o.length===0)return i;let s=i.matches.map(u=>({file:n,startLine:u.range.start.line,endLine:u.range.end.line,fingerprint:u.fingerprint})),c=hh(s,o).map(u=>i.matches.find(l=>l.range.start.line===u.startLine&&l.range.end.line===u.endLine&&l.fingerprint===u.fingerprint));return{...i,matches:c}})}async filterFixedResults(e,n,r){let i=this.documentManager.getFixes(r);if(i.length===0)return n;this.connection.console.log(`[${e.repoRoot}] Filtering fixes for ${r}: ${i.length} fix(es) loaded`);let o=HI(e.repoRoot,r),s=await this.getFileContent(o);return s===null?n:n.map(a=>{let c=i.filter(f=>f.ruleId===a.ruleId);if(c.length===0)return a;let u=new Set;for(let f of c)f.match?.edits?.some(O=>O.oldString&&a1(s,O.oldString))&&f.match.fingerprint&&u.add(f.match.fingerprint);let l=c.length-u.size;u.size>0&&this.connection.console.log(`[${e.repoRoot}] ${r}: ${u.size} fix(es) reverted, ${l} still active`);let E=a.matches.map(f=>({file:r,startLine:f.range.start.line,endLine:f.range.end.line,fingerprint:f.fingerprint})),d=c.filter(f=>!f.match.fingerprint||!u.has(f.match.fingerprint)).map(f=>({file:r,startLine:f.match.range.start.line,endLine:f.match.range.end.line,fingerprint:f.match.fingerprint})),S=hh(E,d).map(f=>a.matches.find(h=>h.range.start.line===f.startLine&&h.range.end.line===f.endLine&&h.fingerprint===f.fingerprint)),p=a.matches.length-S.length;return p>0&&this.connection.console.log(`[${e.repoRoot}] ${r}: Filtered out ${p} match(es) with active fixes`),{...a,matches:S}})}async convertResultsToDiagnostics(e,n,r,i){let o=[],s=new Set;for(let a of n){let c=r.find(u=>u.internalId===a.ruleId);if(!c){this.connection.console.log(`Warning: Could not find rule with internal ID ${a.ruleId}`);continue}for(let u of a.matches){let l=`${u.range.start.line}-${u.range.end.line}`;if(s.has(l))continue;s.add(l);let E=vut(u,c.internalId,i),d=null;u.edits&&u.edits.length>0&&(d=await this.computeFixForMatch(u,e).catch(S=>(this.connection.console.log(`Warning: Failed to compute fix for match: ${S}`),null)));let T={range:{start:{line:u.range.start.line-1,character:u.range.start.column-1},end:{line:u.range.end.line-1,character:u.range.end.column-1}},severity:yr.DiagnosticSeverity.Warning,message:u.description||c.message,code:c.id,codeDescription:{href:`https://app.wispbit.com/rules/${c.internalId}`},source:"wispbit",data:{uri:i,match:u,matchId:E,fix:d?{diff:d.diff,diffs:d.diffs,autofix:c.autofix||!1}:null,rule:{id:c.internalId,displayId:c.id,summary:c.summary||null}}};o.push(T)}}return o}triggerExecution(){this.executionDebounceTimer&&(clearTimeout(this.executionDebounceTimer),this.executionDebounceTimer=null),this.executionDebounceTimer=setTimeout(()=>{this.executionDebounceTimer=null,this.executeQueuedFiles()},this.EXECUTION_DEBOUNCE_MS)}lintDocument(e){if(!this.documentManager.getDocument(e)){this.connection.console.log(`Document not found: ${e}`);return}let r=ys(e),i=this.toRelativePath(r);this.connection.console.log(`File changed: ${i}`),this.triggerExecution()}async executeQueuedFiles(){let e=this.repositoryContextManager.getAllContexts();if(e.length===0){this.connection.console.log("No repositories found, skipping execution");return}this.connection.console.log(`Executing rules for ${e.length} repository(ies)`),this.cleanupProgress(),await this.startBatchProgress(0);try{for(let n of e)await this.executeForContext(n);this.cleanupProgress()}catch(n){this.connection.console.error(`Error executing rules: ${n.message}`),this.connection.console.error(n.stack),this.cleanupProgress()}}async executeForContext(e){e.isExecuting=!0,this.connection.console.log(`[${e.repoRoot}] Executing rules for changed files`);try{let n=await this.loadRulesWithCache(e);e.completedRulesCount=0,e.currentExecutionRules=n;let{commitSelector:r,include:i}=await ed(e.repoRoot);this.connection.console.log(`[${e.repoRoot}] Using diff mode with selector ${r} and includes [${i.join(", ")}]`),e.lastCommitSelector=r,await e.ruleExecutor.execute(n,{mode:"diff",diffOptions:{include:i,commitSelector:r,skipPreExistingViolations:!0}})}catch(n){this.connection.console.error(`[${e.repoRoot}] Error executing rules: ${n.message}`),this.connection.console.error(n.stack)}finally{e.isExecuting=!1}}async startBatchProgress(e){if(this.batchProgressReporter)this.batchProgressReporter.report(e,"Checking workspace");else try{this.progressTokenCreated||(await this.connection.sendRequest("window/workDoneProgress/create",{token:this.batchProgressToken}),this.progressTokenCreated=!0),this.batchProgressReporter=await this.connection.window.createWorkDoneProgress(),this.batchProgressReporter.begin("wispbit",e,"Checking workspace",!1)}catch(n){this.connection.console.log(`Failed to create batch progress: ${n}`)}}cleanupProgress(){this.batchProgressReporter&&(this.batchProgressReporter.done(),this.batchProgressReporter=null)}updateBatchProgress(e,n){if(!this.batchProgressReporter)return;let r=`Checking workspace (${n})`;this.batchProgressReporter.report(e,r)}async processFixQueue(){if(!this.isProcessingFix){for(this.isProcessingFix=!0;this.fixQueue.length>0;){let e=this.fixQueue.shift();e&&await e()}this.isProcessingFix=!1}}handleQuickfix(e){let{uri:n,matchId:r}=e[0];this.fixQueue.push(async()=>{await this.applyQuickfix(n,r)}),this.processFixQueue()}async applyQuickfix(e,n){let i=this.getDiagnosticsForUri(e).find(S=>S.data?.matchId===n);if(!i){this.connection.window.showErrorMessage("Could not apply fix"),this.connection.console.error(`Diagnostic not found for matchId: ${n}`);return}let o=i.data?.match,s=i.data?.rule;if(!o?.edits||o.edits.length===0){this.connection.window.showErrorMessage("No fix available"),this.connection.console.error(`No fix available for matchId ${n}, rule ${s?.id}`);return}let a=this.findContextForFile(e);if(!a){this.connection.window.showErrorMessage("File is not in any repository"),this.connection.console.error(`No repository context found for ${e}`);return}let c=ys(e),u=this.toRelativePath(c,a);this.connection.console.log(`[${a.repoRoot}] Applying fix for matchId ${n}, rule ${s?.id}`);let l=await this.computeFixForMatch(o,a);if(!l){this.connection.window.showErrorMessage("Failed to compute fix"),this.connection.console.error(`[${a.repoRoot}] Failed to compute fix for matchId ${n}, rule ${s?.id}`);return}let E=ys(e),d=[];for(let S of l.fileChanges){let f=S.filePath===E?e:S.fileUri,h=this.documentManager.getDocument(f),O=h?h.lineCount:S.oldContent.split(`
283
+ `).length;h||S.oldContent.length>0||d.push(yr.CreateFile.create(f,{overwrite:!1,ignoreIfExists:!0}));let C={textDocument:{uri:f,version:h?.version??null},edits:[yr.TextEdit.replace({start:{line:0,character:0},end:{line:O,character:0}},S.newContent)]};d.push(C)}let T=await this.connection.workspace.applyEdit({documentChanges:d});T.applied?this.connection.console.log(`[${a.repoRoot}] Applied fix successfully`):this.connection.console.log(`[${a.repoRoot}] Could not apply fix. Reason: ${T.failureReason}, Change: ${T.failedChange}`),await a.ruleProvider.createFix(s?.id,o).catch(S=>{this.connection.console.log(`[${a.repoRoot}] Failed to track fix: ${S.message}`)}),this.removeDiagnosticByMatchId(e,n),this.documentManager.clearFixes(u)}async handleDismiss(e){let{uri:n,matchId:r}=e[0],i=this.findContextForFile(n);if(!i){this.connection.window.showErrorMessage("File is not in any repository"),this.connection.console.error(`No repository context found for ${n}`);return}let o=ys(n),s=this.toRelativePath(o,i),c=this.getDiagnosticsForUri(n).find(d=>d.data?.matchId===r);if(!c){this.connection.window.showErrorMessage("Could not dismiss violation"),this.connection.console.error(`[${i.repoRoot}] Diagnostic not found for matchId: ${r}`);return}let u=c.data?.match,l=c.data?.rule?.id;if(!u){this.connection.window.showErrorMessage("Could not dismiss violation"),this.connection.console.error(`[${i.repoRoot}] Match not found for matchId: ${r}`);return}await i.ruleProvider.createDismissal(l,u);let E=c.data?.rule?.displayId||l;this.connection.console.log(`[${i.repoRoot}] Dismissed violation: ${E} with matchId ${r}`),this.removeDiagnosticByMatchId(n,r),this.documentManager.clearDismissals(s)}async handleGetDismissals(e){let{uri:n}=e[0];if(!n||typeof n!="string")return this.connection.console.log(`Invalid URI provided to getDismissals: ${n}`),[];if(!n.startsWith("file://"))return this.connection.console.log(`URI must be a file:// URL, got: ${n}`),[];let r=this.findContextForFile(n);if(!r)return this.connection.console.log(`No repository context found for ${n}`),[];let i=ys(n),o=this.toRelativePath(i,r);await this.loadDismissalsForFile(r,o);let s=this.documentManager.getDismissals(o),a=await this.loadRulesWithCache(r),c=this.documentManager.getDocument(n);if(!c){let u=Si(n),l=this.documentManager.getAllDocumentUris();for(let E of l)if(Si(E)===u){c=this.documentManager.getDocument(E);break}}return s.map(u=>{let l=a.find(T=>T.internalId===u.ruleId),E="";if(c){let T=c.getText({start:{line:u.startLine-1,character:0},end:{line:u.startLine-1,character:100}});E=T.trim().substring(0,60),T.trim().length>60&&(E+="...")}let d="";if(u.dismissedAt){let T=new Date,S=new Date(u.dismissedAt),p=T.getTime()-S.getTime(),f=Math.floor(p/6e4),h=Math.floor(f/60),O=Math.floor(h/24);f<1?d="just now":f<60?d=`${f} minute${f===1?"":"s"} ago`:h<24?d=`${h} hour${h===1?"":"s"} ago`:d=`${O} day${O===1?"":"s"} ago`}return{dismissalId:u.dismissalId,ruleId:u.ruleId,displayId:l?.id||u.ruleId,ruleName:l?.message||"Unknown rule",line:u.startLine,fingerprint:u.fingerprint,fileName:o,codeSnippet:E,timeAgo:d}})}async handleUndismiss(e){let{uri:n,dismissalId:r}=e[0],i=this.findContextForFile(n);if(!i){this.connection.window.showErrorMessage("File is not in any repository"),this.connection.console.error(`No repository context found for ${n}`);return}let o=ys(n),s=this.toRelativePath(o,i),c=this.documentManager.getDismissals(s).find(T=>T.dismissalId===r);if(!c){this.connection.window.showErrorMessage("Dismissal not found"),this.connection.console.error(`[${i.repoRoot}] Dismissal not found with ID ${r}`);return}await i.ruleProvider.deleteDismissal(c.ruleId,c.file,c.fingerprint);let l=(await this.loadRulesWithCache(i)).find(T=>T.internalId===c.ruleId),E=l?.id||c.ruleId,d=l?.message||"Unknown rule";this.connection.console.log(`Undismissed violation: ${E} at line ${c.startLine}`),this.connection.window.showInformationMessage(`Undismissed violation: ${E} at line ${c.startLine} - ${d}`),this.documentManager.clearDismissals(s),this.triggerExecution()}async handleRemember(e){let{uri:n,range:r,selectedText:i,note:o}=e[0],s=this.findContextForFile(n);if(!s){this.connection.window.showErrorMessage("File is not in any repository"),this.connection.console.error(`No repository context found for ${n}`);return}let a=ys(n),c=this.toRelativePath(a,s);if(!o||o.trim().length===0){this.connection.window.showErrorMessage("Note is required to remember a pattern");return}let l=this.getDiagnosticsForUri(n).filter(E=>E.source==="wispbit"&&E.data?.match).map(E=>({...E.data.match,ruleId:E.data.rule?.id}));this.connection.console.log(`[${s.repoRoot}] Remembering pattern with ${l.length} matches: ${i.substring(0,100)}...`),this.connection.console.log(`[${s.repoRoot}] Note: ${o}`);try{await s.ruleProvider.rememberPattern(c,i,{start:{line:r.start.line+1,column:r.start.character+1},end:{line:r.end.line+1,column:r.end.character+1}},o.trim(),l),this.connection.window.showInformationMessage(`Pattern remembered: ${o.trim()}`)}catch(E){this.connection.console.log(`Failed to remember: ${E.message}`),this.connection.window.showErrorMessage(`Failed to remember: ${E.message}`)}}truncateMessage(e,n=60){return e.length<=n?e:e.substring(0,n)+"..."}generateCodeActions(e,n){let r=[],i=n.filter(c=>c.source==="wispbit"),o=i.filter(c=>c.data?.fix),s=o.length>1&&o.some((c,u)=>o.slice(u+1).some(l=>c.range.start.line<=l.range.end.line&&c.range.end.line>=l.range.start.line)),a=!1;for(let c of i){let u=c.data?.fix,l=u?.autofix||!1,E=u&&(!s||!a);if(u){let T=this.truncateMessage(c.message);r.push({title:`Apply fix: ${T}`,kind:"quickfix",command:{title:"Apply Fix",command:"wispbit.quickfix",arguments:[{uri:e,matchId:c.data?.matchId}]},diagnostics:[c],isPreferred:E}),E&&(a=!0),l&&r.push({title:`Fix: ${T}`,kind:"source.fixAll",command:{title:"Apply Fix",command:"wispbit.quickfix",arguments:[{uri:e,matchId:c.data?.matchId}]},diagnostics:[c],isPreferred:!1})}let d=this.truncateMessage(c.message);r.push({title:`Dismiss: ${d}`,kind:"quickfix",command:{title:"Dismiss",command:"wispbit.dismiss",arguments:[{uri:e,matchId:c.data?.matchId}]},diagnostics:[c]})}return r}generateHover(e,n){let r=e.find(d=>n.line<d.range.start.line||n.line>d.range.end.line?!1:d.range.start.line===d.range.end.line?n.character>=d.range.start.character&&n.character<=d.range.end.character:n.line===d.range.start.line?n.character>=d.range.start.character:n.line===d.range.end.line?n.character<=d.range.end.character:!0);if(!r)return null;let i=String(r.code||""),o;for(let d of this.repositoryContextManager.getAllContexts())if(o=d.rulesById.get(i),o)break;let s=r.data?.fix,a=r.data?.match?.file?.path,c=r.data?.uri,l=(c?this.findContextForFile(c):null)?.repoRoot||this.workspacePath,E="";if(s?.diffs&&s.diffs.length>0)for(let{file:d,diff:T}of s.diffs){if(!(d.path===a)){let p=HI(l,d.path),f=this.pathToNormalizedUri(p);E+=`*[${d.path}](${f})*
284
284
  `}E+="```diff\n",E+=T,E+="\n```\n\n"}return o?.summary&&(o.summary.content&&(E+=`**Summary:** ${o.summary.content}
285
285
 
286
286
  `),o.summary.badExample&&(E+=`**Bad example:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wispbit/local",
3
- "version": "1.0.75",
3
+ "version": "1.0.76",
4
4
  "type": "module",
5
5
  "main": "cli.js",
6
6
  "bin": {