@ketd/gemini-cli-sdk 0.2.2 → 0.2.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.
package/dist/index.d.cts CHANGED
@@ -114,6 +114,7 @@ interface ToolPermissionDecision {
114
114
  * JSON Stream Event Types
115
115
  *
116
116
  * Based on: @google/gemini-cli/packages/core/src/output/types.ts
117
+ * Plus additional event types actually sent by CLI
117
118
  */
118
119
  declare enum JsonStreamEventType {
119
120
  /** Session initialization */
@@ -129,7 +130,13 @@ declare enum JsonStreamEventType {
129
130
  /** Error event */
130
131
  ERROR = "error",
131
132
  /** Final result */
132
- RESULT = "result"
133
+ RESULT = "result",
134
+ /** Message content chunk (streaming) */
135
+ CONTENT = "content",
136
+ /** Message completion with metadata */
137
+ FINISHED = "finished",
138
+ /** Model information */
139
+ MODEL_INFO = "model_info"
133
140
  }
134
141
  /**
135
142
  * Base event interface
@@ -178,13 +185,21 @@ interface ToolResultEvent extends BaseJsonStreamEvent {
178
185
  message: string;
179
186
  };
180
187
  }
188
+ /**
189
+ * Thought summary containing subject and description
190
+ */
191
+ interface ThoughtSummary {
192
+ subject: string;
193
+ description?: string;
194
+ }
181
195
  /**
182
196
  * Thought/reasoning event
197
+ * Emitted by Gemini CLI when the model is thinking
183
198
  */
184
199
  interface ThoughtEvent extends BaseJsonStreamEvent {
185
200
  type: JsonStreamEventType.THOUGHT;
186
- subject: string;
187
- description?: string;
201
+ value: ThoughtSummary;
202
+ traceId?: string;
188
203
  }
189
204
  /**
190
205
  * Error event
@@ -216,10 +231,50 @@ interface ResultEvent extends BaseJsonStreamEvent {
216
231
  };
217
232
  stats?: StreamStats;
218
233
  }
234
+ /**
235
+ * Content event (streaming message chunk)
236
+ * This is the actual event type sent by Gemini CLI for message content
237
+ */
238
+ interface ContentEvent extends BaseJsonStreamEvent {
239
+ type: JsonStreamEventType.CONTENT;
240
+ value: string;
241
+ traceId?: string;
242
+ }
243
+ /**
244
+ * Finished event (message completion with metadata)
245
+ */
246
+ interface FinishedEvent extends BaseJsonStreamEvent {
247
+ type: JsonStreamEventType.FINISHED;
248
+ value: {
249
+ reason: string;
250
+ usageMetadata?: {
251
+ promptTokenCount?: number;
252
+ candidatesTokenCount?: number;
253
+ totalTokenCount?: number;
254
+ trafficType?: string;
255
+ promptTokensDetails?: Array<{
256
+ modality: string;
257
+ tokenCount: number;
258
+ }>;
259
+ candidatesTokensDetails?: Array<{
260
+ modality: string;
261
+ tokenCount: number;
262
+ }>;
263
+ thoughtsTokenCount?: number;
264
+ };
265
+ };
266
+ }
267
+ /**
268
+ * Model information event
269
+ */
270
+ interface ModelInfoEvent extends BaseJsonStreamEvent {
271
+ type: JsonStreamEventType.MODEL_INFO;
272
+ value: string;
273
+ }
219
274
  /**
220
275
  * Union type of all JSON stream events
221
276
  */
222
- type JsonStreamEvent = InitEvent | MessageEvent | ToolUseEvent | ToolResultEvent | ThoughtEvent | ErrorEvent | ResultEvent;
277
+ type JsonStreamEvent = InitEvent | MessageEvent | ToolUseEvent | ToolResultEvent | ThoughtEvent | ErrorEvent | ResultEvent | ContentEvent | FinishedEvent | ModelInfoEvent;
223
278
  /**
224
279
  * Gemini CLI exit codes
225
280
  */
@@ -321,6 +376,33 @@ interface ControlInputMessage {
321
376
  * Union type for input messages
322
377
  */
323
378
  type JsonInputMessage = UserInputMessage | ControlInputMessage;
379
+ /**
380
+ * Hook configuration types (from Gemini CLI)
381
+ */
382
+ interface HookConfig {
383
+ type: 'command';
384
+ command: string;
385
+ timeout?: number;
386
+ }
387
+ interface HookDefinition {
388
+ matcher?: string;
389
+ sequential?: boolean;
390
+ hooks: HookConfig[];
391
+ }
392
+ interface HooksConfiguration {
393
+ BeforeTool?: HookDefinition[];
394
+ AfterTool?: HookDefinition[];
395
+ BeforeAgent?: HookDefinition[];
396
+ AfterAgent?: HookDefinition[];
397
+ BeforeModel?: HookDefinition[];
398
+ AfterModel?: HookDefinition[];
399
+ BeforeToolSelection?: HookDefinition[];
400
+ Notification?: HookDefinition[];
401
+ SessionStart?: HookDefinition[];
402
+ SessionEnd?: HookDefinition[];
403
+ PreCompress?: HookDefinition[];
404
+ disabled?: string[];
405
+ }
324
406
  /**
325
407
  * Options for GeminiStreamClient
326
408
  */
@@ -373,6 +455,17 @@ interface GeminiStreamOptions {
373
455
  * @default 30000
374
456
  */
375
457
  initTimeout?: number;
458
+ /**
459
+ * Hooks configuration
460
+ * Passed to Gemini CLI via temporary settings.json
461
+ */
462
+ hooks?: HooksConfiguration;
463
+ /**
464
+ * Resume from a previous session file path
465
+ * If provided, Gemini CLI will load the session history using --resume flag
466
+ * @example '/path/to/session-2025-01-01T12-00-abc123.json'
467
+ */
468
+ resumeSessionFilePath?: string;
376
469
  }
377
470
 
378
471
  /**
@@ -536,6 +629,7 @@ declare class GeminiStreamClient extends EventEmitter$1 {
536
629
  private status;
537
630
  private initEvent;
538
631
  private initTimeout;
632
+ private tempSettingsPath;
539
633
  constructor(options: GeminiStreamOptions);
540
634
  /**
541
635
  * Start the Gemini CLI process
@@ -569,6 +663,10 @@ declare class GeminiStreamClient extends EventEmitter$1 {
569
663
  * Get process PID
570
664
  */
571
665
  getPid(): number | undefined;
666
+ /**
667
+ * Create temporary settings.json for hooks configuration
668
+ */
669
+ private createTempSettings;
572
670
  /**
573
671
  * Build CLI command arguments
574
672
  */
package/dist/index.d.ts CHANGED
@@ -114,6 +114,7 @@ interface ToolPermissionDecision {
114
114
  * JSON Stream Event Types
115
115
  *
116
116
  * Based on: @google/gemini-cli/packages/core/src/output/types.ts
117
+ * Plus additional event types actually sent by CLI
117
118
  */
118
119
  declare enum JsonStreamEventType {
119
120
  /** Session initialization */
@@ -129,7 +130,13 @@ declare enum JsonStreamEventType {
129
130
  /** Error event */
130
131
  ERROR = "error",
131
132
  /** Final result */
132
- RESULT = "result"
133
+ RESULT = "result",
134
+ /** Message content chunk (streaming) */
135
+ CONTENT = "content",
136
+ /** Message completion with metadata */
137
+ FINISHED = "finished",
138
+ /** Model information */
139
+ MODEL_INFO = "model_info"
133
140
  }
134
141
  /**
135
142
  * Base event interface
@@ -178,13 +185,21 @@ interface ToolResultEvent extends BaseJsonStreamEvent {
178
185
  message: string;
179
186
  };
180
187
  }
188
+ /**
189
+ * Thought summary containing subject and description
190
+ */
191
+ interface ThoughtSummary {
192
+ subject: string;
193
+ description?: string;
194
+ }
181
195
  /**
182
196
  * Thought/reasoning event
197
+ * Emitted by Gemini CLI when the model is thinking
183
198
  */
184
199
  interface ThoughtEvent extends BaseJsonStreamEvent {
185
200
  type: JsonStreamEventType.THOUGHT;
186
- subject: string;
187
- description?: string;
201
+ value: ThoughtSummary;
202
+ traceId?: string;
188
203
  }
189
204
  /**
190
205
  * Error event
@@ -216,10 +231,50 @@ interface ResultEvent extends BaseJsonStreamEvent {
216
231
  };
217
232
  stats?: StreamStats;
218
233
  }
234
+ /**
235
+ * Content event (streaming message chunk)
236
+ * This is the actual event type sent by Gemini CLI for message content
237
+ */
238
+ interface ContentEvent extends BaseJsonStreamEvent {
239
+ type: JsonStreamEventType.CONTENT;
240
+ value: string;
241
+ traceId?: string;
242
+ }
243
+ /**
244
+ * Finished event (message completion with metadata)
245
+ */
246
+ interface FinishedEvent extends BaseJsonStreamEvent {
247
+ type: JsonStreamEventType.FINISHED;
248
+ value: {
249
+ reason: string;
250
+ usageMetadata?: {
251
+ promptTokenCount?: number;
252
+ candidatesTokenCount?: number;
253
+ totalTokenCount?: number;
254
+ trafficType?: string;
255
+ promptTokensDetails?: Array<{
256
+ modality: string;
257
+ tokenCount: number;
258
+ }>;
259
+ candidatesTokensDetails?: Array<{
260
+ modality: string;
261
+ tokenCount: number;
262
+ }>;
263
+ thoughtsTokenCount?: number;
264
+ };
265
+ };
266
+ }
267
+ /**
268
+ * Model information event
269
+ */
270
+ interface ModelInfoEvent extends BaseJsonStreamEvent {
271
+ type: JsonStreamEventType.MODEL_INFO;
272
+ value: string;
273
+ }
219
274
  /**
220
275
  * Union type of all JSON stream events
221
276
  */
222
- type JsonStreamEvent = InitEvent | MessageEvent | ToolUseEvent | ToolResultEvent | ThoughtEvent | ErrorEvent | ResultEvent;
277
+ type JsonStreamEvent = InitEvent | MessageEvent | ToolUseEvent | ToolResultEvent | ThoughtEvent | ErrorEvent | ResultEvent | ContentEvent | FinishedEvent | ModelInfoEvent;
223
278
  /**
224
279
  * Gemini CLI exit codes
225
280
  */
@@ -321,6 +376,33 @@ interface ControlInputMessage {
321
376
  * Union type for input messages
322
377
  */
323
378
  type JsonInputMessage = UserInputMessage | ControlInputMessage;
379
+ /**
380
+ * Hook configuration types (from Gemini CLI)
381
+ */
382
+ interface HookConfig {
383
+ type: 'command';
384
+ command: string;
385
+ timeout?: number;
386
+ }
387
+ interface HookDefinition {
388
+ matcher?: string;
389
+ sequential?: boolean;
390
+ hooks: HookConfig[];
391
+ }
392
+ interface HooksConfiguration {
393
+ BeforeTool?: HookDefinition[];
394
+ AfterTool?: HookDefinition[];
395
+ BeforeAgent?: HookDefinition[];
396
+ AfterAgent?: HookDefinition[];
397
+ BeforeModel?: HookDefinition[];
398
+ AfterModel?: HookDefinition[];
399
+ BeforeToolSelection?: HookDefinition[];
400
+ Notification?: HookDefinition[];
401
+ SessionStart?: HookDefinition[];
402
+ SessionEnd?: HookDefinition[];
403
+ PreCompress?: HookDefinition[];
404
+ disabled?: string[];
405
+ }
324
406
  /**
325
407
  * Options for GeminiStreamClient
326
408
  */
@@ -373,6 +455,17 @@ interface GeminiStreamOptions {
373
455
  * @default 30000
374
456
  */
375
457
  initTimeout?: number;
458
+ /**
459
+ * Hooks configuration
460
+ * Passed to Gemini CLI via temporary settings.json
461
+ */
462
+ hooks?: HooksConfiguration;
463
+ /**
464
+ * Resume from a previous session file path
465
+ * If provided, Gemini CLI will load the session history using --resume flag
466
+ * @example '/path/to/session-2025-01-01T12-00-abc123.json'
467
+ */
468
+ resumeSessionFilePath?: string;
376
469
  }
377
470
 
378
471
  /**
@@ -536,6 +629,7 @@ declare class GeminiStreamClient extends EventEmitter$1 {
536
629
  private status;
537
630
  private initEvent;
538
631
  private initTimeout;
632
+ private tempSettingsPath;
539
633
  constructor(options: GeminiStreamOptions);
540
634
  /**
541
635
  * Start the Gemini CLI process
@@ -569,6 +663,10 @@ declare class GeminiStreamClient extends EventEmitter$1 {
569
663
  * Get process PID
570
664
  */
571
665
  getPid(): number | undefined;
666
+ /**
667
+ * Create temporary settings.json for hooks configuration
668
+ */
669
+ private createTempSettings;
572
670
  /**
573
671
  * Build CLI command arguments
574
672
  */
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { spawn } from 'child_process';
2
2
  import * as readline from 'readline';
3
3
  import { EventEmitter } from 'events';
4
- import * as path from 'path';
5
- import * as fs from 'fs';
4
+ import * as fs2 from 'fs';
5
+ import * as path2 from 'path';
6
+ import * as os from 'os';
6
7
 
7
8
  // src/query.ts
8
9
 
@@ -15,6 +16,9 @@ var JsonStreamEventType = /* @__PURE__ */ ((JsonStreamEventType2) => {
15
16
  JsonStreamEventType2["THOUGHT"] = "thought";
16
17
  JsonStreamEventType2["ERROR"] = "error";
17
18
  JsonStreamEventType2["RESULT"] = "result";
19
+ JsonStreamEventType2["CONTENT"] = "content";
20
+ JsonStreamEventType2["FINISHED"] = "finished";
21
+ JsonStreamEventType2["MODEL_INFO"] = "model_info";
18
22
  return JsonStreamEventType2;
19
23
  })(JsonStreamEventType || {});
20
24
  var ExitCode = /* @__PURE__ */ ((ExitCode2) => {
@@ -384,6 +388,7 @@ var GeminiStreamClient = class extends EventEmitter {
384
388
  status = "idle" /* IDLE */;
385
389
  initEvent = null;
386
390
  initTimeout = null;
391
+ tempSettingsPath = null;
387
392
  /**
388
393
  * Start the Gemini CLI process
389
394
  */
@@ -392,6 +397,9 @@ var GeminiStreamClient = class extends EventEmitter {
392
397
  throw new GeminiSDKError("Process already started");
393
398
  }
394
399
  this.status = "running" /* RUNNING */;
400
+ if (this.options.hooks) {
401
+ await this.createTempSettings();
402
+ }
395
403
  const args = this.buildCommand();
396
404
  const env = this.buildEnv();
397
405
  this.process = spawn("node", args, {
@@ -499,6 +507,17 @@ var GeminiStreamClient = class extends EventEmitter {
499
507
  }
500
508
  this.process = null;
501
509
  this.status = "completed" /* COMPLETED */;
510
+ if (this.tempSettingsPath) {
511
+ try {
512
+ fs2.unlinkSync(this.tempSettingsPath);
513
+ if (this.options.debug) {
514
+ console.log("[GeminiStreamClient] Cleaned up temp settings:", this.tempSettingsPath);
515
+ }
516
+ } catch (error) {
517
+ console.error("[GeminiStreamClient] Failed to clean up temp settings:", error);
518
+ }
519
+ this.tempSettingsPath = null;
520
+ }
502
521
  }
503
522
  /**
504
523
  * Check if client is ready to send messages
@@ -524,6 +543,28 @@ var GeminiStreamClient = class extends EventEmitter {
524
543
  getPid() {
525
544
  return this.process?.pid;
526
545
  }
546
+ /**
547
+ * Create temporary settings.json for hooks configuration
548
+ */
549
+ async createTempSettings() {
550
+ const tempDir = os.tmpdir();
551
+ this.tempSettingsPath = path2.join(tempDir, `gemini-settings-${this.options.sessionId}.json`);
552
+ const settings = {
553
+ tools: {
554
+ enableHooks: true
555
+ },
556
+ hooks: this.options.hooks
557
+ };
558
+ try {
559
+ fs2.writeFileSync(this.tempSettingsPath, JSON.stringify(settings, null, 2), "utf-8");
560
+ if (this.options.debug) {
561
+ console.log("[GeminiStreamClient] Created temp settings:", this.tempSettingsPath);
562
+ console.log("[GeminiStreamClient] Settings content:", JSON.stringify(settings, null, 2));
563
+ }
564
+ } catch (error) {
565
+ throw new GeminiSDKError(`Failed to create temp settings file: ${error}`);
566
+ }
567
+ }
527
568
  /**
528
569
  * Build CLI command arguments
529
570
  */
@@ -535,6 +576,15 @@ var GeminiStreamClient = class extends EventEmitter {
535
576
  "--output-format",
536
577
  "stream-json"
537
578
  ];
579
+ if (this.tempSettingsPath) {
580
+ args.push("--settings-file", this.tempSettingsPath);
581
+ }
582
+ if (this.options.resumeSessionFilePath) {
583
+ args.push("--resume", this.options.resumeSessionFilePath);
584
+ if (this.options.debug) {
585
+ console.log("[GeminiStreamClient] Resuming from session file:", this.options.resumeSessionFilePath);
586
+ }
587
+ }
538
588
  if (this.options.model) {
539
589
  args.push("--model", this.options.model);
540
590
  }
@@ -556,12 +606,28 @@ var GeminiStreamClient = class extends EventEmitter {
556
606
  };
557
607
  if (this.options.apiKey) {
558
608
  const useVertexAI = this.options.env?.GOOGLE_GENAI_USE_VERTEXAI === "true";
609
+ if (this.options.debug) {
610
+ console.log("[GeminiStreamClient] buildEnv() - API Key prefix:", this.options.apiKey.substring(0, 3));
611
+ console.log("[GeminiStreamClient] buildEnv() - GOOGLE_GENAI_USE_VERTEXAI:", this.options.env?.GOOGLE_GENAI_USE_VERTEXAI);
612
+ console.log("[GeminiStreamClient] buildEnv() - useVertexAI:", useVertexAI);
613
+ }
559
614
  if (useVertexAI) {
560
615
  env.GOOGLE_API_KEY = this.options.apiKey;
616
+ if (this.options.debug) {
617
+ console.log("[GeminiStreamClient] buildEnv() - Setting GOOGLE_API_KEY for Vertex AI");
618
+ }
561
619
  } else {
562
620
  env.GEMINI_API_KEY = this.options.apiKey;
621
+ if (this.options.debug) {
622
+ console.log("[GeminiStreamClient] buildEnv() - Setting GEMINI_API_KEY for AI Studio");
623
+ }
563
624
  }
564
625
  }
626
+ if (this.options.debug) {
627
+ console.log("[GeminiStreamClient] buildEnv() - Final env has GOOGLE_API_KEY:", !!env.GOOGLE_API_KEY);
628
+ console.log("[GeminiStreamClient] buildEnv() - Final env has GEMINI_API_KEY:", !!env.GEMINI_API_KEY);
629
+ console.log("[GeminiStreamClient] buildEnv() - Final env GOOGLE_GENAI_USE_VERTEXAI:", env.GOOGLE_GENAI_USE_VERTEXAI);
630
+ }
565
631
  return env;
566
632
  }
567
633
  /**
@@ -680,17 +746,17 @@ var GeminiStreamClient = class extends EventEmitter {
680
746
  function findGeminiCLI(cwd = process.cwd()) {
681
747
  if (process.env.GEMINI_CLI_PATH) {
682
748
  const envPath = process.env.GEMINI_CLI_PATH;
683
- if (fs.existsSync(envPath)) {
749
+ if (fs2.existsSync(envPath)) {
684
750
  return envPath;
685
751
  }
686
752
  }
687
- const localPath = path.join(cwd, "node_modules", "@google", "gemini-cli", "bundle", "gemini.js");
688
- if (fs.existsSync(localPath)) {
753
+ const localPath = path2.join(cwd, "node_modules", "@google", "gemini-cli", "bundle", "gemini.js");
754
+ if (fs2.existsSync(localPath)) {
689
755
  return localPath;
690
756
  }
691
757
  let currentDir = cwd;
692
758
  for (let i = 0; i < 5; i++) {
693
- const parentPath = path.join(
759
+ const parentPath = path2.join(
694
760
  currentDir,
695
761
  "node_modules",
696
762
  "@google",
@@ -698,10 +764,10 @@ function findGeminiCLI(cwd = process.cwd()) {
698
764
  "bundle",
699
765
  "gemini.js"
700
766
  );
701
- if (fs.existsSync(parentPath)) {
767
+ if (fs2.existsSync(parentPath)) {
702
768
  return parentPath;
703
769
  }
704
- const parentDir = path.dirname(currentDir);
770
+ const parentDir = path2.dirname(currentDir);
705
771
  if (parentDir === currentDir) break;
706
772
  currentDir = parentDir;
707
773
  }