@quantiya/codevibe-core 1.0.4 → 1.0.6

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.
@@ -0,0 +1,132 @@
1
+ import { CreateEventInput, CreateSessionInput, UpdateSessionInput, UpdateEventStatusInput, Event, Session, EventSource, DeviceKey } from '../types';
2
+ /**
3
+ * Download URL response
4
+ */
5
+ export interface DownloadUrlResponse {
6
+ downloadUrl: string;
7
+ expiresAt: string;
8
+ }
9
+ /**
10
+ * AppSync GraphQL client with WebSocket subscriptions
11
+ */
12
+ export declare class AppSyncClient {
13
+ private authenticated;
14
+ private currentUserId;
15
+ private currentEmail;
16
+ private tokens;
17
+ private activeSubscriptions;
18
+ private environment;
19
+ constructor();
20
+ /**
21
+ * Get the current authenticated user ID
22
+ */
23
+ getCurrentUserId(): string;
24
+ /**
25
+ * Get the current authenticated user email
26
+ */
27
+ getCurrentUserEmail(): string | null;
28
+ /**
29
+ * Authenticate using stored OAuth tokens from keychain
30
+ */
31
+ authenticateWithStoredTokens(): Promise<boolean>;
32
+ /**
33
+ * Refresh expired tokens
34
+ */
35
+ private refreshTokens;
36
+ /**
37
+ * Check if authenticated
38
+ */
39
+ isAuthenticated(): boolean;
40
+ /**
41
+ * Sign out
42
+ */
43
+ signOut(): void;
44
+ /**
45
+ * Make a GraphQL request
46
+ */
47
+ private graphqlRequest;
48
+ /**
49
+ * Create a session
50
+ */
51
+ createSession(input: CreateSessionInput): Promise<Session>;
52
+ /**
53
+ * Update a session
54
+ */
55
+ updateSession(input: UpdateSessionInput): Promise<Session>;
56
+ /**
57
+ * Get a session
58
+ */
59
+ getSession(sessionId: string): Promise<Session | null>;
60
+ /**
61
+ * Create an event
62
+ */
63
+ createEvent(input: CreateEventInput): Promise<Event>;
64
+ /**
65
+ * Update event status
66
+ */
67
+ updateEventStatus(input: UpdateEventStatusInput): Promise<Event>;
68
+ /**
69
+ * List events for a session
70
+ */
71
+ listEvents(sessionId: string, source?: EventSource, limit?: number): Promise<Event[]>;
72
+ /**
73
+ * List user device keys
74
+ */
75
+ listUserDeviceKeys(): Promise<DeviceKey[]>;
76
+ /**
77
+ * Register device key
78
+ */
79
+ registerDeviceKey(deviceId: string, publicKey: string, platform: string, deviceName: string): Promise<void>;
80
+ /**
81
+ * Get attachment download URL
82
+ */
83
+ getAttachmentDownloadUrl(s3Key: string): Promise<DownloadUrlResponse>;
84
+ /**
85
+ * Subscribe to events for a session
86
+ */
87
+ subscribeToEvents(sessionId: string, onEvent: (event: Event) => void, onError?: (error: Error) => void): () => void;
88
+ /**
89
+ * Build WebSocket URL
90
+ */
91
+ private buildRealtimeUrl;
92
+ /**
93
+ * Create WebSocket subscription
94
+ */
95
+ private createSubscription;
96
+ /**
97
+ * Send subscription start message
98
+ */
99
+ private sendSubscriptionStart;
100
+ /**
101
+ * Reset keep-alive timer
102
+ */
103
+ private resetKeepAliveTimer;
104
+ /**
105
+ * Handle subscription error with two-phase reconnection:
106
+ * Phase 1 (urgent): Exponential backoff for first N attempts
107
+ * Phase 2 (persistent): Fixed interval retry indefinitely
108
+ */
109
+ private handleSubscriptionError;
110
+ /**
111
+ * Cleanup subscription state
112
+ */
113
+ private cleanupSubscriptionState;
114
+ private heartbeatTimers;
115
+ /**
116
+ * Start periodic heartbeat for a session.
117
+ * Updates lastHeartbeatAt on the session every intervalMs (default 2 minutes).
118
+ */
119
+ startHeartbeat(sessionId: string, intervalMs?: number): void;
120
+ /**
121
+ * Stop heartbeat for a session.
122
+ */
123
+ stopHeartbeat(sessionId: string): void;
124
+ /**
125
+ * Send a single heartbeat update.
126
+ */
127
+ private sendHeartbeat;
128
+ /**
129
+ * Cleanup all subscriptions and heartbeats
130
+ */
131
+ cleanupSubscriptions(): void;
132
+ }
@@ -0,0 +1,2 @@
1
+ export { AppSyncClient, DownloadUrlResponse } from './appsync-client';
2
+ export { queries, mutations, subscriptions } from './queries';
@@ -0,0 +1,16 @@
1
+ export declare const queries: {
2
+ getSession: string;
3
+ listEvents: string;
4
+ listUserDeviceKeys: string;
5
+ };
6
+ export declare const mutations: {
7
+ createSession: string;
8
+ updateSession: string;
9
+ createEvent: string;
10
+ updateEventStatus: string;
11
+ registerDeviceKey: string;
12
+ getAttachmentDownloadUrl: string;
13
+ };
14
+ export declare const subscriptions: {
15
+ onEventCreated: string;
16
+ };
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Main CLI entry point
4
+ */
5
+ export declare function runAuthCli(argv: string[]): Promise<void>;
@@ -0,0 +1,87 @@
1
+ import { TokenData } from '../types';
2
+ /**
3
+ * Authentication service for OAuth flows
4
+ */
5
+ export declare class AuthService {
6
+ private static instance;
7
+ private constructor();
8
+ static getInstance(): AuthService;
9
+ /**
10
+ * Open URL in the user's default browser. Cross-platform: macOS, Linux,
11
+ * WSL, Windows. Always prints the URL to stdout first as a fallback —
12
+ * if no browser-opening command is available, the user can copy-paste.
13
+ *
14
+ * On WSL, prefers opening the Windows host browser via WSL interop
15
+ * (wslview → cmd.exe → powershell.exe) before falling back to xdg-open.
16
+ */
17
+ private openBrowser;
18
+ /**
19
+ * Returns the list of browser-opening commands to try in order, based on
20
+ * the current platform. On WSL, returns WSL interop commands first so the
21
+ * Windows browser opens (which is what users actually want on WSL).
22
+ */
23
+ private getBrowserCommands;
24
+ /**
25
+ * Detect whether we're running inside WSL (1 or 2). Returns false on
26
+ * any non-Linux platform or if /proc/sys/kernel/osrelease is not readable.
27
+ */
28
+ private isRunningInWSL;
29
+ /**
30
+ * Try each browser-opening command in order. Advances to the next fallback on:
31
+ * - Spawn failure (ENOENT / the command not being installed)
32
+ * - Synchronous throw from spawn()
33
+ * - Runtime failure where the command spawns but exits with a non-zero
34
+ * code (e.g. wslview when WSL interop is disabled, xdg-open when no
35
+ * default browser is registered, cmd.exe failing to launch start)
36
+ * - Process terminated by signal
37
+ *
38
+ * Stays on the current command when:
39
+ * - Process exits with code 0 (success)
40
+ * - Process is still running after 3 seconds (assumed success — opener
41
+ * is doing real work like launching a slow app, not hung)
42
+ *
43
+ * If all attempts exhaust, logs at debug level — the user still has the
44
+ * sign-in URL printed to stdout as a copy-paste fallback.
45
+ */
46
+ private tryBrowserCommand;
47
+ /**
48
+ * Generate state for CSRF protection
49
+ */
50
+ private generateState;
51
+ /**
52
+ * Build authorization URL
53
+ */
54
+ private buildAuthUrl;
55
+ /**
56
+ * Exchange authorization code for tokens
57
+ */
58
+ private exchangeCodeForTokens;
59
+ /**
60
+ * Decode JWT payload
61
+ */
62
+ private decodeJwt;
63
+ /**
64
+ * Refresh tokens
65
+ */
66
+ refreshTokens(refreshToken: string): Promise<{
67
+ accessToken: string;
68
+ idToken: string;
69
+ expiresIn: number;
70
+ }>;
71
+ /**
72
+ * Login via OAuth browser flow
73
+ */
74
+ login(): Promise<TokenData | null>;
75
+ /**
76
+ * Logout
77
+ */
78
+ logout(): Promise<boolean>;
79
+ /**
80
+ * Get current auth status
81
+ */
82
+ getStatus(): Promise<{
83
+ authenticated: boolean;
84
+ tokens?: TokenData;
85
+ }>;
86
+ }
87
+ export declare const authService: AuthService;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Wraps fetch() and rewrites "fetch failed" errors to include the underlying
3
+ * cause and a user-actionable diagnostic tip when possible. Non-network errors
4
+ * and HTTP error responses (non-2xx) are not affected — the caller still
5
+ * handles response.ok checks themselves.
6
+ *
7
+ * @param url The URL to fetch
8
+ * @param init Standard fetch init options
9
+ * @param context Optional short label (e.g. "token exchange") for the error message
10
+ */
11
+ export declare function fetchWithDiagnostics(url: string, init?: any, context?: string): Promise<Response>;
@@ -0,0 +1,2 @@
1
+ export { AuthService, authService } from './auth-service';
2
+ export { runAuthCli } from './auth-cli';
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Environment type
3
+ */
4
+ export type Environment = 'development' | 'production';
5
+ /**
6
+ * Configuration interface
7
+ */
8
+ export interface Config {
9
+ environment: Environment;
10
+ aws: {
11
+ region: string;
12
+ appsyncUrl: string;
13
+ cognitoUserPoolId: string;
14
+ cognitoClientId: string;
15
+ cognitoDomain: string;
16
+ };
17
+ keychain: {
18
+ serviceName: string;
19
+ };
20
+ server: {
21
+ port: number;
22
+ host: string;
23
+ dynamicPort: boolean;
24
+ };
25
+ claude: {
26
+ command: string;
27
+ defaultTimeout: number;
28
+ };
29
+ codex: {
30
+ command: string;
31
+ defaultTimeout: number;
32
+ sessionsDir: string;
33
+ approvalTimeoutMs: number;
34
+ };
35
+ gemini: {
36
+ command: string;
37
+ defaultTimeout: number;
38
+ transcriptDir: string;
39
+ };
40
+ }
41
+ /**
42
+ * Get environment from process.env.ENVIRONMENT, defaults to 'production'
43
+ */
44
+ export declare function getEnvironment(): Environment;
45
+ /**
46
+ * Load configuration for specific environment
47
+ * If no environment specified, uses process.env.ENVIRONMENT or defaults to 'production'
48
+ */
49
+ export declare function loadConfig(environment?: Environment): Config;
50
+ /**
51
+ * Get current configuration (auto-initializes if not already loaded)
52
+ */
53
+ export declare function getConfig(): Config;
@@ -0,0 +1,2 @@
1
+ export { loadConfig, getConfig, getEnvironment } from './config';
2
+ export type { Config, Environment } from './config';
@@ -0,0 +1,118 @@
1
+ import { EncryptedSessionKey, KeyPair } from '../types';
2
+ /**
3
+ * Error class for cryptographic operations
4
+ */
5
+ export declare class CryptoError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ /**
9
+ * Current encryption version for future algorithm upgrades
10
+ */
11
+ export declare const ENCRYPTION_VERSION = 1;
12
+ /**
13
+ * Service for end-to-end encryption operations
14
+ */
15
+ export declare class CryptoService {
16
+ private static instance;
17
+ private constructor();
18
+ static getInstance(): CryptoService;
19
+ /**
20
+ * Generate a new ECDH P-256 key pair
21
+ * @returns Object with privateKey (base64), publicKey (base64 raw)
22
+ */
23
+ generateKeyPair(): KeyPair;
24
+ /**
25
+ * Generate a random 256-bit session key
26
+ * @returns Base64-encoded session key
27
+ */
28
+ generateSessionKey(): string;
29
+ /**
30
+ * Derive a shared secret using ECDH and HKDF
31
+ * @param privateKeyBase64 Our private key (base64)
32
+ * @param publicKeyBase64 Other party's public key (base64)
33
+ * @returns 256-bit derived key as Buffer
34
+ */
35
+ deriveSharedKey(privateKeyBase64: string, publicKeyBase64: string): Buffer;
36
+ /**
37
+ * Encrypt a session key for a target device using ECDH
38
+ * @param sessionKeyBase64 The session key to encrypt (base64)
39
+ * @param targetPublicKeyBase64 Target device's public key (base64)
40
+ * @returns EncryptedSessionKey containing encrypted key and ephemeral public key
41
+ */
42
+ encryptSessionKey(sessionKeyBase64: string, targetPublicKeyBase64: string): Omit<EncryptedSessionKey, 'deviceId'>;
43
+ /**
44
+ * Decrypt a session key using our private key
45
+ * @param encryptedSessionKey The encrypted session key data
46
+ * @param privateKeyBase64 Our device's private key (base64)
47
+ * @returns Decrypted session key (base64)
48
+ */
49
+ decryptSessionKey(encryptedSessionKey: EncryptedSessionKey, privateKeyBase64: string): string;
50
+ /**
51
+ * Encrypt content using AES-256-GCM
52
+ * @param content String content to encrypt
53
+ * @param sessionKeyBase64 Session key (base64)
54
+ * @returns Base64-encoded ciphertext (nonce + ciphertext + tag)
55
+ */
56
+ encryptContent(content: string, sessionKeyBase64: string): string;
57
+ /**
58
+ * Decrypt content using AES-256-GCM
59
+ * @param encryptedContent Base64-encoded ciphertext
60
+ * @param sessionKeyBase64 Session key (base64)
61
+ * @returns Decrypted string content
62
+ */
63
+ decryptContent(encryptedContent: string, sessionKeyBase64: string): string;
64
+ /**
65
+ * Encrypt JSON-serializable metadata
66
+ * @param metadata Object to encrypt
67
+ * @param sessionKeyBase64 Session key (base64)
68
+ * @returns Base64-encoded encrypted JSON
69
+ */
70
+ encryptMetadata(metadata: Record<string, any>, sessionKeyBase64: string): string;
71
+ /**
72
+ * Decrypt encrypted metadata
73
+ * @param encryptedMetadata Base64-encoded encrypted JSON
74
+ * @param sessionKeyBase64 Session key (base64)
75
+ * @returns Decrypted object
76
+ */
77
+ decryptMetadata(encryptedMetadata: string, sessionKeyBase64: string): Record<string, any>;
78
+ /**
79
+ * Encrypt binary data using AES-256-GCM
80
+ * @param data Binary data to encrypt (Buffer)
81
+ * @param sessionKeyBase64 Session key (base64)
82
+ * @returns Encrypted data (Buffer containing nonce + ciphertext + tag)
83
+ */
84
+ encryptData(data: Buffer, sessionKeyBase64: string): Buffer;
85
+ /**
86
+ * Decrypt binary data using AES-256-GCM
87
+ * @param encryptedData Encrypted data (Buffer containing nonce + ciphertext + tag)
88
+ * @param sessionKeyBase64 Session key (base64)
89
+ * @returns Decrypted binary data (Buffer)
90
+ */
91
+ decryptData(encryptedData: Buffer, sessionKeyBase64: string): Buffer;
92
+ /**
93
+ * Encrypt data using AES-256-GCM
94
+ * @param data Data to encrypt
95
+ * @param key Symmetric key (32 bytes)
96
+ * @returns Combined nonce + ciphertext + tag
97
+ */
98
+ private encrypt;
99
+ /**
100
+ * Decrypt data using AES-256-GCM
101
+ * @param data Combined nonce + ciphertext + tag
102
+ * @param key Symmetric key (32 bytes)
103
+ * @returns Decrypted data
104
+ */
105
+ private decrypt;
106
+ /**
107
+ * Serialize a private key for storage
108
+ */
109
+ serializePrivateKey(privateKeyBase64: string): string;
110
+ /**
111
+ * Deserialize a private key from storage
112
+ */
113
+ deserializePrivateKey(base64: string): string;
114
+ }
115
+ /**
116
+ * Export singleton instance
117
+ */
118
+ export declare const cryptoService: CryptoService;
@@ -0,0 +1 @@
1
+ export { CryptoService, cryptoService, CryptoError, ENCRYPTION_VERSION } from './crypto-service';
@@ -0,0 +1,14 @@
1
+ export { KeychainManager, keychainManager, KeychainError } from './keychain';
2
+ export { CryptoService, cryptoService, CryptoError, ENCRYPTION_VERSION } from './crypto';
3
+ export { AppSyncClient, DownloadUrlResponse } from './appsync';
4
+ export { queries, mutations, subscriptions } from './appsync';
5
+ export { AuthService, authService } from './auth';
6
+ export { runAuthCli } from './auth';
7
+ export { loadConfig, getConfig, getEnvironment } from './config';
8
+ export type { Config, Environment } from './config';
9
+ export { Logger, logger, createLogger } from './logger';
10
+ export { parseInteractivePrompt, normalizeSnapshot, } from './prompt-parser';
11
+ export type { ParsedInteractivePrompt, PromptKind, InteractivePromptOption, } from './prompt-parser';
12
+ export { resumeOrCreateSession, prepareSessionEncryption } from './session';
13
+ export type { ResumeOrCreateSessionInput, ResumeOrCreateSessionResult } from './session';
14
+ export * from './types';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- "use strict";var _e=Object.create;var J=Object.defineProperty;var Me=Object.getOwnPropertyDescriptor;var Be=Object.getOwnPropertyNames;var Fe=Object.getPrototypeOf,qe=Object.prototype.hasOwnProperty;var x=(r,e)=>()=>(r&&(e=r(r=0)),e);var me=(r,e)=>{for(var t in e)J(r,t,{get:e[t],enumerable:!0})},ye=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Be(e))!qe.call(r,s)&&s!==t&&J(r,s,{get:()=>e[s],enumerable:!(n=Me(e,s))||n.enumerable});return r};var f=(r,e,t)=>(t=r!=null?_e(Fe(r)):{},ye(e||!r||!r.__esModule?J(t,"default",{value:r,enumerable:!0}):t,r)),He=r=>ye(J({},"__esModule",{value:!0}),r);var v,C,te,Ve,N,b,fe=x(()=>{"use strict";v=f(require("crypto")),C=class extends Error{constructor(e){super(e),this.name="CryptoError"}},te=1,Ve="CodeVibe E2E v1",N=class r{constructor(){}static getInstance(){return r.instance||(r.instance=new r),r.instance}generateKeyPair(){let e=v.createECDH("prime256v1");e.generateKeys();let n=e.getPublicKey().subarray(1).toString("base64");return{privateKey:e.getPrivateKey().toString("base64"),publicKey:n}}generateSessionKey(){return v.randomBytes(32).toString("base64")}deriveSharedKey(e,t){try{let n=v.createECDH("prime256v1"),s=Buffer.from(e,"base64");n.setPrivateKey(s);let i=Buffer.concat([Buffer.from([4]),Buffer.from(t,"base64")]),o=n.computeSecret(i),a=v.hkdfSync("sha256",o,Buffer.alloc(0),Buffer.from(Ve,"utf8"),32);return Buffer.from(a)}catch(n){throw new C(`Failed to derive shared key: ${n}`)}}encryptSessionKey(e,t){let n=this.generateKeyPair(),s=this.deriveSharedKey(n.privateKey,t),i=Buffer.from(e,"base64");return{encryptedKey:this.encrypt(i,s).toString("base64"),ephemeralPublicKey:n.publicKey}}decryptSessionKey(e,t){let n=this.deriveSharedKey(t,e.ephemeralPublicKey),s=Buffer.from(e.encryptedKey,"base64");return this.decrypt(s,n).toString("base64")}encryptContent(e,t){let n=Buffer.from(t,"base64"),s=Buffer.from(e,"utf8");return this.encrypt(s,n).toString("base64")}decryptContent(e,t){let n=Buffer.from(t,"base64"),s=Buffer.from(e,"base64");return this.decrypt(s,n).toString("utf8")}encryptMetadata(e,t){let n=JSON.stringify(e);return this.encryptContent(n,t)}decryptMetadata(e,t){let n=this.decryptContent(e,t);return JSON.parse(n)}encryptData(e,t){let n=Buffer.from(t,"base64");return this.encrypt(e,n)}decryptData(e,t){let n=Buffer.from(t,"base64");return this.decrypt(e,n)}encrypt(e,t){let n=v.randomBytes(12),s=v.createCipheriv("aes-256-gcm",t,n),i=Buffer.concat([s.update(e),s.final()]),o=s.getAuthTag();return Buffer.concat([n,i,o])}decrypt(e,t){let n=e.subarray(0,12),s=e.subarray(e.length-16),i=e.subarray(12,e.length-16),o=v.createDecipheriv("aes-256-gcm",t,n);o.setAuthTag(s);try{return Buffer.concat([o.update(i),o.final()])}catch{throw new C("Decryption failed: Invalid ciphertext or authentication tag")}}serializePrivateKey(e){return e}deserializePrivateKey(e){return e}},b=N.getInstance()});var z=x(()=>{"use strict";fe()});function h(){let r=process.env.ENVIRONMENT;return r==="development"||r==="production"?r:"production"}function Y(r){let e=r||h();return G={...D[e],aws:{...D[e].aws,region:process.env.AWS_REGION||D[e].aws.region,appsyncUrl:process.env.APPSYNC_URL||D[e].aws.appsyncUrl,cognitoUserPoolId:process.env.COGNITO_USER_POOL_ID||D[e].aws.cognitoUserPoolId,cognitoClientId:process.env.COGNITO_CLIENT_ID||D[e].aws.cognitoClientId,cognitoDomain:process.env.COGNITO_DOMAIN||D[e].aws.cognitoDomain}},he=!0,G}function y(){return(!he||!G)&&Y(),G}var F,q,D,G,he,ve=x(()=>{"use strict";F=f(require("os")),q=f(require("path")),D={development:{environment:"development",aws:{region:"us-east-1",appsyncUrl:"https://te6rjr37sbfpjc4fiunmb2tgy4.appsync-api.us-east-1.amazonaws.com/graphql",cognitoUserPoolId:"us-east-1_yVwWDPvvJ",cognitoClientId:"e9r5apv6v5uui3l928r2ris0r",cognitoDomain:"codevibe-development.auth.us-east-1.amazoncognito.com"},keychain:{serviceName:"ai.quantiya.app.codevibe"},server:{port:3456,host:"127.0.0.1",dynamicPort:!0},claude:{command:"claude",defaultTimeout:6e4},codex:{command:"codex",defaultTimeout:6e4,sessionsDir:q.default.join(F.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:q.default.join(F.default.homedir(),".gemini","tmp")}},production:{environment:"production",aws:{region:"us-east-1",appsyncUrl:"https://jwhyxq4sgrgcdosewp5k4ns5ca.appsync-api.us-east-1.amazonaws.com/graphql",cognitoUserPoolId:"us-east-1_mNRO0j5og",cognitoClientId:"5p04dbc9ojptc5r8n7605fg78f",cognitoDomain:"codevibe-production.auth.us-east-1.amazoncognito.com"},keychain:{serviceName:"ai.quantiya.app.codevibe"},server:{port:3456,host:"127.0.0.1",dynamicPort:!0},claude:{command:"claude",defaultTimeout:6e4},codex:{command:"codex",defaultTimeout:6e4,sessionsDir:q.default.join(F.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:q.default.join(F.default.homedir(),".gemini","tmp")}}},G=null,he=!1});var O=x(()=>{"use strict";ve()});function ne(r){return new P(r)}var R,X,be,Se,P,c,we=x(()=>{"use strict";R=f(require("fs")),X=f(require("path")),be=f(require("os")),Se={debug:0,info:1,warn:2,error:3},P=class{constructor(e){this.name=e.name,this.logFile=e.logFile,this.level=e.level||"info",this.enableConsole=e.console??!1,this.logFile&&this.ensureLogDir()}ensureLogDir(){if(this.logFile){let e=X.dirname(this.logFile);R.existsSync(e)||R.mkdirSync(e,{recursive:!0})}}shouldLog(e){return Se[e]>=Se[this.level]}formatMessage(e,t,n){let s=new Date().toISOString(),i=e.toUpperCase().padEnd(5),o=`[${s}] [${i}] [${this.name}] ${t}`;return n!==void 0&&(typeof n=="object"?o+=` ${JSON.stringify(n)}`:o+=` ${n}`),o}log(e,t,n){if(!this.shouldLog(e))return;let s=this.formatMessage(e,t,n);if(this.logFile)try{R.appendFileSync(this.logFile,s+`
2
- `)}catch{}if(this.enableConsole)switch(e){case"error":console.error(s);break;case"warn":console.warn(s);break;default:console.log(s)}}debug(e,t){this.log("debug",e,t)}info(e,t){this.log("info",e,t)}warn(e,t){this.log("warn",e,t)}error(e,t){this.log("error",e,t)}setLevel(e){this.level=e}};c=new P({name:"codevibe-core",logFile:X.join(be.tmpdir(),"codevibe-core.log"),level:"info"})});var H=x(()=>{"use strict";we()});var Q,Ee,k,I,re,We,K,g,Ie=x(()=>{"use strict";Q=f(require("os")),Ee=require("uuid"),k=f(require("keytar"));z();O();H();I=class extends Error{constructor(e){super(e),this.name="KeychainError"}},re="device-identity",We="tokens-",K=class r{constructor(){this.deviceIdentity=null;this.sessionKeyCache=new Map;this.isRegistered=!1;this._serviceName=null}get serviceName(){return this._serviceName||(this._serviceName=y().keychain.serviceName),this._serviceName}static getInstance(){return r.instance||(r.instance=new r),r.instance}async getDeviceIdentity(){if(this.deviceIdentity)return this.deviceIdentity;try{let e=await k.getPassword(this.serviceName,re);return e?(this.deviceIdentity=JSON.parse(e),c.info(`[KeychainManager] Loaded device identity: ${this.deviceIdentity.deviceId}`),this.deviceIdentity):null}catch(e){return c.error(`[KeychainManager] Failed to load device identity: ${e}`),null}}async setDeviceIdentity(e){try{await k.setPassword(this.serviceName,re,JSON.stringify(e)),this.deviceIdentity=e,c.info(`[KeychainManager] Saved device identity: ${e.deviceId}`)}catch(t){throw c.error(`[KeychainManager] Failed to save device identity: ${t}`),new I(`Failed to save device identity: ${t}`)}}async getOrCreateDeviceIdentity(){let e=await this.getDeviceIdentity();if(e)return e;let t=b.generateKeyPair();return e={deviceId:(0,Ee.v4)().toUpperCase(),privateKey:t.privateKey,publicKey:t.publicKey,createdAt:new Date().toISOString()},await this.setDeviceIdentity(e),c.info(`[KeychainManager] Generated new device identity: ${e.deviceId}`),e}async getDeviceId(){return(await this.getOrCreateDeviceIdentity()).deviceId}async getDevicePublicKey(){return(await this.getOrCreateDeviceIdentity()).publicKey}async getDevicePrivateKey(){return(await this.getOrCreateDeviceIdentity()).privateKey}async hasDeviceIdentity(){return await this.getDeviceIdentity()!==null}async deleteDeviceIdentity(){try{await k.deletePassword(this.serviceName,re),this.deviceIdentity=null,this.sessionKeyCache.clear(),this.isRegistered=!1,c.info("[KeychainManager] Deleted device identity")}catch(e){throw c.error(`[KeychainManager] Failed to delete device identity: ${e}`),new I(`Failed to delete device identity: ${e}`)}}getTokenAccount(e){return`${We}${e}`}async getTokens(e="production"){try{let t=await k.getPassword(this.serviceName,this.getTokenAccount(e));if(!t)return null;let n=JSON.parse(t);return c.debug(`[KeychainManager] Loaded tokens for ${e}`),n}catch(t){return c.error(`[KeychainManager] Failed to load tokens: ${t}`),null}}async setTokens(e,t="production"){try{await k.setPassword(this.serviceName,this.getTokenAccount(t),JSON.stringify(e)),c.info(`[KeychainManager] Saved tokens for ${t}`,{userId:e.userId,email:e.email})}catch(n){throw c.error(`[KeychainManager] Failed to save tokens: ${n}`),new I(`Failed to save tokens: ${n}`)}}async deleteTokens(e="production"){try{let t=await k.deletePassword(this.serviceName,this.getTokenAccount(e));return t&&c.info(`[KeychainManager] Deleted tokens for ${e}`),t}catch(t){return c.error(`[KeychainManager] Failed to delete tokens: ${t}`),!1}}isTokenExpired(e){return Date.now()>=e.expiresAt-3e5}async getSessionKey(e,t){let n=this.sessionKeyCache.get(e);if(n)return n;if(!t||t.length===0)return null;let s=await this.getDeviceId(),i=t.find(l=>l.deviceId===s);if(!i)return c.warn(`[KeychainManager] Device ${s} not found in encryptedKeys`),null;let o=await this.getDevicePrivateKey(),a=b.decryptSessionKey(i,o);return this.sessionKeyCache.set(e,a),c.info(`[KeychainManager] Decrypted and cached session key for ${e}`),a}createSessionKey(e){let t=b.generateSessionKey(),n=e.map(s=>{let i=b.encryptSessionKey(t,s.publicKey);return{deviceId:s.deviceId,encryptedKey:i.encryptedKey,ephemeralPublicKey:i.ephemeralPublicKey}});return c.info(`[KeychainManager] Created session key for ${e.length} devices`),{sessionKey:t,encryptedKeys:n}}cacheSessionKey(e,t){this.sessionKeyCache.set(e,t)}clearSessionKey(e){this.sessionKeyCache.delete(e)}clearAllSessionKeys(){this.sessionKeyCache.clear()}getIsRegistered(){return this.isRegistered}setIsRegistered(e){this.isRegistered=e}getDeviceName(){return Q.hostname()||"CLI Client"}getDevicePlatform(){let e=Q.platform();return e==="darwin"?"MACOS":e==="linux"?"LINUX":e==="win32"?"WINDOWS":"CLI"}async clearAllData(){await this.deleteDeviceIdentity(),await this.deleteTokens("development"),await this.deleteTokens("production"),this.sessionKeyCache.clear(),this.isRegistered=!1,c.info("[KeychainManager] Cleared all data")}},g=K.getInstance()});var ke={};me(ke,{KeychainError:()=>I,KeychainManager:()=>K,keychainManager:()=>g});var U=x(()=>{"use strict";Ie()});var at={};me(at,{AgentType:()=>De,AppSyncClient:()=>W,AuthService:()=>M,CryptoError:()=>C,CryptoService:()=>N,DeliveryStatus:()=>Ce,ENCRYPTION_VERSION:()=>te,EventSource:()=>se,EventType:()=>Ae,KeychainError:()=>I,KeychainManager:()=>K,Logger:()=>P,SessionStatus:()=>ie,authService:()=>T,createLogger:()=>ne,cryptoService:()=>b,getConfig:()=>y,getEnvironment:()=>h,keychainManager:()=>g,loadConfig:()=>Y,logger:()=>c,mutations:()=>E,normalizeSnapshot:()=>ue,parseInteractivePrompt:()=>Oe,prepareSessionEncryption:()=>ee,queries:()=>$,resumeOrCreateSession:()=>ge,runAuthCli:()=>Z,subscriptions:()=>V});module.exports=He(at);U();z();var oe=f(require("ws")),ae=require("uuid");O();H();U();var Te=f(require("dns")),xe=f(require("fs"));if(je())try{Te.setDefaultResultOrder("ipv4first")}catch{}function je(){if(process.platform!=="linux")return!1;try{let r=xe.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(r)}catch{return!1}}async function L(r,e,t){try{return await fetch(r,e)}catch(n){let s=n?.cause?.code,i=n?.cause?.message,o=s||i||n?.message||"unknown",a=Je(s),l=t?`${t}: `:"",p=`Node ${process.version} on ${process.platform}`,m=[`${l}Cannot reach ${r}`,` Underlying error: ${o}`];a&&m.push(` Suggested fix: ${a}`),m.push(` Platform: ${p}`);let u=new Error(m.join(`
3
- `));throw u.cause=n,u}}function Je(r){if(!r)return null;switch(r){case"ENOTFOUND":case"EAI_AGAIN":return'DNS resolution failed. On WSL Ubuntu, check /etc/resolv.conf, or try running with NODE_OPTIONS="--dns-result-order=ipv4first".';case"ETIMEDOUT":case"ECONNREFUSED":case"ECONNRESET":case"EHOSTUNREACH":case"ENETUNREACH":return`Network unreachable. On WSL Ubuntu, try NODE_OPTIONS="--dns-result-order=ipv4first" (WSL's IPv6 is often broken). If behind a corporate proxy, set HTTPS_PROXY.`;case"CERT_HAS_EXPIRED":case"CERT_NOT_YET_VALID":return"TLS certificate time error \u2014 likely system clock drift. On WSL, run `sudo hwclock -s`, or shut down WSL from PowerShell with `wsl --shutdown` and restart.";case"UNABLE_TO_GET_ISSUER_CERT_LOCALLY":case"SELF_SIGNED_CERT_IN_CHAIN":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"DEPTH_ZERO_SELF_SIGNED_CERT":return"Corporate HTTPS proxy detected \u2014 the TLS cert is not trusted by Node. Set NODE_EXTRA_CA_CERTS=/path/to/corporate-ca.pem, or configure HTTPS_PROXY if a proxy is required.";default:return null}}var $={getSession:`
1
+ "use strict";var _e=Object.create;var J=Object.defineProperty;var Me=Object.getOwnPropertyDescriptor;var Be=Object.getOwnPropertyNames;var Fe=Object.getPrototypeOf,qe=Object.prototype.hasOwnProperty;var x=(r,e)=>()=>(r&&(e=r(r=0)),e);var me=(r,e)=>{for(var t in e)J(r,t,{get:e[t],enumerable:!0})},ye=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Be(e))!qe.call(r,s)&&s!==t&&J(r,s,{get:()=>e[s],enumerable:!(n=Me(e,s))||n.enumerable});return r};var f=(r,e,t)=>(t=r!=null?_e(Fe(r)):{},ye(e||!r||!r.__esModule?J(t,"default",{value:r,enumerable:!0}):t,r)),He=r=>ye(J({},"__esModule",{value:!0}),r);var v,C,te,Ve,N,b,fe=x(()=>{"use strict";v=f(require("crypto")),C=class extends Error{constructor(e){super(e),this.name="CryptoError"}},te=1,Ve="CodeVibe E2E v1",N=class r{constructor(){}static getInstance(){return r.instance||(r.instance=new r),r.instance}generateKeyPair(){let e=v.createECDH("prime256v1");e.generateKeys();let n=e.getPublicKey().subarray(1).toString("base64");return{privateKey:e.getPrivateKey().toString("base64"),publicKey:n}}generateSessionKey(){return v.randomBytes(32).toString("base64")}deriveSharedKey(e,t){try{let n=v.createECDH("prime256v1"),s=Buffer.from(e,"base64");n.setPrivateKey(s);let i=Buffer.concat([Buffer.from([4]),Buffer.from(t,"base64")]),o=n.computeSecret(i),a=v.hkdfSync("sha256",o,Buffer.alloc(0),Buffer.from(Ve,"utf8"),32);return Buffer.from(a)}catch(n){throw new C(`Failed to derive shared key: ${n}`)}}encryptSessionKey(e,t){let n=this.generateKeyPair(),s=this.deriveSharedKey(n.privateKey,t),i=Buffer.from(e,"base64");return{encryptedKey:this.encrypt(i,s).toString("base64"),ephemeralPublicKey:n.publicKey}}decryptSessionKey(e,t){let n=this.deriveSharedKey(t,e.ephemeralPublicKey),s=Buffer.from(e.encryptedKey,"base64");return this.decrypt(s,n).toString("base64")}encryptContent(e,t){let n=Buffer.from(t,"base64"),s=Buffer.from(e,"utf8");return this.encrypt(s,n).toString("base64")}decryptContent(e,t){let n=Buffer.from(t,"base64"),s=Buffer.from(e,"base64");return this.decrypt(s,n).toString("utf8")}encryptMetadata(e,t){let n=JSON.stringify(e);return this.encryptContent(n,t)}decryptMetadata(e,t){let n=this.decryptContent(e,t);return JSON.parse(n)}encryptData(e,t){let n=Buffer.from(t,"base64");return this.encrypt(e,n)}decryptData(e,t){let n=Buffer.from(t,"base64");return this.decrypt(e,n)}encrypt(e,t){let n=v.randomBytes(12),s=v.createCipheriv("aes-256-gcm",t,n),i=Buffer.concat([s.update(e),s.final()]),o=s.getAuthTag();return Buffer.concat([n,i,o])}decrypt(e,t){let n=e.subarray(0,12),s=e.subarray(e.length-16),i=e.subarray(12,e.length-16),o=v.createDecipheriv("aes-256-gcm",t,n);o.setAuthTag(s);try{return Buffer.concat([o.update(i),o.final()])}catch{throw new C("Decryption failed: Invalid ciphertext or authentication tag")}}serializePrivateKey(e){return e}deserializePrivateKey(e){return e}},b=N.getInstance()});var z=x(()=>{"use strict";fe()});function h(){let r=process.env.ENVIRONMENT;return r==="development"||r==="production"?r:"production"}function Y(r){let e=r||h();return G={...D[e],aws:{...D[e].aws,region:process.env.AWS_REGION||D[e].aws.region,appsyncUrl:process.env.APPSYNC_URL||D[e].aws.appsyncUrl,cognitoUserPoolId:process.env.COGNITO_USER_POOL_ID||D[e].aws.cognitoUserPoolId,cognitoClientId:process.env.COGNITO_CLIENT_ID||D[e].aws.cognitoClientId,cognitoDomain:process.env.COGNITO_DOMAIN||D[e].aws.cognitoDomain}},he=!0,G}function y(){return(!he||!G)&&Y(),G}var F,q,D,G,he,ve=x(()=>{"use strict";F=f(require("os")),q=f(require("path")),D={development:{environment:"development",aws:{region:"us-east-1",appsyncUrl:"https://te6rjr37sbfpjc4fiunmb2tgy4.appsync-api.us-east-1.amazonaws.com/graphql",cognitoUserPoolId:"us-east-1_yVwWDPvvJ",cognitoClientId:"e9r5apv6v5uui3l928r2ris0r",cognitoDomain:"codevibe-development.auth.us-east-1.amazoncognito.com"},keychain:{serviceName:"ai.quantiya.app.codevibe"},server:{port:3456,host:"127.0.0.1",dynamicPort:!0},claude:{command:"claude",defaultTimeout:6e4},codex:{command:"codex",defaultTimeout:6e4,sessionsDir:q.default.join(F.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:q.default.join(F.default.homedir(),".gemini","tmp")}},production:{environment:"production",aws:{region:"us-east-1",appsyncUrl:"https://jwhyxq4sgrgcdosewp5k4ns5ca.appsync-api.us-east-1.amazonaws.com/graphql",cognitoUserPoolId:"us-east-1_mNRO0j5og",cognitoClientId:"5p04dbc9ojptc5r8n7605fg78f",cognitoDomain:"codevibe-production.auth.us-east-1.amazoncognito.com"},keychain:{serviceName:"ai.quantiya.app.codevibe"},server:{port:3456,host:"127.0.0.1",dynamicPort:!0},claude:{command:"claude",defaultTimeout:6e4},codex:{command:"codex",defaultTimeout:6e4,sessionsDir:q.default.join(F.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:q.default.join(F.default.homedir(),".gemini","tmp")}}},G=null,he=!1});var O=x(()=>{"use strict";ve()});function We(r,e){if(e instanceof Error){let t={name:e.name,message:e.message};e.stack&&(t.stack=e.stack);for(let n of Object.keys(e))n in t||(t[n]=e[n]);return t}return e}function ne(r){return new P(r)}var R,X,be,Se,P,c,we=x(()=>{"use strict";R=f(require("fs")),X=f(require("path")),be=f(require("os")),Se={debug:0,info:1,warn:2,error:3};P=class{constructor(e){this.name=e.name,this.logFile=e.logFile,this.level=e.level||"info",this.enableConsole=e.console??!1,this.logFile&&this.ensureLogDir()}ensureLogDir(){if(this.logFile){let e=X.dirname(this.logFile);R.existsSync(e)||R.mkdirSync(e,{recursive:!0})}}shouldLog(e){return Se[e]>=Se[this.level]}formatMessage(e,t,n){let s=new Date().toISOString(),i=e.toUpperCase().padEnd(5),o=`[${s}] [${i}] [${this.name}] ${t}`;return n!==void 0&&(n instanceof Error?(o+=` ${n.name}: ${n.message}`,n.stack&&(o+=`
2
+ ${n.stack}`)):typeof n=="object"?o+=` ${JSON.stringify(n,We)}`:o+=` ${n}`),o}log(e,t,n){if(!this.shouldLog(e))return;let s=this.formatMessage(e,t,n);if(this.logFile)try{R.appendFileSync(this.logFile,s+`
3
+ `)}catch{}if(this.enableConsole)switch(e){case"error":console.error(s);break;case"warn":console.warn(s);break;default:console.log(s)}}debug(e,t){this.log("debug",e,t)}info(e,t){this.log("info",e,t)}warn(e,t){this.log("warn",e,t)}error(e,t){this.log("error",e,t)}setLevel(e){this.level=e}};c=new P({name:"codevibe-core",logFile:X.join(be.tmpdir(),"codevibe-core.log"),level:"info"})});var H=x(()=>{"use strict";we()});var Q,Ee,I,k,re,je,K,g,ke=x(()=>{"use strict";Q=f(require("os")),Ee=require("uuid"),I=f(require("keytar"));z();O();H();k=class extends Error{constructor(e){super(e),this.name="KeychainError"}},re="device-identity",je="tokens-",K=class r{constructor(){this.deviceIdentity=null;this.sessionKeyCache=new Map;this.isRegistered=!1;this._serviceName=null}get serviceName(){return this._serviceName||(this._serviceName=y().keychain.serviceName),this._serviceName}static getInstance(){return r.instance||(r.instance=new r),r.instance}async getDeviceIdentity(){if(this.deviceIdentity)return this.deviceIdentity;try{let e=await I.getPassword(this.serviceName,re);return e?(this.deviceIdentity=JSON.parse(e),c.info(`[KeychainManager] Loaded device identity: ${this.deviceIdentity.deviceId}`),this.deviceIdentity):null}catch(e){return c.error(`[KeychainManager] Failed to load device identity: ${e}`),null}}async setDeviceIdentity(e){try{await I.setPassword(this.serviceName,re,JSON.stringify(e)),this.deviceIdentity=e,c.info(`[KeychainManager] Saved device identity: ${e.deviceId}`)}catch(t){throw c.error(`[KeychainManager] Failed to save device identity: ${t}`),new k(`Failed to save device identity: ${t}`)}}async getOrCreateDeviceIdentity(){let e=await this.getDeviceIdentity();if(e)return e;let t=b.generateKeyPair();return e={deviceId:(0,Ee.v4)().toUpperCase(),privateKey:t.privateKey,publicKey:t.publicKey,createdAt:new Date().toISOString()},await this.setDeviceIdentity(e),c.info(`[KeychainManager] Generated new device identity: ${e.deviceId}`),e}async getDeviceId(){return(await this.getOrCreateDeviceIdentity()).deviceId}async getDevicePublicKey(){return(await this.getOrCreateDeviceIdentity()).publicKey}async getDevicePrivateKey(){return(await this.getOrCreateDeviceIdentity()).privateKey}async hasDeviceIdentity(){return await this.getDeviceIdentity()!==null}async deleteDeviceIdentity(){try{await I.deletePassword(this.serviceName,re),this.deviceIdentity=null,this.sessionKeyCache.clear(),this.isRegistered=!1,c.info("[KeychainManager] Deleted device identity")}catch(e){throw c.error(`[KeychainManager] Failed to delete device identity: ${e}`),new k(`Failed to delete device identity: ${e}`)}}getTokenAccount(e){return`${je}${e}`}async getTokens(e="production"){try{let t=await I.getPassword(this.serviceName,this.getTokenAccount(e));if(!t)return null;let n=JSON.parse(t);return c.debug(`[KeychainManager] Loaded tokens for ${e}`),n}catch(t){return c.error(`[KeychainManager] Failed to load tokens: ${t}`),null}}async setTokens(e,t="production"){try{await I.setPassword(this.serviceName,this.getTokenAccount(t),JSON.stringify(e)),c.info(`[KeychainManager] Saved tokens for ${t}`,{userId:e.userId,email:e.email})}catch(n){throw c.error(`[KeychainManager] Failed to save tokens: ${n}`),new k(`Failed to save tokens: ${n}`)}}async deleteTokens(e="production"){try{let t=await I.deletePassword(this.serviceName,this.getTokenAccount(e));return t&&c.info(`[KeychainManager] Deleted tokens for ${e}`),t}catch(t){return c.error(`[KeychainManager] Failed to delete tokens: ${t}`),!1}}isTokenExpired(e){return Date.now()>=e.expiresAt-3e5}async getSessionKey(e,t){let n=this.sessionKeyCache.get(e);if(n)return n;if(!t||t.length===0)return null;let s=await this.getDeviceId(),i=t.find(p=>p.deviceId===s);if(!i)return c.warn(`[KeychainManager] Device ${s} not found in encryptedKeys`),null;let o=await this.getDevicePrivateKey(),a=b.decryptSessionKey(i,o);return this.sessionKeyCache.set(e,a),c.info(`[KeychainManager] Decrypted and cached session key for ${e}`),a}createSessionKey(e){let t=b.generateSessionKey(),n=e.map(s=>{let i=b.encryptSessionKey(t,s.publicKey);return{deviceId:s.deviceId,encryptedKey:i.encryptedKey,ephemeralPublicKey:i.ephemeralPublicKey}});return c.info(`[KeychainManager] Created session key for ${e.length} devices`),{sessionKey:t,encryptedKeys:n}}cacheSessionKey(e,t){this.sessionKeyCache.set(e,t)}clearSessionKey(e){this.sessionKeyCache.delete(e)}clearAllSessionKeys(){this.sessionKeyCache.clear()}getIsRegistered(){return this.isRegistered}setIsRegistered(e){this.isRegistered=e}getDeviceName(){return Q.hostname()||"CLI Client"}getDevicePlatform(){let e=Q.platform();return e==="darwin"?"MACOS":e==="linux"?"LINUX":e==="win32"?"WINDOWS":"CLI"}async clearAllData(){await this.deleteDeviceIdentity(),await this.deleteTokens("development"),await this.deleteTokens("production"),this.sessionKeyCache.clear(),this.isRegistered=!1,c.info("[KeychainManager] Cleared all data")}},g=K.getInstance()});var Ie={};me(Ie,{KeychainError:()=>k,KeychainManager:()=>K,keychainManager:()=>g});var U=x(()=>{"use strict";ke()});var ct={};me(ct,{AgentType:()=>De,AppSyncClient:()=>W,AuthService:()=>M,CryptoError:()=>C,CryptoService:()=>N,DeliveryStatus:()=>Ce,ENCRYPTION_VERSION:()=>te,EventSource:()=>se,EventType:()=>Ae,KeychainError:()=>k,KeychainManager:()=>K,Logger:()=>P,SessionStatus:()=>ie,authService:()=>T,createLogger:()=>ne,cryptoService:()=>b,getConfig:()=>y,getEnvironment:()=>h,keychainManager:()=>g,loadConfig:()=>Y,logger:()=>c,mutations:()=>E,normalizeSnapshot:()=>ue,parseInteractivePrompt:()=>Oe,prepareSessionEncryption:()=>ee,queries:()=>$,resumeOrCreateSession:()=>ge,runAuthCli:()=>Z,subscriptions:()=>V});module.exports=He(ct);U();z();var oe=f(require("ws")),ae=require("uuid");O();H();U();var Te=f(require("dns")),xe=f(require("fs"));if(Je())try{Te.setDefaultResultOrder("ipv4first")}catch{}function Je(){if(process.platform!=="linux")return!1;try{let r=xe.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(r)}catch{return!1}}async function L(r,e,t){try{return await fetch(r,e)}catch(n){let s=n?.cause?.code,i=n?.cause?.message,o=s||i||n?.message||"unknown",a=ze(s),p=t?`${t}: `:"",l=`Node ${process.version} on ${process.platform}`,m=[`${p}Cannot reach ${r}`,` Underlying error: ${o}`];a&&m.push(` Suggested fix: ${a}`),m.push(` Platform: ${l}`);let u=new Error(m.join(`
4
+ `));throw u.cause=n,u}}function ze(r){if(!r)return null;switch(r){case"ENOTFOUND":case"EAI_AGAIN":return'DNS resolution failed. On WSL Ubuntu, check /etc/resolv.conf, or try running with NODE_OPTIONS="--dns-result-order=ipv4first".';case"ETIMEDOUT":case"ECONNREFUSED":case"ECONNRESET":case"EHOSTUNREACH":case"ENETUNREACH":return`Network unreachable. On WSL Ubuntu, try NODE_OPTIONS="--dns-result-order=ipv4first" (WSL's IPv6 is often broken). If behind a corporate proxy, set HTTPS_PROXY.`;case"CERT_HAS_EXPIRED":case"CERT_NOT_YET_VALID":return"TLS certificate time error \u2014 likely system clock drift. On WSL, run `sudo hwclock -s`, or shut down WSL from PowerShell with `wsl --shutdown` and restart.";case"UNABLE_TO_GET_ISSUER_CERT_LOCALLY":case"SELF_SIGNED_CERT_IN_CHAIN":case"UNABLE_TO_VERIFY_LEAF_SIGNATURE":case"DEPTH_ZERO_SELF_SIGNED_CERT":return"Corporate HTTPS proxy detected \u2014 the TLS cert is not trusted by Node. Set NODE_EXTRA_CA_CERTS=/path/to/corporate-ca.pem, or configure HTTPS_PROXY if a proxy is required.";default:return null}}var $={getSession:`
4
5
  query GetSession($sessionId: ID!) {
5
6
  getSession(sessionId: $sessionId) {
6
7
  sessionId
@@ -163,7 +164,7 @@
163
164
  isEncrypted
164
165
  }
165
166
  }
166
- `};var Ae=(a=>(a.USER_PROMPT="USER_PROMPT",a.ASSISTANT_RESPONSE="ASSISTANT_RESPONSE",a.TOOL_USE="TOOL_USE",a.NOTIFICATION="NOTIFICATION",a.INTERACTIVE_PROMPT="INTERACTIVE_PROMPT",a.PROMPT_RESPONSE="PROMPT_RESPONSE",a.REASONING="REASONING",a))(Ae||{}),se=(t=>(t.DESKTOP="DESKTOP",t.MOBILE="MOBILE",t))(se||{}),Ce=(n=>(n.SENT="SENT",n.DELIVERED="DELIVERED",n.EXECUTED="EXECUTED",n))(Ce||{});var ie=(n=>(n.ACTIVE="ACTIVE",n.INACTIVE="INACTIVE",n.PAUSED="PAUSED",n))(ie||{}),De=(n=>(n.CLAUDE="CLAUDE",n.GEMINI="GEMINI",n.CODEX="CODEX",n))(De||{});var _={urgentMaxAttempts:10,baseDelayMs:1e3,maxDelayMs:6e4,backoffMultiplier:2,persistentDelayMs:300*1e3},W=class{constructor(){this.authenticated=!1;this.currentUserId=null;this.currentEmail=null;this.tokens=null;this.activeSubscriptions=new Map;this.heartbeatTimers=new Map;this.environment=h(),c.info("[AppSyncClient] Initialized",{environment:this.environment})}getCurrentUserId(){if(!this.currentUserId)throw new Error("Not authenticated. Call authenticateWithStoredTokens() first.");return this.currentUserId}getCurrentUserEmail(){return this.currentEmail}async authenticateWithStoredTokens(){try{let e=await g.getTokens(this.environment);if(!e)return c.debug("[AppSyncClient] No stored tokens found"),!1;if(c.info("[AppSyncClient] Found stored OAuth tokens",{userId:e.userId,email:e.email,expired:g.isTokenExpired(e)}),g.isTokenExpired(e)){if(c.info("[AppSyncClient] Tokens expired, attempting refresh..."),!await this.refreshTokens(e))return c.warn("[AppSyncClient] Token refresh failed"),!1}else this.tokens=e;return this.currentUserId=this.tokens.userId,this.currentEmail=this.tokens.email,this.authenticated=!0,c.info("[AppSyncClient] Authenticated successfully",{userId:this.currentUserId,email:this.currentEmail}),!0}catch(e){return c.error("[AppSyncClient] Authentication failed:",e),!1}}async refreshTokens(e){try{let t=y(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,s=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e.refreshToken}),i=await L(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},"Token refresh");if(!i.ok)return c.error("[AppSyncClient] Token refresh failed",{status:i.status}),!1;let o=await i.json(),a={...e,accessToken:o.access_token,idToken:o.id_token,expiresAt:Date.now()+o.expires_in*1e3};return await g.setTokens(a,this.environment),this.tokens=a,c.info("[AppSyncClient] Tokens refreshed",{expiresAt:new Date(a.expiresAt).toISOString()}),!0}catch(t){return c.error("[AppSyncClient] Token refresh error:",t),!1}}isAuthenticated(){return this.authenticated}signOut(){this.authenticated=!1,this.tokens=null,this.currentUserId=null,this.currentEmail=null,this.cleanupSubscriptions(),c.info("[AppSyncClient] Signed out")}async graphqlRequest(e,t,n=!1){let s=y();if(!this.tokens?.idToken)throw new Error('Not authenticated. Run "codevibe login" first.');let i={"Content-Type":"application/json",Authorization:this.tokens.idToken},o=await L(s.aws.appsyncUrl,{method:"POST",headers:i,body:JSON.stringify({query:e,variables:t})},"AppSync GraphQL request"),a=await o.json();if(o.status===401&&!n&&this.tokens){if(c.info("[AppSyncClient] 401 Unauthorized, refreshing token..."),await this.refreshTokens(this.tokens))return this.graphqlRequest(e,t,!0);throw new Error("Token expired and refresh failed")}if(!o.ok)throw new Error(`GraphQL request failed: ${o.status}`);if(a.errors?.length)throw new Error(`GraphQL error: ${a.errors[0].message}`);return a}async createSession(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},n=await this.graphqlRequest(E.createSession,{input:t});return c.info("[AppSyncClient] Session created",{sessionId:n.data.createSession.sessionId}),n.data.createSession}async updateSession(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},n=await this.graphqlRequest(E.updateSession,{input:t});return c.debug("[AppSyncClient] Session updated",{sessionId:n.data.updateSession.sessionId}),n.data.updateSession}async getSession(e){return(await this.graphqlRequest($.getSession,{sessionId:e})).data.getSession}async createEvent(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},n=await this.graphqlRequest(E.createEvent,{input:t});return c.debug("[AppSyncClient] Event created",{eventId:n.data.createEvent.eventId,type:n.data.createEvent.type}),n.data.createEvent}async updateEventStatus(e){return(await this.graphqlRequest(E.updateEventStatus,{input:e})).data.updateEventStatus}async listEvents(e,t,n){return(await this.graphqlRequest($.listEvents,{sessionId:e,source:t,limit:n})).data.listEvents.items}async listUserDeviceKeys(){return(await this.graphqlRequest($.listUserDeviceKeys,{})).data.listUserDeviceKeys||[]}async registerDeviceKey(e,t,n,s){let i={deviceId:e,publicKey:t,platform:n,deviceName:s};await this.graphqlRequest(E.registerDeviceKey,{input:i}),c.info("[AppSyncClient] Device key registered",{deviceId:e,platform:n})}async getAttachmentDownloadUrl(e){return(await this.graphqlRequest(E.getAttachmentDownloadUrl,{s3Key:e})).data.getAttachmentDownloadUrl}subscribeToEvents(e,t,n){c.info("[AppSyncClient] Subscribing to events",{sessionId:e});let s=this.activeSubscriptions.get(e);s&&(this.cleanupSubscriptionState(s),this.activeSubscriptions.delete(e));let i={ws:null,subscriptionId:(0,ae.v4)(),sessionId:e,onEvent:t,onError:n,reconnectAttempts:0,isReconnecting:!1};return this.activeSubscriptions.set(e,i),this.createSubscription(i),()=>{this.cleanupSubscriptionState(i),this.activeSubscriptions.delete(e)}}buildRealtimeUrl(){let e=y(),t=e.aws.appsyncUrl.replace("https://","wss://").replace("appsync-api","appsync-realtime-api"),n={host:new URL(e.aws.appsyncUrl).host};this.tokens?.idToken&&(n.Authorization=this.tokens.idToken);let s=Buffer.from(JSON.stringify(n)).toString("base64"),i=Buffer.from(JSON.stringify({})).toString("base64");return`${t}?header=${s}&payload=${i}`}createSubscription(e){let{sessionId:t,subscriptionId:n,onEvent:s,onError:i}=e;try{let o=this.buildRealtimeUrl(),a=new oe.default(o,["graphql-ws"]);a.on("open",()=>{c.info("[AppSyncClient] WebSocket connected",{sessionId:t}),a.send(JSON.stringify({type:"connection_init"}))}),a.on("message",l=>{try{let p=JSON.parse(l.toString());switch(p.type){case"connection_ack":this.sendSubscriptionStart(a,e);break;case"start_ack":c.info("[AppSyncClient] Subscription started",{sessionId:t}),e.isReconnecting=!1,e.reconnectAttempts=0,this.startHeartbeat(t);break;case"data":this.resetKeepAliveTimer(e);let m=p.payload?.data?.onEventCreated;m&&m.source==="MOBILE"&&s(m);break;case"ka":this.resetKeepAliveTimer(e);break;case"error":let u=p.payload?.errors?.[0]?.message||"Unknown error";this.handleSubscriptionError(e,new Error(u));break}}catch(p){c.error("[AppSyncClient] Failed to parse message",{error:p})}}),a.on("error",l=>{c.error("[AppSyncClient] WebSocket error",{sessionId:t,error:l.message}),this.handleSubscriptionError(e,l)}),a.on("close",(l,p)=>{c.info("[AppSyncClient] WebSocket closed",{sessionId:t,code:l}),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),this.activeSubscriptions.has(t)&&this.handleSubscriptionError(e,new Error(`WebSocket closed: ${l}`))}),e.ws=a,this.resetKeepAliveTimer(e)}catch(o){this.handleSubscriptionError(e,o)}}sendSubscriptionStart(e,t){let n=y(),{sessionId:s,subscriptionId:i}=t,o={host:new URL(n.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:i,type:"start",payload:{data:JSON.stringify({query:V.onEventCreated,variables:{sessionId:s}}),extensions:{authorization:o}}}))}resetKeepAliveTimer(e){e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.keepAliveTimer=setTimeout(()=>{this.handleSubscriptionError(e,new Error("Keep-alive timeout"))},300*1e3)}handleSubscriptionError(e,t){let{sessionId:n,onError:s}=e;if(e.isReconnecting||!this.activeSubscriptions.has(n))return;e.isReconnecting=!0,e.reconnectAttempts++,this.stopHeartbeat(n);let i=e.reconnectAttempts<=_.urgentMaxAttempts,o;if(i?o=Math.min(_.baseDelayMs*Math.pow(_.backoffMultiplier,e.reconnectAttempts-1),_.maxDelayMs):(o=_.persistentDelayMs,e.reconnectAttempts===_.urgentMaxAttempts+1&&c.info("[AppSyncClient] Switching to persistent reconnect (every 5min)",{sessionId:n})),c.info("[AppSyncClient] Scheduling reconnect",{sessionId:n,attempt:e.reconnectAttempts,phase:i?"urgent":"persistent",delayMs:o}),e.ws){try{e.ws.close(1e3)}catch{}e.ws=null}e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.reconnectTimer=setTimeout(async()=>{if(e.isReconnecting=!1,!!this.activeSubscriptions.has(n)){try{let a=await g.getTokens(this.environment);a&&(g.isTokenExpired(a)?await this.refreshTokens(a)&&c.info("[AppSyncClient] Tokens refreshed before reconnect",{sessionId:n}):this.tokens=a)}catch{c.warn("[AppSyncClient] Token refresh failed before reconnect, using existing tokens",{sessionId:n})}e.subscriptionId=(0,ae.v4)(),this.createSubscription(e)}},o)}cleanupSubscriptionState(e){if(e.reconnectTimer&&clearTimeout(e.reconnectTimer),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.ws){try{e.ws.readyState===oe.default.OPEN&&(e.ws.send(JSON.stringify({id:e.subscriptionId,type:"stop"})),e.ws.close(1e3))}catch{}e.ws=null}}startHeartbeat(e,t=120*1e3){this.stopHeartbeat(e),this.sendHeartbeat(e);let n=setInterval(()=>{this.sendHeartbeat(e)},t);this.heartbeatTimers.set(e,n),c.info("[AppSyncClient] Heartbeat started",{sessionId:e,intervalMs:t})}stopHeartbeat(e){let t=this.heartbeatTimers.get(e);t&&(clearInterval(t),this.heartbeatTimers.delete(e),c.info("[AppSyncClient] Heartbeat stopped",{sessionId:e}))}async sendHeartbeat(e){try{await this.updateSession({sessionId:e,lastHeartbeatAt:new Date().toISOString()}),c.debug("[AppSyncClient] Heartbeat sent",{sessionId:e})}catch(t){c.warn("[AppSyncClient] Heartbeat failed",{sessionId:e,error:t})}}cleanupSubscriptions(){this.activeSubscriptions.forEach(e=>{this.cleanupSubscriptionState(e)}),this.activeSubscriptions.clear(),this.heartbeatTimers.forEach(e=>clearInterval(e)),this.heartbeatTimers.clear()}};var Pe=f(require("crypto")),Ke=f(require("fs")),de=f(require("http")),$e=require("child_process");O();U();H();var j=8080,Ne="/callback",ce=`http://localhost:${j}${Ne}`,M=class r{constructor(){}static getInstance(){return r.instance||(r.instance=new r),r.instance}openBrowser(e){console.log(""),console.log("Opening your browser for sign-in..."),console.log("If your browser does not open automatically, visit this URL manually:"),console.log(` ${e}`),console.log("");let t=this.getBrowserCommands();this.tryBrowserCommand(t,e,0)}getBrowserCommands(){let e=process.platform;if(e==="darwin")return[{cmd:"open",fixedArgs:[]}];if(e==="win32")return[{cmd:"cmd",fixedArgs:["/c","start",""]}];let t=[];return this.isRunningInWSL()&&(t.push({cmd:"wslview",fixedArgs:[]}),t.push({cmd:"cmd.exe",fixedArgs:["/c","start",""]}),t.push({cmd:"powershell.exe",fixedArgs:["-NoProfile","-Command","Start-Process"]})),t.push({cmd:"xdg-open",fixedArgs:[]}),t}isRunningInWSL(){if(process.platform!=="linux")return!1;try{let e=Ke.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(e)}catch{return!1}}tryBrowserCommand(e,t,n){if(n>=e.length){c.debug("[AuthService] No browser-opening command succeeded. User must open the sign-in URL manually (printed to stdout above).");return}let s=e[n],i=[...s.fixedArgs,t],o=!1,a=u=>{o||(o=!0,c.debug(`[AuthService] Browser command '${s.cmd}' ${u}; trying next fallback`),this.tryBrowserCommand(e,t,n+1))},l=u=>{o||(o=!0,c.debug(`[AuthService] Browser command '${s.cmd}' ${u}`))},p;try{p=(0,$e.spawn)(s.cmd,i,{detached:!0,stdio:"ignore"})}catch(u){a(`threw synchronously: ${u?.message||u}`);return}p.on("error",u=>{a(`failed to spawn: ${u?.message||u}`)}),p.on("exit",(u,A)=>{u===0?l("exited successfully"):a(A?`terminated by signal ${A}`:`exited with code ${u}`)}),setTimeout(()=>{l("still running after 3s, assuming success")},3e3).unref(),p.unref()}generateState(){return Pe.randomBytes(32).toString("hex")}buildAuthUrl(e){let t=y(),n=new URLSearchParams({client_id:t.aws.cognitoClientId,response_type:"code",scope:"email openid profile",redirect_uri:ce,state:e});return`https://${t.aws.cognitoDomain}/oauth2/authorize?${n.toString()}`}async exchangeCodeForTokens(e){let t=y(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,s=new URLSearchParams({grant_type:"authorization_code",client_id:t.aws.cognitoClientId,code:e,redirect_uri:ce}),i=await L(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},"Token exchange");if(!i.ok){let a=await i.text();throw new Error(`Token exchange failed: ${i.status} ${a}`)}let o=await i.json();return{accessToken:o.access_token,idToken:o.id_token,refreshToken:o.refresh_token,expiresIn:o.expires_in}}decodeJwt(e){let t=e.split(".");if(t.length!==3)throw new Error("Invalid JWT");return JSON.parse(Buffer.from(t[1],"base64").toString("utf-8"))}async refreshTokens(e){let t=y(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,s=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e}),i=await L(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},"Token refresh");if(!i.ok)throw new Error(`Token refresh failed: ${i.status}`);let o=await i.json();return{accessToken:o.access_token,idToken:o.id_token,expiresIn:o.expires_in}}async login(){let e=await g.getTokens(h());if(e&&!g.isTokenExpired(e))return e;let t=this.generateState(),n=this.buildAuthUrl(t);return new Promise((s,i)=>{let o=de.createServer(async(a,l)=>{if(!a.url?.startsWith(Ne)){l.writeHead(404),l.end("Not found");return}try{let p=new URL(a.url,`http://localhost:${j}`),m=p.searchParams.get("code"),u=p.searchParams.get("state"),A=p.searchParams.get("error");if(A)throw new Error(`OAuth error: ${A}`);if(u!==t)throw new Error("State mismatch");if(!m)throw new Error("No authorization code");let S=await this.exchangeCodeForTokens(m),B=this.decodeJwt(S.idToken),w={accessToken:S.accessToken,idToken:S.idToken,refreshToken:S.refreshToken,expiresAt:Date.now()+S.expiresIn*1e3,userId:B.sub,email:B.email||"unknown"};await g.setTokens(w,h()),l.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),l.end(`
167
+ `};var Ae=(a=>(a.USER_PROMPT="USER_PROMPT",a.ASSISTANT_RESPONSE="ASSISTANT_RESPONSE",a.TOOL_USE="TOOL_USE",a.NOTIFICATION="NOTIFICATION",a.INTERACTIVE_PROMPT="INTERACTIVE_PROMPT",a.PROMPT_RESPONSE="PROMPT_RESPONSE",a.REASONING="REASONING",a))(Ae||{}),se=(t=>(t.DESKTOP="DESKTOP",t.MOBILE="MOBILE",t))(se||{}),Ce=(n=>(n.SENT="SENT",n.DELIVERED="DELIVERED",n.EXECUTED="EXECUTED",n))(Ce||{});var ie=(n=>(n.ACTIVE="ACTIVE",n.INACTIVE="INACTIVE",n.PAUSED="PAUSED",n))(ie||{}),De=(n=>(n.CLAUDE="CLAUDE",n.GEMINI="GEMINI",n.CODEX="CODEX",n))(De||{});var _={urgentMaxAttempts:10,baseDelayMs:1e3,maxDelayMs:6e4,backoffMultiplier:2,persistentDelayMs:300*1e3},W=class{constructor(){this.authenticated=!1;this.currentUserId=null;this.currentEmail=null;this.tokens=null;this.activeSubscriptions=new Map;this.heartbeatTimers=new Map;this.environment=h(),c.info("[AppSyncClient] Initialized",{environment:this.environment})}getCurrentUserId(){if(!this.currentUserId)throw new Error("Not authenticated. Call authenticateWithStoredTokens() first.");return this.currentUserId}getCurrentUserEmail(){return this.currentEmail}async authenticateWithStoredTokens(){try{let e=await g.getTokens(this.environment);if(!e)return c.debug("[AppSyncClient] No stored tokens found"),!1;if(c.info("[AppSyncClient] Found stored OAuth tokens",{userId:e.userId,email:e.email,expired:g.isTokenExpired(e)}),g.isTokenExpired(e)){if(c.info("[AppSyncClient] Tokens expired, attempting refresh..."),!await this.refreshTokens(e))return c.warn("[AppSyncClient] Token refresh failed"),!1}else this.tokens=e;return this.currentUserId=this.tokens.userId,this.currentEmail=this.tokens.email,this.authenticated=!0,c.info("[AppSyncClient] Authenticated successfully",{userId:this.currentUserId,email:this.currentEmail}),!0}catch(e){return c.error("[AppSyncClient] Authentication failed:",e),!1}}async refreshTokens(e){try{let t=y(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,s=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e.refreshToken}),i=await L(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},"Token refresh");if(!i.ok)return c.error("[AppSyncClient] Token refresh failed",{status:i.status}),!1;let o=await i.json(),a={...e,accessToken:o.access_token,idToken:o.id_token,expiresAt:Date.now()+o.expires_in*1e3};return await g.setTokens(a,this.environment),this.tokens=a,c.info("[AppSyncClient] Tokens refreshed",{expiresAt:new Date(a.expiresAt).toISOString()}),!0}catch(t){return c.error("[AppSyncClient] Token refresh error:",t),!1}}isAuthenticated(){return this.authenticated}signOut(){this.authenticated=!1,this.tokens=null,this.currentUserId=null,this.currentEmail=null,this.cleanupSubscriptions(),c.info("[AppSyncClient] Signed out")}async graphqlRequest(e,t,n=!1){let s=y();if(!this.tokens?.idToken)throw new Error('Not authenticated. Run "codevibe login" first.');let i={"Content-Type":"application/json",Authorization:this.tokens.idToken},o=await L(s.aws.appsyncUrl,{method:"POST",headers:i,body:JSON.stringify({query:e,variables:t})},"AppSync GraphQL request"),a=await o.json();if(o.status===401&&!n&&this.tokens){if(c.info("[AppSyncClient] 401 Unauthorized, refreshing token..."),await this.refreshTokens(this.tokens))return this.graphqlRequest(e,t,!0);throw new Error("Token expired and refresh failed")}if(!o.ok)throw new Error(`GraphQL request failed: ${o.status}`);if(a.errors?.length)throw new Error(`GraphQL error: ${a.errors[0].message}`);return a}async createSession(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},n=await this.graphqlRequest(E.createSession,{input:t});return c.info("[AppSyncClient] Session created",{sessionId:n.data.createSession.sessionId}),n.data.createSession}async updateSession(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},n=await this.graphqlRequest(E.updateSession,{input:t});return c.debug("[AppSyncClient] Session updated",{sessionId:n.data.updateSession.sessionId}),n.data.updateSession}async getSession(e){return(await this.graphqlRequest($.getSession,{sessionId:e})).data.getSession}async createEvent(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},n=await this.graphqlRequest(E.createEvent,{input:t});return c.debug("[AppSyncClient] Event created",{eventId:n.data.createEvent.eventId,type:n.data.createEvent.type}),n.data.createEvent}async updateEventStatus(e){return(await this.graphqlRequest(E.updateEventStatus,{input:e})).data.updateEventStatus}async listEvents(e,t,n){return(await this.graphqlRequest($.listEvents,{sessionId:e,source:t,limit:n})).data.listEvents.items}async listUserDeviceKeys(){return(await this.graphqlRequest($.listUserDeviceKeys,{})).data.listUserDeviceKeys||[]}async registerDeviceKey(e,t,n,s){let i={deviceId:e,publicKey:t,platform:n,deviceName:s};await this.graphqlRequest(E.registerDeviceKey,{input:i}),c.info("[AppSyncClient] Device key registered",{deviceId:e,platform:n})}async getAttachmentDownloadUrl(e){return(await this.graphqlRequest(E.getAttachmentDownloadUrl,{s3Key:e})).data.getAttachmentDownloadUrl}subscribeToEvents(e,t,n){c.info("[AppSyncClient] Subscribing to events",{sessionId:e});let s=this.activeSubscriptions.get(e);s&&(this.cleanupSubscriptionState(s),this.activeSubscriptions.delete(e));let i={ws:null,subscriptionId:(0,ae.v4)(),sessionId:e,onEvent:t,onError:n,reconnectAttempts:0,isReconnecting:!1};return this.activeSubscriptions.set(e,i),this.createSubscription(i),()=>{this.cleanupSubscriptionState(i),this.activeSubscriptions.delete(e)}}buildRealtimeUrl(){let e=y(),t=e.aws.appsyncUrl.replace("https://","wss://").replace("appsync-api","appsync-realtime-api"),n={host:new URL(e.aws.appsyncUrl).host};this.tokens?.idToken&&(n.Authorization=this.tokens.idToken);let s=Buffer.from(JSON.stringify(n)).toString("base64"),i=Buffer.from(JSON.stringify({})).toString("base64");return`${t}?header=${s}&payload=${i}`}createSubscription(e){let{sessionId:t,subscriptionId:n,onEvent:s,onError:i}=e;try{let o=this.buildRealtimeUrl(),a=new oe.default(o,["graphql-ws"]);a.on("open",()=>{c.info("[AppSyncClient] WebSocket connected",{sessionId:t}),a.send(JSON.stringify({type:"connection_init"}))}),a.on("message",p=>{try{let l=JSON.parse(p.toString());switch(l.type){case"connection_ack":this.sendSubscriptionStart(a,e);break;case"start_ack":c.info("[AppSyncClient] Subscription started",{sessionId:t}),e.isReconnecting=!1,e.reconnectAttempts=0,this.startHeartbeat(t);break;case"data":this.resetKeepAliveTimer(e);let m=l.payload?.data?.onEventCreated;m&&m.source==="MOBILE"&&s(m);break;case"ka":this.resetKeepAliveTimer(e);break;case"error":let u=l.payload?.errors?.[0]?.message||"Unknown error";this.handleSubscriptionError(e,new Error(u));break}}catch(l){c.error("[AppSyncClient] Failed to parse message",{error:l})}}),a.on("error",p=>{c.error("[AppSyncClient] WebSocket error",{sessionId:t,error:p.message}),this.handleSubscriptionError(e,p)}),a.on("close",(p,l)=>{c.info("[AppSyncClient] WebSocket closed",{sessionId:t,code:p}),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),this.activeSubscriptions.has(t)&&this.handleSubscriptionError(e,new Error(`WebSocket closed: ${p}`))}),e.ws=a,this.resetKeepAliveTimer(e)}catch(o){this.handleSubscriptionError(e,o)}}sendSubscriptionStart(e,t){let n=y(),{sessionId:s,subscriptionId:i}=t,o={host:new URL(n.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:i,type:"start",payload:{data:JSON.stringify({query:V.onEventCreated,variables:{sessionId:s}}),extensions:{authorization:o}}}))}resetKeepAliveTimer(e){e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.keepAliveTimer=setTimeout(()=>{this.handleSubscriptionError(e,new Error("Keep-alive timeout"))},300*1e3)}handleSubscriptionError(e,t){let{sessionId:n,onError:s}=e;if(e.isReconnecting||!this.activeSubscriptions.has(n))return;e.isReconnecting=!0,e.reconnectAttempts++,this.stopHeartbeat(n);let i=e.reconnectAttempts<=_.urgentMaxAttempts,o;if(i?o=Math.min(_.baseDelayMs*Math.pow(_.backoffMultiplier,e.reconnectAttempts-1),_.maxDelayMs):(o=_.persistentDelayMs,e.reconnectAttempts===_.urgentMaxAttempts+1&&c.info("[AppSyncClient] Switching to persistent reconnect (every 5min)",{sessionId:n})),c.info("[AppSyncClient] Scheduling reconnect",{sessionId:n,attempt:e.reconnectAttempts,phase:i?"urgent":"persistent",delayMs:o}),e.ws){try{e.ws.close(1e3)}catch{}e.ws=null}e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.reconnectTimer=setTimeout(async()=>{if(e.isReconnecting=!1,!!this.activeSubscriptions.has(n)){try{let a=await g.getTokens(this.environment);a&&(g.isTokenExpired(a)?await this.refreshTokens(a)&&c.info("[AppSyncClient] Tokens refreshed before reconnect",{sessionId:n}):this.tokens=a)}catch{c.warn("[AppSyncClient] Token refresh failed before reconnect, using existing tokens",{sessionId:n})}e.subscriptionId=(0,ae.v4)(),this.createSubscription(e)}},o)}cleanupSubscriptionState(e){if(e.reconnectTimer&&clearTimeout(e.reconnectTimer),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.ws){try{e.ws.readyState===oe.default.OPEN&&(e.ws.send(JSON.stringify({id:e.subscriptionId,type:"stop"})),e.ws.close(1e3))}catch{}e.ws=null}}startHeartbeat(e,t=120*1e3){this.stopHeartbeat(e),this.sendHeartbeat(e);let n=setInterval(()=>{this.sendHeartbeat(e)},t);this.heartbeatTimers.set(e,n),c.info("[AppSyncClient] Heartbeat started",{sessionId:e,intervalMs:t})}stopHeartbeat(e){let t=this.heartbeatTimers.get(e);t&&(clearInterval(t),this.heartbeatTimers.delete(e),c.info("[AppSyncClient] Heartbeat stopped",{sessionId:e}))}async sendHeartbeat(e){try{await this.updateSession({sessionId:e,lastHeartbeatAt:new Date().toISOString()}),c.debug("[AppSyncClient] Heartbeat sent",{sessionId:e})}catch(t){c.warn("[AppSyncClient] Heartbeat failed",{sessionId:e,error:t})}}cleanupSubscriptions(){this.activeSubscriptions.forEach(e=>{this.cleanupSubscriptionState(e)}),this.activeSubscriptions.clear(),this.heartbeatTimers.forEach(e=>clearInterval(e)),this.heartbeatTimers.clear()}};var Pe=f(require("crypto")),Ke=f(require("fs")),de=f(require("http")),$e=require("child_process");O();U();H();var j=8080,Ne="/callback",ce=`http://localhost:${j}${Ne}`,M=class r{constructor(){}static getInstance(){return r.instance||(r.instance=new r),r.instance}openBrowser(e){console.log(""),console.log("Opening your browser for sign-in..."),console.log("If your browser does not open automatically, visit this URL manually:"),console.log(` ${e}`),console.log("");let t=this.getBrowserCommands();this.tryBrowserCommand(t,e,0)}getBrowserCommands(){let e=process.platform;if(e==="darwin")return[{cmd:"open",fixedArgs:[]}];if(e==="win32")return[{cmd:"cmd",fixedArgs:["/c","start",""]}];let t=[];return this.isRunningInWSL()&&(t.push({cmd:"wslview",fixedArgs:[]}),t.push({cmd:"cmd.exe",fixedArgs:["/c","start",""]}),t.push({cmd:"powershell.exe",fixedArgs:["-NoProfile","-Command","Start-Process"]})),t.push({cmd:"xdg-open",fixedArgs:[]}),t}isRunningInWSL(){if(process.platform!=="linux")return!1;try{let e=Ke.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(e)}catch{return!1}}tryBrowserCommand(e,t,n){if(n>=e.length){c.debug("[AuthService] No browser-opening command succeeded. User must open the sign-in URL manually (printed to stdout above).");return}let s=e[n],i=[...s.fixedArgs,t],o=!1,a=u=>{o||(o=!0,c.debug(`[AuthService] Browser command '${s.cmd}' ${u}; trying next fallback`),this.tryBrowserCommand(e,t,n+1))},p=u=>{o||(o=!0,c.debug(`[AuthService] Browser command '${s.cmd}' ${u}`))},l;try{l=(0,$e.spawn)(s.cmd,i,{detached:!0,stdio:"ignore"})}catch(u){a(`threw synchronously: ${u?.message||u}`);return}l.on("error",u=>{a(`failed to spawn: ${u?.message||u}`)}),l.on("exit",(u,A)=>{u===0?p("exited successfully"):a(A?`terminated by signal ${A}`:`exited with code ${u}`)}),setTimeout(()=>{p("still running after 3s, assuming success")},3e3).unref(),l.unref()}generateState(){return Pe.randomBytes(32).toString("hex")}buildAuthUrl(e){let t=y(),n=new URLSearchParams({client_id:t.aws.cognitoClientId,response_type:"code",scope:"email openid profile",redirect_uri:ce,state:e});return`https://${t.aws.cognitoDomain}/oauth2/authorize?${n.toString()}`}async exchangeCodeForTokens(e){let t=y(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,s=new URLSearchParams({grant_type:"authorization_code",client_id:t.aws.cognitoClientId,code:e,redirect_uri:ce}),i=await L(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},"Token exchange");if(!i.ok){let a=await i.text();throw new Error(`Token exchange failed: ${i.status} ${a}`)}let o=await i.json();return{accessToken:o.access_token,idToken:o.id_token,refreshToken:o.refresh_token,expiresIn:o.expires_in}}decodeJwt(e){let t=e.split(".");if(t.length!==3)throw new Error("Invalid JWT");return JSON.parse(Buffer.from(t[1],"base64").toString("utf-8"))}async refreshTokens(e){let t=y(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,s=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e}),i=await L(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},"Token refresh");if(!i.ok)throw new Error(`Token refresh failed: ${i.status}`);let o=await i.json();return{accessToken:o.access_token,idToken:o.id_token,expiresIn:o.expires_in}}async login(){let e=await g.getTokens(h());if(e&&!g.isTokenExpired(e))return e;let t=this.generateState(),n=this.buildAuthUrl(t);return new Promise((s,i)=>{let o=de.createServer(async(a,p)=>{if(!a.url?.startsWith(Ne)){p.writeHead(404),p.end("Not found");return}try{let l=new URL(a.url,`http://localhost:${j}`),m=l.searchParams.get("code"),u=l.searchParams.get("state"),A=l.searchParams.get("error");if(A)throw new Error(`OAuth error: ${A}`);if(u!==t)throw new Error("State mismatch");if(!m)throw new Error("No authorization code");let S=await this.exchangeCodeForTokens(m),B=this.decodeJwt(S.idToken),w={accessToken:S.accessToken,idToken:S.idToken,refreshToken:S.refreshToken,expiresAt:Date.now()+S.expiresIn*1e3,userId:B.sub,email:B.email||"unknown"};await g.setTokens(w,h()),p.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),p.end(`
167
168
  <!DOCTYPE html>
168
169
  <html>
169
170
  <head><title>Success</title></head>
@@ -172,7 +173,7 @@
172
173
  <p>You can close this window.</p>
173
174
  </body>
174
175
  </html>
175
- `),setTimeout(()=>{o.close(()=>s(w))},500)}catch(p){let m=String(p?.message||p).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");l.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),l.end(`
176
+ `),setTimeout(()=>{o.close(()=>s(w))},500)}catch(l){let m=String(l?.message||l).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");p.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),p.end(`
176
177
  <!DOCTYPE html>
177
178
  <html>
178
179
  <head><title>Error</title></head>
@@ -182,7 +183,7 @@
182
183
  <p style="text-align: center; color: #71717a; margin-top: 24px;">You can close this window and try again in your terminal.</p>
183
184
  </body>
184
185
  </html>
185
- `),setTimeout(()=>{o.close(()=>i(p))},500)}});o.on("error",a=>{a.code==="EADDRINUSE"?i(new Error(`Port ${j} is in use`)):i(a)}),o.listen(j,"localhost",()=>{c.info("[AuthService] Callback server started"),this.openBrowser(n)}),setTimeout(()=>{o.close(()=>i(new Error("Login timeout")))},120*1e3)})}async logout(){let e=y(),t=await g.deleteTokens(h());return t&&new Promise(n=>{let s=de.createServer((i,o)=>{i.url?.startsWith("/signout")?(o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(`
186
+ `),setTimeout(()=>{o.close(()=>i(l))},500)}});o.on("error",a=>{a.code==="EADDRINUSE"?i(new Error(`Port ${j} is in use`)):i(a)}),o.listen(j,"localhost",()=>{c.info("[AuthService] Callback server started"),this.openBrowser(n)}),setTimeout(()=>{o.close(()=>i(new Error("Login timeout")))},120*1e3)})}async logout(){let e=y(),t=await g.deleteTokens(h());return t&&new Promise(n=>{let s=de.createServer((i,o)=>{i.url?.startsWith("/signout")?(o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(`
186
187
  <!DOCTYPE html>
187
188
  <html>
188
189
  <head><title>Signed Out</title></head>
@@ -191,27 +192,27 @@
191
192
  <p>You can close this window.</p>
192
193
  </body>
193
194
  </html>
194
- `),setTimeout(()=>{s.close(()=>n(!0))},500)):(o.writeHead(404),o.end("Not found"))});s.on("error",()=>{n(!0)}),s.listen(j,"localhost",()=>{let i=`https://${e.aws.cognitoDomain}/logout?client_id=${e.aws.cognitoClientId}&logout_uri=${encodeURIComponent(ce.replace("/callback","/signout"))}`;this.openBrowser(i)}),setTimeout(()=>{s.close(()=>n(!0))},30*1e3)})}async getStatus(){let e=await g.getTokens(h());return e?{authenticated:!g.isTokenExpired(e),tokens:e}:{authenticated:!1}}},T=M.getInstance();O();var d={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m"};async function ze(){console.log(`${d.cyan}CodeVibe Login${d.reset}
195
+ `),setTimeout(()=>{s.close(()=>n(!0))},500)):(o.writeHead(404),o.end("Not found"))});s.on("error",()=>{n(!0)}),s.listen(j,"localhost",()=>{let i=`https://${e.aws.cognitoDomain}/logout?client_id=${e.aws.cognitoClientId}&logout_uri=${encodeURIComponent(ce.replace("/callback","/signout"))}`;this.openBrowser(i)}),setTimeout(()=>{s.close(()=>n(!0))},30*1e3)})}async getStatus(){let e=await g.getTokens(h());return e?{authenticated:!g.isTokenExpired(e),tokens:e}:{authenticated:!1}}},T=M.getInstance();O();var d={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m"};async function Ge(){console.log(`${d.cyan}CodeVibe Login${d.reset}
195
196
  `);try{let r=await T.getStatus();if(r.authenticated&&r.tokens){console.log(`${d.yellow}Already logged in as: ${r.tokens.email}${d.reset}`),console.log(`Token expires: ${new Date(r.tokens.expiresAt).toLocaleString()}`),console.log(`
196
197
  Run '${d.dim}codevibe logout${d.reset}' to sign out first.`),process.exit(0);return}console.log("Opening browser for authentication..."),console.log(`${d.dim}Waiting for callback...${d.reset}
197
198
  `);let e=await T.login();e&&(console.log(`
198
199
  ${d.green}\u2713 Authentication successful!${d.reset}`),console.log(` User: ${e.email}`),console.log(` User ID: ${e.userId}`),console.log(` Expires: ${new Date(e.expiresAt).toLocaleString()}`)),process.exit(0)}catch(r){console.log(`
199
- ${d.red}\u2717 Authentication failed${d.reset}`),console.log(` Error: ${r.message}`),process.exit(1)}}async function Ge(){console.log(`${d.cyan}CodeVibe Logout${d.reset}
200
+ ${d.red}\u2717 Authentication failed${d.reset}`),console.log(` Error: ${r.message}`),process.exit(1)}}async function Ye(){console.log(`${d.cyan}CodeVibe Logout${d.reset}
200
201
  `);try{let r=await T.getStatus();if(!r.authenticated){console.log(`${d.yellow}Not logged in.${d.reset}`),process.exit(0);return}let e=r.tokens?.email;await T.logout()?(console.log(`${d.green}\u2713 Logged out successfully.${d.reset}`),console.log(` Previous user: ${e}`),console.log(`
201
- ${d.dim}Clearing browser session...${d.reset}`)):console.log(`${d.red}\u2717 Failed to log out.${d.reset}`),process.exit(0)}catch(r){console.log(`${d.red}\u2717 Logout failed: ${r.message}${d.reset}`),process.exit(1)}}async function Ye(){console.log(`${d.cyan}CodeVibe Auth Status${d.reset}
202
+ ${d.dim}Clearing browser session...${d.reset}`)):console.log(`${d.red}\u2717 Failed to log out.${d.reset}`),process.exit(0)}catch(r){console.log(`${d.red}\u2717 Logout failed: ${r.message}${d.reset}`),process.exit(1)}}async function Xe(){console.log(`${d.cyan}CodeVibe Auth Status${d.reset}
202
203
  `);try{let r=await T.getStatus();if(!r.tokens){console.log(`${d.yellow}Not authenticated.${d.reset}`),console.log(`
203
204
  Run '${d.dim}codevibe login${d.reset}' to sign in.`),process.exit(0);return}let e=!r.authenticated;console.log(e?`${d.yellow}\u26A0 Token expired${d.reset}`:`${d.green}\u2713 Authenticated${d.reset}`),console.log(` User: ${r.tokens.email}`),console.log(` User ID: ${r.tokens.userId}`),console.log(` Expires: ${new Date(r.tokens.expiresAt).toLocaleString()}`),e&&console.log(`
204
- ${d.dim}Token will be refreshed automatically.${d.reset}`),process.exit(0)}catch(r){console.log(`${d.red}\u2717 Status check failed: ${r.message}${d.reset}`),process.exit(1)}}async function Xe(){console.log(`${d.cyan}CodeVibe Reset Device${d.reset}
205
+ ${d.dim}Token will be refreshed automatically.${d.reset}`),process.exit(0)}catch(r){console.log(`${d.red}\u2717 Status check failed: ${r.message}${d.reset}`),process.exit(1)}}async function Qe(){console.log(`${d.cyan}CodeVibe Reset Device${d.reset}
205
206
  `),console.log(`${d.red}\u26A0 WARNING: This will delete your device identity.${d.reset}`),console.log(`${d.red} Old encrypted sessions will become inaccessible.${d.reset}
206
- `);let{keychainManager:r}=await Promise.resolve().then(()=>(U(),ke));try{await r.clearAllData(),console.log(`${d.green}\u2713 Device reset complete.${d.reset}`),console.log(` Run '${d.dim}codevibe login${d.reset}' to set up again.`),process.exit(0)}catch(e){console.log(`${d.red}\u2717 Reset failed: ${e.message}${d.reset}`),process.exit(1)}}function Qe(){console.log(`CodeVibe Authentication
207
+ `);let{keychainManager:r}=await Promise.resolve().then(()=>(U(),Ie));try{await r.clearAllData(),console.log(`${d.green}\u2713 Device reset complete.${d.reset}`),console.log(` Run '${d.dim}codevibe login${d.reset}' to set up again.`),process.exit(0)}catch(e){console.log(`${d.red}\u2717 Reset failed: ${e.message}${d.reset}`),process.exit(1)}}function Ze(){console.log(`CodeVibe Authentication
207
208
  `),console.log("Usage:"),console.log(" codevibe login - Sign in via browser"),console.log(" codevibe logout - Sign out"),console.log(" codevibe status - Show auth status"),console.log(" codevibe reset-device - Reset device identity (destructive)"),console.log(`
208
209
  Environment:`),console.log(' Set ENVIRONMENT env var to "development" or "production" (default)'),console.log(" Example: ENVIRONMENT=development codevibe login")}async function Z(r){let e=h();console.log(`${d.dim}Environment: ${e}${d.reset}
209
- `);let n=r.slice(2).filter(s=>!s.startsWith("--"))[0];switch(n){case"login":await ze();break;case"logout":await Ge();break;case"status":await Ye();break;case"reset-device":await Xe();break;default:Qe(),process.exit(n?1:0)}}require.main===module&&Z(process.argv).catch(r=>{console.error("Error:",r),process.exit(1)});O();H();var Ze=/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;function Oe(r){let e=ue(r);if(!e)return null;let t=et(e);if(t)return t;let n=tt(e);return n||null}function ue(r){return r.replace(/\r/g,`
210
- `).replace(Ze,"").replace(/[│┌┐└┘─├┤┬┴┼╌╎╭╮╯╰║═╔╗╚╝╠╣╦╩╬]/g," ").replace(/[ \t]+\n/g,`
210
+ `);let n=r.slice(2).filter(s=>!s.startsWith("--"))[0];switch(n){case"login":await Ge();break;case"logout":await Ye();break;case"status":await Xe();break;case"reset-device":await Qe();break;default:Ze(),process.exit(n?1:0)}}require.main===module&&Z(process.argv).catch(r=>{console.error("Error:",r),process.exit(1)});O();H();var et=/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;function Oe(r){let e=ue(r);if(!e)return null;let t=tt(e);if(t)return t;let n=nt(e);return n||null}function ue(r){return r.replace(/\r/g,`
211
+ `).replace(et,"").replace(/[│┌┐└┘─├┤┬┴┼╌╎╭╮╯╰║═╔╗╚╝╠╣╦╩╬]/g," ").replace(/[ \t]+\n/g,`
211
212
  `).replace(/\n{3,}/g,`
212
213
 
213
- `).trim()}function et(r){let e=r.split(`
214
- `).map(m=>m.trim()),t=nt(e,m=>/\[(?:y\/n|Y\/n|y\/N)\]/.test(m)),n=t>=0?e[t]:null;if(!n)return null;let s=Ue(e,t),i=s.length>0?s.join(`
215
- `):n,o=i.toLowerCase(),a=o.includes("what to change")||o.includes("what should")||o.includes("provide")||o.includes("instructions");return{kind:"yes_no",promptText:i,options:a?[{number:"1",text:"Yes"},{number:"2",text:"No, provide instructions"}]:[{number:"1",text:"Yes"},{number:"2",text:"No"}],submitMap:{1:"y",2:"n"},requiresFollowUpText:a}}function tt(r){let e=r.split(`
216
- `).map(l=>l.trim()),t=rt(e);if(t.length<2)return null;let n=t.map(({line:l})=>Re(l)).filter(l=>!!l),s={};for(let l of n)s[l.number]=l.number;let i=t[0]?.index??-1,o=Ue(e,i-1);return{kind:"numbered",promptText:o.length>0?o.join(`
217
- `):"Select an option",options:n,submitMap:s}}function nt(r,e){for(let t=r.length-1;t>=0;t-=1)if(e(r[t]))return t;return-1}function Re(r){let e=r.match(/^(?:[>›❯▸▶➜➤*●]\s*)?(\d+)\.\s+(.*)$/);return e?{number:e[1],text:e[2]}:null}function rt(r){let e=r.map((n,s)=>({index:s,line:n,parsed:Re(n)})).filter(n=>!!n.parsed);if(e.length===0)return[];let t=[e[e.length-1]];for(let n=e.length-2;n>=0;n-=1){let s=e[n],i=t[0];if(s.index!==i.index-1)break;t.unshift(s)}return t.map(({index:n,line:s})=>({index:n,line:s}))}function Ue(r,e){if(e<0)return[];let t=le(r,e);if(t<0)return[];let{start:n,end:s}=pe(r,t),i=r.slice(n,s+1).filter(Boolean);if(it(i)){let u=st(r,n-1);return u.length>0?u:i}if(n<=1)return i;let o=n-1;if(o=le(r,o),o<0||o===n-1)return i;let{start:a,end:l}=pe(r,o),p=r.slice(a,l+1).filter(Boolean);return p.some(Le)?[...p,...i]:i}function Le(r){return/^(?:would you like to|do you want to|the model would like to|action required|confirm)\b/i.test(r)}function le(r,e){let t=e;for(;t>=0&&!r[t];)t-=1;return t}function pe(r,e){let t=e;for(;t>=0&&r[t];)t-=1;return{start:t+1,end:e}}function st(r,e){let t=[],n=e;for(;n>=0&&t.length<2&&(n=le(r,n),!(n<0));){let{start:i,end:o}=pe(r,n),a=r.slice(i,o+1).filter(Boolean);a.length>0&&t.unshift(a),n=i-1}if(t.length===0)return[];let s=t.findIndex(i=>i.some(Le));return s>=0?t.slice(s).flat():t[t.length-1]}function it(r){return r.length===0?!1:r.filter(ot).length>=Math.max(2,Math.ceil(r.length/2))}function ot(r){return/^\d+\s/.test(r)}z();U();async function ee(r,e,t){try{let n=await e.listUserDeviceKeys();if(n.length===0)return t.info("No device keys found, session will not be encrypted"),null;t.info("Preparing session encryption",{sessionId:r,deviceCount:n.length});let{sessionKey:s,encryptedKeys:i}=g.createSessionKey(n);return t.info("Session encryption prepared",{sessionId:r,deviceCount:i.length}),{sessionKey:s,encryptedKeys:i}}catch(n){return t.warn("Failed to prepare session encryption:",n),null}}async function ge(r,e,t){let{sessionId:n,userId:s,agentType:i,projectPath:o,metadata:a}=r,l=null;try{l=await e.getSession(n)}catch(S){t.warn("Failed to get session (will attempt to create new)",{sessionId:n,error:S})}if(l){t.info("Session exists in backend - reactivating",{sessionId:n,previousStatus:l.status});try{await e.updateSession({sessionId:n,status:"ACTIVE"})}catch(w){t.warn("Failed to reactivate existing session, will continue",{sessionId:n,error:w})}let S=null,B=l.encryptedKeys;if(l.isEncrypted&&B?.length)try{let w=await g.getSessionKey(n,B);w?(S=w,g.cacheSessionKey(n,w),t.info("Session key retrieved for resumed session",{sessionId:n})):t.warn("No encrypted key for this device; proceeding without decryption",{sessionId:n})}catch(w){t.warn("Failed to retrieve session key for resumed session",{sessionId:n,error:w})}return{resumed:!0,sessionKey:S}}let p=await ee(n,e,t),m=o,u=a;p&&(m=b.encryptContent(o,p.sessionKey),u&&Object.keys(u).length>0&&(u={encrypted:b.encryptMetadata(u,p.sessionKey)}),t.info("Session data encrypted",{sessionId:n})),t.info("Creating new session in backend",{sessionId:n,userId:s,agentType:i,isEncrypted:!!p}),await e.createSession({sessionId:n,userId:s,agentType:i,projectPath:m,status:"ACTIVE",metadata:u,isEncrypted:p?!0:void 0,creatorDeviceId:p?await g.getDeviceId():void 0,encryptionVersion:p?1:void 0,encryptedKeys:p?.encryptedKeys});let A=p?.sessionKey||null;return p&&g.cacheSessionKey(n,p.sessionKey),t.info("Session created",{sessionId:n,userId:s,isEncrypted:!!p}),{resumed:!1,sessionKey:A}}0&&(module.exports={AgentType,AppSyncClient,AuthService,CryptoError,CryptoService,DeliveryStatus,ENCRYPTION_VERSION,EventSource,EventType,KeychainError,KeychainManager,Logger,SessionStatus,authService,createLogger,cryptoService,getConfig,getEnvironment,keychainManager,loadConfig,logger,mutations,normalizeSnapshot,parseInteractivePrompt,prepareSessionEncryption,queries,resumeOrCreateSession,runAuthCli,subscriptions});
214
+ `).trim()}function tt(r){let e=r.split(`
215
+ `).map(m=>m.trim()),t=rt(e,m=>/\[(?:y\/n|Y\/n|y\/N)\]/.test(m)),n=t>=0?e[t]:null;if(!n)return null;let s=Ue(e,t),i=s.length>0?s.join(`
216
+ `):n,o=i.toLowerCase(),a=o.includes("what to change")||o.includes("what should")||o.includes("provide")||o.includes("instructions");return{kind:"yes_no",promptText:i,options:a?[{number:"1",text:"Yes"},{number:"2",text:"No, provide instructions"}]:[{number:"1",text:"Yes"},{number:"2",text:"No"}],submitMap:{1:"y",2:"n"},requiresFollowUpText:a}}function nt(r){let e=r.split(`
217
+ `).map(p=>p.trim()),t=st(e);if(t.length<2)return null;let n=t.map(({line:p})=>Re(p)).filter(p=>!!p),s={};for(let p of n)s[p.number]=p.number;let i=t[0]?.index??-1,o=Ue(e,i-1);return{kind:"numbered",promptText:o.length>0?o.join(`
218
+ `):"Select an option",options:n,submitMap:s}}function rt(r,e){for(let t=r.length-1;t>=0;t-=1)if(e(r[t]))return t;return-1}function Re(r){let e=r.match(/^(?:[>›❯▸▶➜➤*●]\s*)?(\d+)\.\s+(.*)$/);return e?{number:e[1],text:e[2]}:null}function st(r){let e=r.map((n,s)=>({index:s,line:n,parsed:Re(n)})).filter(n=>!!n.parsed);if(e.length===0)return[];let t=[e[e.length-1]];for(let n=e.length-2;n>=0;n-=1){let s=e[n],i=t[0];if(s.index!==i.index-1)break;t.unshift(s)}return t.map(({index:n,line:s})=>({index:n,line:s}))}function Ue(r,e){if(e<0)return[];let t=pe(r,e);if(t<0)return[];let{start:n,end:s}=le(r,t),i=r.slice(n,s+1).filter(Boolean);if(ot(i)){let u=it(r,n-1);return u.length>0?u:i}if(n<=1)return i;let o=n-1;if(o=pe(r,o),o<0||o===n-1)return i;let{start:a,end:p}=le(r,o),l=r.slice(a,p+1).filter(Boolean);return l.some(Le)?[...l,...i]:i}function Le(r){return/^(?:would you like to|do you want to|the model would like to|action required|confirm)\b/i.test(r)}function pe(r,e){let t=e;for(;t>=0&&!r[t];)t-=1;return t}function le(r,e){let t=e;for(;t>=0&&r[t];)t-=1;return{start:t+1,end:e}}function it(r,e){let t=[],n=e;for(;n>=0&&t.length<2&&(n=pe(r,n),!(n<0));){let{start:i,end:o}=le(r,n),a=r.slice(i,o+1).filter(Boolean);a.length>0&&t.unshift(a),n=i-1}if(t.length===0)return[];let s=t.findIndex(i=>i.some(Le));return s>=0?t.slice(s).flat():t[t.length-1]}function ot(r){return r.length===0?!1:r.filter(at).length>=Math.max(2,Math.ceil(r.length/2))}function at(r){return/^\d+\s/.test(r)}z();U();async function ee(r,e,t){try{let n=await e.listUserDeviceKeys();if(n.length===0)return t.info("No device keys found, session will not be encrypted"),null;t.info("Preparing session encryption",{sessionId:r,deviceCount:n.length});let{sessionKey:s,encryptedKeys:i}=g.createSessionKey(n);return t.info("Session encryption prepared",{sessionId:r,deviceCount:i.length}),{sessionKey:s,encryptedKeys:i}}catch(n){return t.warn("Failed to prepare session encryption:",n),null}}async function ge(r,e,t){let{sessionId:n,userId:s,agentType:i,projectPath:o,metadata:a}=r,p=null;try{p=await e.getSession(n)}catch(S){t.warn("Failed to get session (will attempt to create new)",{sessionId:n,error:S})}if(p){t.info("Session exists in backend - reactivating",{sessionId:n,previousStatus:p.status});try{await e.updateSession({sessionId:n,status:"ACTIVE"})}catch(w){t.warn("Failed to reactivate existing session, will continue",{sessionId:n,error:w})}let S=null,B=p.encryptedKeys;if(p.isEncrypted&&B?.length)try{let w=await g.getSessionKey(n,B);w?(S=w,g.cacheSessionKey(n,w),t.info("Session key retrieved for resumed session",{sessionId:n})):t.warn("No encrypted key for this device; proceeding without decryption",{sessionId:n})}catch(w){t.warn("Failed to retrieve session key for resumed session",{sessionId:n,error:w})}return{resumed:!0,sessionKey:S}}let l=await ee(n,e,t),m=o,u=a;l&&(m=b.encryptContent(o,l.sessionKey),u&&Object.keys(u).length>0&&(u={encrypted:b.encryptMetadata(u,l.sessionKey)}),t.info("Session data encrypted",{sessionId:n})),t.info("Creating new session in backend",{sessionId:n,userId:s,agentType:i,isEncrypted:!!l}),await e.createSession({sessionId:n,userId:s,agentType:i,projectPath:m,status:"ACTIVE",metadata:u,isEncrypted:l?!0:void 0,creatorDeviceId:l?await g.getDeviceId():void 0,encryptionVersion:l?1:void 0,encryptedKeys:l?.encryptedKeys});let A=l?.sessionKey||null;return l&&g.cacheSessionKey(n,l.sessionKey),t.info("Session created",{sessionId:n,userId:s,isEncrypted:!!l}),{resumed:!1,sessionKey:A}}0&&(module.exports={AgentType,AppSyncClient,AuthService,CryptoError,CryptoService,DeliveryStatus,ENCRYPTION_VERSION,EventSource,EventType,KeychainError,KeychainManager,Logger,SessionStatus,authService,createLogger,cryptoService,getConfig,getEnvironment,keychainManager,loadConfig,logger,mutations,normalizeSnapshot,parseInteractivePrompt,prepareSessionEncryption,queries,resumeOrCreateSession,runAuthCli,subscriptions});
@@ -0,0 +1 @@
1
+ export { KeychainManager, keychainManager, KeychainError } from './keychain-manager';
@@ -0,0 +1,125 @@
1
+ import { DeviceIdentity, TokenData, EncryptedSessionKey } from '../types';
2
+ /**
3
+ * Error class for keychain operations
4
+ */
5
+ export declare class KeychainError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ /**
9
+ * Manages device identity and OAuth tokens using native keychain
10
+ */
11
+ export declare class KeychainManager {
12
+ private static instance;
13
+ private deviceIdentity;
14
+ private sessionKeyCache;
15
+ private isRegistered;
16
+ private _serviceName;
17
+ private constructor();
18
+ /**
19
+ * Get the keychain service name (lazy-loaded from config)
20
+ */
21
+ private get serviceName();
22
+ static getInstance(): KeychainManager;
23
+ /**
24
+ * Get the device identity from keychain
25
+ */
26
+ getDeviceIdentity(): Promise<DeviceIdentity | null>;
27
+ /**
28
+ * Set the device identity in keychain
29
+ */
30
+ setDeviceIdentity(identity: DeviceIdentity): Promise<void>;
31
+ /**
32
+ * Get or create device identity
33
+ */
34
+ getOrCreateDeviceIdentity(): Promise<DeviceIdentity>;
35
+ /**
36
+ * Get device ID (creates identity if needed)
37
+ */
38
+ getDeviceId(): Promise<string>;
39
+ /**
40
+ * Get device public key (creates identity if needed)
41
+ */
42
+ getDevicePublicKey(): Promise<string>;
43
+ /**
44
+ * Get device private key (creates identity if needed)
45
+ */
46
+ getDevicePrivateKey(): Promise<string>;
47
+ /**
48
+ * Check if device identity exists
49
+ */
50
+ hasDeviceIdentity(): Promise<boolean>;
51
+ /**
52
+ * Delete device identity (reset device)
53
+ */
54
+ deleteDeviceIdentity(): Promise<void>;
55
+ /**
56
+ * Get token account name for environment
57
+ */
58
+ private getTokenAccount;
59
+ /**
60
+ * Get OAuth tokens for environment
61
+ */
62
+ getTokens(environment?: string): Promise<TokenData | null>;
63
+ /**
64
+ * Save OAuth tokens for environment
65
+ */
66
+ setTokens(tokens: TokenData, environment?: string): Promise<void>;
67
+ /**
68
+ * Delete OAuth tokens for environment
69
+ */
70
+ deleteTokens(environment?: string): Promise<boolean>;
71
+ /**
72
+ * Check if token is expired
73
+ */
74
+ isTokenExpired(tokens: TokenData): boolean;
75
+ /**
76
+ * Get session key for a session, decrypting from encryptedKeys if needed
77
+ */
78
+ getSessionKey(sessionId: string, encryptedKeys?: EncryptedSessionKey[]): Promise<string | null>;
79
+ /**
80
+ * Generate and encrypt a new session key for all devices
81
+ */
82
+ createSessionKey(devicePublicKeys: Array<{
83
+ deviceId: string;
84
+ publicKey: string;
85
+ }>): {
86
+ sessionKey: string;
87
+ encryptedKeys: EncryptedSessionKey[];
88
+ };
89
+ /**
90
+ * Cache a session key
91
+ */
92
+ cacheSessionKey(sessionId: string, sessionKey: string): void;
93
+ /**
94
+ * Clear cached session key
95
+ */
96
+ clearSessionKey(sessionId: string): void;
97
+ /**
98
+ * Clear all cached session keys
99
+ */
100
+ clearAllSessionKeys(): void;
101
+ /**
102
+ * Get registration status
103
+ */
104
+ getIsRegistered(): boolean;
105
+ /**
106
+ * Set registration status
107
+ */
108
+ setIsRegistered(registered: boolean): void;
109
+ /**
110
+ * Get device name for registration
111
+ */
112
+ getDeviceName(): string;
113
+ /**
114
+ * Get platform for registration
115
+ */
116
+ getDevicePlatform(): string;
117
+ /**
118
+ * Clear all data (device identity + all tokens)
119
+ */
120
+ clearAllData(): Promise<void>;
121
+ }
122
+ /**
123
+ * Export singleton instance
124
+ */
125
+ export declare const keychainManager: KeychainManager;
@@ -0,0 +1 @@
1
+ export { Logger, logger, createLogger } from './logger';
@@ -0,0 +1,35 @@
1
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
2
+ interface LoggerOptions {
3
+ name: string;
4
+ logFile?: string;
5
+ level?: LogLevel;
6
+ console?: boolean;
7
+ }
8
+ /**
9
+ * Simple logger for CodeVibe plugins
10
+ */
11
+ export declare class Logger {
12
+ private name;
13
+ private logFile?;
14
+ private level;
15
+ private enableConsole;
16
+ constructor(options: LoggerOptions);
17
+ private ensureLogDir;
18
+ private shouldLog;
19
+ private formatMessage;
20
+ private log;
21
+ debug(message: string, data?: any): void;
22
+ info(message: string, data?: any): void;
23
+ warn(message: string, data?: any): void;
24
+ error(message: string, data?: any): void;
25
+ setLevel(level: LogLevel): void;
26
+ }
27
+ /**
28
+ * Create a logger with custom options
29
+ */
30
+ export declare function createLogger(options: LoggerOptions): Logger;
31
+ /**
32
+ * Default shared logger instance
33
+ */
34
+ export declare const logger: Logger;
35
+ export {};
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared prompt parser for interactive terminal prompts.
3
+ *
4
+ * Parses terminal snapshots (from tmux capture-pane) to extract
5
+ * interactive prompt options displayed by CLI tools (Gemini, Codex, etc.).
6
+ *
7
+ * Used by multiple plugins to dynamically capture options instead of hardcoding.
8
+ */
9
+ export type PromptKind = 'yes_no' | 'numbered' | 'text';
10
+ export interface InteractivePromptOption {
11
+ number: string;
12
+ text: string;
13
+ }
14
+ export interface ParsedInteractivePrompt {
15
+ kind: PromptKind;
16
+ promptText: string;
17
+ options: InteractivePromptOption[];
18
+ submitMap: Record<string, string>;
19
+ requiresFollowUpText?: boolean;
20
+ }
21
+ /**
22
+ * Parse a terminal snapshot to extract interactive prompt options.
23
+ *
24
+ * Detects two prompt types:
25
+ * - Yes/No prompts: [y/n] patterns
26
+ * - Numbered prompts: "1. Allow once", "2. Allow for this session", etc.
27
+ *
28
+ * Returns null if no prompt is detected.
29
+ */
30
+ export declare function parseInteractivePrompt(snapshot: string): ParsedInteractivePrompt | null;
31
+ /**
32
+ * Strip ANSI escape codes, box-drawing characters, and normalize whitespace
33
+ * from terminal output.
34
+ *
35
+ * Box-drawing characters (│, ┌, ┐, └, ┘, ─, etc.) are used by TUI apps like
36
+ * Gemini CLI to render bordered panels. Stripping them exposes the text content
37
+ * so the parser can match option lines inside boxes.
38
+ */
39
+ export declare function normalizeSnapshot(snapshot: string): string;
@@ -0,0 +1,2 @@
1
+ export { resumeOrCreateSession, prepareSessionEncryption } from './session-resume';
2
+ export type { ResumeOrCreateSessionInput, ResumeOrCreateSessionResult } from './session-resume';
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Centralized session resume/create logic for all CodeVibe plugins.
3
+ *
4
+ * All three plugins (Claude, Codex, Gemini) need the same pattern:
5
+ * 1. Check if session exists in backend (getSession)
6
+ * 2. If exists: reactivate + restore E2E session key from encryptedKeys
7
+ * 3. If not exists: generate encryption keys + create session
8
+ *
9
+ * This module eliminates the duplication across plugins.
10
+ */
11
+ import { AppSyncClient } from '../appsync';
12
+ import { Logger } from '../logger';
13
+ import { AgentType, EncryptedSessionKey } from '../types';
14
+ export interface ResumeOrCreateSessionInput {
15
+ sessionId: string;
16
+ userId: string;
17
+ agentType: AgentType;
18
+ projectPath: string;
19
+ metadata?: Record<string, any>;
20
+ }
21
+ export interface ResumeOrCreateSessionResult {
22
+ /** Whether an existing session was found and reactivated */
23
+ resumed: boolean;
24
+ /** The E2E session key (for encrypting/decrypting events), or null if no encryption */
25
+ sessionKey: string | null;
26
+ }
27
+ /**
28
+ * Prepare E2E encryption for a new session.
29
+ *
30
+ * Generates a random session key and encrypts it for all registered devices.
31
+ * Does NOT cache the session key — callers should cache only after the session
32
+ * is successfully created in the backend.
33
+ *
34
+ * @returns Encryption data or null if no device keys found / error
35
+ */
36
+ export declare function prepareSessionEncryption(sessionId: string, appSyncClient: AppSyncClient, logger: Logger): Promise<{
37
+ sessionKey: string;
38
+ encryptedKeys: EncryptedSessionKey[];
39
+ } | null>;
40
+ /**
41
+ * Resume an existing session or create a new one.
42
+ *
43
+ * Resume path (session exists in backend):
44
+ * - Reactivates session (status → ACTIVE)
45
+ * - Restores E2E session key from encryptedKeys
46
+ *
47
+ * Create path (session does not exist):
48
+ * - Prepares E2E encryption (generates key, encrypts for all devices)
49
+ * - Encrypts projectPath and metadata
50
+ * - Creates session in backend
51
+ * - Caches session key only after successful creation
52
+ *
53
+ * @throws Propagates createSession errors (e.g., SESSION_LIMIT_EXCEEDED)
54
+ */
55
+ export declare function resumeOrCreateSession(input: ResumeOrCreateSessionInput, appSyncClient: AppSyncClient, logger: Logger): Promise<ResumeOrCreateSessionResult>;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Stored OAuth tokens
3
+ */
4
+ export interface TokenData {
5
+ accessToken: string;
6
+ idToken: string;
7
+ refreshToken: string;
8
+ expiresAt: number;
9
+ userId: string;
10
+ email: string;
11
+ }
12
+ /**
13
+ * Environment configuration
14
+ */
15
+ export type Environment = 'development' | 'production';
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Encrypted session key for E2E encryption
3
+ */
4
+ export interface EncryptedSessionKey {
5
+ deviceId: string;
6
+ encryptedKey: string;
7
+ ephemeralPublicKey: string;
8
+ }
9
+ /**
10
+ * Device key stored with backend
11
+ */
12
+ export interface DeviceKey {
13
+ userId: string;
14
+ deviceId: string;
15
+ publicKey: string;
16
+ platform: string;
17
+ deviceName?: string;
18
+ createdAt: string;
19
+ lastUsedAt?: string;
20
+ }
21
+ /**
22
+ * Key pair for ECDH
23
+ */
24
+ export interface KeyPair {
25
+ privateKey: string;
26
+ publicKey: string;
27
+ }
28
+ /**
29
+ * Device identity stored in keychain
30
+ */
31
+ export interface DeviceIdentity {
32
+ deviceId: string;
33
+ privateKey: string;
34
+ publicKey: string;
35
+ createdAt: string;
36
+ }
37
+ /**
38
+ * GraphQL input for registering device key
39
+ */
40
+ export interface RegisterDeviceKeyInput {
41
+ deviceId: string;
42
+ publicKey: string;
43
+ platform: string;
44
+ deviceName?: string;
45
+ }
46
+ /**
47
+ * GraphQL input for granting session key
48
+ */
49
+ export interface GrantSessionKeyInput {
50
+ sessionId: string;
51
+ deviceId: string;
52
+ encryptedKey: string;
53
+ ephemeralPublicKey: string;
54
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Event types matching GraphQL schema
3
+ */
4
+ export declare enum EventType {
5
+ USER_PROMPT = "USER_PROMPT",
6
+ ASSISTANT_RESPONSE = "ASSISTANT_RESPONSE",
7
+ TOOL_USE = "TOOL_USE",
8
+ NOTIFICATION = "NOTIFICATION",
9
+ INTERACTIVE_PROMPT = "INTERACTIVE_PROMPT",
10
+ PROMPT_RESPONSE = "PROMPT_RESPONSE",
11
+ REASONING = "REASONING"
12
+ }
13
+ export declare enum EventSource {
14
+ DESKTOP = "DESKTOP",
15
+ MOBILE = "MOBILE"
16
+ }
17
+ export declare enum DeliveryStatus {
18
+ SENT = "SENT",
19
+ DELIVERED = "DELIVERED",
20
+ EXECUTED = "EXECUTED"
21
+ }
22
+ /**
23
+ * Attachment type (for images/files attached to messages)
24
+ */
25
+ export interface Attachment {
26
+ id: string;
27
+ type: string;
28
+ filename?: string;
29
+ s3Key: string;
30
+ size?: number;
31
+ width?: number;
32
+ height?: number;
33
+ isEncrypted?: boolean;
34
+ }
35
+ /**
36
+ * Event type
37
+ */
38
+ export interface Event {
39
+ eventId: string;
40
+ sessionId: string;
41
+ type: EventType;
42
+ source: EventSource;
43
+ content: string;
44
+ timestamp: string;
45
+ metadata?: Record<string, any>;
46
+ promptId?: string;
47
+ attachments?: Attachment[];
48
+ deliveryStatus?: DeliveryStatus;
49
+ deliveredAt?: string;
50
+ executedAt?: string;
51
+ isEncrypted?: boolean;
52
+ }
53
+ /**
54
+ * GraphQL input for creating events
55
+ */
56
+ export interface CreateEventInput {
57
+ sessionId: string;
58
+ type: EventType;
59
+ source: EventSource;
60
+ content: string;
61
+ metadata?: Record<string, any>;
62
+ promptId?: string;
63
+ timestamp?: string;
64
+ isEncrypted?: boolean;
65
+ }
66
+ /**
67
+ * GraphQL input for updating event status
68
+ */
69
+ export interface UpdateEventStatusInput {
70
+ eventId: string;
71
+ sessionId: string;
72
+ timestamp: string;
73
+ deliveryStatus: DeliveryStatus;
74
+ }
@@ -0,0 +1,4 @@
1
+ export * from './events';
2
+ export * from './session';
3
+ export * from './encryption';
4
+ export * from './auth';
@@ -0,0 +1,59 @@
1
+ import { EncryptedSessionKey } from './encryption';
2
+ /**
3
+ * Session status enum
4
+ */
5
+ export declare enum SessionStatus {
6
+ ACTIVE = "ACTIVE",
7
+ INACTIVE = "INACTIVE",
8
+ PAUSED = "PAUSED"
9
+ }
10
+ /**
11
+ * Agent type for multi-agent support
12
+ */
13
+ export declare enum AgentType {
14
+ CLAUDE = "CLAUDE",
15
+ GEMINI = "GEMINI",
16
+ CODEX = "CODEX"
17
+ }
18
+ /**
19
+ * Session type
20
+ */
21
+ export interface Session {
22
+ sessionId: string;
23
+ userId: string;
24
+ agentType: AgentType;
25
+ projectPath: string;
26
+ status: SessionStatus;
27
+ createdAt: string;
28
+ updatedAt: string;
29
+ metadata?: Record<string, any>;
30
+ isEncrypted?: boolean;
31
+ encryptedKeys?: EncryptedSessionKey[];
32
+ creatorDeviceId?: string;
33
+ encryptionVersion?: number;
34
+ lastHeartbeatAt?: string;
35
+ }
36
+ /**
37
+ * GraphQL input for creating sessions
38
+ */
39
+ export interface CreateSessionInput {
40
+ sessionId?: string;
41
+ userId: string;
42
+ agentType?: AgentType;
43
+ projectPath: string;
44
+ status?: SessionStatus;
45
+ metadata?: Record<string, any>;
46
+ encryptedKeys?: EncryptedSessionKey[];
47
+ creatorDeviceId?: string;
48
+ isEncrypted?: boolean;
49
+ encryptionVersion?: number;
50
+ }
51
+ /**
52
+ * GraphQL input for updating sessions
53
+ */
54
+ export interface UpdateSessionInput {
55
+ sessionId: string;
56
+ status?: SessionStatus;
57
+ metadata?: Record<string, any>;
58
+ lastHeartbeatAt?: string;
59
+ }
package/package.json CHANGED
@@ -1,18 +1,21 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Core library for CodeVibe plugins - shared keychain, crypto, AppSync, and auth functionality",
5
5
  "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
6
7
  "bin": {
7
8
  "codevibe": "./bin/codevibe.js"
8
9
  },
9
10
  "files": [
11
+ "dist/**/*.d.ts",
10
12
  "dist/index.js",
11
13
  "bin"
12
14
  ],
13
15
  "scripts": {
14
16
  "typecheck": "tsc --noEmit",
15
- "build": "rm -rf dist && npm run typecheck && esbuild src/index.ts --bundle --platform=node --target=node18 --minify --packages=external --outfile=dist/index.js",
17
+ "emit-types": "tsc --emitDeclarationOnly",
18
+ "build": "rm -rf dist && npm run emit-types && esbuild src/index.ts --bundle --platform=node --target=node18 --minify --packages=external --outfile=dist/index.js",
16
19
  "clean": "rm -rf dist",
17
20
  "prepublishOnly": "npm run build",
18
21
  "test": "echo \"No tests yet\" && exit 0"