@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.cjs CHANGED
@@ -77,6 +77,101 @@ var JsonInputMessageType = /* @__PURE__ */ ((JsonInputMessageType2) => {
77
77
  return JsonInputMessageType2;
78
78
  })(JsonInputMessageType || {});
79
79
 
80
+ // src/logger.ts
81
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
82
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
83
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
84
+ LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
85
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
86
+ LogLevel2[LogLevel2["SILENT"] = 4] = "SILENT";
87
+ return LogLevel2;
88
+ })(LogLevel || {});
89
+ var consoleLogger = {
90
+ debug: (message, ...args) => console.log(message, ...args),
91
+ info: (message, ...args) => console.log(message, ...args),
92
+ warn: (message, ...args) => console.warn(message, ...args),
93
+ error: (message, ...args) => console.error(message, ...args)
94
+ };
95
+ var silentLogger = {
96
+ debug: () => {
97
+ },
98
+ info: () => {
99
+ },
100
+ warn: () => {
101
+ },
102
+ error: () => {
103
+ }
104
+ };
105
+ var SDKLogger = class {
106
+ logger;
107
+ level;
108
+ prefix;
109
+ constructor(options = {}) {
110
+ this.logger = options.logger || consoleLogger;
111
+ this.level = options.level ?? 1 /* INFO */;
112
+ this.prefix = options.prefix || "";
113
+ }
114
+ /**
115
+ * Update logger configuration
116
+ */
117
+ configure(options) {
118
+ if (options.logger !== void 0) {
119
+ this.logger = options.logger;
120
+ }
121
+ if (options.level !== void 0) {
122
+ this.level = options.level;
123
+ }
124
+ if (options.prefix !== void 0) {
125
+ this.prefix = options.prefix;
126
+ }
127
+ }
128
+ /**
129
+ * Set log level
130
+ */
131
+ setLevel(level) {
132
+ this.level = level;
133
+ }
134
+ /**
135
+ * Set custom logger implementation
136
+ */
137
+ setLogger(logger) {
138
+ this.logger = logger;
139
+ }
140
+ formatMessage(message) {
141
+ return this.prefix ? `${this.prefix} ${message}` : message;
142
+ }
143
+ debug(message, ...args) {
144
+ if (this.level <= 0 /* DEBUG */) {
145
+ this.logger.debug(this.formatMessage(message), ...args);
146
+ }
147
+ }
148
+ info(message, ...args) {
149
+ if (this.level <= 1 /* INFO */) {
150
+ this.logger.info(this.formatMessage(message), ...args);
151
+ }
152
+ }
153
+ warn(message, ...args) {
154
+ if (this.level <= 2 /* WARN */) {
155
+ this.logger.warn(this.formatMessage(message), ...args);
156
+ }
157
+ }
158
+ error(message, ...args) {
159
+ if (this.level <= 3 /* ERROR */) {
160
+ this.logger.error(this.formatMessage(message), ...args);
161
+ }
162
+ }
163
+ };
164
+ var sdkLogger = new SDKLogger({
165
+ prefix: "[GeminiSDK]",
166
+ level: 1 /* INFO */
167
+ });
168
+ function createLogger(component, options = {}) {
169
+ return new SDKLogger({
170
+ ...options,
171
+ prefix: options.prefix || `[${component}]`
172
+ });
173
+ }
174
+
80
175
  // src/query.ts
81
176
  function buildCliArgs(options, prompt) {
82
177
  const args = [];
@@ -108,7 +203,7 @@ function buildCliArgs(options, prompt) {
108
203
  args.push(prompt);
109
204
  return args;
110
205
  }
111
- function buildEnv(options) {
206
+ function buildEnv(options, logger) {
112
207
  const env = {
113
208
  ...process.env,
114
209
  ...options.env
@@ -119,25 +214,19 @@ function buildEnv(options) {
119
214
  if (useVertexAI) {
120
215
  env.GOOGLE_API_KEY = options.apiKey;
121
216
  env.GOOGLE_GENAI_USE_VERTEXAI = "true";
122
- if (options.debug) {
123
- console.log("[SDK] Vertex AI mode: Setting GOOGLE_API_KEY:", options.apiKey.substring(0, 10) + "...");
124
- }
217
+ logger.debug("Vertex AI mode: Setting GOOGLE_API_KEY:", options.apiKey.substring(0, 10) + "...");
125
218
  } else {
126
219
  env.GEMINI_API_KEY = options.apiKey;
127
- if (options.debug) {
128
- console.log("[SDK] Standard mode: Setting GEMINI_API_KEY:", options.apiKey.substring(0, 10) + "...");
129
- }
220
+ logger.debug("Standard mode: Setting GEMINI_API_KEY:", options.apiKey.substring(0, 10) + "...");
130
221
  }
131
222
  }
132
223
  if (!useVertexAI && env.GOOGLE_API_KEY) {
133
224
  delete env.GOOGLE_API_KEY;
134
- if (options.debug) {
135
- console.log("[SDK] Removed GOOGLE_API_KEY from environment (not using Vertex AI)");
136
- }
225
+ logger.debug("Removed GOOGLE_API_KEY from environment (not using Vertex AI)");
137
226
  }
138
227
  if (options.debug) {
139
228
  env.DEBUG = "1";
140
- console.log("[SDK] Environment variables set:", {
229
+ logger.debug("Environment variables set:", {
141
230
  GEMINI_API_KEY: env.GEMINI_API_KEY ? "***" : void 0,
142
231
  GOOGLE_API_KEY: env.GOOGLE_API_KEY ? "***" : void 0,
143
232
  GOOGLE_GENAI_USE_VERTEXAI: env.GOOGLE_GENAI_USE_VERTEXAI,
@@ -147,6 +236,10 @@ function buildEnv(options) {
147
236
  return env;
148
237
  }
149
238
  async function* query(prompt, options) {
239
+ const logger = createLogger("GeminiSDK", {
240
+ logger: options.logger,
241
+ level: options.debug ? 0 /* DEBUG */ : 1 /* INFO */
242
+ });
150
243
  if (!options.pathToGeminiCLI) {
151
244
  throw new GeminiSDKError("pathToGeminiCLI is required");
152
245
  }
@@ -156,7 +249,7 @@ async function* query(prompt, options) {
156
249
  );
157
250
  }
158
251
  const args = buildCliArgs(options, prompt);
159
- const env = buildEnv(options);
252
+ const env = buildEnv(options, logger);
160
253
  const cwd = options.cwd || process.cwd();
161
254
  const nodeExecutable = options.pathToNode || "node";
162
255
  let geminiProcess;
@@ -172,9 +265,7 @@ async function* query(prompt, options) {
172
265
  const stderrChunks = [];
173
266
  geminiProcess.stderr?.on("data", (data) => {
174
267
  stderrChunks.push(data);
175
- if (options.debug) {
176
- console.error("[Gemini CLI stderr]:", data.toString());
177
- }
268
+ logger.error("stderr:", data.toString());
178
269
  });
179
270
  let timeoutId;
180
271
  if (options.timeout) {
@@ -194,10 +285,8 @@ async function* query(prompt, options) {
194
285
  hasYieldedEvents = true;
195
286
  yield event;
196
287
  } catch (parseError) {
197
- if (options.debug) {
198
- console.error("[Gemini SDK] Failed to parse JSON line:", line);
199
- console.error("[Gemini SDK] Parse error:", parseError);
200
- }
288
+ logger.debug("Failed to parse JSON line:", line);
289
+ logger.debug("Parse error:", parseError);
201
290
  }
202
291
  }
203
292
  } catch (error) {
@@ -400,6 +489,10 @@ var GeminiStreamClient = class extends events.EventEmitter {
400
489
  constructor(options) {
401
490
  super();
402
491
  this.options = options;
492
+ this.logger = createLogger("GeminiStreamClient", {
493
+ logger: options.logger,
494
+ level: options.debug ? 0 /* DEBUG */ : 1 /* INFO */
495
+ });
403
496
  if (!options.pathToGeminiCLI) {
404
497
  throw new GeminiSDKError("pathToGeminiCLI is required");
405
498
  }
@@ -414,6 +507,7 @@ var GeminiStreamClient = class extends events.EventEmitter {
414
507
  initEvent = null;
415
508
  initTimeout = null;
416
509
  tempSettingsPath = null;
510
+ logger;
417
511
  /**
418
512
  * Start the Gemini CLI process
419
513
  */
@@ -422,7 +516,7 @@ var GeminiStreamClient = class extends events.EventEmitter {
422
516
  throw new GeminiSDKError("Process already started");
423
517
  }
424
518
  this.status = "running" /* RUNNING */;
425
- if (this.options.hooks || this.options.mcpServers) {
519
+ if (this.options.hooks || this.options.mcpServers || this.options.tools || this.options.context) {
426
520
  await this.createTempSettings();
427
521
  }
428
522
  const args = this.buildCommand();
@@ -457,9 +551,11 @@ var GeminiStreamClient = class extends events.EventEmitter {
457
551
  }
458
552
  if (this.process.stderr) {
459
553
  this.process.stderr.on("data", (chunk) => {
460
- if (this.options.debug) {
461
- console.error("[GeminiStreamClient] stderr:", chunk.toString());
554
+ const message = chunk.toString().trim();
555
+ if (!message || message.includes("Flushing log events")) {
556
+ return;
462
557
  }
558
+ this.logger.error("stderr:", message);
463
559
  });
464
560
  }
465
561
  this.emit("started");
@@ -595,11 +691,9 @@ var GeminiStreamClient = class extends events.EventEmitter {
595
691
  if (this.tempSettingsPath) {
596
692
  try {
597
693
  fs__namespace.unlinkSync(this.tempSettingsPath);
598
- if (this.options.debug) {
599
- console.log("[GeminiStreamClient] Cleaned up temp settings:", this.tempSettingsPath);
600
- }
694
+ this.logger.debug("Cleaned up temp settings:", this.tempSettingsPath);
601
695
  } catch (error) {
602
- console.error("[GeminiStreamClient] Failed to clean up temp settings:", error);
696
+ this.logger.error("Failed to clean up temp settings:", error);
603
697
  }
604
698
  this.tempSettingsPath = null;
605
699
  }
@@ -634,37 +728,55 @@ var GeminiStreamClient = class extends events.EventEmitter {
634
728
  * Note: Gemini CLI does not support --settings-file parameter.
635
729
  * Instead, it loads settings from GEMINI_CONFIG_DIR/settings.json
636
730
  * where GEMINI_CONFIG_DIR is set via environment variable.
731
+ *
732
+ * This method merges with existing settings.json if present, preserving
733
+ * any configuration written by the host application (e.g., tools.discoveryCommand).
637
734
  */
638
735
  async createTempSettings() {
639
736
  const geminiConfigDir = this.options.env?.GEMINI_CONFIG_DIR;
640
737
  if (!geminiConfigDir) {
641
738
  throw new GeminiSDKError(
642
- "GEMINI_CONFIG_DIR is required in options.env when using hooks or mcpServers. Please set options.env.GEMINI_CONFIG_DIR to a directory path."
739
+ "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."
643
740
  );
644
741
  }
645
742
  if (!fs__namespace.existsSync(geminiConfigDir)) {
646
743
  fs__namespace.mkdirSync(geminiConfigDir, { recursive: true });
647
- if (this.options.debug) {
648
- console.log("[GeminiStreamClient] Created config directory:", geminiConfigDir);
649
- }
744
+ this.logger.debug("Created config directory:", geminiConfigDir);
650
745
  }
651
746
  this.tempSettingsPath = path2__namespace.join(geminiConfigDir, "settings.json");
652
- const settings = {};
653
- if (this.options.hooks) {
747
+ let existingSettings = {};
748
+ if (fs__namespace.existsSync(this.tempSettingsPath)) {
749
+ try {
750
+ const content = fs__namespace.readFileSync(this.tempSettingsPath, "utf-8");
751
+ existingSettings = JSON.parse(content);
752
+ this.logger.debug("Read existing settings:", JSON.stringify(existingSettings, null, 2));
753
+ } catch (error) {
754
+ this.logger.warn("Failed to read existing settings.json, will overwrite:", error);
755
+ }
756
+ }
757
+ const settings = { ...existingSettings };
758
+ if (this.options.tools || this.options.hooks) {
759
+ const existingTools = settings.tools || {};
654
760
  settings.tools = {
655
- enableHooks: true
761
+ ...existingTools,
762
+ ...this.options.tools,
763
+ // enableHooks is set to true if hooks are configured
764
+ ...this.options.hooks ? { enableHooks: true } : {}
656
765
  };
766
+ }
767
+ if (this.options.hooks) {
657
768
  settings.hooks = this.options.hooks;
658
769
  }
770
+ if (this.options.context) {
771
+ settings.context = this.options.context;
772
+ }
659
773
  if (this.options.mcpServers) {
660
774
  settings.mcpServers = this.options.mcpServers;
661
775
  }
662
776
  try {
663
777
  fs__namespace.writeFileSync(this.tempSettingsPath, JSON.stringify(settings, null, 2), "utf-8");
664
- if (this.options.debug) {
665
- console.log("[GeminiStreamClient] Wrote settings to:", this.tempSettingsPath);
666
- console.log("[GeminiStreamClient] Settings content:", JSON.stringify(settings, null, 2));
667
- }
778
+ this.logger.debug("Wrote settings to:", this.tempSettingsPath);
779
+ this.logger.debug("Settings content:", JSON.stringify(settings, null, 2));
668
780
  } catch (error) {
669
781
  throw new GeminiSDKError(`Failed to write settings file: ${error}`);
670
782
  }
@@ -682,9 +794,7 @@ var GeminiStreamClient = class extends events.EventEmitter {
682
794
  ];
683
795
  if (this.options.resumeSessionFilePath) {
684
796
  args.push("--resume-from-file", this.options.resumeSessionFilePath);
685
- if (this.options.debug) {
686
- console.log("[GeminiStreamClient] Resuming from session file:", this.options.resumeSessionFilePath);
687
- }
797
+ this.logger.debug("Resuming from session file:", this.options.resumeSessionFilePath);
688
798
  }
689
799
  if (this.options.model) {
690
800
  args.push("--model", this.options.model);
@@ -707,28 +817,20 @@ var GeminiStreamClient = class extends events.EventEmitter {
707
817
  };
708
818
  if (this.options.apiKey) {
709
819
  const useVertexAI = this.options.env?.GOOGLE_GENAI_USE_VERTEXAI === "true";
710
- if (this.options.debug) {
711
- console.log("[GeminiStreamClient] buildEnv() - API Key prefix:", this.options.apiKey.substring(0, 3));
712
- console.log("[GeminiStreamClient] buildEnv() - GOOGLE_GENAI_USE_VERTEXAI:", this.options.env?.GOOGLE_GENAI_USE_VERTEXAI);
713
- console.log("[GeminiStreamClient] buildEnv() - useVertexAI:", useVertexAI);
714
- }
820
+ this.logger.debug("buildEnv() - API Key prefix:", this.options.apiKey.substring(0, 3));
821
+ this.logger.debug("buildEnv() - GOOGLE_GENAI_USE_VERTEXAI:", this.options.env?.GOOGLE_GENAI_USE_VERTEXAI);
822
+ this.logger.debug("buildEnv() - useVertexAI:", useVertexAI);
715
823
  if (useVertexAI) {
716
824
  env.GOOGLE_API_KEY = this.options.apiKey;
717
- if (this.options.debug) {
718
- console.log("[GeminiStreamClient] buildEnv() - Setting GOOGLE_API_KEY for Vertex AI");
719
- }
825
+ this.logger.debug("buildEnv() - Setting GOOGLE_API_KEY for Vertex AI");
720
826
  } else {
721
827
  env.GEMINI_API_KEY = this.options.apiKey;
722
- if (this.options.debug) {
723
- console.log("[GeminiStreamClient] buildEnv() - Setting GEMINI_API_KEY for AI Studio");
724
- }
828
+ this.logger.debug("buildEnv() - Setting GEMINI_API_KEY for AI Studio");
725
829
  }
726
830
  }
727
- if (this.options.debug) {
728
- console.log("[GeminiStreamClient] buildEnv() - Final env has GOOGLE_API_KEY:", !!env.GOOGLE_API_KEY);
729
- console.log("[GeminiStreamClient] buildEnv() - Final env has GEMINI_API_KEY:", !!env.GEMINI_API_KEY);
730
- console.log("[GeminiStreamClient] buildEnv() - Final env GOOGLE_GENAI_USE_VERTEXAI:", env.GOOGLE_GENAI_USE_VERTEXAI);
731
- }
831
+ this.logger.debug("buildEnv() - Final env has GOOGLE_API_KEY:", !!env.GOOGLE_API_KEY);
832
+ this.logger.debug("buildEnv() - Final env has GEMINI_API_KEY:", !!env.GEMINI_API_KEY);
833
+ this.logger.debug("buildEnv() - Final env GOOGLE_GENAI_USE_VERTEXAI:", env.GOOGLE_GENAI_USE_VERTEXAI);
732
834
  return env;
733
835
  }
734
836
  /**
@@ -739,19 +841,15 @@ var GeminiStreamClient = class extends events.EventEmitter {
739
841
  throw new GeminiSDKError("stdin stream not available");
740
842
  }
741
843
  const json = JSON.stringify(message);
742
- if (this.options.debug) {
743
- console.log("[GeminiStreamClient] Writing message to stdin:", json.substring(0, 100));
744
- }
844
+ this.logger.debug("Writing message to stdin:", json.substring(0, 100));
745
845
  const success = this.stdinStream.write(json + "\n", (error) => {
746
846
  if (error) {
747
- console.error("[GeminiStreamClient] Write error:", error);
748
- } else if (this.options.debug) {
749
- console.log("[GeminiStreamClient] Write callback: message flushed to stdin");
847
+ this.logger.error("Write error:", error);
848
+ } else {
849
+ this.logger.debug("Write callback: message flushed to stdin");
750
850
  }
751
851
  });
752
- if (this.options.debug) {
753
- console.log("[GeminiStreamClient] Write success:", success, "Stream writable:", this.stdinStream.writable);
754
- }
852
+ this.logger.debug("Write success:", success, "Stream writable:", this.stdinStream.writable);
755
853
  }
756
854
  /**
757
855
  * Start reading JSONL events from stdout
@@ -766,23 +864,17 @@ var GeminiStreamClient = class extends events.EventEmitter {
766
864
  return;
767
865
  }
768
866
  if (trimmed.startsWith("[")) {
769
- if (this.options.debug) {
770
- console.log("[GeminiStreamClient] Skipping debug output:", trimmed.substring(0, 100));
771
- }
772
867
  return;
773
868
  }
774
869
  try {
775
870
  const event = JSON.parse(trimmed);
776
871
  this.handleEvent(event);
777
872
  } catch (error) {
778
- console.error("[GeminiStreamClient] Failed to parse JSON:", trimmed);
779
- console.error("[GeminiStreamClient] Error:", error);
873
+ this.logger.error("Failed to parse JSON:", trimmed);
874
+ this.logger.error("Error:", error);
780
875
  }
781
876
  });
782
877
  this.readlineInterface.on("close", () => {
783
- if (this.options.debug) {
784
- console.log("[GeminiStreamClient] readline interface closed");
785
- }
786
878
  });
787
879
  }
788
880
  /**
@@ -824,9 +916,7 @@ var GeminiStreamClient = class extends events.EventEmitter {
824
916
  * Handle process exit
825
917
  */
826
918
  handleProcessExit(code, signal) {
827
- if (this.options.debug) {
828
- console.log("[GeminiStreamClient] Process exited:", { code, signal });
829
- }
919
+ this.logger.debug("Process exited:", { code, signal });
830
920
  if (code !== 0 && code !== null) {
831
921
  this.status = "error" /* ERROR */;
832
922
  this.emit("error", new GeminiSDKError(`Process exited with code ${code}`, code));
@@ -845,7 +935,7 @@ var GeminiStreamClient = class extends events.EventEmitter {
845
935
  * Handle process error
846
936
  */
847
937
  handleProcessError(error) {
848
- console.error("[GeminiStreamClient] Process error:", error);
938
+ this.logger.error("Process error:", error);
849
939
  this.status = "error" /* ERROR */;
850
940
  this.emit("error", error);
851
941
  }
@@ -904,7 +994,7 @@ function validateModel(model) {
904
994
  return defaultModel;
905
995
  }
906
996
  if (!model.startsWith("gemini-")) {
907
- console.warn(`Warning: Model name "${model}" does not start with "gemini-"`);
997
+ sdkLogger.warn(`Warning: Model name "${model}" does not start with "gemini-"`);
908
998
  }
909
999
  return model;
910
1000
  }
@@ -929,12 +1019,17 @@ exports.GeminiSDKError = GeminiSDKError;
929
1019
  exports.GeminiStreamClient = GeminiStreamClient;
930
1020
  exports.JsonInputMessageType = JsonInputMessageType;
931
1021
  exports.JsonStreamEventType = JsonStreamEventType;
1022
+ exports.LogLevel = LogLevel;
932
1023
  exports.ProcessStatus = ProcessStatus;
1024
+ exports.SDKLogger = SDKLogger;
1025
+ exports.createLogger = createLogger;
933
1026
  exports.findGeminiCLI = findGeminiCLI;
934
1027
  exports.formatDuration = formatDuration;
935
1028
  exports.formatTokens = formatTokens;
936
1029
  exports.getApiKey = getApiKey;
937
1030
  exports.query = query;
1031
+ exports.sdkLogger = sdkLogger;
1032
+ exports.silentLogger = silentLogger;
938
1033
  exports.validateApiKey = validateApiKey;
939
1034
  exports.validateModel = validateModel;
940
1035
  //# sourceMappingURL=index.cjs.map