@ketd/gemini-cli-sdk 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -53,6 +53,101 @@ var JsonInputMessageType = /* @__PURE__ */ ((JsonInputMessageType2) => {
53
53
  return JsonInputMessageType2;
54
54
  })(JsonInputMessageType || {});
55
55
 
56
+ // src/logger.ts
57
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
58
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
59
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
60
+ LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
61
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
62
+ LogLevel2[LogLevel2["SILENT"] = 4] = "SILENT";
63
+ return LogLevel2;
64
+ })(LogLevel || {});
65
+ var consoleLogger = {
66
+ debug: (message, ...args) => console.log(message, ...args),
67
+ info: (message, ...args) => console.log(message, ...args),
68
+ warn: (message, ...args) => console.warn(message, ...args),
69
+ error: (message, ...args) => console.error(message, ...args)
70
+ };
71
+ var silentLogger = {
72
+ debug: () => {
73
+ },
74
+ info: () => {
75
+ },
76
+ warn: () => {
77
+ },
78
+ error: () => {
79
+ }
80
+ };
81
+ var SDKLogger = class {
82
+ logger;
83
+ level;
84
+ prefix;
85
+ constructor(options = {}) {
86
+ this.logger = options.logger || consoleLogger;
87
+ this.level = options.level ?? 1 /* INFO */;
88
+ this.prefix = options.prefix || "";
89
+ }
90
+ /**
91
+ * Update logger configuration
92
+ */
93
+ configure(options) {
94
+ if (options.logger !== void 0) {
95
+ this.logger = options.logger;
96
+ }
97
+ if (options.level !== void 0) {
98
+ this.level = options.level;
99
+ }
100
+ if (options.prefix !== void 0) {
101
+ this.prefix = options.prefix;
102
+ }
103
+ }
104
+ /**
105
+ * Set log level
106
+ */
107
+ setLevel(level) {
108
+ this.level = level;
109
+ }
110
+ /**
111
+ * Set custom logger implementation
112
+ */
113
+ setLogger(logger) {
114
+ this.logger = logger;
115
+ }
116
+ formatMessage(message) {
117
+ return this.prefix ? `${this.prefix} ${message}` : message;
118
+ }
119
+ debug(message, ...args) {
120
+ if (this.level <= 0 /* DEBUG */) {
121
+ this.logger.debug(this.formatMessage(message), ...args);
122
+ }
123
+ }
124
+ info(message, ...args) {
125
+ if (this.level <= 1 /* INFO */) {
126
+ this.logger.info(this.formatMessage(message), ...args);
127
+ }
128
+ }
129
+ warn(message, ...args) {
130
+ if (this.level <= 2 /* WARN */) {
131
+ this.logger.warn(this.formatMessage(message), ...args);
132
+ }
133
+ }
134
+ error(message, ...args) {
135
+ if (this.level <= 3 /* ERROR */) {
136
+ this.logger.error(this.formatMessage(message), ...args);
137
+ }
138
+ }
139
+ };
140
+ var sdkLogger = new SDKLogger({
141
+ prefix: "[GeminiSDK]",
142
+ level: 1 /* INFO */
143
+ });
144
+ function createLogger(component, options = {}) {
145
+ return new SDKLogger({
146
+ ...options,
147
+ prefix: options.prefix || `[${component}]`
148
+ });
149
+ }
150
+
56
151
  // src/query.ts
57
152
  function buildCliArgs(options, prompt) {
58
153
  const args = [];
@@ -84,7 +179,7 @@ function buildCliArgs(options, prompt) {
84
179
  args.push(prompt);
85
180
  return args;
86
181
  }
87
- function buildEnv(options) {
182
+ function buildEnv(options, logger) {
88
183
  const env = {
89
184
  ...process.env,
90
185
  ...options.env
@@ -95,25 +190,19 @@ function buildEnv(options) {
95
190
  if (useVertexAI) {
96
191
  env.GOOGLE_API_KEY = options.apiKey;
97
192
  env.GOOGLE_GENAI_USE_VERTEXAI = "true";
98
- if (options.debug) {
99
- console.log("[SDK] Vertex AI mode: Setting GOOGLE_API_KEY:", options.apiKey.substring(0, 10) + "...");
100
- }
193
+ logger.debug("Vertex AI mode: Setting GOOGLE_API_KEY:", options.apiKey.substring(0, 10) + "...");
101
194
  } else {
102
195
  env.GEMINI_API_KEY = options.apiKey;
103
- if (options.debug) {
104
- console.log("[SDK] Standard mode: Setting GEMINI_API_KEY:", options.apiKey.substring(0, 10) + "...");
105
- }
196
+ logger.debug("Standard mode: Setting GEMINI_API_KEY:", options.apiKey.substring(0, 10) + "...");
106
197
  }
107
198
  }
108
199
  if (!useVertexAI && env.GOOGLE_API_KEY) {
109
200
  delete env.GOOGLE_API_KEY;
110
- if (options.debug) {
111
- console.log("[SDK] Removed GOOGLE_API_KEY from environment (not using Vertex AI)");
112
- }
201
+ logger.debug("Removed GOOGLE_API_KEY from environment (not using Vertex AI)");
113
202
  }
114
203
  if (options.debug) {
115
204
  env.DEBUG = "1";
116
- console.log("[SDK] Environment variables set:", {
205
+ logger.debug("Environment variables set:", {
117
206
  GEMINI_API_KEY: env.GEMINI_API_KEY ? "***" : void 0,
118
207
  GOOGLE_API_KEY: env.GOOGLE_API_KEY ? "***" : void 0,
119
208
  GOOGLE_GENAI_USE_VERTEXAI: env.GOOGLE_GENAI_USE_VERTEXAI,
@@ -123,6 +212,10 @@ function buildEnv(options) {
123
212
  return env;
124
213
  }
125
214
  async function* query(prompt, options) {
215
+ const logger = createLogger("GeminiSDK", {
216
+ logger: options.logger,
217
+ level: options.debug ? 0 /* DEBUG */ : 1 /* INFO */
218
+ });
126
219
  if (!options.pathToGeminiCLI) {
127
220
  throw new GeminiSDKError("pathToGeminiCLI is required");
128
221
  }
@@ -132,7 +225,7 @@ async function* query(prompt, options) {
132
225
  );
133
226
  }
134
227
  const args = buildCliArgs(options, prompt);
135
- const env = buildEnv(options);
228
+ const env = buildEnv(options, logger);
136
229
  const cwd = options.cwd || process.cwd();
137
230
  const nodeExecutable = options.pathToNode || "node";
138
231
  let geminiProcess;
@@ -148,9 +241,7 @@ async function* query(prompt, options) {
148
241
  const stderrChunks = [];
149
242
  geminiProcess.stderr?.on("data", (data) => {
150
243
  stderrChunks.push(data);
151
- if (options.debug) {
152
- console.error("[Gemini CLI stderr]:", data.toString());
153
- }
244
+ logger.error("stderr:", data.toString());
154
245
  });
155
246
  let timeoutId;
156
247
  if (options.timeout) {
@@ -170,10 +261,8 @@ async function* query(prompt, options) {
170
261
  hasYieldedEvents = true;
171
262
  yield event;
172
263
  } catch (parseError) {
173
- if (options.debug) {
174
- console.error("[Gemini SDK] Failed to parse JSON line:", line);
175
- console.error("[Gemini SDK] Parse error:", parseError);
176
- }
264
+ logger.debug("Failed to parse JSON line:", line);
265
+ logger.debug("Parse error:", parseError);
177
266
  }
178
267
  }
179
268
  } catch (error) {
@@ -376,6 +465,10 @@ var GeminiStreamClient = class extends EventEmitter {
376
465
  constructor(options) {
377
466
  super();
378
467
  this.options = options;
468
+ this.logger = createLogger("GeminiStreamClient", {
469
+ logger: options.logger,
470
+ level: options.debug ? 0 /* DEBUG */ : 1 /* INFO */
471
+ });
379
472
  if (!options.pathToGeminiCLI) {
380
473
  throw new GeminiSDKError("pathToGeminiCLI is required");
381
474
  }
@@ -390,6 +483,7 @@ var GeminiStreamClient = class extends EventEmitter {
390
483
  initEvent = null;
391
484
  initTimeout = null;
392
485
  tempSettingsPath = null;
486
+ logger;
393
487
  /**
394
488
  * Start the Gemini CLI process
395
489
  */
@@ -398,7 +492,7 @@ var GeminiStreamClient = class extends EventEmitter {
398
492
  throw new GeminiSDKError("Process already started");
399
493
  }
400
494
  this.status = "running" /* RUNNING */;
401
- if (this.options.hooks || this.options.mcpServers) {
495
+ if (this.options.hooks || this.options.mcpServers || this.options.tools || this.options.context) {
402
496
  await this.createTempSettings();
403
497
  }
404
498
  const args = this.buildCommand();
@@ -433,9 +527,11 @@ var GeminiStreamClient = class extends EventEmitter {
433
527
  }
434
528
  if (this.process.stderr) {
435
529
  this.process.stderr.on("data", (chunk) => {
436
- if (this.options.debug) {
437
- console.error("[GeminiStreamClient] stderr:", chunk.toString());
530
+ const message = chunk.toString().trim();
531
+ if (!message || message.includes("Flushing log events")) {
532
+ return;
438
533
  }
534
+ this.logger.error("stderr:", message);
439
535
  });
440
536
  }
441
537
  this.emit("started");
@@ -571,11 +667,9 @@ var GeminiStreamClient = class extends EventEmitter {
571
667
  if (this.tempSettingsPath) {
572
668
  try {
573
669
  fs.unlinkSync(this.tempSettingsPath);
574
- if (this.options.debug) {
575
- console.log("[GeminiStreamClient] Cleaned up temp settings:", this.tempSettingsPath);
576
- }
670
+ this.logger.debug("Cleaned up temp settings:", this.tempSettingsPath);
577
671
  } catch (error) {
578
- console.error("[GeminiStreamClient] Failed to clean up temp settings:", error);
672
+ this.logger.error("Failed to clean up temp settings:", error);
579
673
  }
580
674
  this.tempSettingsPath = null;
581
675
  }
@@ -610,37 +704,55 @@ var GeminiStreamClient = class extends EventEmitter {
610
704
  * Note: Gemini CLI does not support --settings-file parameter.
611
705
  * Instead, it loads settings from GEMINI_CONFIG_DIR/settings.json
612
706
  * where GEMINI_CONFIG_DIR is set via environment variable.
707
+ *
708
+ * This method merges with existing settings.json if present, preserving
709
+ * any configuration written by the host application (e.g., tools.discoveryCommand).
613
710
  */
614
711
  async createTempSettings() {
615
712
  const geminiConfigDir = this.options.env?.GEMINI_CONFIG_DIR;
616
713
  if (!geminiConfigDir) {
617
714
  throw new GeminiSDKError(
618
- "GEMINI_CONFIG_DIR is required in options.env when using hooks or mcpServers. Please set options.env.GEMINI_CONFIG_DIR to a directory path."
715
+ "GEMINI_CONFIG_DIR is required in options.env when using hooks, mcpServers, tools, or context. Please set options.env.GEMINI_CONFIG_DIR to a directory path."
619
716
  );
620
717
  }
621
718
  if (!fs.existsSync(geminiConfigDir)) {
622
719
  fs.mkdirSync(geminiConfigDir, { recursive: true });
623
- if (this.options.debug) {
624
- console.log("[GeminiStreamClient] Created config directory:", geminiConfigDir);
625
- }
720
+ this.logger.debug("Created config directory:", geminiConfigDir);
626
721
  }
627
722
  this.tempSettingsPath = path2.join(geminiConfigDir, "settings.json");
628
- const settings = {};
629
- if (this.options.hooks) {
723
+ let existingSettings = {};
724
+ if (fs.existsSync(this.tempSettingsPath)) {
725
+ try {
726
+ const content = fs.readFileSync(this.tempSettingsPath, "utf-8");
727
+ existingSettings = JSON.parse(content);
728
+ this.logger.debug("Read existing settings:", JSON.stringify(existingSettings, null, 2));
729
+ } catch (error) {
730
+ this.logger.warn("Failed to read existing settings.json, will overwrite:", error);
731
+ }
732
+ }
733
+ const settings = { ...existingSettings };
734
+ if (this.options.tools || this.options.hooks) {
735
+ const existingTools = settings.tools || {};
630
736
  settings.tools = {
631
- enableHooks: true
737
+ ...existingTools,
738
+ ...this.options.tools,
739
+ // enableHooks is set to true if hooks are configured
740
+ ...this.options.hooks ? { enableHooks: true } : {}
632
741
  };
742
+ }
743
+ if (this.options.hooks) {
633
744
  settings.hooks = this.options.hooks;
634
745
  }
746
+ if (this.options.context) {
747
+ settings.context = this.options.context;
748
+ }
635
749
  if (this.options.mcpServers) {
636
750
  settings.mcpServers = this.options.mcpServers;
637
751
  }
638
752
  try {
639
753
  fs.writeFileSync(this.tempSettingsPath, JSON.stringify(settings, null, 2), "utf-8");
640
- if (this.options.debug) {
641
- console.log("[GeminiStreamClient] Wrote settings to:", this.tempSettingsPath);
642
- console.log("[GeminiStreamClient] Settings content:", JSON.stringify(settings, null, 2));
643
- }
754
+ this.logger.debug("Wrote settings to:", this.tempSettingsPath);
755
+ this.logger.debug("Settings content:", JSON.stringify(settings, null, 2));
644
756
  } catch (error) {
645
757
  throw new GeminiSDKError(`Failed to write settings file: ${error}`);
646
758
  }
@@ -658,9 +770,7 @@ var GeminiStreamClient = class extends EventEmitter {
658
770
  ];
659
771
  if (this.options.resumeSessionFilePath) {
660
772
  args.push("--resume-from-file", this.options.resumeSessionFilePath);
661
- if (this.options.debug) {
662
- console.log("[GeminiStreamClient] Resuming from session file:", this.options.resumeSessionFilePath);
663
- }
773
+ this.logger.debug("Resuming from session file:", this.options.resumeSessionFilePath);
664
774
  }
665
775
  if (this.options.model) {
666
776
  args.push("--model", this.options.model);
@@ -683,28 +793,20 @@ var GeminiStreamClient = class extends EventEmitter {
683
793
  };
684
794
  if (this.options.apiKey) {
685
795
  const useVertexAI = this.options.env?.GOOGLE_GENAI_USE_VERTEXAI === "true";
686
- if (this.options.debug) {
687
- console.log("[GeminiStreamClient] buildEnv() - API Key prefix:", this.options.apiKey.substring(0, 3));
688
- console.log("[GeminiStreamClient] buildEnv() - GOOGLE_GENAI_USE_VERTEXAI:", this.options.env?.GOOGLE_GENAI_USE_VERTEXAI);
689
- console.log("[GeminiStreamClient] buildEnv() - useVertexAI:", useVertexAI);
690
- }
796
+ this.logger.debug("buildEnv() - API Key prefix:", this.options.apiKey.substring(0, 3));
797
+ this.logger.debug("buildEnv() - GOOGLE_GENAI_USE_VERTEXAI:", this.options.env?.GOOGLE_GENAI_USE_VERTEXAI);
798
+ this.logger.debug("buildEnv() - useVertexAI:", useVertexAI);
691
799
  if (useVertexAI) {
692
800
  env.GOOGLE_API_KEY = this.options.apiKey;
693
- if (this.options.debug) {
694
- console.log("[GeminiStreamClient] buildEnv() - Setting GOOGLE_API_KEY for Vertex AI");
695
- }
801
+ this.logger.debug("buildEnv() - Setting GOOGLE_API_KEY for Vertex AI");
696
802
  } else {
697
803
  env.GEMINI_API_KEY = this.options.apiKey;
698
- if (this.options.debug) {
699
- console.log("[GeminiStreamClient] buildEnv() - Setting GEMINI_API_KEY for AI Studio");
700
- }
804
+ this.logger.debug("buildEnv() - Setting GEMINI_API_KEY for AI Studio");
701
805
  }
702
806
  }
703
- if (this.options.debug) {
704
- console.log("[GeminiStreamClient] buildEnv() - Final env has GOOGLE_API_KEY:", !!env.GOOGLE_API_KEY);
705
- console.log("[GeminiStreamClient] buildEnv() - Final env has GEMINI_API_KEY:", !!env.GEMINI_API_KEY);
706
- console.log("[GeminiStreamClient] buildEnv() - Final env GOOGLE_GENAI_USE_VERTEXAI:", env.GOOGLE_GENAI_USE_VERTEXAI);
707
- }
807
+ this.logger.debug("buildEnv() - Final env has GOOGLE_API_KEY:", !!env.GOOGLE_API_KEY);
808
+ this.logger.debug("buildEnv() - Final env has GEMINI_API_KEY:", !!env.GEMINI_API_KEY);
809
+ this.logger.debug("buildEnv() - Final env GOOGLE_GENAI_USE_VERTEXAI:", env.GOOGLE_GENAI_USE_VERTEXAI);
708
810
  return env;
709
811
  }
710
812
  /**
@@ -715,19 +817,15 @@ var GeminiStreamClient = class extends EventEmitter {
715
817
  throw new GeminiSDKError("stdin stream not available");
716
818
  }
717
819
  const json = JSON.stringify(message);
718
- if (this.options.debug) {
719
- console.log("[GeminiStreamClient] Writing message to stdin:", json.substring(0, 100));
720
- }
820
+ this.logger.debug("Writing message to stdin:", json.substring(0, 100));
721
821
  const success = this.stdinStream.write(json + "\n", (error) => {
722
822
  if (error) {
723
- console.error("[GeminiStreamClient] Write error:", error);
724
- } else if (this.options.debug) {
725
- console.log("[GeminiStreamClient] Write callback: message flushed to stdin");
823
+ this.logger.error("Write error:", error);
824
+ } else {
825
+ this.logger.debug("Write callback: message flushed to stdin");
726
826
  }
727
827
  });
728
- if (this.options.debug) {
729
- console.log("[GeminiStreamClient] Write success:", success, "Stream writable:", this.stdinStream.writable);
730
- }
828
+ this.logger.debug("Write success:", success, "Stream writable:", this.stdinStream.writable);
731
829
  }
732
830
  /**
733
831
  * Start reading JSONL events from stdout
@@ -742,23 +840,17 @@ var GeminiStreamClient = class extends EventEmitter {
742
840
  return;
743
841
  }
744
842
  if (trimmed.startsWith("[")) {
745
- if (this.options.debug) {
746
- console.log("[GeminiStreamClient] Skipping debug output:", trimmed.substring(0, 100));
747
- }
748
843
  return;
749
844
  }
750
845
  try {
751
846
  const event = JSON.parse(trimmed);
752
847
  this.handleEvent(event);
753
848
  } catch (error) {
754
- console.error("[GeminiStreamClient] Failed to parse JSON:", trimmed);
755
- console.error("[GeminiStreamClient] Error:", error);
849
+ this.logger.error("Failed to parse JSON:", trimmed);
850
+ this.logger.error("Error:", error);
756
851
  }
757
852
  });
758
853
  this.readlineInterface.on("close", () => {
759
- if (this.options.debug) {
760
- console.log("[GeminiStreamClient] readline interface closed");
761
- }
762
854
  });
763
855
  }
764
856
  /**
@@ -800,9 +892,7 @@ var GeminiStreamClient = class extends EventEmitter {
800
892
  * Handle process exit
801
893
  */
802
894
  handleProcessExit(code, signal) {
803
- if (this.options.debug) {
804
- console.log("[GeminiStreamClient] Process exited:", { code, signal });
805
- }
895
+ this.logger.debug("Process exited:", { code, signal });
806
896
  if (code !== 0 && code !== null) {
807
897
  this.status = "error" /* ERROR */;
808
898
  this.emit("error", new GeminiSDKError(`Process exited with code ${code}`, code));
@@ -821,7 +911,7 @@ var GeminiStreamClient = class extends EventEmitter {
821
911
  * Handle process error
822
912
  */
823
913
  handleProcessError(error) {
824
- console.error("[GeminiStreamClient] Process error:", error);
914
+ this.logger.error("Process error:", error);
825
915
  this.status = "error" /* ERROR */;
826
916
  this.emit("error", error);
827
917
  }
@@ -880,7 +970,7 @@ function validateModel(model) {
880
970
  return defaultModel;
881
971
  }
882
972
  if (!model.startsWith("gemini-")) {
883
- console.warn(`Warning: Model name "${model}" does not start with "gemini-"`);
973
+ sdkLogger.warn(`Warning: Model name "${model}" does not start with "gemini-"`);
884
974
  }
885
975
  return model;
886
976
  }
@@ -899,6 +989,6 @@ function formatTokens(tokens) {
899
989
  return tokens.toLocaleString();
900
990
  }
901
991
 
902
- export { ExitCode, GeminiClient, GeminiSDKError, GeminiStreamClient, JsonInputMessageType, JsonStreamEventType, ProcessStatus, findGeminiCLI, formatDuration, formatTokens, getApiKey, query, validateApiKey, validateModel };
992
+ export { ExitCode, GeminiClient, GeminiSDKError, GeminiStreamClient, JsonInputMessageType, JsonStreamEventType, LogLevel, ProcessStatus, SDKLogger, createLogger, findGeminiCLI, formatDuration, formatTokens, getApiKey, query, sdkLogger, silentLogger, validateApiKey, validateModel };
903
993
  //# sourceMappingURL=index.js.map
904
994
  //# sourceMappingURL=index.js.map