opencode-sonarqube 0.1.19 → 0.1.20

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/dist/index.js +69 -93
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -20188,62 +20188,58 @@ function shouldIgnoreFile2(filePath) {
20188
20188
  return IGNORED_FILE_PATTERNS2.some((pattern) => pattern.test(filePath));
20189
20189
  }
20190
20190
  var SonarQubePlugin = async ({ client, directory, worktree }) => {
20191
- debugLog.info("=== PLUGIN START ===", { directory, worktree, cwd: process.cwd() });
20192
- const resolveValidDirectory = () => {
20193
- const log = (msg) => {
20194
- try {
20195
- appendFileSync4("/tmp/sonarqube-plugin-debug.log", `${new Date().toISOString()} [RESOLVE] ${msg}
20191
+ const safeLog = (msg) => {
20192
+ try {
20193
+ appendFileSync4("/tmp/sonarqube-plugin-debug.log", `${new Date().toISOString()} [PLUGIN] ${msg}
20196
20194
  `);
20197
- } catch {}
20198
- };
20199
- log(`START worktree=${worktree} directory=${directory} cwd=${process.cwd()}`);
20195
+ } catch {}
20196
+ };
20197
+ safeLog(`=== PLUGIN START === directory=${directory} worktree=${worktree} cwd=${process.cwd()}`);
20198
+ const resolveValidDirectory = () => {
20200
20199
  if (worktree && worktree !== "/" && worktree.length > 1) {
20201
- log(`USING worktree=${worktree}`);
20200
+ safeLog(`USING worktree=${worktree}`);
20202
20201
  return worktree;
20203
20202
  }
20204
20203
  if (directory && directory !== "/" && directory.length > 1) {
20205
- log(`USING directory=${directory}`);
20204
+ safeLog(`USING directory=${directory}`);
20206
20205
  return directory;
20207
20206
  }
20208
20207
  const cwd = process.cwd();
20209
20208
  if (cwd && cwd !== "/" && cwd.length > 1) {
20210
- log(`USING cwd=${cwd}`);
20209
+ safeLog(`USING cwd=${cwd}`);
20211
20210
  return cwd;
20212
20211
  }
20213
20212
  try {
20214
20213
  const pluginUrl = import.meta.url;
20215
- log(`import.meta.url=${pluginUrl}`);
20216
- const pluginPath = pluginUrl.replace("file://", "");
20214
+ const pluginPath = decodeURIComponent(pluginUrl.replace("file://", ""));
20217
20215
  const pathParts = pluginPath.split("/");
20218
20216
  const nodeModulesIndex = pathParts.findIndex((p) => p === "node_modules");
20219
- log(`pathParts nodeModulesIndex=${nodeModulesIndex}`);
20220
20217
  if (nodeModulesIndex > 0) {
20221
20218
  const projectPath = pathParts.slice(0, nodeModulesIndex).join("/");
20222
- log(`extracted projectPath=${projectPath}`);
20223
20219
  if (projectPath && projectPath !== "/" && projectPath.length > 1) {
20220
+ safeLog(`USING import.meta.url derived path=${projectPath}`);
20224
20221
  return projectPath;
20225
20222
  }
20226
20223
  }
20227
- } catch (e) {
20228
- log(`import.meta.url FAILED: ${e}`);
20229
- }
20224
+ } catch {}
20230
20225
  const homeDir = process.env["HOME"] || "/Users";
20231
- log(`FALLBACK home=${homeDir}`);
20226
+ safeLog(`FALLBACK home=${homeDir}`);
20232
20227
  return homeDir;
20233
20228
  };
20234
20229
  const effectiveDirectory = resolveValidDirectory();
20230
+ safeLog(`FINAL effectiveDirectory=${effectiveDirectory}`);
20235
20231
  try {
20236
- appendFileSync4("/tmp/sonarqube-plugin-debug.log", `${new Date().toISOString()} [RESOLVE] FINAL effective=${effectiveDirectory}
20237
- `);
20238
- } catch {}
20239
- await client.app.log({
20240
- body: {
20241
- service: "opencode-sonarqube",
20242
- level: "info",
20243
- message: "SonarQube plugin initialized",
20244
- extra: { directory, worktree, effectiveDirectory }
20245
- }
20246
- });
20232
+ await client.app.log({
20233
+ body: {
20234
+ service: "opencode-sonarqube",
20235
+ level: "info",
20236
+ message: "SonarQube plugin initialized",
20237
+ extra: { directory, worktree, effectiveDirectory }
20238
+ }
20239
+ });
20240
+ } catch {
20241
+ safeLog("client.app.log failed (non-fatal)");
20242
+ }
20247
20243
  let pluginConfig;
20248
20244
  let lastAnalysisResult;
20249
20245
  const getConfig = () => pluginConfig;
@@ -20616,8 +20612,17 @@ Git operation completed with changes. Consider running:
20616
20612
  return;
20617
20613
  await showToast("Code pushed - SonarQube will analyze on server", "info");
20618
20614
  };
20615
+ const safeAsync = (fn, name) => {
20616
+ return async (...args) => {
20617
+ try {
20618
+ return await fn(...args);
20619
+ } catch (error45) {
20620
+ safeLog(`[ERROR] ${name} failed: ${error45}`);
20621
+ }
20622
+ };
20623
+ };
20619
20624
  const returnHooks = {
20620
- event: async ({ event }) => {
20625
+ event: safeAsync(async ({ event }) => {
20621
20626
  handleSessionTrackingEvent(event);
20622
20627
  handleFileEditedEvent(event);
20623
20628
  if (event.type === "session.created" && currentSessionId) {
@@ -20629,8 +20634,8 @@ Git operation completed with changes. Consider running:
20629
20634
  if (event.type === "session.error") {
20630
20635
  await showToast("SonarQube: Analysis error occurred", "error");
20631
20636
  }
20632
- },
20633
- "tool.execute.before": async (input, output) => {
20637
+ }, "event"),
20638
+ "tool.execute.before": safeAsync(async (input, output) => {
20634
20639
  if (input.tool === "sonarqube") {
20635
20640
  await loadPluginConfig();
20636
20641
  }
@@ -20638,71 +20643,49 @@ Git operation completed with changes. Consider running:
20638
20643
  if (isBashTool && currentSessionId) {
20639
20644
  await handlePreCommitCheck(output);
20640
20645
  }
20641
- },
20642
- "tool.execute.after": async (input, output) => {
20646
+ }, "tool.execute.before"),
20647
+ "tool.execute.after": safeAsync(async (input, output) => {
20643
20648
  await logSonarQubeResult(input, output);
20644
20649
  await trackFileChanges(input, output);
20645
20650
  await handleGitOperations(input, output);
20646
- },
20647
- "experimental.session.compacting": async (_input, output) => {
20651
+ }, "tool.execute.after"),
20652
+ "experimental.session.compacting": safeAsync(async (_input, output) => {
20648
20653
  const context = buildCompactionContext();
20649
20654
  if (context) {
20650
20655
  output.context.push(context);
20651
20656
  }
20652
- },
20653
- "experimental.chat.system.transform": async (_input, output) => {
20654
- try {
20655
- const { appendFileSync: appendFileSync5 } = await import("node:fs");
20656
- appendFileSync5("/tmp/sonarqube-plugin-debug.log", `${new Date().toISOString()} [HOOK] experimental.chat.system.transform ENTERED
20657
- `);
20658
- } catch {}
20659
- debugLog.info("=== experimental.chat.system.transform START ===");
20657
+ }, "experimental.session.compacting"),
20658
+ "experimental.chat.system.transform": safeAsync(async (_input, output) => {
20659
+ safeLog("experimental.chat.system.transform ENTERED");
20660
20660
  await loadPluginConfig();
20661
20661
  const sonarConfig = pluginConfig?.["sonarqube"];
20662
- debugLog.info("system.transform: Loading config", { hasSonarConfig: !!sonarConfig });
20663
20662
  const config2 = loadConfig(sonarConfig);
20664
- debugLog.info("system.transform: Config result", { hasConfig: !!config2, level: config2?.level });
20665
20663
  if (!config2 || config2.level === "off") {
20666
- debugLog.info("system.transform: No config or level=off, skipping");
20667
20664
  return;
20668
20665
  }
20669
- try {
20670
- const dir = getDirectory();
20671
- debugLog.info("system.transform: Loading project state", { directory: dir });
20672
- const state = await getProjectState(dir);
20673
- debugLog.info("system.transform: State loaded", {
20674
- hasState: !!state,
20675
- projectKey: state?.projectKey,
20676
- hasToken: !!state?.projectToken
20677
- });
20678
- if (!state || !state.projectKey) {
20679
- debugLog.info("system.transform: No state or projectKey, skipping");
20680
- return;
20681
- }
20682
- debugLog.info("system.transform: Creating API", {
20683
- url: config2.url,
20666
+ const dir = getDirectory();
20667
+ const state = await getProjectState(dir);
20668
+ if (!state || !state.projectKey) {
20669
+ return;
20670
+ }
20671
+ const api2 = createSonarQubeAPI(config2, state);
20672
+ const [qgStatus, counts, newCodeResponse] = await Promise.all([
20673
+ api2.qualityGate.getStatus(state.projectKey),
20674
+ api2.issues.getCounts(state.projectKey),
20675
+ api2.issues.search({
20684
20676
  projectKey: state.projectKey,
20685
- tokenLength: state.projectToken?.length
20686
- });
20687
- const api2 = createSonarQubeAPI(config2, state);
20688
- debugLog.info("system.transform: Fetching quality data", { projectKey: state.projectKey });
20689
- const [qgStatus, counts, newCodeResponse] = await Promise.all([
20690
- api2.qualityGate.getStatus(state.projectKey),
20691
- api2.issues.getCounts(state.projectKey),
20692
- api2.issues.search({
20693
- projectKey: state.projectKey,
20694
- inNewCode: true,
20695
- resolved: false,
20696
- pageSize: 1
20697
- }).catch(() => ({ paging: { total: 0 } }))
20698
- ]);
20699
- const hasIssues = counts.blocker > 0 || counts.critical > 0;
20700
- const qgFailed = qgStatus.projectStatus.status !== "OK";
20701
- const newCodeIssues = newCodeResponse.paging.total;
20702
- if (!hasIssues && !qgFailed && newCodeIssues === 0) {
20703
- return;
20704
- }
20705
- const systemContext = `## SonarQube Code Quality Status
20677
+ inNewCode: true,
20678
+ resolved: false,
20679
+ pageSize: 1
20680
+ }).catch(() => ({ paging: { total: 0 } }))
20681
+ ]);
20682
+ const hasIssues = counts.blocker > 0 || counts.critical > 0;
20683
+ const qgFailed = qgStatus.projectStatus.status !== "OK";
20684
+ const newCodeIssues = newCodeResponse.paging.total;
20685
+ if (!hasIssues && !qgFailed && newCodeIssues === 0) {
20686
+ return;
20687
+ }
20688
+ const systemContext = `## SonarQube Code Quality Status
20706
20689
 
20707
20690
  **Quality Gate:** ${qgStatus.projectStatus.status}${qgFailed ? " (FAILED)" : ""}
20708
20691
  **Outstanding Issues:** ${counts.blocker} blockers, ${counts.critical} critical, ${counts.major} major
@@ -20716,15 +20699,8 @@ ${config2.level === "enterprise" ? `This project follows enterprise-level qualit
20716
20699
  - \`sonarqube({ action: "newissues" })\` - See issues in your recent changes (Clean as You Code)
20717
20700
  - \`sonarqube({ action: "worstfiles" })\` - Find files needing most attention
20718
20701
  - \`sonarqube({ action: "issues" })\` - See all issues`;
20719
- output.system.push(systemContext);
20720
- } catch (error45) {
20721
- try {
20722
- const { appendFileSync: appendFileSync5 } = await import("node:fs");
20723
- appendFileSync5("/tmp/sonarqube-plugin-debug.log", `${new Date().toISOString()} [ERROR] experimental.chat.system.transform FAILED: ${error45}
20724
- `);
20725
- } catch {}
20726
- }
20727
- },
20702
+ output.system.push(systemContext);
20703
+ }, "experimental.chat.system.transform"),
20728
20704
  tool: {
20729
20705
  sonarqube: tool({
20730
20706
  description: `Run SonarQube code analysis and get quality metrics.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-sonarqube",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "OpenCode Plugin for SonarQube integration - Enterprise-level code quality from the start",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -38,7 +38,7 @@
38
38
  "homepage": "https://github.com/mguttmann/opencode-sonarqube#readme",
39
39
  "dependencies": {
40
40
  "@opencode-ai/plugin": "^1.1.34",
41
- "opencode-sonarqube": "0.1.19",
41
+ "opencode-sonarqube": "0.1.20",
42
42
  "zod": "^3.24.0"
43
43
  },
44
44
  "devDependencies": {