@quantiya/codevibe-claude-plugin 1.0.15 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codevibe-claude",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Sync Claude Code sessions with iOS mobile app via AWS backend. Control Claude Code from your phone with real-time bidirectional synchronization.",
5
5
  "author": {
6
6
  "name": "CodeVibe Team"
@@ -45,30 +45,51 @@ if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
45
45
  SENT_UUIDS_CONTENT=$(cat "$SENT_UUIDS_FILE")
46
46
  fi
47
47
 
48
- # Single jq invocation: find last user UUID, build chain, extract unsent assistant text
49
- # This replaces two slow bash while-loops that spawned jq per line (O(n) jq processes → 1)
48
+ # Single jq invocation: find the most recent REAL user prompt, then take all
49
+ # assistant messages after it in file order, filter out already-sent UUIDs,
50
+ # extract text content.
51
+ #
52
+ # Previous implementation used a UUID-parent chain starting from the "last
53
+ # user message" — but because the transcript includes tool_result entries as
54
+ # type "user", the chain starting point was the last tool_result, not the
55
+ # real user prompt. That meant only the ONE assistant message immediately
56
+ # after the last tool_result was captured, and every earlier assistant text
57
+ # block in the same turn was silently lost. This was bug #39 (2026-04-14):
58
+ # users saw ~1/10 of mid-turn assistant text on mobile during long responses.
59
+ #
60
+ # Fix: a real user prompt has at least one content block of type "text".
61
+ # Tool_result user messages have content blocks of type "tool_result". We
62
+ # find the INDEX of the last real user prompt in file order, then take every
63
+ # subsequent assistant message (they're all part of the current turn).
50
64
  ASSISTANT_MESSAGES=$(jq -r --slurp --arg sent "$SENT_UUIDS_CONTENT" '
51
- # Find last user prompt UUID
52
- (map(select(.type == "user")) | last | .uuid // empty) as $lastUserUuid |
53
- if ($lastUserUuid | length) == 0 then empty
65
+ # Index of the last "real" user prompt. A real prompt has .message.content
66
+ # that is EITHER a string (simple text prompt) OR an array containing at
67
+ # least one content block of type "text" (mixed content). Tool_result user
68
+ # messages have an array of content blocks where every block is type
69
+ # "tool_result" — those are NOT real prompts and must be excluded.
70
+ (
71
+ [ range(0; length) as $i
72
+ | select(.[$i].type == "user" and (
73
+ (.[$i].message.content | type) == "string" or
74
+ ((.[$i].message.content | type) == "array" and
75
+ (.[$i].message.content | any(.type? == "text")))
76
+ ))
77
+ | $i
78
+ ]
79
+ | last // -1
80
+ ) as $startIdx |
81
+ if $startIdx < 0 then empty
54
82
  else
55
- # Build UUID chain from last user prompt
56
- reduce .[] as $msg (
57
- [$lastUserUuid];
58
- if (. | any(. == ($msg.parentUuid // ""))) then
59
- . + [($msg.uuid // "")]
60
- else . end
61
- ) as $chain |
62
- # Parse sent UUIDs
83
+ # Parse sent UUIDs list
63
84
  ($sent | split("\n") | map(select(. != ""))) as $sentList |
64
- # Filter: assistant messages in chain, not sent, with text content
85
+ # Take messages after the real user prompt, filter to unsent assistant text
86
+ .[($startIdx + 1):] |
65
87
  .[] |
66
88
  select(.type == "assistant") |
67
- select(.uuid as $u | $chain | any(. == $u)) |
68
89
  select(.uuid as $u | $sentList | any(. == $u) | not) |
69
90
  {
70
91
  uuid: .uuid,
71
- text: ([.message.content[]? | select(.type == "text") | .text // empty] | join(" "))
92
+ text: ([.message.content[]? | select(.type == "text") | .text // empty] | join("\n\n"))
72
93
  } |
73
94
  select(.text | length > 0) |
74
95
  "\(.uuid)\t\(.text | @base64)"
package/hooks/stop.sh CHANGED
@@ -44,29 +44,46 @@ if [ -f "$SENT_UUIDS_FILE" ]; then
44
44
  SENT_UUIDS_CONTENT=$(cat "$SENT_UUIDS_FILE")
45
45
  fi
46
46
 
47
- # Single jq invocation: find last user UUID, build chain, extract assistant messages
48
- # This replaces two slow bash while-loops that spawned jq per line (O(n) jq processes → 1)
47
+ # Find the index of the most recent REAL user prompt, then emit assistant
48
+ # text + tool_use events from all subsequent messages in file order.
49
+ #
50
+ # Previous implementation used a UUID-parent chain starting from the "last
51
+ # user message" — but tool_result messages ALSO have type "user", so the
52
+ # chain start was usually the last tool_result, missing every assistant
53
+ # message earlier in the same turn. Bug #39 (fixed 2026-04-14).
54
+ #
55
+ # A real user prompt has at least one content block of type "text". Tool_result
56
+ # user messages have content blocks of type "tool_result". We find the index
57
+ # of the last real user prompt and walk forward from there in file order.
58
+ #
49
59
  # Output format: tab-separated lines: uuid\ttype\tcontent
50
60
  # type is "text" for base64-encoded assistant text, "tool_use" for JSON tool uses
51
61
  # Text is base64-encoded because it may contain newlines which break line-by-line read
52
62
  TRANSCRIPT_EVENTS=$(jq -r --slurp --arg sent "$SENT_UUIDS_CONTENT" '
53
- # Find last user prompt UUID
54
- (map(select(.type == "user")) | last | .uuid // empty) as $lastUserUuid |
55
- if ($lastUserUuid | length) == 0 then empty
63
+ # Index of the last "real" user prompt. A real prompt has .message.content
64
+ # that is EITHER a string (simple text prompt) OR an array containing at
65
+ # least one content block of type "text" (mixed content). Tool_result user
66
+ # messages have an array of content blocks where every block is type
67
+ # "tool_result" — those are NOT real prompts and must be excluded.
68
+ (
69
+ [ range(0; length) as $i
70
+ | select(.[$i].type == "user" and (
71
+ (.[$i].message.content | type) == "string" or
72
+ ((.[$i].message.content | type) == "array" and
73
+ (.[$i].message.content | any(.type? == "text")))
74
+ ))
75
+ | $i
76
+ ]
77
+ | last // -1
78
+ ) as $startIdx |
79
+ if $startIdx < 0 then empty
56
80
  else
57
- # Build UUID chain from last user prompt
58
- reduce .[] as $msg (
59
- [$lastUserUuid];
60
- if (. | any(. == ($msg.parentUuid // ""))) then
61
- . + [($msg.uuid // "")]
62
- else . end
63
- ) as $chain |
64
81
  # Parse sent UUIDs
65
82
  ($sent | split("\n") | map(select(. != ""))) as $sentList |
66
- # Filter: assistant messages in chain
83
+ # Take messages after the real user prompt
84
+ .[($startIdx + 1):] |
67
85
  .[] |
68
86
  select(.type == "assistant") |
69
- select(.uuid as $u | $chain | any(. == $u)) |
70
87
  . as $msg |
71
88
  # Emit text content (base64-encoded to preserve newlines)
72
89
  (
@@ -75,7 +92,7 @@ TRANSCRIPT_EVENTS=$(jq -r --slurp --arg sent "$SENT_UUIDS_CONTENT" '
75
92
  if $alreadySent then
76
93
  "\($uuid)\talready_sent\t"
77
94
  else
78
- ([$msg.message.content[]? | select(.type == "text") | .text // empty] | join(" ")) as $text |
95
+ ([$msg.message.content[]? | select(.type == "text") | .text // empty] | join("\n\n")) as $text |
79
96
  if ($text | length) > 0 then
80
97
  "\($uuid)\ttext\t\($text | @base64)"
81
98
  else empty end
@@ -1,9 +1,9 @@
1
- "use strict";var Ze=Object.create;var Y=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var nt=Object.getPrototypeOf,rt=Object.prototype.hasOwnProperty;var E=(r,e)=>()=>(r&&(e=r(r=0)),e);var Te=(r,e)=>{for(var t in e)Y(r,t,{get:e[t],enumerable:!0})},xe=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of tt(e))!rt.call(r,s)&&s!==t&&Y(r,s,{get:()=>e[s],enumerable:!(n=et(e,s))||n.enumerable});return r};var y=(r,e,t)=>(t=r!=null?Ze(nt(r)):{},xe(e||!r||!r.__esModule?Y(t,"default",{value:r,enumerable:!0}):t,r)),st=r=>xe(Y({},"__esModule",{value:!0}),r);function it(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 se(r){return new P(r)}var R,G,Ce,Ae,P,c,Pe=E(()=>{"use strict";R=y(require("fs")),G=y(require("path")),Ce=y(require("os")),Ae={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=G.dirname(this.logFile);R.existsSync(e)||R.mkdirSync(e,{recursive:!0})}}shouldLog(e){return Ae[e]>=Ae[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,it)}`: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:G.join(Ce.tmpdir(),"codevibe-core.log"),level:"info"})});var L=E(()=>{"use strict";Pe()});function ot(r){for(let e of r)try{process.stderr.write(e+`
4
- `)}catch{}}function at(){if(D!==null||oe!==null)return;let keytarLoadError=null;try{let nodeRequire=eval("require");I=nodeRequire("keytar")}catch(r){keytarLoadError=r instanceof Error?r.message:String(r),I=null}if(I){D="keytar",c.info("[keychain-backend] Using keytar (OS-native keyring)");return}let optedIn=process.env.CODEVIBE_ALLOW_FILE_KEYCHAIN==="1";if(!optedIn){oe=new X(["CodeVibe could not load the OS-native keyring (keytar).",`Reason: ${keytarLoadError??"unknown"}`,"","Options to fix this:"," 1. (Linux) Install libsecret and a keyring daemon:"," sudo apt install libsecret-1-0 gnome-keyring"," Then unlock the keyring for your user session.",""," 2. (Headless / CI / Docker) Opt in to file-based credential"," storage at ~/.codevibe/ (0600 files). This is equivalent"," in trust to ~/.ssh/id_rsa \u2014 not the OS keyring:"," export CODEVIBE_ALLOW_FILE_KEYCHAIN=1"].join(`
5
- `));return}ot(["","\u26A0 CodeVibe: OS keyring unavailable. Using file-based credential storage.","\u26A0 Location: ~/.codevibe/ (directory 0700, files 0600)","\u26A0 Trust level: equivalent to ~/.ssh/id_rsa \u2014 weaker than OS keyring.",`\u26A0 Keytar load error: ${keytarLoadError??"unknown"}`,"\u26A0 To use the OS keyring instead, unset CODEVIBE_ALLOW_FILE_KEYCHAIN and","\u26A0 install libsecret-1-0 + a running keyring daemon.",""]),c.warn(`[keychain-backend] Using file-based fallback at ~/.codevibe (CODEVIBE_ALLOW_FILE_KEYCHAIN=1). Keytar load error: ${keytarLoadError??"unknown"}`),ie=ae.join(De.homedir(),".codevibe");try{A.mkdirSync(ie,{recursive:!0,mode:448})}catch{}D="file"}function ct(r){return r.replace(/[^a-zA-Z0-9._-]/g,"_")}function Ke(r){return ae.join(ie,`${ct(r)}.json`)}function ce(r){try{let e=A.readFileSync(Ke(r),"utf-8"),t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function Oe(r,e){let t=Ke(r);A.writeFileSync(t,JSON.stringify(e,null,2),{mode:384});try{A.chmodSync(t,384)}catch{}}function de(){if(at(),D===null)throw oe??new X("Keychain backend not initialized")}async function le(r,e){return de(),D==="keytar"&&I?I.getPassword(r,e):ce(r)[e]??null}async function pe(r,e,t){if(de(),D==="keytar"&&I){await I.setPassword(r,e,t);return}let n=ce(r);n[e]=t,Oe(r,n)}async function ue(r,e){if(de(),D==="keytar"&&I)return I.deletePassword(r,e);let t=ce(r);return e in t?(delete t[e],Oe(r,t),!0):!1}var De,ae,A,X,D,I,ie,oe,$e=E(()=>{"use strict";De=y(require("os")),ae=y(require("path")),A=y(require("fs"));L();X=class extends Error{constructor(e){super(e),this.name="KeychainBackendUnavailableError"}},D=null,I=null,ie="",oe=null});var v,K,ge,lt,U,b,Ne=E(()=>{"use strict";v=y(require("crypto")),K=class extends Error{constructor(e){super(e),this.name="CryptoError"}},ge=1,lt="CodeVibe E2E v1",U=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(lt,"utf8"),32);return Buffer.from(a)}catch(n){throw new K(`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 K("Decryption failed: Invalid ciphertext or authentication tag")}}serializePrivateKey(e){return e}deserializePrivateKey(e){return e}},b=U.getInstance()});var Q=E(()=>{"use strict";Ne()});function h(){let r=process.env.ENVIRONMENT;return r==="development"||r==="production"?r:"production"}function ee(r){let e=r||h();return Z={...O[e],aws:{...O[e].aws,region:process.env.AWS_REGION||O[e].aws.region,appsyncUrl:process.env.APPSYNC_URL||O[e].aws.appsyncUrl,cognitoUserPoolId:process.env.COGNITO_USER_POOL_ID||O[e].aws.cognitoUserPoolId,cognitoClientId:process.env.COGNITO_CLIENT_ID||O[e].aws.cognitoClientId,cognitoDomain:process.env.COGNITO_DOMAIN||O[e].aws.cognitoDomain}},Re=!0,Z}function f(){return(!Re||!Z)&&ee(),Z}var V,W,O,Z,Re,Le=E(()=>{"use strict";V=y(require("os")),W=y(require("path")),O={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:W.default.join(V.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:W.default.join(V.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:W.default.join(V.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:W.default.join(V.default.homedir(),".gemini","tmp")}}},Z=null,Re=!1});var _=E(()=>{"use strict";Le()});var te,Ue,T,me,pt,$,g,_e=E(()=>{"use strict";te=y(require("os")),Ue=require("uuid");$e();Q();_();L();T=class extends Error{constructor(e){super(e),this.name="KeychainError"}},me="device-identity",pt="tokens-",$=class r{constructor(){this.deviceIdentity=null;this.sessionKeyCache=new Map;this.isRegistered=!1;this._serviceName=null}get serviceName(){return this._serviceName||(this._serviceName=f().keychain.serviceName),this._serviceName}static getInstance(){return r.instance||(r.instance=new r),r.instance}async getDeviceIdentity(){if(this.deviceIdentity)return this.deviceIdentity;let e=await le(this.serviceName,me);return e?(this.deviceIdentity=JSON.parse(e),c.info(`[KeychainManager] Loaded device identity: ${this.deviceIdentity.deviceId}`),this.deviceIdentity):null}async setDeviceIdentity(e){try{await pe(this.serviceName,me,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 T(`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,Ue.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 ue(this.serviceName,me),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 T(`Failed to delete device identity: ${e}`)}}getTokenAccount(e){return`${pt}${e}`}async getTokens(e="production"){let t=await le(this.serviceName,this.getTokenAccount(e));if(!t)return null;let n=JSON.parse(t);return c.debug(`[KeychainManager] Loaded tokens for ${e}`),n}async setTokens(e,t="production"){try{await pe(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 T(`Failed to save tokens: ${n}`)}}async deleteTokens(e="production"){try{let t=await ue(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 te.hostname()||"CLI Client"}getDevicePlatform(){let e=te.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=$.getInstance()});var Me={};Te(Me,{KeychainError:()=>T,KeychainManager:()=>$,keychainManager:()=>g});var M=E(()=>{"use strict";_e()});var At={};Te(At,{AgentType:()=>Ve,AppSyncClient:()=>J,AuthService:()=>q,CryptoError:()=>K,CryptoService:()=>U,DeliveryStatus:()=>He,ENCRYPTION_VERSION:()=>ge,EventSource:()=>ye,EventType:()=>qe,KeychainError:()=>T,KeychainManager:()=>$,Logger:()=>P,SessionStatus:()=>fe,authService:()=>x,createLogger:()=>se,cryptoService:()=>b,getConfig:()=>f,getEnvironment:()=>h,keychainManager:()=>g,loadConfig:()=>ee,logger:()=>c,mutations:()=>k,normalizeSnapshot:()=>Ee,parseInteractivePrompt:()=>Ye,prepareSessionEncryption:()=>re,queries:()=>N,resumeOrCreateSession:()=>Ie,runAuthCli:()=>ne,subscriptions:()=>j});module.exports=st(At);M();Q();var he=y(require("ws")),ve=require("uuid");_();L();M();var Be=y(require("dns")),Fe=y(require("fs"));if(ut())try{Be.setDefaultResultOrder("ipv4first")}catch{}function ut(){if(process.platform!=="linux")return!1;try{let r=Fe.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(r)}catch{return!1}}async function B(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=gt(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(`
6
- `));throw u.cause=n,u}}function gt(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 N={getSession:`
1
+ "use strict";var Ze=Object.create;var Y=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var nt=Object.getPrototypeOf,rt=Object.prototype.hasOwnProperty;var E=(r,e)=>()=>(r&&(e=r(r=0)),e);var Te=(r,e)=>{for(var t in e)Y(r,t,{get:e[t],enumerable:!0})},xe=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of tt(e))!rt.call(r,i)&&i!==t&&Y(r,i,{get:()=>e[i],enumerable:!(n=et(e,i))||n.enumerable});return r};var y=(r,e,t)=>(t=r!=null?Ze(nt(r)):{},xe(e||!r||!r.__esModule?Y(t,"default",{value:r,enumerable:!0}):t,r)),it=r=>xe(Y({},"__esModule",{value:!0}),r);function st(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 ie(r){return new D(r)}var $,G,Ce,Ae,D,c,De=E(()=>{"use strict";$=y(require("fs")),G=y(require("path")),Ce=y(require("os")),Ae={debug:0,info:1,warn:2,error:3};D=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=G.dirname(this.logFile);$.existsSync(e)||$.mkdirSync(e,{recursive:!0})}}shouldLog(e){return Ae[e]>=Ae[this.level]}formatMessage(e,t,n){let i=new Date().toISOString(),s=e.toUpperCase().padEnd(5),o=`[${i}] [${s}] [${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,st)}`:o+=` ${n}`),o}log(e,t,n){if(!this.shouldLog(e))return;let i=this.formatMessage(e,t,n);if(this.logFile)try{$.appendFileSync(this.logFile,i+`
3
+ `)}catch{}if(this.enableConsole)switch(e){case"error":console.error(i);break;case"warn":console.warn(i);break;default:console.log(i)}}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 D({name:"codevibe-core",logFile:G.join(Ce.tmpdir(),"codevibe-core.log"),level:"info"})});var L=E(()=>{"use strict";De()});function ot(r){for(let e of r)try{process.stderr.write(e+`
4
+ `)}catch{}}function at(){se=ae.join(Pe.homedir(),".codevibe");try{A.mkdirSync(se,{recursive:!0,mode:448})}catch{}P="file"}function ct(){if(P!==null||oe!==null)return;let optedIn=process.env.CODEVIBE_ALLOW_FILE_KEYCHAIN==="1";if(optedIn){ot(["","\u26A0 CodeVibe: file-based credential storage selected (CODEVIBE_ALLOW_FILE_KEYCHAIN=1).","\u26A0 Location: ~/.codevibe/ (directory 0700, files 0600)","\u26A0 Trust level: equivalent to ~/.ssh/id_rsa \u2014 weaker than OS keyring.","\u26A0 To use the OS keyring instead, unset CODEVIBE_ALLOW_FILE_KEYCHAIN and","\u26A0 install libsecret-1-0 + a running keyring daemon (Linux) or use the","\u26A0 native Keychain (macOS) / Credential Manager (Windows).",""]),c.warn("[keychain-backend] Using file-based storage at ~/.codevibe (CODEVIBE_ALLOW_FILE_KEYCHAIN=1 explicit opt-in)"),at();return}let keytarLoadError=null;try{let nodeRequire=eval("require");I=nodeRequire("keytar")}catch(r){keytarLoadError=r instanceof Error?r.message:String(r),I=null}if(I){P="keytar",c.info("[keychain-backend] Using keytar (OS-native keyring)");return}oe=new X(["CodeVibe could not load the OS-native keyring (keytar).",`Reason: ${keytarLoadError??"unknown"}`,"","Options to fix this:"," 1. (Linux) Install libsecret and a keyring daemon:"," sudo apt install libsecret-1-0 gnome-keyring"," Then unlock the keyring for your user session.",""," 2. (Headless / CI / Docker) Opt in to file-based credential"," storage at ~/.codevibe/ (0600 files). This is equivalent"," in trust to ~/.ssh/id_rsa \u2014 not the OS keyring:"," export CODEVIBE_ALLOW_FILE_KEYCHAIN=1"].join(`
5
+ `))}function dt(r){return r.replace(/[^a-zA-Z0-9._-]/g,"_")}function Ke(r){return ae.join(se,`${dt(r)}.json`)}function ce(r){try{let e=A.readFileSync(Ke(r),"utf-8"),t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function Oe(r,e){let t=Ke(r);A.writeFileSync(t,JSON.stringify(e,null,2),{mode:384});try{A.chmodSync(t,384)}catch{}}function de(){if(ct(),P===null)throw oe??new X("Keychain backend not initialized")}async function le(r,e){return de(),P==="keytar"&&I?I.getPassword(r,e):ce(r)[e]??null}async function pe(r,e,t){if(de(),P==="keytar"&&I){await I.setPassword(r,e,t);return}let n=ce(r);n[e]=t,Oe(r,n)}async function ue(r,e){if(de(),P==="keytar"&&I)return I.deletePassword(r,e);let t=ce(r);return e in t?(delete t[e],Oe(r,t),!0):!1}var Pe,ae,A,X,P,I,se,oe,Ne=E(()=>{"use strict";Pe=y(require("os")),ae=y(require("path")),A=y(require("fs"));L();X=class extends Error{constructor(e){super(e),this.name="KeychainBackendUnavailableError"}},P=null,I=null,se="",oe=null});var v,K,ge,pt,U,b,Re=E(()=>{"use strict";v=y(require("crypto")),K=class extends Error{constructor(e){super(e),this.name="CryptoError"}},ge=1,pt="CodeVibe E2E v1",U=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"),i=Buffer.from(e,"base64");n.setPrivateKey(i);let s=Buffer.concat([Buffer.from([4]),Buffer.from(t,"base64")]),o=n.computeSecret(s),a=v.hkdfSync("sha256",o,Buffer.alloc(0),Buffer.from(pt,"utf8"),32);return Buffer.from(a)}catch(n){throw new K(`Failed to derive shared key: ${n}`)}}encryptSessionKey(e,t){let n=this.generateKeyPair(),i=this.deriveSharedKey(n.privateKey,t),s=Buffer.from(e,"base64");return{encryptedKey:this.encrypt(s,i).toString("base64"),ephemeralPublicKey:n.publicKey}}decryptSessionKey(e,t){let n=this.deriveSharedKey(t,e.ephemeralPublicKey),i=Buffer.from(e.encryptedKey,"base64");return this.decrypt(i,n).toString("base64")}encryptContent(e,t){let n=Buffer.from(t,"base64"),i=Buffer.from(e,"utf8");return this.encrypt(i,n).toString("base64")}decryptContent(e,t){let n=Buffer.from(t,"base64"),i=Buffer.from(e,"base64");return this.decrypt(i,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),i=v.createCipheriv("aes-256-gcm",t,n),s=Buffer.concat([i.update(e),i.final()]),o=i.getAuthTag();return Buffer.concat([n,s,o])}decrypt(e,t){let n=e.subarray(0,12),i=e.subarray(e.length-16),s=e.subarray(12,e.length-16),o=v.createDecipheriv("aes-256-gcm",t,n);o.setAuthTag(i);try{return Buffer.concat([o.update(s),o.final()])}catch{throw new K("Decryption failed: Invalid ciphertext or authentication tag")}}serializePrivateKey(e){return e}deserializePrivateKey(e){return e}},b=U.getInstance()});var Q=E(()=>{"use strict";Re()});function h(){let r=process.env.ENVIRONMENT;return r==="development"||r==="production"?r:"production"}function ee(r){let e=r||h();return Z={...O[e],aws:{...O[e].aws,region:process.env.AWS_REGION||O[e].aws.region,appsyncUrl:process.env.APPSYNC_URL||O[e].aws.appsyncUrl,cognitoUserPoolId:process.env.COGNITO_USER_POOL_ID||O[e].aws.cognitoUserPoolId,cognitoClientId:process.env.COGNITO_CLIENT_ID||O[e].aws.cognitoClientId,cognitoDomain:process.env.COGNITO_DOMAIN||O[e].aws.cognitoDomain}},$e=!0,Z}function f(){return(!$e||!Z)&&ee(),Z}var V,W,O,Z,$e,Le=E(()=>{"use strict";V=y(require("os")),W=y(require("path")),O={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:W.default.join(V.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:W.default.join(V.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:W.default.join(V.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:W.default.join(V.default.homedir(),".gemini","tmp")}}},Z=null,$e=!1});var _=E(()=>{"use strict";Le()});var te,Ue,T,me,ut,N,g,_e=E(()=>{"use strict";te=y(require("os")),Ue=require("uuid");Ne();Q();_();L();T=class extends Error{constructor(e){super(e),this.name="KeychainError"}},me="device-identity",ut="tokens-",N=class r{constructor(){this.deviceIdentity=null;this.sessionKeyCache=new Map;this.isRegistered=!1;this._serviceName=null}get serviceName(){return this._serviceName||(this._serviceName=f().keychain.serviceName),this._serviceName}static getInstance(){return r.instance||(r.instance=new r),r.instance}async getDeviceIdentity(){if(this.deviceIdentity)return this.deviceIdentity;let e=await le(this.serviceName,me);return e?(this.deviceIdentity=JSON.parse(e),c.info(`[KeychainManager] Loaded device identity: ${this.deviceIdentity.deviceId}`),this.deviceIdentity):null}async setDeviceIdentity(e){try{await pe(this.serviceName,me,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 T(`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,Ue.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 ue(this.serviceName,me),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 T(`Failed to delete device identity: ${e}`)}}getTokenAccount(e){return`${ut}${e}`}async getTokens(e="production"){let t=await le(this.serviceName,this.getTokenAccount(e));if(!t)return null;let n=JSON.parse(t);return c.debug(`[KeychainManager] Loaded tokens for ${e}`),n}async setTokens(e,t="production"){try{await pe(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 T(`Failed to save tokens: ${n}`)}}async deleteTokens(e="production"){try{let t=await ue(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 i=await this.getDeviceId(),s=t.find(l=>l.deviceId===i);if(!s)return c.warn(`[KeychainManager] Device ${i} not found in encryptedKeys`),null;let o=await this.getDevicePrivateKey(),a=b.decryptSessionKey(s,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(i=>{let s=b.encryptSessionKey(t,i.publicKey);return{deviceId:i.deviceId,encryptedKey:s.encryptedKey,ephemeralPublicKey:s.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 te.hostname()||"CLI Client"}getDevicePlatform(){let e=te.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=N.getInstance()});var Me={};Te(Me,{KeychainError:()=>T,KeychainManager:()=>N,keychainManager:()=>g});var M=E(()=>{"use strict";_e()});var Ct={};Te(Ct,{AgentType:()=>Ve,AppSyncClient:()=>J,AuthService:()=>q,CryptoError:()=>K,CryptoService:()=>U,DeliveryStatus:()=>He,ENCRYPTION_VERSION:()=>ge,EventSource:()=>ye,EventType:()=>qe,KeychainError:()=>T,KeychainManager:()=>N,Logger:()=>D,SessionStatus:()=>fe,authService:()=>x,createLogger:()=>ie,cryptoService:()=>b,getConfig:()=>f,getEnvironment:()=>h,keychainManager:()=>g,loadConfig:()=>ee,logger:()=>c,mutations:()=>k,normalizeSnapshot:()=>Ee,parseInteractivePrompt:()=>Ye,prepareSessionEncryption:()=>re,queries:()=>R,resumeOrCreateSession:()=>Ie,runAuthCli:()=>ne,subscriptions:()=>j});module.exports=it(Ct);M();Q();var he=y(require("ws")),ve=require("uuid");_();L();M();var Be=y(require("dns")),Fe=y(require("fs"));if(gt())try{Be.setDefaultResultOrder("ipv4first")}catch{}function gt(){if(process.platform!=="linux")return!1;try{let r=Fe.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(r)}catch{return!1}}async function B(r,e,t){try{return await fetch(r,e)}catch(n){let i=n?.cause?.code,s=n?.cause?.message,o=i||s||n?.message||"unknown",a=mt(i),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(`
6
+ `));throw u.cause=n,u}}function mt(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 R={getSession:`
7
7
  query GetSession($sessionId: ID!) {
8
8
  getSession(sessionId: $sessionId) {
9
9
  sessionId
@@ -166,7 +166,7 @@ ${n.stack}`)):typeof n=="object"?o+=` ${JSON.stringify(n,it)}`:o+=` ${n}`),o}log
166
166
  isEncrypted
167
167
  }
168
168
  }
169
- `};var qe=(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))(qe||{}),ye=(t=>(t.DESKTOP="DESKTOP",t.MOBILE="MOBILE",t))(ye||{}),He=(n=>(n.SENT="SENT",n.DELIVERED="DELIVERED",n.EXECUTED="EXECUTED",n))(He||{});var fe=(n=>(n.ACTIVE="ACTIVE",n.INACTIVE="INACTIVE",n.PAUSED="PAUSED",n))(fe||{}),Ve=(n=>(n.CLAUDE="CLAUDE",n.GEMINI="GEMINI",n.CODEX="CODEX",n))(Ve||{});var F={urgentMaxAttempts:10,baseDelayMs:1e3,maxDelayMs:6e4,backoffMultiplier:2,persistentDelayMs:300*1e3},J=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=f(),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 B(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=f();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 B(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(k.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(k.updateSession,{input:t});return c.debug("[AppSyncClient] Session updated",{sessionId:n.data.updateSession.sessionId}),n.data.updateSession}async getSession(e){return(await this.graphqlRequest(N.getSession,{sessionId:e})).data.getSession}async createEvent(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},n=await this.graphqlRequest(k.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(k.updateEventStatus,{input:e})).data.updateEventStatus}async listEvents(e,t,n){return(await this.graphqlRequest(N.listEvents,{sessionId:e,source:t,limit:n})).data.listEvents.items}async listUserDeviceKeys(){return(await this.graphqlRequest(N.listUserDeviceKeys,{})).data.listUserDeviceKeys||[]}async registerDeviceKey(e,t,n,s){let i={deviceId:e,publicKey:t,platform:n,deviceName:s};await this.graphqlRequest(k.registerDeviceKey,{input:i}),c.info("[AppSyncClient] Device key registered",{deviceId:e,platform:n})}async getAttachmentDownloadUrl(e){return(await this.graphqlRequest(k.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,ve.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=f(),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 he.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=f(),{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:j.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<=F.urgentMaxAttempts,o;if(i?o=Math.min(F.baseDelayMs*Math.pow(F.backoffMultiplier,e.reconnectAttempts-1),F.maxDelayMs):(o=F.persistentDelayMs,e.reconnectAttempts===F.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,ve.v4)(),this.createSubscription(e)}},o)}cleanupSubscriptionState(e){if(e.reconnectTimer&&clearTimeout(e.reconnectTimer),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.ws){try{e.ws.readyState===he.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 We=y(require("crypto")),je=y(require("fs")),be=y(require("http")),Je=require("child_process");_();M();L();var z=8080,ze="/callback",Se=`http://localhost:${z}${ze}`,q=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=je.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,Je.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,C)=>{u===0?l("exited successfully"):a(C?`terminated by signal ${C}`:`exited with code ${u}`)}),setTimeout(()=>{l("still running after 3s, assuming success")},3e3).unref(),p.unref()}generateState(){return We.randomBytes(32).toString("hex")}buildAuthUrl(e){let t=f(),n=new URLSearchParams({client_id:t.aws.cognitoClientId,response_type:"code",scope:"email openid profile",redirect_uri:Se,state:e});return`https://${t.aws.cognitoDomain}/oauth2/authorize?${n.toString()}`}async exchangeCodeForTokens(e){let t=f(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,s=new URLSearchParams({grant_type:"authorization_code",client_id:t.aws.cognitoClientId,code:e,redirect_uri:Se}),i=await B(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=f(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,s=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e}),i=await B(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=be.createServer(async(a,l)=>{if(!a.url?.startsWith(ze)){l.writeHead(404),l.end("Not found");return}try{let p=new URL(a.url,`http://localhost:${z}`),m=p.searchParams.get("code"),u=p.searchParams.get("state"),C=p.searchParams.get("error");if(C)throw new Error(`OAuth error: ${C}`);if(u!==t)throw new Error("State mismatch");if(!m)throw new Error("No authorization code");let S=await this.exchangeCodeForTokens(m),H=this.decodeJwt(S.idToken),w={accessToken:S.accessToken,idToken:S.idToken,refreshToken:S.refreshToken,expiresAt:Date.now()+S.expiresIn*1e3,userId:H.sub,email:H.email||"unknown"};await g.setTokens(w,h()),l.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),l.end(`
169
+ `};var qe=(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))(qe||{}),ye=(t=>(t.DESKTOP="DESKTOP",t.MOBILE="MOBILE",t))(ye||{}),He=(n=>(n.SENT="SENT",n.DELIVERED="DELIVERED",n.EXECUTED="EXECUTED",n))(He||{});var fe=(n=>(n.ACTIVE="ACTIVE",n.INACTIVE="INACTIVE",n.PAUSED="PAUSED",n))(fe||{}),Ve=(n=>(n.CLAUDE="CLAUDE",n.GEMINI="GEMINI",n.CODEX="CODEX",n))(Ve||{});var F={urgentMaxAttempts:10,baseDelayMs:1e3,maxDelayMs:6e4,backoffMultiplier:2,persistentDelayMs:300*1e3},J=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=f(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e.refreshToken}),s=await B(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},"Token refresh");if(!s.ok)return c.error("[AppSyncClient] Token refresh failed",{status:s.status}),!1;let o=await s.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 i=f();if(!this.tokens?.idToken)throw new Error('Not authenticated. Run "codevibe login" first.');let s={"Content-Type":"application/json",Authorization:this.tokens.idToken},o=await B(i.aws.appsyncUrl,{method:"POST",headers:s,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(k.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(k.updateSession,{input:t});return c.debug("[AppSyncClient] Session updated",{sessionId:n.data.updateSession.sessionId}),n.data.updateSession}async getSession(e){return(await this.graphqlRequest(R.getSession,{sessionId:e})).data.getSession}async createEvent(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},n=await this.graphqlRequest(k.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(k.updateEventStatus,{input:e})).data.updateEventStatus}async listEvents(e,t,n){return(await this.graphqlRequest(R.listEvents,{sessionId:e,source:t,limit:n})).data.listEvents.items}async listUserDeviceKeys(){return(await this.graphqlRequest(R.listUserDeviceKeys,{})).data.listUserDeviceKeys||[]}async registerDeviceKey(e,t,n,i){let s={deviceId:e,publicKey:t,platform:n,deviceName:i};await this.graphqlRequest(k.registerDeviceKey,{input:s}),c.info("[AppSyncClient] Device key registered",{deviceId:e,platform:n})}async getAttachmentDownloadUrl(e){return(await this.graphqlRequest(k.getAttachmentDownloadUrl,{s3Key:e})).data.getAttachmentDownloadUrl}subscribeToEvents(e,t,n){c.info("[AppSyncClient] Subscribing to events",{sessionId:e});let i=this.activeSubscriptions.get(e);i&&(this.cleanupSubscriptionState(i),this.activeSubscriptions.delete(e));let s={ws:null,subscriptionId:(0,ve.v4)(),sessionId:e,onEvent:t,onError:n,reconnectAttempts:0,isReconnecting:!1,destroyed:!1};return this.activeSubscriptions.set(e,s),this.createSubscription(s),()=>{this.cleanupSubscriptionState(s),this.activeSubscriptions.delete(e)}}buildRealtimeUrl(){let e=f(),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 i=Buffer.from(JSON.stringify(n)).toString("base64"),s=Buffer.from(JSON.stringify({})).toString("base64");return`${t}?header=${i}&payload=${s}`}createSubscription(e){let{sessionId:t,subscriptionId:n,onEvent:i,onError:s}=e;try{let o=this.buildRealtimeUrl(),a=new he.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"&&i(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),!e.destroyed&&this.activeSubscriptions.get(t)===e&&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=f(),{sessionId:i,subscriptionId:s}=t,o={host:new URL(n.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:s,type:"start",payload:{data:JSON.stringify({query:j.onEventCreated,variables:{sessionId:i}}),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:i}=e;if(e.isReconnecting||!this.activeSubscriptions.has(n))return;e.isReconnecting=!0,e.reconnectAttempts++,this.stopHeartbeat(n);let s=e.reconnectAttempts<=F.urgentMaxAttempts,o;if(s?o=Math.min(F.baseDelayMs*Math.pow(F.backoffMultiplier,e.reconnectAttempts-1),F.maxDelayMs):(o=F.persistentDelayMs,e.reconnectAttempts===F.urgentMaxAttempts+1&&c.info("[AppSyncClient] Switching to persistent reconnect (every 5min)",{sessionId:n})),c.info("[AppSyncClient] Scheduling reconnect",{sessionId:n,attempt:e.reconnectAttempts,phase:s?"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,e.destroyed||this.activeSubscriptions.get(n)!==e){c.info("[AppSyncClient] Reconnect skipped \u2014 state is no longer canonical",{sessionId:n});return}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})}if(e.destroyed||this.activeSubscriptions.get(n)!==e){c.info("[AppSyncClient] Reconnect skipped after token refresh \u2014 state no longer canonical",{sessionId:n});return}e.subscriptionId=(0,ve.v4)(),this.createSubscription(e)},o)}cleanupSubscriptionState(e){if(e.destroyed=!0,e.reconnectTimer&&(clearTimeout(e.reconnectTimer),e.reconnectTimer=void 0),e.keepAliveTimer&&(clearTimeout(e.keepAliveTimer),e.keepAliveTimer=void 0),e.ws){try{e.ws.readyState===he.default.OPEN&&e.ws.send(JSON.stringify({id:e.subscriptionId,type:"stop"}))}catch{}try{e.ws.close(1e3)}catch{}try{e.ws.removeAllListeners()}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 We=y(require("crypto")),je=y(require("fs")),be=y(require("http")),Je=require("child_process");_();M();L();var z=8080,ze="/callback",Se=`http://localhost:${z}${ze}`,q=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=je.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 i=e[n],s=[...i.fixedArgs,t],o=!1,a=u=>{o||(o=!0,c.debug(`[AuthService] Browser command '${i.cmd}' ${u}; trying next fallback`),this.tryBrowserCommand(e,t,n+1))},l=u=>{o||(o=!0,c.debug(`[AuthService] Browser command '${i.cmd}' ${u}`))},p;try{p=(0,Je.spawn)(i.cmd,s,{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,C)=>{u===0?l("exited successfully"):a(C?`terminated by signal ${C}`:`exited with code ${u}`)}),setTimeout(()=>{l("still running after 3s, assuming success")},3e3).unref(),p.unref()}generateState(){return We.randomBytes(32).toString("hex")}buildAuthUrl(e){let t=f(),n=new URLSearchParams({client_id:t.aws.cognitoClientId,response_type:"code",scope:"email openid profile",redirect_uri:Se,state:e});return`https://${t.aws.cognitoDomain}/oauth2/authorize?${n.toString()}`}async exchangeCodeForTokens(e){let t=f(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"authorization_code",client_id:t.aws.cognitoClientId,code:e,redirect_uri:Se}),s=await B(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},"Token exchange");if(!s.ok){let a=await s.text();throw new Error(`Token exchange failed: ${s.status} ${a}`)}let o=await s.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=f(),n=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e}),s=await B(n,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},"Token refresh");if(!s.ok)throw new Error(`Token refresh failed: ${s.status}`);let o=await s.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((i,s)=>{let o=be.createServer(async(a,l)=>{if(!a.url?.startsWith(ze)){l.writeHead(404),l.end("Not found");return}try{let p=new URL(a.url,`http://localhost:${z}`),m=p.searchParams.get("code"),u=p.searchParams.get("state"),C=p.searchParams.get("error");if(C)throw new Error(`OAuth error: ${C}`);if(u!==t)throw new Error("State mismatch");if(!m)throw new Error("No authorization code");let S=await this.exchangeCodeForTokens(m),H=this.decodeJwt(S.idToken),w={accessToken:S.accessToken,idToken:S.idToken,refreshToken:S.refreshToken,expiresAt:Date.now()+S.expiresIn*1e3,userId:H.sub,email:H.email||"unknown"};await g.setTokens(w,h()),l.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),l.end(`
170
170
  <!DOCTYPE html>
171
171
  <html>
172
172
  <head><title>Success</title></head>
@@ -175,7 +175,7 @@ ${n.stack}`)):typeof n=="object"?o+=` ${JSON.stringify(n,it)}`:o+=` ${n}`),o}log
175
175
  <p>You can close this window.</p>
176
176
  </body>
177
177
  </html>
178
- `),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(`
178
+ `),setTimeout(()=>{o.close(()=>i(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(`
179
179
  <!DOCTYPE html>
180
180
  <html>
181
181
  <head><title>Error</title></head>
@@ -185,7 +185,7 @@ ${n.stack}`)):typeof n=="object"?o+=` ${JSON.stringify(n,it)}`:o+=` ${n}`),o}log
185
185
  <p style="text-align: center; color: #71717a; margin-top: 24px;">You can close this window and try again in your terminal.</p>
186
186
  </body>
187
187
  </html>
188
- `),setTimeout(()=>{o.close(()=>i(p))},500)}});o.on("error",a=>{a.code==="EADDRINUSE"?i(new Error(`Port ${z} is in use`)):i(a)}),o.listen(z,"localhost",()=>{c.info("[AuthService] Callback server started"),this.openBrowser(n)}),setTimeout(()=>{o.close(()=>i(new Error("Login timeout")))},120*1e3)})}async logout(){let e=f(),t=await g.deleteTokens(h());return t&&new Promise(n=>{let s=be.createServer((i,o)=>{i.url?.startsWith("/signout")?(o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(`
188
+ `),setTimeout(()=>{o.close(()=>s(p))},500)}});o.on("error",a=>{a.code==="EADDRINUSE"?s(new Error(`Port ${z} is in use`)):s(a)}),o.listen(z,"localhost",()=>{c.info("[AuthService] Callback server started"),this.openBrowser(n)}),setTimeout(()=>{o.close(()=>s(new Error("Login timeout")))},120*1e3)})}async logout(){let e=f(),t=await g.deleteTokens(h());return t&&new Promise(n=>{let i=be.createServer((s,o)=>{s.url?.startsWith("/signout")?(o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(`
189
189
  <!DOCTYPE html>
190
190
  <html>
191
191
  <head><title>Signed Out</title></head>
@@ -194,27 +194,27 @@ ${n.stack}`)):typeof n=="object"?o+=` ${JSON.stringify(n,it)}`:o+=` ${n}`),o}log
194
194
  <p>You can close this window.</p>
195
195
  </body>
196
196
  </html>
197
- `),setTimeout(()=>{s.close(()=>n(!0))},500)):(o.writeHead(404),o.end("Not found"))});s.on("error",()=>{n(!0)}),s.listen(z,"localhost",()=>{let i=`https://${e.aws.cognitoDomain}/logout?client_id=${e.aws.cognitoClientId}&logout_uri=${encodeURIComponent(Se.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}}},x=q.getInstance();_();var d={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m"};async function mt(){console.log(`${d.cyan}CodeVibe Login${d.reset}
197
+ `),setTimeout(()=>{i.close(()=>n(!0))},500)):(o.writeHead(404),o.end("Not found"))});i.on("error",()=>{n(!0)}),i.listen(z,"localhost",()=>{let s=`https://${e.aws.cognitoDomain}/logout?client_id=${e.aws.cognitoClientId}&logout_uri=${encodeURIComponent(Se.replace("/callback","/signout"))}`;this.openBrowser(s)}),setTimeout(()=>{i.close(()=>n(!0))},30*1e3)})}async getStatus(){let e=await g.getTokens(h());return e?{authenticated:!g.isTokenExpired(e),tokens:e}:{authenticated:!1}}},x=q.getInstance();_();var d={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m"};async function yt(){console.log(`${d.cyan}CodeVibe Login${d.reset}
198
198
  `);try{let r=await x.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(`
199
199
  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}
200
200
  `);let e=await x.login();e&&(console.log(`
201
201
  ${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(`
202
- ${d.red}\u2717 Authentication failed${d.reset}`),console.log(` Error: ${r.message}`),process.exit(1)}}async function yt(){console.log(`${d.cyan}CodeVibe Logout${d.reset}
202
+ ${d.red}\u2717 Authentication failed${d.reset}`),console.log(` Error: ${r.message}`),process.exit(1)}}async function ft(){console.log(`${d.cyan}CodeVibe Logout${d.reset}
203
203
  `);try{let r=await x.getStatus();if(!r.authenticated){console.log(`${d.yellow}Not logged in.${d.reset}`),process.exit(0);return}let e=r.tokens?.email;await x.logout()?(console.log(`${d.green}\u2713 Logged out successfully.${d.reset}`),console.log(` Previous user: ${e}`),console.log(`
204
- ${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 ft(){console.log(`${d.cyan}CodeVibe Auth Status${d.reset}
204
+ ${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 ht(){console.log(`${d.cyan}CodeVibe Auth Status${d.reset}
205
205
  `);try{let r=await x.getStatus();if(!r.tokens){console.log(`${d.yellow}Not authenticated.${d.reset}`),console.log(`
206
206
  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(`
207
- ${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 ht(){console.log(`${d.cyan}CodeVibe Reset Device${d.reset}
207
+ ${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 vt(){console.log(`${d.cyan}CodeVibe Reset Device${d.reset}
208
208
  `),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}
209
- `);let{keychainManager:r}=await Promise.resolve().then(()=>(M(),Me));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 vt(){console.log(`CodeVibe Authentication
209
+ `);let{keychainManager:r}=await Promise.resolve().then(()=>(M(),Me));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 St(){console.log(`CodeVibe Authentication
210
210
  `),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(`
211
211
  Environment:`),console.log(' Set ENVIRONMENT env var to "development" or "production" (default)'),console.log(" Example: ENVIRONMENT=development codevibe login")}async function ne(r){let e=h();console.log(`${d.dim}Environment: ${e}${d.reset}
212
- `);let n=r.slice(2).filter(s=>!s.startsWith("--"))[0];switch(n){case"login":await mt();break;case"logout":await yt();break;case"status":await ft();break;case"reset-device":await ht();break;default:vt(),process.exit(n?1:0)}}require.main===module&&ne(process.argv).catch(r=>{console.error("Error:",r),process.exit(1)});_();L();var St=/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;function Ye(r){let e=Ee(r);if(!e)return null;let t=bt(e);if(t)return t;let n=wt(e);return n||null}function Ee(r){return r.replace(/\r/g,`
213
- `).replace(St,"").replace(/[│┌┐└┘─├┤┬┴┼╌╎╭╮╯╰║═╔╗╚╝╠╣╦╩╬]/g," ").replace(/[ \t]+\n/g,`
212
+ `);let n=r.slice(2).filter(i=>!i.startsWith("--"))[0];switch(n){case"login":await yt();break;case"logout":await ft();break;case"status":await ht();break;case"reset-device":await vt();break;default:St(),process.exit(n?1:0)}}require.main===module&&ne(process.argv).catch(r=>{console.error("Error:",r),process.exit(1)});_();L();var bt=/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;function Ye(r){let e=Ee(r);if(!e)return null;let t=wt(e);if(t)return t;let n=kt(e);return n||null}function Ee(r){return r.replace(/\r/g,`
213
+ `).replace(bt,"").replace(/[│┌┐└┘─├┤┬┴┼╌╎╭╮╯╰║═╔╗╚╝╠╣╦╩╬]/g," ").replace(/[ \t]+\n/g,`
214
214
  `).replace(/\n{3,}/g,`
215
215
 
216
- `).trim()}function bt(r){let e=r.split(`
217
- `).map(m=>m.trim()),t=kt(e,m=>/\[(?:y\/n|Y\/n|y\/N)\]/.test(m)),n=t>=0?e[t]:null;if(!n)return null;let s=Xe(e,t),i=s.length>0?s.join(`
218
- `):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 wt(r){let e=r.split(`
219
- `).map(l=>l.trim()),t=Et(e);if(t.length<2)return null;let n=t.map(({line:l})=>Ge(l)).filter(l=>!!l),s={};for(let l of n)s[l.number]=l.number;let i=t[0]?.index??-1,o=Xe(e,i-1);return{kind:"numbered",promptText:o.length>0?o.join(`
220
- `):"Select an option",options:n,submitMap:s}}function kt(r,e){for(let t=r.length-1;t>=0;t-=1)if(e(r[t]))return t;return-1}function Ge(r){let e=r.match(/^(?:[>›❯▸▶➜➤*●]\s*)?(\d+)\.\s+(.*)$/);return e?{number:e[1],text:e[2]}:null}function Et(r){let e=r.map((n,s)=>({index:s,line:n,parsed:Ge(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 Xe(r,e){if(e<0)return[];let t=we(r,e);if(t<0)return[];let{start:n,end:s}=ke(r,t),i=r.slice(n,s+1).filter(Boolean);if(Tt(i)){let u=It(r,n-1);return u.length>0?u:i}if(n<=1)return i;let o=n-1;if(o=we(r,o),o<0||o===n-1)return i;let{start:a,end:l}=ke(r,o),p=r.slice(a,l+1).filter(Boolean);return p.some(Qe)?[...p,...i]:i}function Qe(r){return/^(?:would you like to|do you want to|the model would like to|action required|confirm)\b/i.test(r)}function we(r,e){let t=e;for(;t>=0&&!r[t];)t-=1;return t}function ke(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=we(r,n),!(n<0));){let{start:i,end:o}=ke(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(Qe));return s>=0?t.slice(s).flat():t[t.length-1]}function Tt(r){return r.length===0?!1:r.filter(xt).length>=Math.max(2,Math.ceil(r.length/2))}function xt(r){return/^\d+\s/.test(r)}Q();M();async function re(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 Ie(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,H=l.encryptedKeys;if(l.isEncrypted&&H?.length)try{let w=await g.getSessionKey(n,H);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 re(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 C=p?.sessionKey||null;return p&&g.cacheSessionKey(n,p.sessionKey),t.info("Session created",{sessionId:n,userId:s,isEncrypted:!!p}),{resumed:!1,sessionKey:C}}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});
216
+ `).trim()}function wt(r){let e=r.split(`
217
+ `).map(m=>m.trim()),t=Et(e,m=>/\[(?:y\/n|Y\/n|y\/N)\]/.test(m)),n=t>=0?e[t]:null;if(!n)return null;let i=Xe(e,t),s=i.length>0?i.join(`
218
+ `):n,o=s.toLowerCase(),a=o.includes("what to change")||o.includes("what should")||o.includes("provide")||o.includes("instructions");return{kind:"yes_no",promptText:s,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 kt(r){let e=r.split(`
219
+ `).map(l=>l.trim()),t=It(e);if(t.length<2)return null;let n=t.map(({line:l})=>Ge(l)).filter(l=>!!l),i={};for(let l of n)i[l.number]=l.number;let s=t[0]?.index??-1,o=Xe(e,s-1);return{kind:"numbered",promptText:o.length>0?o.join(`
220
+ `):"Select an option",options:n,submitMap:i}}function Et(r,e){for(let t=r.length-1;t>=0;t-=1)if(e(r[t]))return t;return-1}function Ge(r){let e=r.match(/^(?:[>›❯▸▶➜➤*●]\s*)?(\d+)\.\s+(.*)$/);return e?{number:e[1],text:e[2]}:null}function It(r){let e=r.map((n,i)=>({index:i,line:n,parsed:Ge(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 i=e[n],s=t[0];if(i.index!==s.index-1)break;t.unshift(i)}return t.map(({index:n,line:i})=>({index:n,line:i}))}function Xe(r,e){if(e<0)return[];let t=we(r,e);if(t<0)return[];let{start:n,end:i}=ke(r,t),s=r.slice(n,i+1).filter(Boolean);if(xt(s)){let u=Tt(r,n-1);return u.length>0?u:s}if(n<=1)return s;let o=n-1;if(o=we(r,o),o<0||o===n-1)return s;let{start:a,end:l}=ke(r,o),p=r.slice(a,l+1).filter(Boolean);return p.some(Qe)?[...p,...s]:s}function Qe(r){return/^(?:would you like to|do you want to|the model would like to|action required|confirm)\b/i.test(r)}function we(r,e){let t=e;for(;t>=0&&!r[t];)t-=1;return t}function ke(r,e){let t=e;for(;t>=0&&r[t];)t-=1;return{start:t+1,end:e}}function Tt(r,e){let t=[],n=e;for(;n>=0&&t.length<2&&(n=we(r,n),!(n<0));){let{start:s,end:o}=ke(r,n),a=r.slice(s,o+1).filter(Boolean);a.length>0&&t.unshift(a),n=s-1}if(t.length===0)return[];let i=t.findIndex(s=>s.some(Qe));return i>=0?t.slice(i).flat():t[t.length-1]}function xt(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)}Q();M();async function re(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:i,encryptedKeys:s}=g.createSessionKey(n);return t.info("Session encryption prepared",{sessionId:r,deviceCount:s.length}),{sessionKey:i,encryptedKeys:s}}catch(n){return t.warn("Failed to prepare session encryption:",n),null}}async function Ie(r,e,t){let{sessionId:n,userId:i,agentType:s,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,H=l.encryptedKeys;if(l.isEncrypted&&H?.length)try{let w=await g.getSessionKey(n,H);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 re(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:i,agentType:s,isEncrypted:!!p}),await e.createSession({sessionId:n,userId:i,agentType:s,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 C=p?.sessionKey||null;return p&&g.cacheSessionKey(n,p.sessionKey),t.info("Session created",{sessionId:n,userId:i,isEncrypted:!!p}),{resumed:!1,sessionKey:C}}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});
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Core library for CodeVibe plugins - shared keychain, crypto, AppSync, and auth functionality",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-claude-plugin",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Control Claude Code from your iPhone and Android — real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
5
5
  "main": "dist/server.js",
6
6
  "bin": {
@@ -47,7 +47,7 @@
47
47
  "node": ">=18.0.0"
48
48
  },
49
49
  "dependencies": {
50
- "@quantiya/codevibe-core": "^1.0.7",
50
+ "@quantiya/codevibe-core": "^1.0.9",
51
51
  "dotenv": "^16.6.1",
52
52
  "express": "^5.1.0",
53
53
  "graphql": "^16.12.0",