@quantiya/codevibe-codex-plugin 1.0.7 → 1.0.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.
@@ -1,255 +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.TmuxPaneObserver = void 0;
37
- const fs = __importStar(require("fs"));
38
- const os = __importStar(require("os"));
39
- const path = __importStar(require("path"));
40
- const crypto_1 = require("crypto");
41
- const child_process_1 = require("child_process");
42
- const events_1 = require("events");
43
- const util_1 = require("util");
44
- const logger_1 = require("./logger");
45
- const execAsync = (0, util_1.promisify)(child_process_1.exec);
46
- /**
47
- * Foundation for tmux-based prompt detection.
48
- *
49
- * This first pass intentionally keeps the surface area small:
50
- * - manage the active tmux session name
51
- * - capture a clean pane snapshot on demand
52
- * - provide an evented type that server.ts can wire into later
53
- *
54
- * Real-time pipe-pane streaming will be added in a follow-up patch.
55
- */
56
- class TmuxPaneObserver extends events_1.EventEmitter {
57
- constructor() {
58
- super(...arguments);
59
- this.sessionName = null;
60
- this.started = false;
61
- this.pipeFilePath = null;
62
- this.filePosition = 0;
63
- this.watcher = null;
64
- this.processing = false;
65
- this.pendingRead = false;
66
- this.lastPromptHash = null;
67
- }
68
- async start(sessionName) {
69
- if (this.started && this.sessionName === sessionName) {
70
- logger_1.logger.debug('Tmux pane observer already started', { sessionName });
71
- return;
72
- }
73
- if (this.started) {
74
- await this.stop();
75
- }
76
- this.sessionName = sessionName;
77
- this.started = true;
78
- this.filePosition = 0;
79
- this.lastPromptHash = null;
80
- this.pipeFilePath = path.join(os.tmpdir(), `codevibe-codex-pane-${process.pid}.log`);
81
- fs.mkdirSync(path.dirname(this.pipeFilePath), { recursive: true });
82
- fs.writeFileSync(this.pipeFilePath, '');
83
- await this.enablePipePane();
84
- this.startFileWatcher();
85
- logger_1.logger.info('Tmux pane observer started', { sessionName });
86
- }
87
- async stop() {
88
- if (!this.started) {
89
- return;
90
- }
91
- try {
92
- await this.disablePipePane();
93
- }
94
- catch (error) {
95
- logger_1.logger.debug('Failed to disable tmux pipe-pane cleanly', { error });
96
- }
97
- if (this.watcher) {
98
- this.watcher.close();
99
- this.watcher = null;
100
- }
101
- if (this.pipeFilePath) {
102
- try {
103
- fs.unlinkSync(this.pipeFilePath);
104
- }
105
- catch {
106
- // Ignore cleanup failure
107
- }
108
- }
109
- logger_1.logger.info('Tmux pane observer stopped', { sessionName: this.sessionName });
110
- this.started = false;
111
- this.sessionName = null;
112
- this.pipeFilePath = null;
113
- this.filePosition = 0;
114
- this.processing = false;
115
- this.pendingRead = false;
116
- this.lastPromptHash = null;
117
- this.removeAllListeners('prompt-candidate');
118
- this.removeAllListeners('observer-error');
119
- }
120
- async captureSnapshot(lines = 120) {
121
- if (!this.sessionName) {
122
- throw new Error('Tmux pane observer is not started');
123
- }
124
- const safeLines = Math.max(1, Math.floor(lines));
125
- const escapedSession = this.escapeShellArg(this.sessionName);
126
- const cmd = `tmux capture-pane -p -e -S -${safeLines} -t '${escapedSession}'`;
127
- try {
128
- const { stdout } = await execAsync(cmd);
129
- return stdout;
130
- }
131
- catch (error) {
132
- logger_1.logger.error('Failed to capture tmux pane snapshot', {
133
- sessionName: this.sessionName,
134
- error,
135
- });
136
- this.emit('observer-error', error);
137
- throw error;
138
- }
139
- }
140
- escapeShellArg(value) {
141
- return value.replace(/'/g, `'\\''`);
142
- }
143
- async enablePipePane() {
144
- if (!this.sessionName || !this.pipeFilePath) {
145
- throw new Error('Tmux pane observer is not initialized');
146
- }
147
- const escapedSession = this.escapeShellArg(this.sessionName);
148
- const escapedFile = this.escapeShellArg(this.pipeFilePath);
149
- const cmd = `tmux pipe-pane -O -t '${escapedSession}' "cat >> '${escapedFile}'"`;
150
- await execAsync(cmd);
151
- logger_1.logger.debug('Enabled tmux pipe-pane mirroring', {
152
- sessionName: this.sessionName,
153
- pipeFilePath: this.pipeFilePath,
154
- });
155
- }
156
- async disablePipePane() {
157
- if (!this.sessionName) {
158
- return;
159
- }
160
- const escapedSession = this.escapeShellArg(this.sessionName);
161
- const cmd = `tmux pipe-pane -t '${escapedSession}'`;
162
- await execAsync(cmd);
163
- }
164
- startFileWatcher() {
165
- if (!this.pipeFilePath) {
166
- return;
167
- }
168
- this.watcher = fs.watch(this.pipeFilePath, (eventType) => {
169
- if (eventType !== 'change') {
170
- return;
171
- }
172
- void this.processFileChanges();
173
- });
174
- }
175
- async processFileChanges() {
176
- if (!this.pipeFilePath) {
177
- return;
178
- }
179
- if (this.processing) {
180
- this.pendingRead = true;
181
- return;
182
- }
183
- this.processing = true;
184
- try {
185
- do {
186
- this.pendingRead = false;
187
- const chunk = this.readAppendedChunk();
188
- if (!chunk) {
189
- continue;
190
- }
191
- if (!this.looksLikePromptDelta(chunk)) {
192
- continue;
193
- }
194
- const snapshot = await this.captureSnapshot();
195
- if (!snapshot || !this.looksLikePromptSnapshot(snapshot)) {
196
- continue;
197
- }
198
- const promptHash = this.hashPromptSnapshot(snapshot);
199
- if (promptHash === this.lastPromptHash) {
200
- continue;
201
- }
202
- this.lastPromptHash = promptHash;
203
- this.emit('prompt-candidate', {
204
- rawDelta: chunk,
205
- snapshot,
206
- detectedAt: Date.now(),
207
- });
208
- } while (this.pendingRead);
209
- }
210
- catch (error) {
211
- logger_1.logger.error('Failed to process tmux pane changes', { error });
212
- this.emit('observer-error', error);
213
- }
214
- finally {
215
- this.processing = false;
216
- }
217
- }
218
- readAppendedChunk() {
219
- if (!this.pipeFilePath) {
220
- return '';
221
- }
222
- const stat = fs.statSync(this.pipeFilePath);
223
- if (stat.size <= this.filePosition) {
224
- return '';
225
- }
226
- const fd = fs.openSync(this.pipeFilePath, 'r');
227
- try {
228
- const length = stat.size - this.filePosition;
229
- const buffer = Buffer.alloc(length);
230
- fs.readSync(fd, buffer, 0, length, this.filePosition);
231
- this.filePosition = stat.size;
232
- return buffer.toString('utf-8');
233
- }
234
- finally {
235
- fs.closeSync(fd);
236
- }
237
- }
238
- looksLikePromptDelta(chunk) {
239
- return /\[(?:y\/n|Y\/n|y\/N)\]|\b(?:apply|approve|allow|reject|deny|continue)\b/i.test(chunk);
240
- }
241
- looksLikePromptSnapshot(snapshot) {
242
- const recentText = snapshot.split('\n').slice(-20).join('\n');
243
- return /\[(?:y\/n|Y\/n|y\/N)\]|^\s*\d+\.\s+/im.test(recentText);
244
- }
245
- hashPromptSnapshot(snapshot) {
246
- const normalized = snapshot
247
- .replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, '')
248
- .replace(/\r/g, '\n')
249
- .replace(/[ \t]+\n/g, '\n')
250
- .trim();
251
- return (0, crypto_1.createHash)('sha256').update(normalized).digest('hex');
252
- }
253
- }
254
- exports.TmuxPaneObserver = TmuxPaneObserver;
255
- //# sourceMappingURL=tmux-pane-observer.js.map
@@ -1,169 +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.saveTokens = saveTokens;
37
- exports.loadTokens = loadTokens;
38
- exports.deleteTokens = deleteTokens;
39
- exports.isTokenExpired = isTokenExpired;
40
- exports.isAuthenticated = isAuthenticated;
41
- exports.getTokenFilePath = getTokenFilePath;
42
- exports.getTokenExpiration = getTokenExpiration;
43
- const fs = __importStar(require("fs"));
44
- const path = __importStar(require("path"));
45
- const os = __importStar(require("os"));
46
- const logger_1 = require("./logger");
47
- // Token storage location - environment-specific
48
- const TOKEN_DIR = path.join(os.homedir(), '.codevibe-codex');
49
- // Get environment-specific token file
50
- function getTokenFile() {
51
- const environment = process.env.ENVIRONMENT || 'production';
52
- return path.join(TOKEN_DIR, `tokens-${environment}.json`);
53
- }
54
- /**
55
- * Ensure the token directory exists with proper permissions
56
- */
57
- function ensureTokenDir() {
58
- if (!fs.existsSync(TOKEN_DIR)) {
59
- fs.mkdirSync(TOKEN_DIR, { mode: 0o700 }); // rwx------
60
- logger_1.logger.debug('Created token directory', { path: TOKEN_DIR });
61
- }
62
- }
63
- /**
64
- * Save tokens to secure file storage
65
- */
66
- function saveTokens(tokens) {
67
- try {
68
- ensureTokenDir();
69
- const tokenFile = getTokenFile();
70
- const content = JSON.stringify(tokens, null, 2);
71
- fs.writeFileSync(tokenFile, content, { mode: 0o600 }); // rw-------
72
- logger_1.logger.info('Tokens saved successfully', {
73
- userId: tokens.userId,
74
- email: tokens.email,
75
- expiresAt: new Date(tokens.expiresAt).toISOString(),
76
- environment: process.env.ENVIRONMENT || 'production',
77
- });
78
- }
79
- catch (error) {
80
- logger_1.logger.error('Failed to save tokens:', error);
81
- throw new Error(`Failed to save tokens: ${error}`);
82
- }
83
- }
84
- /**
85
- * Load tokens from secure file storage
86
- * Returns null if no tokens are stored or if they're invalid
87
- */
88
- function loadTokens() {
89
- try {
90
- const tokenFile = getTokenFile();
91
- if (!fs.existsSync(tokenFile)) {
92
- logger_1.logger.debug('No tokens file found', { environment: process.env.ENVIRONMENT || 'production' });
93
- return null;
94
- }
95
- const content = fs.readFileSync(tokenFile, 'utf-8');
96
- const tokens = JSON.parse(content);
97
- // Validate required fields
98
- if (!tokens.accessToken || !tokens.refreshToken || !tokens.expiresAt) {
99
- logger_1.logger.warn('Invalid tokens file - missing required fields');
100
- return null;
101
- }
102
- logger_1.logger.debug('Tokens loaded', {
103
- userId: tokens.userId,
104
- email: tokens.email,
105
- expiresAt: new Date(tokens.expiresAt).toISOString(),
106
- isExpired: isTokenExpired(tokens),
107
- });
108
- return tokens;
109
- }
110
- catch (error) {
111
- logger_1.logger.error('Failed to load tokens:', error);
112
- return null;
113
- }
114
- }
115
- /**
116
- * Delete stored tokens (logout)
117
- */
118
- function deleteTokens() {
119
- try {
120
- const tokenFile = getTokenFile();
121
- if (fs.existsSync(tokenFile)) {
122
- fs.unlinkSync(tokenFile);
123
- logger_1.logger.info('Tokens deleted successfully', { environment: process.env.ENVIRONMENT || 'production' });
124
- return true;
125
- }
126
- logger_1.logger.debug('No tokens file to delete', { environment: process.env.ENVIRONMENT || 'production' });
127
- return false;
128
- }
129
- catch (error) {
130
- logger_1.logger.error('Failed to delete tokens:', error);
131
- return false;
132
- }
133
- }
134
- /**
135
- * Check if the access token is expired or about to expire
136
- * Considers token expired if less than 5 minutes remaining
137
- */
138
- function isTokenExpired(tokens) {
139
- const bufferMs = 5 * 60 * 1000; // 5 minutes buffer
140
- return Date.now() >= (tokens.expiresAt - bufferMs);
141
- }
142
- /**
143
- * Check if user is authenticated (has valid, non-expired tokens)
144
- */
145
- function isAuthenticated() {
146
- const tokens = loadTokens();
147
- if (!tokens) {
148
- return false;
149
- }
150
- // Even if access token is expired, we can refresh if we have a refresh token
151
- return !!tokens.refreshToken;
152
- }
153
- /**
154
- * Get the token file path (for display purposes)
155
- */
156
- function getTokenFilePath() {
157
- return getTokenFile();
158
- }
159
- /**
160
- * Get token expiration date
161
- */
162
- function getTokenExpiration() {
163
- const tokens = loadTokens();
164
- if (!tokens) {
165
- return null;
166
- }
167
- return new Date(tokens.expiresAt);
168
- }
169
- //# sourceMappingURL=token-storage.js.map
package/dist/types.js DELETED
@@ -1,17 +0,0 @@
1
- "use strict";
2
- //
3
- // types.ts
4
- // CodeVibe Codex Plugin
5
- //
6
- // Re-export shared types from codevibe-core and define plugin-specific types
7
- //
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.AgentType = exports.SessionStatus = exports.DeliveryStatus = exports.EventSource = exports.EventType = void 0;
10
- // Re-export all shared types from core
11
- var codevibe_core_1 = require("@quantiya/codevibe-core");
12
- Object.defineProperty(exports, "EventType", { enumerable: true, get: function () { return codevibe_core_1.EventType; } });
13
- Object.defineProperty(exports, "EventSource", { enumerable: true, get: function () { return codevibe_core_1.EventSource; } });
14
- Object.defineProperty(exports, "DeliveryStatus", { enumerable: true, get: function () { return codevibe_core_1.DeliveryStatus; } });
15
- Object.defineProperty(exports, "SessionStatus", { enumerable: true, get: function () { return codevibe_core_1.SessionStatus; } });
16
- Object.defineProperty(exports, "AgentType", { enumerable: true, get: function () { return codevibe_core_1.AgentType; } });
17
- //# sourceMappingURL=types.js.map