@ketd/gemini-cli-sdk 0.3.7 → 0.3.9

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.d.cts CHANGED
@@ -268,7 +268,9 @@ declare enum JsonStreamEventType {
268
268
  /** Message completion with metadata */
269
269
  FINISHED = "finished",
270
270
  /** Model information */
271
- MODEL_INFO = "model_info"
271
+ MODEL_INFO = "model_info",
272
+ /** Ask user questions (CLI → Host) */
273
+ ASK_USER = "ask_user"
272
274
  }
273
275
  /**
274
276
  * Base event interface
@@ -410,10 +412,45 @@ interface ModelInfoEvent extends BaseJsonStreamEvent {
410
412
  type: JsonStreamEventType.MODEL_INFO;
411
413
  value: string;
412
414
  }
415
+ /**
416
+ * Question option for AskUserEvent
417
+ */
418
+ interface QuestionOption {
419
+ label: string;
420
+ description: string;
421
+ }
422
+ /**
423
+ * Question type for AskUserEvent
424
+ */
425
+ declare enum QuestionType {
426
+ CHOICE = "choice",
427
+ TEXT = "text",
428
+ YESNO = "yesno"
429
+ }
430
+ /**
431
+ * Question in AskUserEvent
432
+ */
433
+ interface Question {
434
+ question: string;
435
+ header: string;
436
+ type?: QuestionType;
437
+ options?: QuestionOption[];
438
+ multiSelect?: boolean;
439
+ placeholder?: string;
440
+ }
441
+ /**
442
+ * Ask user event (CLI → Host)
443
+ * Emitted when the ask_user tool needs structured user input
444
+ */
445
+ interface AskUserEvent extends BaseJsonStreamEvent {
446
+ type: JsonStreamEventType.ASK_USER;
447
+ questions: Question[];
448
+ correlation_id: string;
449
+ }
413
450
  /**
414
451
  * Union type of all JSON stream events
415
452
  */
416
- type JsonStreamEvent = InitEvent | MessageEvent | ToolUseEvent | ToolCallRequestEvent | ToolResultEvent | ThoughtEvent | ErrorEvent | ResultEvent | ContentEvent | FinishedEvent | ModelInfoEvent;
453
+ type JsonStreamEvent = InitEvent | MessageEvent | ToolUseEvent | ToolCallRequestEvent | ToolResultEvent | ThoughtEvent | ErrorEvent | ResultEvent | ContentEvent | FinishedEvent | ModelInfoEvent | AskUserEvent;
417
454
  /**
418
455
  * Gemini CLI exit codes
419
456
  */
@@ -491,7 +528,9 @@ declare enum JsonInputMessageType {
491
528
  /** User message */
492
529
  USER = "user",
493
530
  /** Control command */
494
- CONTROL = "control"
531
+ CONTROL = "control",
532
+ /** Response to ask_user event (Host → CLI) */
533
+ ASK_USER_RESPONSE = "ask_user_response"
495
534
  }
496
535
  /**
497
536
  * User message sent to CLI
@@ -559,10 +598,21 @@ interface ControlInputMessage {
559
598
  control: InterruptControl | TruncateHistoryControl | ResumeSessionControl | ReplaceHistoryControl;
560
599
  session_id?: string;
561
600
  }
601
+ /**
602
+ * Response to ask_user event (Host → CLI)
603
+ * Sent when the host has collected user answers for an ask_user request
604
+ */
605
+ interface AskUserResponseInputMessage {
606
+ type: JsonInputMessageType.ASK_USER_RESPONSE;
607
+ correlation_id: string;
608
+ answers: {
609
+ [questionIndex: string]: string;
610
+ };
611
+ }
562
612
  /**
563
613
  * Union type for input messages
564
614
  */
565
- type JsonInputMessage = UserInputMessage | ControlInputMessage;
615
+ type JsonInputMessage = UserInputMessage | ControlInputMessage | AskUserResponseInputMessage;
566
616
  /**
567
617
  * Hook configuration types (from Gemini CLI)
568
618
  */
@@ -961,6 +1011,8 @@ declare class GeminiStreamClient extends EventEmitter$1 {
961
1011
  private initTimeout;
962
1012
  private tempSettingsPath;
963
1013
  private logger;
1014
+ /** stderr 行缓冲,处理 chunk 分片导致的半行问题 */
1015
+ private stderrLineBuffer;
964
1016
  constructor(options: GeminiStreamOptions);
965
1017
  /**
966
1018
  * Start the Gemini CLI process
@@ -1019,6 +1071,18 @@ declare class GeminiStreamClient extends EventEmitter$1 {
1019
1071
  role: string;
1020
1072
  parts: unknown[];
1021
1073
  }>): Promise<void>;
1074
+ /**
1075
+ * Send a response to an ask_user request from the CLI
1076
+ *
1077
+ * When the CLI emits an 'ask_user' event (from the ask_user tool),
1078
+ * the host collects user answers and sends them back via this method.
1079
+ *
1080
+ * @param correlationId - The correlation_id from the AskUserEvent
1081
+ * @param answers - Map of question index to user's answer string
1082
+ */
1083
+ sendAskUserResponse(correlationId: string, answers: {
1084
+ [questionIndex: string]: string;
1085
+ }): void;
1022
1086
  /**
1023
1087
  * Stop the CLI process
1024
1088
  */
@@ -1082,6 +1146,20 @@ declare class GeminiStreamClient extends EventEmitter$1 {
1082
1146
  * Handle process error
1083
1147
  */
1084
1148
  private handleProcessError;
1149
+ /**
1150
+ * 处理 stderr chunk:按行切分并识别 turn finished reason
1151
+ */
1152
+ private processStderrChunk;
1153
+ /**
1154
+ * 进程结束时,处理 stderr 缓冲里最后一行(若存在)
1155
+ */
1156
+ private flushStderrLineBuffer;
1157
+ /**
1158
+ * 处理单行 stderr:
1159
+ * - 识别 [StreamJsonMode] Turn finished: <reason>,并发出 FINISHED 结构化事件
1160
+ * - 其余日志按原行为输出
1161
+ */
1162
+ private processStderrLine;
1085
1163
  }
1086
1164
 
1087
1165
  /**
@@ -1137,4 +1215,4 @@ declare function formatDuration(ms: number): string;
1137
1215
  */
1138
1216
  declare function formatTokens(tokens: number): string;
1139
1217
 
1140
- export { type ContextConfig, type ControlInputMessage, type ControlSubtype, type ErrorEvent, ExitCode, GeminiClient, type GeminiOptions, GeminiSDKError, GeminiStreamClient, type GeminiStreamOptions, type HooksConfiguration, type InitEvent, type InterruptControl, type JsonInputMessage, JsonInputMessageType, type JsonStreamEvent, JsonStreamEventType, LogLevel, type Logger, type LoggerOptions, type MCPServerConfig, type MCPServersConfig, type MessageEvent, ProcessStatus, type QueryResult, type ResultEvent, type ResumeSessionControl, SDKLogger, type StreamStats, type ThoughtEvent, type ToolPermissionDecision, type ToolPermissionRequest, type ToolResultEvent, type ToolUseEvent, type ToolsConfig, type TruncateHistoryControl, type UserInputMessage, createLogger, findGeminiCLI, formatDuration, formatTokens, getApiKey, query, sdkLogger, silentLogger, validateApiKey, validateModel };
1218
+ export { type AskUserEvent, type AskUserResponseInputMessage, type ContextConfig, type ControlInputMessage, type ControlSubtype, type ErrorEvent, ExitCode, GeminiClient, type GeminiOptions, GeminiSDKError, GeminiStreamClient, type GeminiStreamOptions, type HooksConfiguration, type InitEvent, type InterruptControl, type JsonInputMessage, JsonInputMessageType, type JsonStreamEvent, JsonStreamEventType, LogLevel, type Logger, type LoggerOptions, type MCPServerConfig, type MCPServersConfig, type MessageEvent, ProcessStatus, type QueryResult, type Question, type QuestionOption, QuestionType, type ResultEvent, type ResumeSessionControl, SDKLogger, type StreamStats, type ThoughtEvent, type ToolPermissionDecision, type ToolPermissionRequest, type ToolResultEvent, type ToolUseEvent, type ToolsConfig, type TruncateHistoryControl, type UserInputMessage, createLogger, findGeminiCLI, formatDuration, formatTokens, getApiKey, query, sdkLogger, silentLogger, validateApiKey, validateModel };
package/dist/index.d.ts CHANGED
@@ -268,7 +268,9 @@ declare enum JsonStreamEventType {
268
268
  /** Message completion with metadata */
269
269
  FINISHED = "finished",
270
270
  /** Model information */
271
- MODEL_INFO = "model_info"
271
+ MODEL_INFO = "model_info",
272
+ /** Ask user questions (CLI → Host) */
273
+ ASK_USER = "ask_user"
272
274
  }
273
275
  /**
274
276
  * Base event interface
@@ -410,10 +412,45 @@ interface ModelInfoEvent extends BaseJsonStreamEvent {
410
412
  type: JsonStreamEventType.MODEL_INFO;
411
413
  value: string;
412
414
  }
415
+ /**
416
+ * Question option for AskUserEvent
417
+ */
418
+ interface QuestionOption {
419
+ label: string;
420
+ description: string;
421
+ }
422
+ /**
423
+ * Question type for AskUserEvent
424
+ */
425
+ declare enum QuestionType {
426
+ CHOICE = "choice",
427
+ TEXT = "text",
428
+ YESNO = "yesno"
429
+ }
430
+ /**
431
+ * Question in AskUserEvent
432
+ */
433
+ interface Question {
434
+ question: string;
435
+ header: string;
436
+ type?: QuestionType;
437
+ options?: QuestionOption[];
438
+ multiSelect?: boolean;
439
+ placeholder?: string;
440
+ }
441
+ /**
442
+ * Ask user event (CLI → Host)
443
+ * Emitted when the ask_user tool needs structured user input
444
+ */
445
+ interface AskUserEvent extends BaseJsonStreamEvent {
446
+ type: JsonStreamEventType.ASK_USER;
447
+ questions: Question[];
448
+ correlation_id: string;
449
+ }
413
450
  /**
414
451
  * Union type of all JSON stream events
415
452
  */
416
- type JsonStreamEvent = InitEvent | MessageEvent | ToolUseEvent | ToolCallRequestEvent | ToolResultEvent | ThoughtEvent | ErrorEvent | ResultEvent | ContentEvent | FinishedEvent | ModelInfoEvent;
453
+ type JsonStreamEvent = InitEvent | MessageEvent | ToolUseEvent | ToolCallRequestEvent | ToolResultEvent | ThoughtEvent | ErrorEvent | ResultEvent | ContentEvent | FinishedEvent | ModelInfoEvent | AskUserEvent;
417
454
  /**
418
455
  * Gemini CLI exit codes
419
456
  */
@@ -491,7 +528,9 @@ declare enum JsonInputMessageType {
491
528
  /** User message */
492
529
  USER = "user",
493
530
  /** Control command */
494
- CONTROL = "control"
531
+ CONTROL = "control",
532
+ /** Response to ask_user event (Host → CLI) */
533
+ ASK_USER_RESPONSE = "ask_user_response"
495
534
  }
496
535
  /**
497
536
  * User message sent to CLI
@@ -559,10 +598,21 @@ interface ControlInputMessage {
559
598
  control: InterruptControl | TruncateHistoryControl | ResumeSessionControl | ReplaceHistoryControl;
560
599
  session_id?: string;
561
600
  }
601
+ /**
602
+ * Response to ask_user event (Host → CLI)
603
+ * Sent when the host has collected user answers for an ask_user request
604
+ */
605
+ interface AskUserResponseInputMessage {
606
+ type: JsonInputMessageType.ASK_USER_RESPONSE;
607
+ correlation_id: string;
608
+ answers: {
609
+ [questionIndex: string]: string;
610
+ };
611
+ }
562
612
  /**
563
613
  * Union type for input messages
564
614
  */
565
- type JsonInputMessage = UserInputMessage | ControlInputMessage;
615
+ type JsonInputMessage = UserInputMessage | ControlInputMessage | AskUserResponseInputMessage;
566
616
  /**
567
617
  * Hook configuration types (from Gemini CLI)
568
618
  */
@@ -961,6 +1011,8 @@ declare class GeminiStreamClient extends EventEmitter$1 {
961
1011
  private initTimeout;
962
1012
  private tempSettingsPath;
963
1013
  private logger;
1014
+ /** stderr 行缓冲,处理 chunk 分片导致的半行问题 */
1015
+ private stderrLineBuffer;
964
1016
  constructor(options: GeminiStreamOptions);
965
1017
  /**
966
1018
  * Start the Gemini CLI process
@@ -1019,6 +1071,18 @@ declare class GeminiStreamClient extends EventEmitter$1 {
1019
1071
  role: string;
1020
1072
  parts: unknown[];
1021
1073
  }>): Promise<void>;
1074
+ /**
1075
+ * Send a response to an ask_user request from the CLI
1076
+ *
1077
+ * When the CLI emits an 'ask_user' event (from the ask_user tool),
1078
+ * the host collects user answers and sends them back via this method.
1079
+ *
1080
+ * @param correlationId - The correlation_id from the AskUserEvent
1081
+ * @param answers - Map of question index to user's answer string
1082
+ */
1083
+ sendAskUserResponse(correlationId: string, answers: {
1084
+ [questionIndex: string]: string;
1085
+ }): void;
1022
1086
  /**
1023
1087
  * Stop the CLI process
1024
1088
  */
@@ -1082,6 +1146,20 @@ declare class GeminiStreamClient extends EventEmitter$1 {
1082
1146
  * Handle process error
1083
1147
  */
1084
1148
  private handleProcessError;
1149
+ /**
1150
+ * 处理 stderr chunk:按行切分并识别 turn finished reason
1151
+ */
1152
+ private processStderrChunk;
1153
+ /**
1154
+ * 进程结束时,处理 stderr 缓冲里最后一行(若存在)
1155
+ */
1156
+ private flushStderrLineBuffer;
1157
+ /**
1158
+ * 处理单行 stderr:
1159
+ * - 识别 [StreamJsonMode] Turn finished: <reason>,并发出 FINISHED 结构化事件
1160
+ * - 其余日志按原行为输出
1161
+ */
1162
+ private processStderrLine;
1085
1163
  }
1086
1164
 
1087
1165
  /**
@@ -1137,4 +1215,4 @@ declare function formatDuration(ms: number): string;
1137
1215
  */
1138
1216
  declare function formatTokens(tokens: number): string;
1139
1217
 
1140
- export { type ContextConfig, type ControlInputMessage, type ControlSubtype, type ErrorEvent, ExitCode, GeminiClient, type GeminiOptions, GeminiSDKError, GeminiStreamClient, type GeminiStreamOptions, type HooksConfiguration, type InitEvent, type InterruptControl, type JsonInputMessage, JsonInputMessageType, type JsonStreamEvent, JsonStreamEventType, LogLevel, type Logger, type LoggerOptions, type MCPServerConfig, type MCPServersConfig, type MessageEvent, ProcessStatus, type QueryResult, type ResultEvent, type ResumeSessionControl, SDKLogger, type StreamStats, type ThoughtEvent, type ToolPermissionDecision, type ToolPermissionRequest, type ToolResultEvent, type ToolUseEvent, type ToolsConfig, type TruncateHistoryControl, type UserInputMessage, createLogger, findGeminiCLI, formatDuration, formatTokens, getApiKey, query, sdkLogger, silentLogger, validateApiKey, validateModel };
1218
+ export { type AskUserEvent, type AskUserResponseInputMessage, type ContextConfig, type ControlInputMessage, type ControlSubtype, type ErrorEvent, ExitCode, GeminiClient, type GeminiOptions, GeminiSDKError, GeminiStreamClient, type GeminiStreamOptions, type HooksConfiguration, type InitEvent, type InterruptControl, type JsonInputMessage, JsonInputMessageType, type JsonStreamEvent, JsonStreamEventType, LogLevel, type Logger, type LoggerOptions, type MCPServerConfig, type MCPServersConfig, type MessageEvent, ProcessStatus, type QueryResult, type Question, type QuestionOption, QuestionType, type ResultEvent, type ResumeSessionControl, SDKLogger, type StreamStats, type ThoughtEvent, type ToolPermissionDecision, type ToolPermissionRequest, type ToolResultEvent, type ToolUseEvent, type ToolsConfig, type TruncateHistoryControl, type UserInputMessage, createLogger, findGeminiCLI, formatDuration, formatTokens, getApiKey, query, sdkLogger, silentLogger, validateApiKey, validateModel };
package/dist/index.js CHANGED
@@ -19,8 +19,15 @@ var JsonStreamEventType = /* @__PURE__ */ ((JsonStreamEventType2) => {
19
19
  JsonStreamEventType2["CONTENT"] = "content";
20
20
  JsonStreamEventType2["FINISHED"] = "finished";
21
21
  JsonStreamEventType2["MODEL_INFO"] = "model_info";
22
+ JsonStreamEventType2["ASK_USER"] = "ask_user";
22
23
  return JsonStreamEventType2;
23
24
  })(JsonStreamEventType || {});
25
+ var QuestionType = /* @__PURE__ */ ((QuestionType2) => {
26
+ QuestionType2["CHOICE"] = "choice";
27
+ QuestionType2["TEXT"] = "text";
28
+ QuestionType2["YESNO"] = "yesno";
29
+ return QuestionType2;
30
+ })(QuestionType || {});
24
31
  var ExitCode = /* @__PURE__ */ ((ExitCode2) => {
25
32
  ExitCode2[ExitCode2["SUCCESS"] = 0] = "SUCCESS";
26
33
  ExitCode2[ExitCode2["GENERAL_ERROR"] = 1] = "GENERAL_ERROR";
@@ -50,6 +57,7 @@ var GeminiSDKError = class _GeminiSDKError extends Error {
50
57
  var JsonInputMessageType = /* @__PURE__ */ ((JsonInputMessageType2) => {
51
58
  JsonInputMessageType2["USER"] = "user";
52
59
  JsonInputMessageType2["CONTROL"] = "control";
60
+ JsonInputMessageType2["ASK_USER_RESPONSE"] = "ask_user_response";
53
61
  return JsonInputMessageType2;
54
62
  })(JsonInputMessageType || {});
55
63
 
@@ -484,6 +492,8 @@ var GeminiStreamClient = class extends EventEmitter {
484
492
  initTimeout = null;
485
493
  tempSettingsPath = null;
486
494
  logger;
495
+ /** stderr 行缓冲,处理 chunk 分片导致的半行问题 */
496
+ stderrLineBuffer = "";
487
497
  /**
488
498
  * Start the Gemini CLI process
489
499
  */
@@ -527,11 +537,7 @@ var GeminiStreamClient = class extends EventEmitter {
527
537
  }
528
538
  if (this.process.stderr) {
529
539
  this.process.stderr.on("data", (chunk) => {
530
- const message = chunk.toString().trim();
531
- if (!message || message.includes("Flushing log events")) {
532
- return;
533
- }
534
- this.logger.error("stderr:", message);
540
+ this.processStderrChunk(chunk.toString());
535
541
  });
536
542
  }
537
543
  this.emit("started");
@@ -662,6 +668,26 @@ var GeminiStreamClient = class extends EventEmitter {
662
668
  };
663
669
  this.writeMessage(message);
664
670
  }
671
+ /**
672
+ * Send a response to an ask_user request from the CLI
673
+ *
674
+ * When the CLI emits an 'ask_user' event (from the ask_user tool),
675
+ * the host collects user answers and sends them back via this method.
676
+ *
677
+ * @param correlationId - The correlation_id from the AskUserEvent
678
+ * @param answers - Map of question index to user's answer string
679
+ */
680
+ sendAskUserResponse(correlationId, answers) {
681
+ if (!this.isReady()) {
682
+ throw new GeminiSDKError("Client not ready. Call start() first.");
683
+ }
684
+ const message = {
685
+ type: "ask_user_response" /* ASK_USER_RESPONSE */,
686
+ correlation_id: correlationId,
687
+ answers
688
+ };
689
+ this.writeMessage(message);
690
+ }
665
691
  /**
666
692
  * Stop the CLI process
667
693
  */
@@ -924,6 +950,7 @@ var GeminiStreamClient = class extends EventEmitter {
924
950
  * Handle process exit
925
951
  */
926
952
  handleProcessExit(code, signal) {
953
+ this.flushStderrLineBuffer();
927
954
  this.logger.debug("Process exited:", { code, signal });
928
955
  if (code !== 0 && code !== null) {
929
956
  this.status = "error" /* ERROR */;
@@ -947,6 +974,50 @@ var GeminiStreamClient = class extends EventEmitter {
947
974
  this.status = "error" /* ERROR */;
948
975
  this.emit("error", error);
949
976
  }
977
+ /**
978
+ * 处理 stderr chunk:按行切分并识别 turn finished reason
979
+ */
980
+ processStderrChunk(chunkText) {
981
+ this.stderrLineBuffer += chunkText;
982
+ const lines = this.stderrLineBuffer.split(/\r?\n/);
983
+ this.stderrLineBuffer = lines.pop() ?? "";
984
+ for (const line of lines) {
985
+ this.processStderrLine(line);
986
+ }
987
+ }
988
+ /**
989
+ * 进程结束时,处理 stderr 缓冲里最后一行(若存在)
990
+ */
991
+ flushStderrLineBuffer() {
992
+ if (!this.stderrLineBuffer) return;
993
+ this.processStderrLine(this.stderrLineBuffer);
994
+ this.stderrLineBuffer = "";
995
+ }
996
+ /**
997
+ * 处理单行 stderr:
998
+ * - 识别 [StreamJsonMode] Turn finished: <reason>,并发出 FINISHED 结构化事件
999
+ * - 其余日志按原行为输出
1000
+ */
1001
+ processStderrLine(rawLine) {
1002
+ const line = rawLine.trim();
1003
+ if (!line || line.includes("Flushing log events")) {
1004
+ return;
1005
+ }
1006
+ const match = line.match(/\[StreamJsonMode\]\s+Turn finished:\s*(.+)\s*$/);
1007
+ if (match) {
1008
+ const reason = match[1]?.trim();
1009
+ if (reason) {
1010
+ this.emit("event", {
1011
+ type: "finished" /* FINISHED */,
1012
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1013
+ value: {
1014
+ reason
1015
+ }
1016
+ });
1017
+ }
1018
+ }
1019
+ this.logger.error("stderr:", line);
1020
+ }
950
1021
  };
951
1022
  function findGeminiCLI(cwd = process.cwd()) {
952
1023
  if (process.env.GEMINI_CLI_PATH) {
@@ -1021,6 +1092,6 @@ function formatTokens(tokens) {
1021
1092
  return tokens.toLocaleString();
1022
1093
  }
1023
1094
 
1024
- export { ExitCode, GeminiClient, GeminiSDKError, GeminiStreamClient, JsonInputMessageType, JsonStreamEventType, LogLevel, ProcessStatus, SDKLogger, createLogger, findGeminiCLI, formatDuration, formatTokens, getApiKey, query, sdkLogger, silentLogger, validateApiKey, validateModel };
1095
+ export { ExitCode, GeminiClient, GeminiSDKError, GeminiStreamClient, JsonInputMessageType, JsonStreamEventType, LogLevel, ProcessStatus, QuestionType, SDKLogger, createLogger, findGeminiCLI, formatDuration, formatTokens, getApiKey, query, sdkLogger, silentLogger, validateApiKey, validateModel };
1025
1096
  //# sourceMappingURL=index.js.map
1026
1097
  //# sourceMappingURL=index.js.map