@quantiya/codevibe-gemini-plugin 1.0.6 → 1.0.7
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/server.js +13 -1424
- package/package.json +5 -4
- package/dist/appsync-client.js +0 -819
- package/dist/auth-cli.js +0 -472
- package/dist/command-executor.js +0 -127
- package/dist/config.js +0 -106
- package/dist/crypto-service.js +0 -278
- package/dist/http-api.js +0 -582
- package/dist/key-manager.js +0 -287
- package/dist/logger.js +0 -18
- package/dist/prompt-responder.js +0 -132
- package/dist/token-storage.js +0 -169
- package/dist/transcript-watcher.js +0 -324
- package/dist/types.js +0 -16
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.TranscriptWatcher = void 0;
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const crypto = __importStar(require("crypto"));
|
|
40
|
-
const chokidar = __importStar(require("chokidar"));
|
|
41
|
-
const events_1 = require("events");
|
|
42
|
-
const logger_1 = require("./logger");
|
|
43
|
-
/**
|
|
44
|
-
* Watches Gemini CLI transcript files for changes and emits events for new messages.
|
|
45
|
-
* This is a workaround since Gemini CLI hooks are not fully implemented yet.
|
|
46
|
-
*/
|
|
47
|
-
class TranscriptWatcher extends events_1.EventEmitter {
|
|
48
|
-
constructor(workingDirectory) {
|
|
49
|
-
super();
|
|
50
|
-
this.watcher = null;
|
|
51
|
-
this.sentMessageIds = new Set();
|
|
52
|
-
this.currentSessionId = null;
|
|
53
|
-
this.currentTranscriptPath = null;
|
|
54
|
-
this.projectHash = null;
|
|
55
|
-
this.workingDirectory = workingDirectory;
|
|
56
|
-
this.geminiDir = path.join(process.env.HOME || '', '.gemini', 'tmp');
|
|
57
|
-
this.projectHash = this.computeProjectHash(workingDirectory);
|
|
58
|
-
this.watcherStartTime = new Date();
|
|
59
|
-
logger_1.logger.info('TranscriptWatcher initialized', {
|
|
60
|
-
workingDirectory,
|
|
61
|
-
geminiDir: this.geminiDir,
|
|
62
|
-
projectHash: this.projectHash,
|
|
63
|
-
watcherStartTime: this.watcherStartTime.toISOString(),
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Compute the project hash the same way Gemini CLI does
|
|
68
|
-
* Based on the working directory path
|
|
69
|
-
*/
|
|
70
|
-
computeProjectHash(dir) {
|
|
71
|
-
return crypto.createHash('sha256').update(dir).digest('hex');
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Start watching for transcript changes
|
|
75
|
-
*/
|
|
76
|
-
start() {
|
|
77
|
-
if (this.watcher) {
|
|
78
|
-
logger_1.logger.warn('TranscriptWatcher already started');
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
// Watch the project-specific chats directory
|
|
82
|
-
const chatsDir = path.join(this.geminiDir, this.projectHash, 'chats');
|
|
83
|
-
logger_1.logger.info('Starting TranscriptWatcher', { chatsDir });
|
|
84
|
-
// Check if directory exists, if not watch parent and wait for it
|
|
85
|
-
if (!fs.existsSync(chatsDir)) {
|
|
86
|
-
logger_1.logger.info('Chats directory does not exist yet, watching parent directory');
|
|
87
|
-
// Watch the entire gemini tmp dir for new project directories
|
|
88
|
-
this.watchForSessionCreation();
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
this.watchChatsDirectory(chatsDir);
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Watch for the chats directory to be created
|
|
95
|
-
*/
|
|
96
|
-
watchForSessionCreation() {
|
|
97
|
-
const projectDir = path.join(this.geminiDir, this.projectHash);
|
|
98
|
-
// Create watcher for the project directory or parent
|
|
99
|
-
const watchPath = fs.existsSync(projectDir) ? projectDir : this.geminiDir;
|
|
100
|
-
this.watcher = chokidar.watch(watchPath, {
|
|
101
|
-
persistent: true,
|
|
102
|
-
ignoreInitial: true, // Only watch for NEW files, not existing ones
|
|
103
|
-
depth: 3,
|
|
104
|
-
awaitWriteFinish: {
|
|
105
|
-
stabilityThreshold: 200, // Reduced from 500ms for lower latency
|
|
106
|
-
pollInterval: 50
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
this.watcher.on('add', (filePath) => {
|
|
110
|
-
// Look for session files matching pattern
|
|
111
|
-
if (filePath.includes(this.projectHash) && filePath.includes('/chats/session-') && filePath.endsWith('.json')) {
|
|
112
|
-
logger_1.logger.info('Session file discovered', { filePath });
|
|
113
|
-
this.handleSessionFile(filePath);
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
this.watcher.on('change', (filePath) => {
|
|
117
|
-
if (filePath.includes(this.projectHash) && filePath.includes('/chats/session-') && filePath.endsWith('.json')) {
|
|
118
|
-
if (filePath === this.currentTranscriptPath) {
|
|
119
|
-
this.handleTranscriptChange(filePath);
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
// This might be a resumed session - check and switch if needed
|
|
123
|
-
logger_1.logger.info('Session file changed (possible resume)', { filePath, currentPath: this.currentTranscriptPath });
|
|
124
|
-
this.handleSessionFile(filePath);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
this.watcher.on('error', (err) => {
|
|
129
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
130
|
-
logger_1.logger.error('Watcher error', { error: error.message });
|
|
131
|
-
this.emit('error', error);
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Watch a specific chats directory for session files
|
|
136
|
-
*/
|
|
137
|
-
watchChatsDirectory(chatsDir) {
|
|
138
|
-
// DON'T scan for existing files - only react to NEW files or changes
|
|
139
|
-
// This prevents picking up stale session files that won't be used.
|
|
140
|
-
// When user types in Gemini CLI, it will either:
|
|
141
|
-
// 1. Create a NEW session file (triggers 'add' event)
|
|
142
|
-
// 2. Update existing session file (triggers 'change' event)
|
|
143
|
-
// Either way, we'll detect the ACTIVE session correctly.
|
|
144
|
-
this.watcher = chokidar.watch(chatsDir, {
|
|
145
|
-
persistent: true,
|
|
146
|
-
ignoreInitial: true, // Don't re-emit 'add' for files we already scanned
|
|
147
|
-
awaitWriteFinish: {
|
|
148
|
-
stabilityThreshold: 200, // Reduced from 500ms for lower latency
|
|
149
|
-
pollInterval: 50
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
this.watcher.on('add', (filePath) => {
|
|
153
|
-
if (filePath.endsWith('.json') && filePath.includes('session-')) {
|
|
154
|
-
logger_1.logger.info('New session file detected', { filePath });
|
|
155
|
-
this.handleSessionFile(filePath);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
this.watcher.on('change', (filePath) => {
|
|
159
|
-
if (filePath.endsWith('.json') && filePath.includes('session-')) {
|
|
160
|
-
// Handle changes to any session file (for resume scenarios)
|
|
161
|
-
if (filePath === this.currentTranscriptPath) {
|
|
162
|
-
this.handleTranscriptChange(filePath);
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
// This might be a resumed session - check and switch if needed
|
|
166
|
-
logger_1.logger.info('Session file changed (possible resume)', { filePath, currentPath: this.currentTranscriptPath });
|
|
167
|
-
this.handleSessionFile(filePath);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
this.watcher.on('error', (err) => {
|
|
172
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
173
|
-
logger_1.logger.error('Watcher error', { error: error.message });
|
|
174
|
-
this.emit('error', error);
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Scan for RECENT session files in the chats directory (modified within last 5 minutes)
|
|
179
|
-
* This allows picking up sessions where Gemini CLI is already running,
|
|
180
|
-
* while avoiding old session files from previous days that would load stale events.
|
|
181
|
-
*/
|
|
182
|
-
scanForRecentSession(chatsDir) {
|
|
183
|
-
const RECENT_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
|
|
184
|
-
try {
|
|
185
|
-
if (!fs.existsSync(chatsDir)) {
|
|
186
|
-
logger_1.logger.debug('Chats directory does not exist yet', { chatsDir });
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
const now = Date.now();
|
|
190
|
-
const files = fs.readdirSync(chatsDir)
|
|
191
|
-
.filter(f => f.startsWith('session-') && f.endsWith('.json'))
|
|
192
|
-
.map(f => ({
|
|
193
|
-
name: f,
|
|
194
|
-
path: path.join(chatsDir, f),
|
|
195
|
-
mtime: fs.statSync(path.join(chatsDir, f)).mtime
|
|
196
|
-
}))
|
|
197
|
-
.filter(f => (now - f.mtime.getTime()) < RECENT_THRESHOLD_MS) // Only recent files
|
|
198
|
-
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
199
|
-
if (files.length > 0) {
|
|
200
|
-
const ageSeconds = Math.round((now - files[0].mtime.getTime()) / 1000);
|
|
201
|
-
logger_1.logger.info('Found recent session file', {
|
|
202
|
-
name: files[0].name,
|
|
203
|
-
ageSeconds,
|
|
204
|
-
totalFiles: fs.readdirSync(chatsDir).filter(f => f.startsWith('session-')).length,
|
|
205
|
-
});
|
|
206
|
-
this.handleSessionFile(files[0].path);
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
const totalFiles = fs.readdirSync(chatsDir).filter(f => f.startsWith('session-')).length;
|
|
210
|
-
logger_1.logger.info('No recent session files found (all older than 5 minutes)', {
|
|
211
|
-
totalFiles,
|
|
212
|
-
thresholdMinutes: RECENT_THRESHOLD_MS / 60000,
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
logger_1.logger.error('Error scanning for sessions', { error: error.message });
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Handle a new or updated session file
|
|
222
|
-
*/
|
|
223
|
-
handleSessionFile(filePath) {
|
|
224
|
-
try {
|
|
225
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
226
|
-
const transcript = JSON.parse(content);
|
|
227
|
-
// If this is a new session, emit session-discovered
|
|
228
|
-
if (this.currentSessionId !== transcript.sessionId) {
|
|
229
|
-
logger_1.logger.info('New session discovered', {
|
|
230
|
-
sessionId: transcript.sessionId,
|
|
231
|
-
projectHash: transcript.projectHash
|
|
232
|
-
});
|
|
233
|
-
this.currentSessionId = transcript.sessionId;
|
|
234
|
-
this.currentTranscriptPath = filePath;
|
|
235
|
-
this.sentMessageIds.clear(); // Reset for new session
|
|
236
|
-
this.emit('session-discovered', transcript.sessionId, transcript.projectHash, filePath);
|
|
237
|
-
}
|
|
238
|
-
// Process messages
|
|
239
|
-
this.processMessages(transcript);
|
|
240
|
-
}
|
|
241
|
-
catch (err) {
|
|
242
|
-
logger_1.logger.error('Error reading session file', {
|
|
243
|
-
filePath,
|
|
244
|
-
error: err instanceof Error ? err.message : String(err)
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Handle transcript file changes
|
|
250
|
-
*/
|
|
251
|
-
handleTranscriptChange(filePath) {
|
|
252
|
-
logger_1.logger.debug('Transcript changed', { filePath });
|
|
253
|
-
this.handleSessionFile(filePath);
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Process messages and emit events for new ones
|
|
257
|
-
* Only processes messages created after the watcher started to prevent
|
|
258
|
-
* loading historical messages from the transcript file.
|
|
259
|
-
*/
|
|
260
|
-
processMessages(transcript) {
|
|
261
|
-
for (const message of transcript.messages) {
|
|
262
|
-
// Skip messages we've already processed (within this watcher instance)
|
|
263
|
-
if (this.sentMessageIds.has(message.id)) {
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
// Skip messages that were created before the watcher started
|
|
267
|
-
// This prevents loading old messages from the transcript file on startup
|
|
268
|
-
const messageTime = new Date(message.timestamp);
|
|
269
|
-
if (messageTime < this.watcherStartTime) {
|
|
270
|
-
// Mark as processed so we don't check again
|
|
271
|
-
this.sentMessageIds.add(message.id);
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
this.sentMessageIds.add(message.id);
|
|
275
|
-
logger_1.logger.debug('New message detected', {
|
|
276
|
-
id: message.id,
|
|
277
|
-
type: message.type,
|
|
278
|
-
contentLength: message.content.length
|
|
279
|
-
});
|
|
280
|
-
this.emit('new-message', transcript.sessionId, message);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Get the current session ID
|
|
285
|
-
*/
|
|
286
|
-
getSessionId() {
|
|
287
|
-
return this.currentSessionId;
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Get the project hash for the working directory
|
|
291
|
-
*/
|
|
292
|
-
getProjectHash() {
|
|
293
|
-
return this.projectHash;
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Manually set the session ID (e.g., when passed from wrapper)
|
|
297
|
-
*/
|
|
298
|
-
setSessionId(sessionId) {
|
|
299
|
-
this.currentSessionId = sessionId;
|
|
300
|
-
// Try to find the transcript file for this session
|
|
301
|
-
if (this.projectHash) {
|
|
302
|
-
const chatsDir = path.join(this.geminiDir, this.projectHash, 'chats');
|
|
303
|
-
if (fs.existsSync(chatsDir)) {
|
|
304
|
-
const files = fs.readdirSync(chatsDir).filter(f => f.includes(sessionId));
|
|
305
|
-
if (files.length > 0) {
|
|
306
|
-
this.currentTranscriptPath = path.join(chatsDir, files[0]);
|
|
307
|
-
logger_1.logger.info('Found transcript for session', { sessionId, path: this.currentTranscriptPath });
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Stop watching
|
|
314
|
-
*/
|
|
315
|
-
stop() {
|
|
316
|
-
if (this.watcher) {
|
|
317
|
-
this.watcher.close();
|
|
318
|
-
this.watcher = null;
|
|
319
|
-
logger_1.logger.info('TranscriptWatcher stopped');
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
exports.TranscriptWatcher = TranscriptWatcher;
|
|
324
|
-
//# sourceMappingURL=transcript-watcher.js.map
|
package/dist/types.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_TOOL_APPROVAL_OPTIONS = exports.DeliveryStatus = exports.AgentType = exports.SessionStatus = exports.EventSource = exports.EventType = void 0;
|
|
4
|
-
// Re-export shared types from codevibe-core
|
|
5
|
-
var codevibe_core_1 = require("@quantiya/codevibe-core");
|
|
6
|
-
Object.defineProperty(exports, "EventType", { enumerable: true, get: function () { return codevibe_core_1.EventType; } });
|
|
7
|
-
Object.defineProperty(exports, "EventSource", { enumerable: true, get: function () { return codevibe_core_1.EventSource; } });
|
|
8
|
-
Object.defineProperty(exports, "SessionStatus", { enumerable: true, get: function () { return codevibe_core_1.SessionStatus; } });
|
|
9
|
-
Object.defineProperty(exports, "AgentType", { enumerable: true, get: function () { return codevibe_core_1.AgentType; } });
|
|
10
|
-
Object.defineProperty(exports, "DeliveryStatus", { enumerable: true, get: function () { return codevibe_core_1.DeliveryStatus; } });
|
|
11
|
-
exports.DEFAULT_TOOL_APPROVAL_OPTIONS = [
|
|
12
|
-
{ number: '1', text: 'Allow once' },
|
|
13
|
-
{ number: '2', text: 'Allow for this session' },
|
|
14
|
-
{ number: '3', text: 'Deny' },
|
|
15
|
-
];
|
|
16
|
-
//# sourceMappingURL=types.js.map
|