opencode-sonarqube 0.1.2 → 0.1.4

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 +288 -147
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4104,94 +4104,6 @@ var init_types2 = __esm(() => {
4104
4104
  };
4105
4105
  });
4106
4106
 
4107
- // src/utils/logger.ts
4108
- class Logger {
4109
- service;
4110
- minLevel;
4111
- client;
4112
- constructor(service, options) {
4113
- this.service = service;
4114
- this.minLevel = options?.minLevel ?? "info";
4115
- this.client = options?.client;
4116
- }
4117
- shouldLog(level) {
4118
- const levels = ["debug", "info", "warn", "error"];
4119
- return levels.indexOf(level) >= levels.indexOf(this.minLevel);
4120
- }
4121
- formatMessage(level, message, extra) {
4122
- const timestamp = new Date().toISOString();
4123
- const color = LOG_COLORS[level];
4124
- const prefix = `${color}[${this.service}]${RESET}`;
4125
- const levelStr = `${color}${level.toUpperCase()}${RESET}`;
4126
- let formatted = `${prefix} ${timestamp} ${levelStr}: ${message}`;
4127
- if (extra && Object.keys(extra).length > 0) {
4128
- formatted += ` ${JSON.stringify(extra)}`;
4129
- }
4130
- return formatted;
4131
- }
4132
- async log(level, message, extra) {
4133
- if (!this.shouldLog(level))
4134
- return;
4135
- if (this.client) {
4136
- try {
4137
- await this.client.app.log({
4138
- service: this.service,
4139
- level,
4140
- message,
4141
- extra
4142
- });
4143
- return;
4144
- } catch {}
4145
- }
4146
- const formatted = this.formatMessage(level, message, extra);
4147
- switch (level) {
4148
- case "debug":
4149
- console.debug(formatted);
4150
- break;
4151
- case "info":
4152
- console.info(formatted);
4153
- break;
4154
- case "warn":
4155
- console.warn(formatted);
4156
- break;
4157
- case "error":
4158
- console.error(formatted);
4159
- break;
4160
- }
4161
- }
4162
- debug(message, extra) {
4163
- this.log("debug", message, extra);
4164
- }
4165
- info(message, extra) {
4166
- this.log("info", message, extra);
4167
- }
4168
- warn(message, extra) {
4169
- this.log("warn", message, extra);
4170
- }
4171
- error(message, extra) {
4172
- this.log("error", message, extra);
4173
- }
4174
- child(subService) {
4175
- return new Logger(`${this.service}:${subService}`, {
4176
- minLevel: this.minLevel,
4177
- client: this.client
4178
- });
4179
- }
4180
- }
4181
- function createLogger(service, client) {
4182
- return new Logger(service, { client });
4183
- }
4184
- var LOG_COLORS, RESET = "\x1B[0m", logger;
4185
- var init_logger = __esm(() => {
4186
- LOG_COLORS = {
4187
- debug: "\x1B[90m",
4188
- info: "\x1B[36m",
4189
- warn: "\x1B[33m",
4190
- error: "\x1B[31m"
4191
- };
4192
- logger = new Logger("opencode-sonarqube");
4193
- });
4194
-
4195
4107
  // src/utils/state.ts
4196
4108
  function getStatePath(directory) {
4197
4109
  return `${directory}/${STATE_DIR}/${STATE_FILE}`;
@@ -4205,20 +4117,30 @@ async function hasProjectState(directory) {
4205
4117
  }
4206
4118
  async function loadProjectState(directory) {
4207
4119
  const statePath = getStatePath(directory);
4120
+ logger4.info(">>> loadProjectState called", { directory, statePath });
4208
4121
  const exists = await Bun.file(statePath).exists();
4122
+ logger4.info("State file exists check", { exists, statePath });
4209
4123
  if (!exists) {
4210
- logger4.debug("No project state found", { directory });
4124
+ logger4.info("No project state file found", { directory, statePath });
4211
4125
  return null;
4212
4126
  }
4213
4127
  try {
4214
4128
  const content = await Bun.file(statePath).text();
4129
+ logger4.info("State file content loaded", { contentLength: content.length });
4215
4130
  const data = JSON.parse(content);
4131
+ logger4.info("State file parsed", { keys: Object.keys(data) });
4216
4132
  const state = ProjectStateSchema.parse(data);
4217
- logger4.debug("Loaded project state", { projectKey: state.projectKey });
4133
+ logger4.info("<<< loadProjectState success", {
4134
+ projectKey: state.projectKey,
4135
+ projectKeyLength: state.projectKey?.length,
4136
+ hasToken: !!state.projectToken,
4137
+ tokenLength: state.projectToken?.length
4138
+ });
4218
4139
  return state;
4219
4140
  } catch (error45) {
4220
- logger4.warn("Failed to load project state", {
4221
- error: error45 instanceof Error ? error45.message : String(error45)
4141
+ logger4.error("Failed to load project state", {
4142
+ error: error45 instanceof Error ? error45.message : String(error45),
4143
+ statePath
4222
4144
  });
4223
4145
  return null;
4224
4146
  }
@@ -4275,8 +4197,20 @@ ${entry}
4275
4197
  var logger4, STATE_DIR = ".sonarqube", STATE_FILE = "project.json";
4276
4198
  var init_state = __esm(() => {
4277
4199
  init_types2();
4278
- init_logger();
4279
- logger4 = new Logger("state-manager");
4200
+ logger4 = {
4201
+ info: (msg, extra) => {
4202
+ console.log(`[SONARQUBE-STATE] ${msg}`, extra ? JSON.stringify(extra) : "");
4203
+ },
4204
+ warn: (msg, extra) => {
4205
+ console.warn(`[SONARQUBE-STATE] ${msg}`, extra ? JSON.stringify(extra) : "");
4206
+ },
4207
+ error: (msg, extra) => {
4208
+ console.error(`[SONARQUBE-STATE] ${msg}`, extra ? JSON.stringify(extra) : "");
4209
+ },
4210
+ debug: (msg, extra) => {
4211
+ console.log(`[SONARQUBE-STATE] ${msg}`, extra ? JSON.stringify(extra) : "");
4212
+ }
4213
+ };
4280
4214
  });
4281
4215
 
4282
4216
  // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
@@ -16601,6 +16535,17 @@ function tool(input) {
16601
16535
  tool.schema = exports_external;
16602
16536
  // src/utils/config.ts
16603
16537
  init_types2();
16538
+ var configLogger = {
16539
+ info: (msg, extra) => {
16540
+ console.log(`[SONARQUBE-CONFIG] ${msg}`, extra ? JSON.stringify(extra) : "");
16541
+ },
16542
+ warn: (msg, extra) => {
16543
+ console.warn(`[SONARQUBE-CONFIG] ${msg}`, extra ? JSON.stringify(extra) : "");
16544
+ },
16545
+ error: (msg, extra) => {
16546
+ console.error(`[SONARQUBE-CONFIG] ${msg}`, extra ? JSON.stringify(extra) : "");
16547
+ }
16548
+ };
16604
16549
  var DEFAULT_CONFIG = {
16605
16550
  level: "enterprise",
16606
16551
  autoAnalyze: true,
@@ -16609,9 +16554,16 @@ var DEFAULT_CONFIG = {
16609
16554
  sources: "src"
16610
16555
  };
16611
16556
  function loadConfig(rawConfig) {
16557
+ configLogger.info(">>> loadConfig called", { hasRawConfig: !!rawConfig });
16612
16558
  const envUrl = process.env["SONAR_HOST_URL"];
16613
16559
  const envUser = process.env["SONAR_USER"];
16614
16560
  const envPassword = process.env["SONAR_PASSWORD"];
16561
+ configLogger.info("Environment variables", {
16562
+ hasEnvUrl: !!envUrl,
16563
+ hasEnvUser: !!envUser,
16564
+ hasEnvPassword: !!envPassword,
16565
+ envUrl: envUrl ? `${envUrl.substring(0, 20)}...` : undefined
16566
+ });
16615
16567
  const configToValidate = {
16616
16568
  ...DEFAULT_CONFIG,
16617
16569
  ...rawConfig,
@@ -16620,13 +16572,19 @@ function loadConfig(rawConfig) {
16620
16572
  ...envPassword && { password: envPassword }
16621
16573
  };
16622
16574
  if (!configToValidate.url || !configToValidate.user || !configToValidate.password) {
16575
+ configLogger.warn("Missing required config", {
16576
+ hasUrl: !!configToValidate.url,
16577
+ hasUser: !!configToValidate.user,
16578
+ hasPassword: !!configToValidate.password
16579
+ });
16623
16580
  return null;
16624
16581
  }
16625
16582
  const result = SonarQubeConfigSchema.safeParse(configToValidate);
16626
16583
  if (!result.success) {
16627
- console.error("SonarQube config validation failed:", result.error.format());
16584
+ configLogger.error("Config validation failed", { errors: result.error.format() });
16628
16585
  return null;
16629
16586
  }
16587
+ configLogger.info("<<< loadConfig success", { url: result.data.url, level: result.data.level });
16630
16588
  return result.data;
16631
16589
  }
16632
16590
  async function deriveProjectKey(directory) {
@@ -16676,8 +16634,94 @@ function sanitizeProjectKey(input) {
16676
16634
  return input.toLowerCase().replaceAll(/[^a-z0-9-_]/g, "-").replaceAll(/-+/g, "-").replaceAll(/(?:^-)|(?:-$)/g, "").slice(0, 400);
16677
16635
  }
16678
16636
 
16637
+ // src/utils/logger.ts
16638
+ var LOG_COLORS = {
16639
+ debug: "\x1B[90m",
16640
+ info: "\x1B[36m",
16641
+ warn: "\x1B[33m",
16642
+ error: "\x1B[31m"
16643
+ };
16644
+ var RESET = "\x1B[0m";
16645
+
16646
+ class Logger {
16647
+ service;
16648
+ minLevel;
16649
+ client;
16650
+ constructor(service, options) {
16651
+ this.service = service;
16652
+ this.minLevel = options?.minLevel ?? "info";
16653
+ this.client = options?.client;
16654
+ }
16655
+ shouldLog(level) {
16656
+ const levels = ["debug", "info", "warn", "error"];
16657
+ return levels.indexOf(level) >= levels.indexOf(this.minLevel);
16658
+ }
16659
+ formatMessage(level, message, extra) {
16660
+ const timestamp = new Date().toISOString();
16661
+ const color = LOG_COLORS[level];
16662
+ const prefix = `${color}[${this.service}]${RESET}`;
16663
+ const levelStr = `${color}${level.toUpperCase()}${RESET}`;
16664
+ let formatted = `${prefix} ${timestamp} ${levelStr}: ${message}`;
16665
+ if (extra && Object.keys(extra).length > 0) {
16666
+ formatted += ` ${JSON.stringify(extra)}`;
16667
+ }
16668
+ return formatted;
16669
+ }
16670
+ async log(level, message, extra) {
16671
+ if (!this.shouldLog(level))
16672
+ return;
16673
+ if (this.client) {
16674
+ try {
16675
+ await this.client.app.log({
16676
+ service: this.service,
16677
+ level,
16678
+ message,
16679
+ extra
16680
+ });
16681
+ return;
16682
+ } catch {}
16683
+ }
16684
+ const formatted = this.formatMessage(level, message, extra);
16685
+ switch (level) {
16686
+ case "debug":
16687
+ console.debug(formatted);
16688
+ break;
16689
+ case "info":
16690
+ console.info(formatted);
16691
+ break;
16692
+ case "warn":
16693
+ console.warn(formatted);
16694
+ break;
16695
+ case "error":
16696
+ console.error(formatted);
16697
+ break;
16698
+ }
16699
+ }
16700
+ debug(message, extra) {
16701
+ this.log("debug", message, extra);
16702
+ }
16703
+ info(message, extra) {
16704
+ this.log("info", message, extra);
16705
+ }
16706
+ warn(message, extra) {
16707
+ this.log("warn", message, extra);
16708
+ }
16709
+ error(message, extra) {
16710
+ this.log("error", message, extra);
16711
+ }
16712
+ child(subService) {
16713
+ return new Logger(`${this.service}:${subService}`, {
16714
+ minLevel: this.minLevel,
16715
+ client: this.client
16716
+ });
16717
+ }
16718
+ }
16719
+ var logger = new Logger("opencode-sonarqube");
16720
+ function createLogger(service, client) {
16721
+ return new Logger(service, { client });
16722
+ }
16723
+
16679
16724
  // src/scanner/config.ts
16680
- init_logger();
16681
16725
  var logger2 = new Logger("scanner-config");
16682
16726
  async function checkProjectFiles(directory) {
16683
16727
  const checks3 = await Promise.all([
@@ -16945,7 +16989,6 @@ async function writePropertiesFile(options, config2, directory) {
16945
16989
  }
16946
16990
  // src/api/client.ts
16947
16991
  init_types2();
16948
- init_logger();
16949
16992
  function buildUrl(baseUrl, endpoint, params) {
16950
16993
  let url2 = `${baseUrl}${endpoint}`;
16951
16994
  if (!params) {
@@ -17032,11 +17075,10 @@ function buildAuthHeader(auth) {
17032
17075
  class SonarQubeClient {
17033
17076
  baseUrl;
17034
17077
  auth;
17035
- logger;
17036
- constructor(config2, logger3) {
17078
+ constructor(config2, _logger) {
17037
17079
  this.baseUrl = normalizeUrl(config2.url);
17038
17080
  this.auth = config2.auth;
17039
- this.logger = logger3 ?? new Logger("sonarqube-client");
17081
+ console.log(`[SONARQUBE-CLIENT] Created client for ${this.baseUrl}`);
17040
17082
  }
17041
17083
  async request(endpoint, options = {}) {
17042
17084
  const { method = "GET", params, body } = options;
@@ -17049,19 +17091,36 @@ class SonarQubeClient {
17049
17091
  if (requestBody) {
17050
17092
  headers["Content-Type"] = "application/x-www-form-urlencoded";
17051
17093
  }
17052
- this.logger.debug(`API Request: ${method} ${endpoint}`, { params, hasBody: !!body });
17094
+ console.log(`[SONARQUBE-API] >>> ${method} ${endpoint}`, JSON.stringify({
17095
+ url: url2,
17096
+ params,
17097
+ hasBody: !!body,
17098
+ bodyKeys: body ? Object.keys(body) : []
17099
+ }));
17053
17100
  try {
17054
17101
  const response = await fetch(url2, {
17055
17102
  method,
17056
17103
  headers,
17057
17104
  body: requestBody
17058
17105
  });
17106
+ console.log(`[SONARQUBE-API] <<< ${method} ${endpoint}`, JSON.stringify({
17107
+ status: response.status,
17108
+ ok: response.ok
17109
+ }));
17059
17110
  if (!response.ok) {
17111
+ console.error(`[SONARQUBE-API] ERROR: ${method} ${endpoint}`, JSON.stringify({
17112
+ status: response.status,
17113
+ url: url2
17114
+ }));
17060
17115
  await handleResponseError(response);
17061
17116
  }
17062
17117
  const text = await response.text();
17063
17118
  return parseResponseBody(text);
17064
17119
  } catch (error45) {
17120
+ console.error(`[SONARQUBE-API] EXCEPTION: ${method} ${endpoint}`, JSON.stringify({
17121
+ error: String(error45),
17122
+ url: url2
17123
+ }));
17065
17124
  handleFetchError(error45, this.baseUrl);
17066
17125
  }
17067
17126
  }
@@ -17127,8 +17186,6 @@ function createClientWithCredentials(url2, user, password, logger3) {
17127
17186
  }
17128
17187
  // src/api/projects.ts
17129
17188
  init_types2();
17130
- init_logger();
17131
-
17132
17189
  class ProjectsAPI {
17133
17190
  client;
17134
17191
  logger;
@@ -17229,8 +17286,6 @@ class ProjectsAPI {
17229
17286
  }
17230
17287
  }
17231
17288
  // src/api/issues.ts
17232
- init_logger();
17233
-
17234
17289
  class IssuesAPI {
17235
17290
  client;
17236
17291
  logger;
@@ -17380,7 +17435,6 @@ class IssuesAPI {
17380
17435
  }
17381
17436
  // src/api/quality-gate.ts
17382
17437
  init_types2();
17383
- init_logger();
17384
17438
  var METRIC_KEYS = {
17385
17439
  coverage: "coverage",
17386
17440
  newCoverage: "new_coverage",
@@ -17717,8 +17771,6 @@ class QualityGateAPI {
17717
17771
  }
17718
17772
  }
17719
17773
  // src/api/rules.ts
17720
- init_logger();
17721
-
17722
17774
  class RulesAPI {
17723
17775
  client;
17724
17776
  logger;
@@ -17822,8 +17874,6 @@ class RulesAPI {
17822
17874
  }
17823
17875
  }
17824
17876
  // src/api/sources.ts
17825
- init_logger();
17826
-
17827
17877
  class SourcesAPI {
17828
17878
  client;
17829
17879
  logger;
@@ -17962,8 +18012,6 @@ class SourcesAPI {
17962
18012
  }
17963
18013
  }
17964
18014
  // src/api/duplications.ts
17965
- init_logger();
17966
-
17967
18015
  class DuplicationsAPI {
17968
18016
  client;
17969
18017
  logger;
@@ -18072,8 +18120,6 @@ class DuplicationsAPI {
18072
18120
  }
18073
18121
  }
18074
18122
  // src/api/ce.ts
18075
- init_logger();
18076
-
18077
18123
  class ComputeEngineAPI {
18078
18124
  client;
18079
18125
  logger;
@@ -18189,8 +18235,6 @@ class ComputeEngineAPI {
18189
18235
  }
18190
18236
  }
18191
18237
  // src/api/analyses.ts
18192
- init_logger();
18193
-
18194
18238
  class ProjectAnalysesAPI {
18195
18239
  client;
18196
18240
  logger;
@@ -18199,7 +18243,14 @@ class ProjectAnalysesAPI {
18199
18243
  this.logger = logger3 ?? new Logger("sonarqube-analyses");
18200
18244
  }
18201
18245
  async getAnalyses(options) {
18202
- this.logger.debug(`Getting analyses for ${options.projectKey}`);
18246
+ this.logger.info(`>>> getAnalyses called`, {
18247
+ projectKey: options.projectKey,
18248
+ projectKeyLength: options.projectKey?.length
18249
+ });
18250
+ if (!options.projectKey) {
18251
+ this.logger.error(`getAnalyses: projectKey is empty/undefined!`);
18252
+ return [];
18253
+ }
18203
18254
  try {
18204
18255
  const response = await this.client.get("/api/project_analyses/search", {
18205
18256
  project: options.projectKey,
@@ -18209,9 +18260,10 @@ class ProjectAnalysesAPI {
18209
18260
  to: options.to,
18210
18261
  ps: options.pageSize ?? 10
18211
18262
  });
18263
+ this.logger.info(`<<< getAnalyses success`, { analysesCount: response.analyses.length });
18212
18264
  return response.analyses;
18213
18265
  } catch (error45) {
18214
- this.logger.warn(`Failed to get analyses: ${error45}`);
18266
+ this.logger.error(`getAnalyses failed`, { error: String(error45), projectKey: options.projectKey });
18215
18267
  return [];
18216
18268
  }
18217
18269
  }
@@ -18251,8 +18303,6 @@ class ProjectAnalysesAPI {
18251
18303
  }
18252
18304
  }
18253
18305
  // src/api/profiles.ts
18254
- init_logger();
18255
-
18256
18306
  class QualityProfilesAPI {
18257
18307
  client;
18258
18308
  logger;
@@ -18261,12 +18311,17 @@ class QualityProfilesAPI {
18261
18311
  this.logger = logger3 ?? new Logger("sonarqube-profiles");
18262
18312
  }
18263
18313
  async getProjectProfiles(projectKey) {
18264
- this.logger.debug(`Getting profiles for project ${projectKey}`);
18314
+ this.logger.info(`>>> getProjectProfiles called`, { projectKey, projectKeyLength: projectKey?.length });
18315
+ if (!projectKey) {
18316
+ this.logger.error(`getProjectProfiles: projectKey is empty/undefined!`);
18317
+ return [];
18318
+ }
18265
18319
  try {
18266
18320
  const response = await this.client.get("/api/qualityprofiles/search", { project: projectKey });
18321
+ this.logger.info(`<<< getProjectProfiles success`, { profileCount: response.profiles.length });
18267
18322
  return response.profiles;
18268
18323
  } catch (error45) {
18269
- this.logger.warn(`Failed to get project profiles: ${error45}`);
18324
+ this.logger.error(`getProjectProfiles failed`, { error: String(error45), projectKey });
18270
18325
  return [];
18271
18326
  }
18272
18327
  }
@@ -18340,8 +18395,6 @@ class QualityProfilesAPI {
18340
18395
  }
18341
18396
  }
18342
18397
  // src/api/branches.ts
18343
- init_logger();
18344
-
18345
18398
  class BranchesAPI {
18346
18399
  client;
18347
18400
  logger;
@@ -18350,12 +18403,17 @@ class BranchesAPI {
18350
18403
  this.logger = logger3 ?? new Logger("sonarqube-branches");
18351
18404
  }
18352
18405
  async getBranches(projectKey) {
18353
- this.logger.debug(`Getting branches for ${projectKey}`);
18406
+ this.logger.info(`>>> getBranches called`, { projectKey, projectKeyLength: projectKey?.length });
18407
+ if (!projectKey) {
18408
+ this.logger.error(`getBranches: projectKey is empty/undefined!`);
18409
+ return [];
18410
+ }
18354
18411
  try {
18355
18412
  const response = await this.client.get("/api/project_branches/list", { project: projectKey });
18413
+ this.logger.info(`<<< getBranches success`, { branchCount: response.branches.length });
18356
18414
  return response.branches;
18357
18415
  } catch (error45) {
18358
- this.logger.warn(`Failed to get branches: ${error45}`);
18416
+ this.logger.error(`getBranches failed`, { error: String(error45), projectKey });
18359
18417
  return [];
18360
18418
  }
18361
18419
  }
@@ -18459,7 +18517,6 @@ class BranchesAPI {
18459
18517
  }
18460
18518
  }
18461
18519
  // src/api/metrics.ts
18462
- init_logger();
18463
18520
  var COMMON_METRICS = [
18464
18521
  "ncloc",
18465
18522
  "lines",
@@ -18619,8 +18676,6 @@ class MetricsAPI {
18619
18676
  }
18620
18677
  }
18621
18678
  // src/api/components.ts
18622
- init_logger();
18623
-
18624
18679
  class ComponentsAPI {
18625
18680
  client;
18626
18681
  logger;
@@ -18734,8 +18789,6 @@ class ComponentsAPI {
18734
18789
  }
18735
18790
  }
18736
18791
  // src/api/index.ts
18737
- init_logger();
18738
-
18739
18792
  class SonarQubeAPI {
18740
18793
  client;
18741
18794
  projects;
@@ -18797,6 +18850,16 @@ function createSonarQubeAPIWithToken(url2, token, logger3) {
18797
18850
  return new SonarQubeAPI(client, logger3);
18798
18851
  }
18799
18852
  function createSonarQubeAPI(config2, state, logger3) {
18853
+ console.log(`[SONARQUBE-API] >>> createSonarQubeAPI called`, JSON.stringify({
18854
+ url: config2.url,
18855
+ projectKey: state.projectKey,
18856
+ projectKeyLength: state.projectKey?.length,
18857
+ hasToken: !!state.projectToken,
18858
+ tokenLength: state.projectToken?.length
18859
+ }));
18860
+ if (!state.projectToken) {
18861
+ console.error(`[SONARQUBE-API] createSonarQubeAPI: projectToken is missing!`);
18862
+ }
18800
18863
  return createSonarQubeAPIWithToken(config2.url, state.projectToken, logger3);
18801
18864
  }
18802
18865
 
@@ -18901,7 +18964,6 @@ function formatIssueBlock(issue2, _number2) {
18901
18964
  }
18902
18965
 
18903
18966
  // src/scanner/runner.ts
18904
- init_logger();
18905
18967
  var logger3 = new Logger("scanner-runner");
18906
18968
  async function runScanner(config2, state, options, directory) {
18907
18969
  const dir = directory ?? process.cwd();
@@ -19076,8 +19138,17 @@ function shouldBlockOnResult(result, level) {
19076
19138
  // src/bootstrap/index.ts
19077
19139
  init_types2();
19078
19140
  init_state();
19079
- init_logger();
19080
- var logger5 = new Logger("bootstrap");
19141
+ var logger5 = {
19142
+ info: (msg, extra) => {
19143
+ console.log(`[SONARQUBE-BOOTSTRAP] ${msg}`, extra ? JSON.stringify(extra) : "");
19144
+ },
19145
+ warn: (msg, extra) => {
19146
+ console.warn(`[SONARQUBE-BOOTSTRAP] ${msg}`, extra ? JSON.stringify(extra) : "");
19147
+ },
19148
+ error: (msg, extra) => {
19149
+ console.error(`[SONARQUBE-BOOTSTRAP] ${msg}`, extra ? JSON.stringify(extra) : "");
19150
+ }
19151
+ };
19081
19152
  var QUALITY_GATE_MAPPING = {
19082
19153
  enterprise: "Sonar way",
19083
19154
  standard: "Sonar way",
@@ -19085,12 +19156,22 @@ var QUALITY_GATE_MAPPING = {
19085
19156
  off: "Sonar way"
19086
19157
  };
19087
19158
  async function needsBootstrap(directory) {
19159
+ logger5.info(">>> needsBootstrap called", { directory });
19088
19160
  const hasState = await hasProjectState(directory);
19161
+ logger5.info("hasProjectState result", { hasState, directory });
19089
19162
  if (!hasState) {
19163
+ logger5.info("<<< needsBootstrap: true (no state file)");
19090
19164
  return true;
19091
19165
  }
19092
19166
  const state = await loadProjectState(directory);
19093
- return !state?.setupComplete;
19167
+ const needsBoot = !state?.setupComplete;
19168
+ logger5.info("<<< needsBootstrap result", {
19169
+ needsBoot,
19170
+ hasState: !!state,
19171
+ setupComplete: state?.setupComplete,
19172
+ projectKey: state?.projectKey
19173
+ });
19174
+ return needsBoot;
19094
19175
  }
19095
19176
  async function getProjectState(directory) {
19096
19177
  return loadProjectState(directory);
@@ -19227,7 +19308,6 @@ async function configureProjectSettings(client, projectKey, languages, config2)
19227
19308
  }
19228
19309
 
19229
19310
  // src/hooks/index.ts
19230
- init_logger();
19231
19311
  var logger6 = new Logger("sonarqube-hooks");
19232
19312
  var editedFiles = new Set;
19233
19313
  var lastAnalysisTime = 0;
@@ -19388,7 +19468,6 @@ function createHooks(getConfig, getDirectory) {
19388
19468
 
19389
19469
  // src/tools/sonarqube.ts
19390
19470
  init_zod();
19391
- init_logger();
19392
19471
  var logger7 = new Logger("sonarqube-tool");
19393
19472
  var SonarQubeToolArgsSchema = exports_external2.object({
19394
19473
  action: exports_external2.enum(["analyze", "issues", "newissues", "status", "init", "setup", "validate", "hotspots", "duplications", "rule", "history", "profile", "branches", "metrics", "worstfiles"]).describe("Action to perform: analyze (run scanner), issues (all issues), newissues (only new code issues), status (quality gate), init/setup (initialize), validate (enterprise check), hotspots (security review), duplications (code duplicates), rule (explain rule), history (past analyses), profile (quality profile), branches (branch status), metrics (detailed metrics), worstfiles (files with most issues)"),
@@ -19989,8 +20068,18 @@ function getSeveritiesFromLevel(level) {
19989
20068
  }
19990
20069
 
19991
20070
  // src/index.ts
19992
- init_logger();
19993
20071
  init_types2();
20072
+ var debugLog = {
20073
+ info: (msg, extra) => {
20074
+ console.log(`[SONARQUBE-DEBUG] ${msg}`, extra ? JSON.stringify(extra) : "");
20075
+ },
20076
+ warn: (msg, extra) => {
20077
+ console.warn(`[SONARQUBE-DEBUG] ${msg}`, extra ? JSON.stringify(extra) : "");
20078
+ },
20079
+ error: (msg, extra) => {
20080
+ console.error(`[SONARQUBE-DEBUG] ${msg}`, extra ? JSON.stringify(extra) : "");
20081
+ }
20082
+ };
19994
20083
  var IGNORED_FILE_PATTERNS2 = [
19995
20084
  /node_modules/,
19996
20085
  /\.git/,
@@ -20007,6 +20096,7 @@ function shouldIgnoreFile2(filePath) {
20007
20096
  return IGNORED_FILE_PATTERNS2.some((pattern) => pattern.test(filePath));
20008
20097
  }
20009
20098
  var SonarQubePlugin = async ({ client, directory, worktree }) => {
20099
+ debugLog.info("=== PLUGIN START ===", { directory, worktree });
20010
20100
  await client.app.log({
20011
20101
  body: {
20012
20102
  service: "opencode-sonarqube",
@@ -20020,38 +20110,71 @@ var SonarQubePlugin = async ({ client, directory, worktree }) => {
20020
20110
  const getConfig = () => pluginConfig;
20021
20111
  const getDirectory = () => worktree ?? directory;
20022
20112
  const loadPluginConfig = async () => {
20023
- if (pluginConfig)
20113
+ debugLog.info("loadPluginConfig called", { hasExistingConfig: !!pluginConfig });
20114
+ if (pluginConfig) {
20115
+ debugLog.info("Config already loaded, skipping");
20024
20116
  return;
20117
+ }
20025
20118
  try {
20026
- const configFile = Bun.file(`${getDirectory()}/opencode.json`);
20119
+ const configPath = `${getDirectory()}/opencode.json`;
20120
+ debugLog.info("Loading config from", { configPath });
20121
+ const configFile = Bun.file(configPath);
20027
20122
  if (await configFile.exists()) {
20028
20123
  pluginConfig = await configFile.json();
20124
+ debugLog.info("Config loaded", { keys: Object.keys(pluginConfig ?? {}) });
20125
+ } else {
20126
+ debugLog.info("No opencode.json found");
20029
20127
  }
20030
- } catch {}
20128
+ } catch (error45) {
20129
+ debugLog.warn("Config load error", { error: String(error45) });
20130
+ }
20031
20131
  };
20032
20132
  const hooks = createHooks(getConfig, getDirectory);
20033
20133
  let currentSessionId;
20034
20134
  let initialCheckDone = false;
20035
20135
  const performInitialQualityCheck = async (sessionId) => {
20036
- if (initialCheckDone)
20136
+ debugLog.info("=== performInitialQualityCheck START ===", { sessionId, initialCheckDone });
20137
+ if (initialCheckDone) {
20138
+ debugLog.info("Initial check already done, skipping");
20037
20139
  return;
20140
+ }
20038
20141
  initialCheckDone = true;
20039
20142
  try {
20040
20143
  await loadPluginConfig();
20041
20144
  const sonarConfig = pluginConfig?.["sonarqube"];
20145
+ debugLog.info("Loading SonarQube config", { hasSonarConfig: !!sonarConfig });
20042
20146
  const config2 = loadConfig(sonarConfig);
20043
- if (!config2 || config2.level === "off")
20147
+ debugLog.info("Config loaded", { hasConfig: !!config2, level: config2?.level });
20148
+ if (!config2 || config2.level === "off") {
20149
+ debugLog.info("Config missing or level=off, skipping");
20044
20150
  return;
20045
- if (await needsBootstrap(getDirectory()))
20151
+ }
20152
+ const dir = getDirectory();
20153
+ debugLog.info("Checking needsBootstrap", { directory: dir });
20154
+ const needsBoot = await needsBootstrap(dir);
20155
+ debugLog.info("needsBootstrap result", { needsBoot });
20156
+ if (needsBoot) {
20157
+ debugLog.info("Bootstrap needed, skipping initial check");
20046
20158
  return;
20047
- const state = await getProjectState(getDirectory());
20048
- if (!state || !state.projectKey)
20159
+ }
20160
+ debugLog.info("Loading project state");
20161
+ const state = await getProjectState(dir);
20162
+ debugLog.info("Project state loaded", {
20163
+ hasState: !!state,
20164
+ projectKey: state?.projectKey,
20165
+ hasToken: !!state?.projectToken
20166
+ });
20167
+ if (!state || !state.projectKey) {
20168
+ debugLog.info("No state or projectKey, skipping");
20049
20169
  return;
20170
+ }
20171
+ debugLog.info("Creating API and fetching quality status", { projectKey: state.projectKey });
20050
20172
  const api2 = createSonarQubeAPI(config2, state);
20051
20173
  const [qgStatus, counts] = await Promise.all([
20052
20174
  api2.qualityGate.getStatus(state.projectKey),
20053
20175
  api2.issues.getCounts(state.projectKey)
20054
20176
  ]);
20177
+ debugLog.info("Quality status fetched", { qgStatus: qgStatus.projectStatus.status, counts });
20055
20178
  const hasIssues = counts.blocker > 0 || counts.critical > 0 || counts.major > 0;
20056
20179
  const qgFailed = qgStatus.projectStatus.status !== "OK";
20057
20180
  if (hasIssues || qgFailed) {
@@ -20383,18 +20506,36 @@ Git operation completed with changes. Consider running:
20383
20506
  }
20384
20507
  },
20385
20508
  "experimental.chat.system.transform": async (_input, output) => {
20509
+ debugLog.info("=== experimental.chat.system.transform START ===");
20386
20510
  await loadPluginConfig();
20387
20511
  const sonarConfig = pluginConfig?.["sonarqube"];
20512
+ debugLog.info("system.transform: Loading config", { hasSonarConfig: !!sonarConfig });
20388
20513
  const config2 = loadConfig(sonarConfig);
20514
+ debugLog.info("system.transform: Config result", { hasConfig: !!config2, level: config2?.level });
20389
20515
  if (!config2 || config2.level === "off") {
20516
+ debugLog.info("system.transform: No config or level=off, skipping");
20390
20517
  return;
20391
20518
  }
20392
20519
  try {
20393
- const state = await getProjectState(getDirectory());
20520
+ const dir = getDirectory();
20521
+ debugLog.info("system.transform: Loading project state", { directory: dir });
20522
+ const state = await getProjectState(dir);
20523
+ debugLog.info("system.transform: State loaded", {
20524
+ hasState: !!state,
20525
+ projectKey: state?.projectKey,
20526
+ hasToken: !!state?.projectToken
20527
+ });
20394
20528
  if (!state || !state.projectKey) {
20529
+ debugLog.info("system.transform: No state or projectKey, skipping");
20395
20530
  return;
20396
20531
  }
20532
+ debugLog.info("system.transform: Creating API", {
20533
+ url: config2.url,
20534
+ projectKey: state.projectKey,
20535
+ tokenLength: state.projectToken?.length
20536
+ });
20397
20537
  const api2 = createSonarQubeAPI(config2, state);
20538
+ debugLog.info("system.transform: Fetching quality data", { projectKey: state.projectKey });
20398
20539
  const [qgStatus, counts, newCodeResponse] = await Promise.all([
20399
20540
  api2.qualityGate.getStatus(state.projectKey),
20400
20541
  api2.issues.getCounts(state.projectKey),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-sonarqube",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
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",