@quantiya/codevibe-codex-plugin 1.0.7 → 1.0.8
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 +22 -1051
- package/package.json +5 -4
- package/dist/approval-detector.js +0 -174
- package/dist/appsync-client.js +0 -937
- package/dist/auth-cli.js +0 -241
- package/dist/config.js +0 -116
- package/dist/crypto-service.js +0 -278
- package/dist/event-mapper.js +0 -302
- package/dist/key-manager.js +0 -287
- package/dist/logger.js +0 -18
- package/dist/prompt-parser.js +0 -8
- package/dist/prompt-responder.js +0 -78
- package/dist/session-id-cache.js +0 -90
- package/dist/session-log-watcher.js +0 -372
- package/dist/tmux-pane-observer.js +0 -255
- package/dist/token-storage.js +0 -169
- package/dist/types.js +0 -17
package/dist/event-mapper.js
DELETED
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mapLogEntryToEvent = mapLogEntryToEvent;
|
|
4
|
-
exports.extractOldNewFromPatch = extractOldNewFromPatch;
|
|
5
|
-
exports.extractFileFromPatch = extractFileFromPatch;
|
|
6
|
-
exports.clearPendingCalls = clearPendingCalls;
|
|
7
|
-
exports.getPendingCallsCount = getPendingCallsCount;
|
|
8
|
-
exports.getPendingCall = getPendingCall;
|
|
9
|
-
const uuid_1 = require("uuid");
|
|
10
|
-
const codevibe_core_1 = require("@quantiya/codevibe-core");
|
|
11
|
-
const logger_1 = require("./logger");
|
|
12
|
-
/**
|
|
13
|
-
* Maps Codex JSONL log entries to CodeVibe events
|
|
14
|
-
*
|
|
15
|
-
* Codex log entry types:
|
|
16
|
-
* - session_meta: Session metadata (handled by watcher)
|
|
17
|
-
* - event_msg: User/agent messages, reasoning, token counts
|
|
18
|
-
* - response_item: Function calls and outputs
|
|
19
|
-
* - turn_context: Turn metadata (ignored)
|
|
20
|
-
*/
|
|
21
|
-
// Track pending function calls to match with outputs
|
|
22
|
-
const pendingCalls = new Map();
|
|
23
|
-
/**
|
|
24
|
-
* Map a Codex log entry to a CodeVibe event
|
|
25
|
-
* Returns null if the entry should not be synced
|
|
26
|
-
*/
|
|
27
|
-
function mapLogEntryToEvent(entry, sessionId) {
|
|
28
|
-
const base = {
|
|
29
|
-
sessionId,
|
|
30
|
-
source: codevibe_core_1.EventSource.DESKTOP,
|
|
31
|
-
};
|
|
32
|
-
// Handle event_msg types
|
|
33
|
-
if (entry.type === 'event_msg' && entry.payload) {
|
|
34
|
-
const payloadType = entry.payload.type;
|
|
35
|
-
switch (payloadType) {
|
|
36
|
-
case 'user_message':
|
|
37
|
-
return {
|
|
38
|
-
...base,
|
|
39
|
-
type: codevibe_core_1.EventType.USER_PROMPT,
|
|
40
|
-
content: entry.payload.message || '',
|
|
41
|
-
metadata: {
|
|
42
|
-
images: entry.payload.images || [],
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
case 'agent_message':
|
|
46
|
-
return {
|
|
47
|
-
...base,
|
|
48
|
-
type: codevibe_core_1.EventType.ASSISTANT_RESPONSE,
|
|
49
|
-
content: entry.payload.message || '',
|
|
50
|
-
};
|
|
51
|
-
case 'agent_reasoning':
|
|
52
|
-
// Send as REASONING event type for visual indicator in iOS
|
|
53
|
-
return {
|
|
54
|
-
...base,
|
|
55
|
-
type: codevibe_core_1.EventType.REASONING,
|
|
56
|
-
content: entry.payload.text || '',
|
|
57
|
-
};
|
|
58
|
-
case 'token_count':
|
|
59
|
-
// Skip token counts - could be used for metadata updates
|
|
60
|
-
logger_1.logger.debug('Skipping token_count entry');
|
|
61
|
-
return null;
|
|
62
|
-
default:
|
|
63
|
-
logger_1.logger.debug('Unknown event_msg type', { type: payloadType });
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
// Handle response_item types (tool calls)
|
|
68
|
-
if (entry.type === 'response_item' && entry.payload) {
|
|
69
|
-
const itemType = entry.payload.type;
|
|
70
|
-
// Function call start (shell commands, etc.)
|
|
71
|
-
if (itemType === 'function_call') {
|
|
72
|
-
const { name, arguments: args, call_id } = entry.payload;
|
|
73
|
-
// Parse arguments
|
|
74
|
-
let parsedArgs = {};
|
|
75
|
-
try {
|
|
76
|
-
parsedArgs = JSON.parse(args || '{}');
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
parsedArgs = { raw: args };
|
|
80
|
-
}
|
|
81
|
-
// Generate event ID so we can update it later
|
|
82
|
-
const eventId = (0, uuid_1.v4)();
|
|
83
|
-
// Store for matching with output
|
|
84
|
-
pendingCalls.set(call_id, {
|
|
85
|
-
name,
|
|
86
|
-
input: args,
|
|
87
|
-
eventId,
|
|
88
|
-
});
|
|
89
|
-
// Map tool name to friendly name
|
|
90
|
-
const toolName = mapToolName(name);
|
|
91
|
-
const content = formatToolCallContent(name, parsedArgs);
|
|
92
|
-
return {
|
|
93
|
-
...base,
|
|
94
|
-
type: codevibe_core_1.EventType.TOOL_USE,
|
|
95
|
-
content,
|
|
96
|
-
metadata: {
|
|
97
|
-
toolName,
|
|
98
|
-
toolInput: parsedArgs,
|
|
99
|
-
callId: call_id,
|
|
100
|
-
status: 'running',
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
// Function call output
|
|
105
|
-
if (itemType === 'function_call_output') {
|
|
106
|
-
const { call_id, output } = entry.payload;
|
|
107
|
-
const pending = pendingCalls.get(call_id);
|
|
108
|
-
pendingCalls.delete(call_id);
|
|
109
|
-
const toolName = pending?.name ? mapToolName(pending.name) : 'Tool';
|
|
110
|
-
const truncatedOutput = truncateOutput(output, 500);
|
|
111
|
-
return {
|
|
112
|
-
...base,
|
|
113
|
-
type: codevibe_core_1.EventType.TOOL_USE,
|
|
114
|
-
content: `${toolName} completed:\n${truncatedOutput}`,
|
|
115
|
-
metadata: {
|
|
116
|
-
toolName,
|
|
117
|
-
toolOutput: output,
|
|
118
|
-
callId: call_id,
|
|
119
|
-
status: 'completed',
|
|
120
|
-
},
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
// Custom tool call (file edits with apply_patch)
|
|
124
|
-
if (itemType === 'custom_tool_call') {
|
|
125
|
-
const { name, call_id, input, status } = entry.payload;
|
|
126
|
-
// Store for matching with output
|
|
127
|
-
pendingCalls.set(call_id, {
|
|
128
|
-
name,
|
|
129
|
-
input,
|
|
130
|
-
eventId: (0, uuid_1.v4)(),
|
|
131
|
-
});
|
|
132
|
-
// Parse the patch to extract file info and diff content
|
|
133
|
-
const fileInfo = extractFileFromPatch(input);
|
|
134
|
-
const { oldString, newString } = extractOldNewFromPatch(input);
|
|
135
|
-
const content = fileInfo
|
|
136
|
-
? `Editing: ${fileInfo.filePath}`
|
|
137
|
-
: `Applying patch`;
|
|
138
|
-
return {
|
|
139
|
-
...base,
|
|
140
|
-
type: codevibe_core_1.EventType.TOOL_USE,
|
|
141
|
-
content,
|
|
142
|
-
metadata: {
|
|
143
|
-
tool_name: 'Edit',
|
|
144
|
-
tool_input: {
|
|
145
|
-
file_path: fileInfo?.filePath || '',
|
|
146
|
-
old_string: oldString,
|
|
147
|
-
new_string: newString,
|
|
148
|
-
},
|
|
149
|
-
callId: call_id,
|
|
150
|
-
status: status || 'running',
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
// Custom tool call output
|
|
155
|
-
if (itemType === 'custom_tool_call_output') {
|
|
156
|
-
const { call_id, output } = entry.payload;
|
|
157
|
-
const pending = pendingCalls.get(call_id);
|
|
158
|
-
pendingCalls.delete(call_id);
|
|
159
|
-
// Parse output JSON
|
|
160
|
-
let parsedOutput = {};
|
|
161
|
-
try {
|
|
162
|
-
parsedOutput = JSON.parse(output || '{}');
|
|
163
|
-
}
|
|
164
|
-
catch {
|
|
165
|
-
parsedOutput = { raw: output };
|
|
166
|
-
}
|
|
167
|
-
const success = parsedOutput.output?.includes('Success') || !parsedOutput.error;
|
|
168
|
-
return {
|
|
169
|
-
...base,
|
|
170
|
-
type: codevibe_core_1.EventType.TOOL_USE,
|
|
171
|
-
content: success ? 'File edit applied successfully' : `Edit failed: ${parsedOutput.error || 'Unknown error'}`,
|
|
172
|
-
metadata: {
|
|
173
|
-
toolName: 'Edit',
|
|
174
|
-
toolOutput: parsedOutput,
|
|
175
|
-
callId: call_id,
|
|
176
|
-
status: 'completed',
|
|
177
|
-
success,
|
|
178
|
-
},
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
logger_1.logger.debug('Unknown response_item type', { type: itemType });
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
// Skip turn_context and other types
|
|
185
|
-
if (entry.type === 'turn_context') {
|
|
186
|
-
logger_1.logger.debug('Skipping turn_context entry');
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
logger_1.logger.debug('Unhandled log entry type', { type: entry.type });
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Map Codex tool names to friendly display names
|
|
194
|
-
*/
|
|
195
|
-
function mapToolName(name) {
|
|
196
|
-
const mapping = {
|
|
197
|
-
'shell_command': 'Bash',
|
|
198
|
-
'shell': 'Bash',
|
|
199
|
-
'apply_patch': 'Edit',
|
|
200
|
-
'write_file': 'Write',
|
|
201
|
-
'read_file': 'Read',
|
|
202
|
-
'list_files': 'Glob',
|
|
203
|
-
'search_files': 'Grep',
|
|
204
|
-
'web_search': 'WebSearch',
|
|
205
|
-
'web_fetch': 'WebFetch',
|
|
206
|
-
};
|
|
207
|
-
return mapping[name] || name;
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Format tool call content for display
|
|
211
|
-
*/
|
|
212
|
-
function formatToolCallContent(name, args) {
|
|
213
|
-
switch (name) {
|
|
214
|
-
case 'shell_command':
|
|
215
|
-
case 'shell':
|
|
216
|
-
return `Running: ${args.command || 'command'}`;
|
|
217
|
-
case 'read_file':
|
|
218
|
-
return `Reading: ${args.file_path || args.path || 'file'}`;
|
|
219
|
-
case 'write_file':
|
|
220
|
-
return `Writing: ${args.file_path || args.path || 'file'}`;
|
|
221
|
-
case 'list_files':
|
|
222
|
-
return `Listing: ${args.path || '.'}`;
|
|
223
|
-
case 'search_files':
|
|
224
|
-
return `Searching for: ${args.pattern || args.query || 'pattern'}`;
|
|
225
|
-
case 'web_search':
|
|
226
|
-
return `Searching web: ${args.query || 'query'}`;
|
|
227
|
-
default:
|
|
228
|
-
return `Running ${mapToolName(name)}`;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Extract old and new strings from a Codex apply_patch payload.
|
|
233
|
-
* Parses unified-diff-style hunks into old/new content for iOS diff preview.
|
|
234
|
-
*/
|
|
235
|
-
function extractOldNewFromPatch(patch) {
|
|
236
|
-
const oldLines = [];
|
|
237
|
-
const newLines = [];
|
|
238
|
-
const hunkHeaderPattern = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
|
|
239
|
-
for (const line of patch.split('\n')) {
|
|
240
|
-
if (hunkHeaderPattern.test(line) || line.startsWith('***') || line.startsWith('---') || line.startsWith('+++')) {
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
if (line.startsWith('-')) {
|
|
244
|
-
oldLines.push(line.slice(1));
|
|
245
|
-
}
|
|
246
|
-
else if (line.startsWith('+')) {
|
|
247
|
-
newLines.push(line.slice(1));
|
|
248
|
-
}
|
|
249
|
-
else if (line.startsWith(' ')) {
|
|
250
|
-
const ctx = line.slice(1);
|
|
251
|
-
oldLines.push(ctx);
|
|
252
|
-
newLines.push(ctx);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return {
|
|
256
|
-
oldString: oldLines.join('\n'),
|
|
257
|
-
newString: newLines.join('\n'),
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Extract file path from patch content
|
|
262
|
-
* Patch format: *** Begin Patch\n*** Update File: path\n...
|
|
263
|
-
*/
|
|
264
|
-
function extractFileFromPatch(input) {
|
|
265
|
-
if (!input)
|
|
266
|
-
return null;
|
|
267
|
-
// Match "*** Update File: path" or "*** Add File: path"
|
|
268
|
-
const match = input.match(/\*\*\* (?:Update|Add|Delete) File: (.+)/);
|
|
269
|
-
if (match) {
|
|
270
|
-
return { filePath: match[1].trim() };
|
|
271
|
-
}
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Truncate output for display
|
|
276
|
-
*/
|
|
277
|
-
function truncateOutput(output, maxLength) {
|
|
278
|
-
if (!output)
|
|
279
|
-
return '';
|
|
280
|
-
if (output.length <= maxLength)
|
|
281
|
-
return output;
|
|
282
|
-
return output.substring(0, maxLength) + '...';
|
|
283
|
-
}
|
|
284
|
-
/**
|
|
285
|
-
* Clear pending calls (call on session end)
|
|
286
|
-
*/
|
|
287
|
-
function clearPendingCalls() {
|
|
288
|
-
pendingCalls.clear();
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Get count of pending calls (for approval detection)
|
|
292
|
-
*/
|
|
293
|
-
function getPendingCallsCount() {
|
|
294
|
-
return pendingCalls.size;
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Get pending call info by ID
|
|
298
|
-
*/
|
|
299
|
-
function getPendingCall(callId) {
|
|
300
|
-
return pendingCalls.get(callId);
|
|
301
|
-
}
|
|
302
|
-
//# sourceMappingURL=event-mapper.js.map
|
package/dist/key-manager.js
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
//
|
|
3
|
-
// key-manager.ts
|
|
4
|
-
// CodeVibe Codex Plugin
|
|
5
|
-
//
|
|
6
|
-
// Manages device encryption keys and session keys for E2E encryption
|
|
7
|
-
//
|
|
8
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
-
if (k2 === undefined) k2 = k;
|
|
10
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
-
}
|
|
14
|
-
Object.defineProperty(o, k2, desc);
|
|
15
|
-
}) : (function(o, m, k, k2) {
|
|
16
|
-
if (k2 === undefined) k2 = k;
|
|
17
|
-
o[k2] = m[k];
|
|
18
|
-
}));
|
|
19
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
-
}) : function(o, v) {
|
|
22
|
-
o["default"] = v;
|
|
23
|
-
});
|
|
24
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
-
var ownKeys = function(o) {
|
|
26
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
-
var ar = [];
|
|
28
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
-
return ar;
|
|
30
|
-
};
|
|
31
|
-
return ownKeys(o);
|
|
32
|
-
};
|
|
33
|
-
return function (mod) {
|
|
34
|
-
if (mod && mod.__esModule) return mod;
|
|
35
|
-
var result = {};
|
|
36
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
-
__setModuleDefault(result, mod);
|
|
38
|
-
return result;
|
|
39
|
-
};
|
|
40
|
-
})();
|
|
41
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.keyManager = exports.KeyManager = exports.KeyManagerError = void 0;
|
|
43
|
-
const fs = __importStar(require("fs"));
|
|
44
|
-
const path = __importStar(require("path"));
|
|
45
|
-
const os = __importStar(require("os"));
|
|
46
|
-
const uuid_1 = require("uuid");
|
|
47
|
-
const crypto_service_1 = require("./crypto-service");
|
|
48
|
-
const logger_1 = require("./logger");
|
|
49
|
-
// Errors that can occur during key management
|
|
50
|
-
class KeyManagerError extends Error {
|
|
51
|
-
constructor(message) {
|
|
52
|
-
super(message);
|
|
53
|
-
this.name = 'KeyManagerError';
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
exports.KeyManagerError = KeyManagerError;
|
|
57
|
-
// Storage directory for keys
|
|
58
|
-
const CONFIG_DIR = path.join(os.homedir(), '.codevibe-codex');
|
|
59
|
-
const DEVICE_KEY_FILE = 'device-key.json';
|
|
60
|
-
/**
|
|
61
|
-
* Manages device and session encryption keys
|
|
62
|
-
*/
|
|
63
|
-
class KeyManager {
|
|
64
|
-
constructor() {
|
|
65
|
-
this.deviceKey = null;
|
|
66
|
-
this.sessionKeyCache = new Map(); // sessionId -> base64 session key
|
|
67
|
-
this.isRegistered = false;
|
|
68
|
-
this.ensureConfigDir();
|
|
69
|
-
this.loadDeviceKey();
|
|
70
|
-
}
|
|
71
|
-
static getInstance() {
|
|
72
|
-
if (!KeyManager.instance) {
|
|
73
|
-
KeyManager.instance = new KeyManager();
|
|
74
|
-
}
|
|
75
|
-
return KeyManager.instance;
|
|
76
|
-
}
|
|
77
|
-
// MARK: - Device Key Management
|
|
78
|
-
/**
|
|
79
|
-
* Get or generate the device ID
|
|
80
|
-
*/
|
|
81
|
-
getDeviceId() {
|
|
82
|
-
if (this.deviceKey) {
|
|
83
|
-
return this.deviceKey.deviceId;
|
|
84
|
-
}
|
|
85
|
-
// Generate and store new device key if none exists
|
|
86
|
-
this.generateAndStoreDeviceKey();
|
|
87
|
-
return this.deviceKey.deviceId;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Get the current device's key pair, generating if needed
|
|
91
|
-
*/
|
|
92
|
-
getOrCreateDeviceKeyPair() {
|
|
93
|
-
if (!this.deviceKey) {
|
|
94
|
-
this.generateAndStoreDeviceKey();
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
privateKey: this.deviceKey.privateKey,
|
|
98
|
-
publicKey: this.deviceKey.publicKey,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Get the device's public key (base64)
|
|
103
|
-
*/
|
|
104
|
-
getDevicePublicKey() {
|
|
105
|
-
const keyPair = this.getOrCreateDeviceKeyPair();
|
|
106
|
-
return keyPair.publicKey;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Check if we have a device key
|
|
110
|
-
*/
|
|
111
|
-
hasDeviceKey() {
|
|
112
|
-
return this.deviceKey !== null;
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Check if device key is registered with backend
|
|
116
|
-
*/
|
|
117
|
-
getIsRegistered() {
|
|
118
|
-
return this.isRegistered;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Set registration status
|
|
122
|
-
*/
|
|
123
|
-
setIsRegistered(registered) {
|
|
124
|
-
this.isRegistered = registered;
|
|
125
|
-
}
|
|
126
|
-
// MARK: - Session Key Management
|
|
127
|
-
/**
|
|
128
|
-
* Get session key for a session, decrypting from encryptedKeys if needed
|
|
129
|
-
*/
|
|
130
|
-
getSessionKey(sessionId, encryptedKeys) {
|
|
131
|
-
// Check cache first
|
|
132
|
-
const cachedKey = this.sessionKeyCache.get(sessionId);
|
|
133
|
-
if (cachedKey) {
|
|
134
|
-
return cachedKey;
|
|
135
|
-
}
|
|
136
|
-
// Try to decrypt from encrypted keys
|
|
137
|
-
if (!encryptedKeys || encryptedKeys.length === 0) {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
const deviceId = this.getDeviceId();
|
|
141
|
-
const ourEncryptedKey = encryptedKeys.find((k) => k.deviceId === deviceId);
|
|
142
|
-
if (!ourEncryptedKey) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
// Load our private key
|
|
146
|
-
if (!this.deviceKey) {
|
|
147
|
-
throw new KeyManagerError('Device key not found');
|
|
148
|
-
}
|
|
149
|
-
// Decrypt session key
|
|
150
|
-
const sessionKey = crypto_service_1.cryptoService.decryptSessionKey(ourEncryptedKey, this.deviceKey.privateKey);
|
|
151
|
-
// Cache for future use
|
|
152
|
-
this.sessionKeyCache.set(sessionId, sessionKey);
|
|
153
|
-
return sessionKey;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Generate and encrypt a new session key for all devices
|
|
157
|
-
*/
|
|
158
|
-
createSessionKey(devicePublicKeys) {
|
|
159
|
-
// Generate random session key
|
|
160
|
-
const sessionKey = crypto_service_1.cryptoService.generateSessionKey();
|
|
161
|
-
// Encrypt for each device
|
|
162
|
-
const encryptedKeys = devicePublicKeys.map((device) => {
|
|
163
|
-
const encrypted = crypto_service_1.cryptoService.encryptSessionKey(sessionKey, device.publicKey);
|
|
164
|
-
return {
|
|
165
|
-
deviceId: device.deviceId,
|
|
166
|
-
encryptedKey: encrypted.encryptedKey,
|
|
167
|
-
ephemeralPublicKey: encrypted.ephemeralPublicKey,
|
|
168
|
-
};
|
|
169
|
-
});
|
|
170
|
-
return { sessionKey, encryptedKeys };
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Cache a session key (after successfully decrypting or creating)
|
|
174
|
-
*/
|
|
175
|
-
cacheSessionKey(sessionId, sessionKey) {
|
|
176
|
-
this.sessionKeyCache.set(sessionId, sessionKey);
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Clear cached session key (on session end)
|
|
180
|
-
*/
|
|
181
|
-
clearSessionKey(sessionId) {
|
|
182
|
-
this.sessionKeyCache.delete(sessionId);
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Clear all cached session keys (on sign out)
|
|
186
|
-
*/
|
|
187
|
-
clearAllSessionKeys() {
|
|
188
|
-
this.sessionKeyCache.clear();
|
|
189
|
-
}
|
|
190
|
-
// MARK: - Key Storage
|
|
191
|
-
ensureConfigDir() {
|
|
192
|
-
if (!fs.existsSync(CONFIG_DIR)) {
|
|
193
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
getKeyFilePath() {
|
|
197
|
-
return path.join(CONFIG_DIR, DEVICE_KEY_FILE);
|
|
198
|
-
}
|
|
199
|
-
loadDeviceKey() {
|
|
200
|
-
const keyFilePath = this.getKeyFilePath();
|
|
201
|
-
if (!fs.existsSync(keyFilePath)) {
|
|
202
|
-
this.deviceKey = null;
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
try {
|
|
206
|
-
const data = fs.readFileSync(keyFilePath, 'utf8');
|
|
207
|
-
const stored = JSON.parse(data);
|
|
208
|
-
this.deviceKey = stored.device;
|
|
209
|
-
logger_1.logger.info(`[KeyManager] Loaded device key: ${this.deviceKey.deviceId}`);
|
|
210
|
-
}
|
|
211
|
-
catch (error) {
|
|
212
|
-
logger_1.logger.error(`[KeyManager] Failed to load device key: ${error}`);
|
|
213
|
-
this.deviceKey = null;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
saveDeviceKey() {
|
|
217
|
-
if (!this.deviceKey) {
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
const keyFilePath = this.getKeyFilePath();
|
|
221
|
-
const stored = {
|
|
222
|
-
device: this.deviceKey,
|
|
223
|
-
};
|
|
224
|
-
try {
|
|
225
|
-
fs.writeFileSync(keyFilePath, JSON.stringify(stored, null, 2), {
|
|
226
|
-
mode: 0o600, // Owner read/write only
|
|
227
|
-
});
|
|
228
|
-
logger_1.logger.info(`[KeyManager] Saved device key: ${this.deviceKey.deviceId}`);
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
logger_1.logger.error(`[KeyManager] Failed to save device key: ${error}`);
|
|
232
|
-
throw new KeyManagerError(`Failed to save device key: ${error}`);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
generateAndStoreDeviceKey() {
|
|
236
|
-
const keyPair = crypto_service_1.cryptoService.generateKeyPair();
|
|
237
|
-
const deviceId = (0, uuid_1.v4)().toUpperCase();
|
|
238
|
-
this.deviceKey = {
|
|
239
|
-
deviceId,
|
|
240
|
-
privateKey: keyPair.privateKey,
|
|
241
|
-
publicKey: keyPair.publicKey,
|
|
242
|
-
createdAt: new Date().toISOString(),
|
|
243
|
-
};
|
|
244
|
-
this.saveDeviceKey();
|
|
245
|
-
logger_1.logger.info(`[KeyManager] Generated new device key: ${deviceId}`);
|
|
246
|
-
}
|
|
247
|
-
// MARK: - Helpers
|
|
248
|
-
/**
|
|
249
|
-
* Get device name for registration
|
|
250
|
-
*/
|
|
251
|
-
getDeviceName() {
|
|
252
|
-
return os.hostname() || 'CLI Client';
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Get platform for registration
|
|
256
|
-
*/
|
|
257
|
-
getDevicePlatform() {
|
|
258
|
-
const platform = os.platform();
|
|
259
|
-
if (platform === 'darwin') {
|
|
260
|
-
return 'MACOS';
|
|
261
|
-
}
|
|
262
|
-
else if (platform === 'linux') {
|
|
263
|
-
return 'LINUX';
|
|
264
|
-
}
|
|
265
|
-
else if (platform === 'win32') {
|
|
266
|
-
return 'WINDOWS';
|
|
267
|
-
}
|
|
268
|
-
return 'CLI';
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Clear all encryption data (on sign out)
|
|
272
|
-
*/
|
|
273
|
-
clearAllData() {
|
|
274
|
-
const keyFilePath = this.getKeyFilePath();
|
|
275
|
-
if (fs.existsSync(keyFilePath)) {
|
|
276
|
-
fs.unlinkSync(keyFilePath);
|
|
277
|
-
}
|
|
278
|
-
this.deviceKey = null;
|
|
279
|
-
this.sessionKeyCache.clear();
|
|
280
|
-
this.isRegistered = false;
|
|
281
|
-
logger_1.logger.info('[KeyManager] Cleared all encryption data');
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
exports.KeyManager = KeyManager;
|
|
285
|
-
// Export singleton instance
|
|
286
|
-
exports.keyManager = KeyManager.getInstance();
|
|
287
|
-
//# sourceMappingURL=key-manager.js.map
|
package/dist/logger.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.logger = void 0;
|
|
7
|
-
/**
|
|
8
|
-
* Plugin-specific logger for CodeVibe Codex Plugin
|
|
9
|
-
*/
|
|
10
|
-
const os_1 = __importDefault(require("os"));
|
|
11
|
-
const path_1 = __importDefault(require("path"));
|
|
12
|
-
const codevibe_core_1 = require("@quantiya/codevibe-core");
|
|
13
|
-
exports.logger = (0, codevibe_core_1.createLogger)({
|
|
14
|
-
name: 'codevibe-codex',
|
|
15
|
-
logFile: path_1.default.join(os_1.default.tmpdir(), 'codevibe-codex-mcp.log'),
|
|
16
|
-
level: 'debug',
|
|
17
|
-
});
|
|
18
|
-
//# sourceMappingURL=logger.js.map
|
package/dist/prompt-parser.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.normalizeSnapshot = exports.parseInteractivePrompt = void 0;
|
|
4
|
-
// Re-export shared prompt parser from codevibe-core
|
|
5
|
-
var codevibe_core_1 = require("@quantiya/codevibe-core");
|
|
6
|
-
Object.defineProperty(exports, "parseInteractivePrompt", { enumerable: true, get: function () { return codevibe_core_1.parseInteractivePrompt; } });
|
|
7
|
-
Object.defineProperty(exports, "normalizeSnapshot", { enumerable: true, get: function () { return codevibe_core_1.normalizeSnapshot; } });
|
|
8
|
-
//# sourceMappingURL=prompt-parser.js.map
|
package/dist/prompt-responder.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PromptResponder = void 0;
|
|
4
|
-
const child_process_1 = require("child_process");
|
|
5
|
-
const util_1 = require("util");
|
|
6
|
-
const logger_1 = require("./logger");
|
|
7
|
-
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
8
|
-
class PromptResponder {
|
|
9
|
-
/**
|
|
10
|
-
* Send input to the Codex CLI via tmux
|
|
11
|
-
* Requires tmux session (set by codevibe-codex wrapper)
|
|
12
|
-
*/
|
|
13
|
-
async sendInput(sessionId, input) {
|
|
14
|
-
logger_1.logger.info('Attempting to send input to Codex', { sessionId, input });
|
|
15
|
-
try {
|
|
16
|
-
const tmuxSession = process.env.CODEVIBE_CODEX_TMUX_SESSION;
|
|
17
|
-
if (!tmuxSession) {
|
|
18
|
-
logger_1.logger.error('No tmux session found - codevibe-codex wrapper is required', {
|
|
19
|
-
sessionId,
|
|
20
|
-
hint: 'Start Codex CLI using the codevibe-codex wrapper script',
|
|
21
|
-
});
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
logger_1.logger.info('Using tmux send-keys', { tmuxSession });
|
|
25
|
-
await this.sendViaTmux(tmuxSession, input);
|
|
26
|
-
logger_1.logger.info('Successfully sent input to Codex', { sessionId, input });
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
logger_1.logger.error('Failed to send input to Codex', {
|
|
31
|
-
sessionId,
|
|
32
|
-
error: error instanceof Error ? error.message : String(error),
|
|
33
|
-
});
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Send input via tmux send-keys
|
|
39
|
-
* Works even when screen is locked
|
|
40
|
-
*/
|
|
41
|
-
async sendViaTmux(sessionName, input) {
|
|
42
|
-
// Escape special characters for tmux
|
|
43
|
-
const escaped = input
|
|
44
|
-
.replace(/\\/g, '\\\\')
|
|
45
|
-
.replace(/"/g, '\\"')
|
|
46
|
-
.replace(/\$/g, '\\$')
|
|
47
|
-
.replace(/`/g, '\\`');
|
|
48
|
-
logger_1.logger.info('Sending via tmux', { sessionName, inputLength: input.length });
|
|
49
|
-
try {
|
|
50
|
-
// Send the input text
|
|
51
|
-
const textCmd = `tmux send-keys -t "${sessionName}" -l "${escaped}"`;
|
|
52
|
-
await execAsync(textCmd);
|
|
53
|
-
// Wait for text to be processed
|
|
54
|
-
await this.delay(500);
|
|
55
|
-
// Send Enter key
|
|
56
|
-
const enterCmd = `tmux send-keys -t "${sessionName}" Enter`;
|
|
57
|
-
await execAsync(enterCmd);
|
|
58
|
-
logger_1.logger.info('tmux send-keys completed');
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
logger_1.logger.error('tmux send-keys failed', { sessionName, error });
|
|
62
|
-
throw error;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
delay(ms) {
|
|
66
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Check if input looks like an approval response
|
|
70
|
-
*/
|
|
71
|
-
isApprovalResponse(content) {
|
|
72
|
-
const normalized = content.trim().toLowerCase();
|
|
73
|
-
const approvalResponses = ['y', 'n', 'a', 'q', 'e', 'yes', 'no'];
|
|
74
|
-
return approvalResponses.includes(normalized) || /^[0-9]+$/.test(normalized);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
exports.PromptResponder = PromptResponder;
|
|
78
|
-
//# sourceMappingURL=prompt-responder.js.map
|