@quantiya/codevibe-claude-plugin 1.0.36 → 1.0.38

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.
Files changed (201) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/bin/codevibe-claude +17 -3
  3. package/dist/server.js +13 -13
  4. package/hooks/stop.sh +30 -10
  5. package/node_modules/@quantiya/codevibe-core/dist/auth/auth-telemetry.d.ts +56 -0
  6. package/node_modules/@quantiya/codevibe-core/dist/index.js +30 -30
  7. package/node_modules/@quantiya/codevibe-core/dist/keychain/keychain-manager.d.ts +16 -2
  8. package/node_modules/@quantiya/codevibe-core/dist/session/session-rekey.d.ts +40 -0
  9. package/node_modules/@quantiya/codevibe-core/dist/session/session-resume.d.ts +1 -0
  10. package/node_modules/@quantiya/codevibe-core/package.json +1 -1
  11. package/node_modules/body-parser/README.md +18 -18
  12. package/node_modules/body-parser/index.js +6 -15
  13. package/node_modules/body-parser/lib/read.js +17 -20
  14. package/node_modules/body-parser/lib/types/json.js +8 -16
  15. package/node_modules/body-parser/lib/types/raw.js +3 -4
  16. package/node_modules/body-parser/lib/types/text.js +3 -4
  17. package/node_modules/body-parser/lib/types/urlencoded.js +8 -8
  18. package/node_modules/body-parser/lib/utils.js +11 -9
  19. package/node_modules/body-parser/package.json +2 -2
  20. package/node_modules/content-disposition/README.md +7 -8
  21. package/node_modules/content-disposition/index.js +118 -40
  22. package/node_modules/content-disposition/package.json +8 -11
  23. package/node_modules/express/Readme.md +39 -29
  24. package/node_modules/express/lib/application.js +1 -1
  25. package/node_modules/express/lib/request.js +5 -6
  26. package/node_modules/express/lib/response.js +14 -0
  27. package/node_modules/express/lib/utils.js +3 -1
  28. package/node_modules/express/package.json +6 -5
  29. package/node_modules/finalhandler/HISTORY.md +6 -0
  30. package/node_modules/finalhandler/README.md +26 -23
  31. package/node_modules/finalhandler/package.json +13 -9
  32. package/node_modules/graphql/execution/execute.d.ts +14 -1
  33. package/node_modules/graphql/execution/execute.js +63 -13
  34. package/node_modules/graphql/execution/execute.mjs +63 -13
  35. package/node_modules/graphql/execution/subscribe.js +1 -0
  36. package/node_modules/graphql/execution/subscribe.mjs +2 -0
  37. package/node_modules/graphql/execution/values.js +4 -4
  38. package/node_modules/graphql/execution/values.mjs +4 -4
  39. package/node_modules/graphql/index.d.ts +1 -0
  40. package/node_modules/graphql/language/ast.d.ts +10 -1
  41. package/node_modules/graphql/language/ast.js +8 -1
  42. package/node_modules/graphql/language/ast.mjs +8 -1
  43. package/node_modules/graphql/language/directiveLocation.d.ts +1 -0
  44. package/node_modules/graphql/language/directiveLocation.js +1 -0
  45. package/node_modules/graphql/language/directiveLocation.mjs +1 -0
  46. package/node_modules/graphql/language/index.d.ts +1 -0
  47. package/node_modules/graphql/language/kinds.d.ts +1 -0
  48. package/node_modules/graphql/language/kinds.js +1 -0
  49. package/node_modules/graphql/language/kinds.mjs +1 -0
  50. package/node_modules/graphql/language/parser.d.ts +14 -0
  51. package/node_modules/graphql/language/parser.js +33 -0
  52. package/node_modules/graphql/language/parser.mjs +33 -0
  53. package/node_modules/graphql/language/predicates.js +3 -1
  54. package/node_modules/graphql/language/predicates.mjs +5 -1
  55. package/node_modules/graphql/language/printer.js +13 -1
  56. package/node_modules/graphql/language/printer.mjs +13 -1
  57. package/node_modules/graphql/package.json +1 -1
  58. package/node_modules/graphql/type/directives.d.ts +9 -1
  59. package/node_modules/graphql/type/directives.js +10 -1
  60. package/node_modules/graphql/type/directives.mjs +10 -1
  61. package/node_modules/graphql/type/introspection.js +24 -1
  62. package/node_modules/graphql/type/introspection.mjs +24 -1
  63. package/node_modules/graphql/utilities/buildASTSchema.js +4 -0
  64. package/node_modules/graphql/utilities/buildASTSchema.mjs +4 -0
  65. package/node_modules/graphql/utilities/buildClientSchema.js +1 -0
  66. package/node_modules/graphql/utilities/buildClientSchema.mjs +1 -0
  67. package/node_modules/graphql/utilities/coerceInputValue.js +2 -2
  68. package/node_modules/graphql/utilities/coerceInputValue.mjs +2 -2
  69. package/node_modules/graphql/utilities/extendSchema.js +58 -3
  70. package/node_modules/graphql/utilities/extendSchema.mjs +58 -3
  71. package/node_modules/graphql/utilities/getIntrospectionQuery.d.ts +16 -0
  72. package/node_modules/graphql/utilities/getIntrospectionQuery.js +31 -38
  73. package/node_modules/graphql/utilities/getIntrospectionQuery.mjs +31 -38
  74. package/node_modules/graphql/utilities/introspectionFromSchema.js +1 -0
  75. package/node_modules/graphql/utilities/introspectionFromSchema.mjs +1 -0
  76. package/node_modules/graphql/utilities/printSchema.js +1 -0
  77. package/node_modules/graphql/utilities/printSchema.mjs +1 -0
  78. package/node_modules/graphql/utilities/valueFromAST.js +12 -2
  79. package/node_modules/graphql/utilities/valueFromAST.mjs +12 -2
  80. package/node_modules/graphql/validation/rules/KnownDirectivesRule.js +4 -0
  81. package/node_modules/graphql/validation/rules/KnownDirectivesRule.mjs +4 -0
  82. package/node_modules/graphql/validation/rules/UniqueDirectivesPerLocationRule.js +12 -0
  83. package/node_modules/graphql/validation/rules/UniqueDirectivesPerLocationRule.mjs +12 -0
  84. package/node_modules/graphql/validation/rules/ValuesOfCorrectTypeRule.js +5 -11
  85. package/node_modules/graphql/validation/rules/ValuesOfCorrectTypeRule.mjs +5 -11
  86. package/node_modules/graphql/validation/validate.js +12 -0
  87. package/node_modules/graphql/validation/validate.mjs +13 -2
  88. package/node_modules/graphql/version.js +2 -2
  89. package/node_modules/graphql/version.mjs +2 -2
  90. package/node_modules/hasown/CHANGELOG.md +11 -0
  91. package/node_modules/hasown/eslint.config.mjs +6 -0
  92. package/node_modules/hasown/index.d.ts +1 -0
  93. package/node_modules/hasown/package.json +14 -14
  94. package/node_modules/iconv-lite/lib/index.d.ts +114 -26
  95. package/node_modules/iconv-lite/lib/index.js +39 -40
  96. package/node_modules/iconv-lite/package.json +13 -2
  97. package/node_modules/iconv-lite/types/encodings.d.ts +423 -0
  98. package/node_modules/node-abi/abi_registry.json +10 -3
  99. package/node_modules/{semver → node-abi/node_modules/semver}/README.md +19 -4
  100. package/node_modules/{semver → node-abi/node_modules/semver}/bin/semver.js +14 -10
  101. package/node_modules/node-abi/node_modules/semver/functions/truncate.js +48 -0
  102. package/node_modules/{semver → node-abi/node_modules/semver}/index.js +2 -0
  103. package/node_modules/{semver → node-abi/node_modules/semver}/internal/re.js +1 -1
  104. package/node_modules/{semver → node-abi/node_modules/semver}/package.json +3 -3
  105. package/node_modules/{semver → node-abi/node_modules/semver}/range.bnf +5 -4
  106. package/node_modules/node-abi/package.json +1 -1
  107. package/node_modules/path-to-regexp/Readme.md +3 -3
  108. package/node_modules/path-to-regexp/dist/index.d.ts +3 -0
  109. package/node_modules/path-to-regexp/dist/index.js +215 -193
  110. package/node_modules/path-to-regexp/dist/index.js.map +1 -1
  111. package/node_modules/path-to-regexp/package.json +2 -2
  112. package/node_modules/qs/.editorconfig +1 -1
  113. package/node_modules/qs/.github/SECURITY.md +11 -0
  114. package/node_modules/qs/.github/THREAT_MODEL.md +78 -0
  115. package/node_modules/qs/CHANGELOG.md +190 -0
  116. package/node_modules/qs/README.md +29 -4
  117. package/node_modules/qs/dist/qs.js +21 -21
  118. package/node_modules/qs/eslint.config.mjs +56 -0
  119. package/node_modules/qs/lib/parse.js +94 -49
  120. package/node_modules/qs/lib/utils.js +85 -11
  121. package/node_modules/qs/package.json +10 -9
  122. package/node_modules/qs/test/parse.js +391 -13
  123. package/node_modules/qs/test/stringify.js +16 -3
  124. package/node_modules/qs/test/utils.js +173 -3
  125. package/node_modules/send/package.json +11 -8
  126. package/node_modules/serve-static/README.md +23 -23
  127. package/node_modules/serve-static/package.json +6 -3
  128. package/node_modules/side-channel-list/CHANGELOG.md +25 -4
  129. package/node_modules/side-channel-list/index.js +1 -3
  130. package/node_modules/side-channel-list/package.json +8 -8
  131. package/node_modules/side-channel-list/test/index.js +50 -0
  132. package/node_modules/uuid/dist/v35.js +3 -0
  133. package/node_modules/uuid/dist/v6.js +3 -0
  134. package/node_modules/uuid/dist-node/v35.js +3 -0
  135. package/node_modules/uuid/dist-node/v6.js +3 -0
  136. package/node_modules/uuid/package.json +1 -1
  137. package/node_modules/ws/index.js +15 -6
  138. package/node_modules/ws/lib/constants.js +1 -0
  139. package/node_modules/ws/lib/permessage-deflate.js +6 -6
  140. package/node_modules/ws/lib/websocket-server.js +10 -6
  141. package/node_modules/ws/lib/websocket.js +19 -14
  142. package/node_modules/ws/package.json +4 -3
  143. package/node_modules/ws/wrapper.mjs +14 -1
  144. package/package.json +2 -2
  145. package/node_modules/content-disposition/HISTORY.md +0 -72
  146. package/node_modules/express/History.md +0 -3858
  147. package/node_modules/hasown/.eslintrc +0 -5
  148. package/node_modules/iconv-lite/Changelog.md +0 -236
  149. package/node_modules/qs/.eslintrc +0 -39
  150. package/node_modules/send/HISTORY.md +0 -580
  151. package/node_modules/serve-static/HISTORY.md +0 -516
  152. /package/node_modules/{semver → node-abi/node_modules/semver}/LICENSE +0 -0
  153. /package/node_modules/{semver → node-abi/node_modules/semver}/classes/comparator.js +0 -0
  154. /package/node_modules/{semver → node-abi/node_modules/semver}/classes/index.js +0 -0
  155. /package/node_modules/{semver → node-abi/node_modules/semver}/classes/range.js +0 -0
  156. /package/node_modules/{semver → node-abi/node_modules/semver}/classes/semver.js +0 -0
  157. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/clean.js +0 -0
  158. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/cmp.js +0 -0
  159. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/coerce.js +0 -0
  160. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/compare-build.js +0 -0
  161. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/compare-loose.js +0 -0
  162. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/compare.js +0 -0
  163. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/diff.js +0 -0
  164. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/eq.js +0 -0
  165. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/gt.js +0 -0
  166. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/gte.js +0 -0
  167. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/inc.js +0 -0
  168. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/lt.js +0 -0
  169. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/lte.js +0 -0
  170. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/major.js +0 -0
  171. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/minor.js +0 -0
  172. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/neq.js +0 -0
  173. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/parse.js +0 -0
  174. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/patch.js +0 -0
  175. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/prerelease.js +0 -0
  176. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/rcompare.js +0 -0
  177. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/rsort.js +0 -0
  178. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/satisfies.js +0 -0
  179. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/sort.js +0 -0
  180. /package/node_modules/{semver → node-abi/node_modules/semver}/functions/valid.js +0 -0
  181. /package/node_modules/{semver → node-abi/node_modules/semver}/internal/constants.js +0 -0
  182. /package/node_modules/{semver → node-abi/node_modules/semver}/internal/debug.js +0 -0
  183. /package/node_modules/{semver → node-abi/node_modules/semver}/internal/identifiers.js +0 -0
  184. /package/node_modules/{semver → node-abi/node_modules/semver}/internal/lrucache.js +0 -0
  185. /package/node_modules/{semver → node-abi/node_modules/semver}/internal/parse-options.js +0 -0
  186. /package/node_modules/{semver → node-abi/node_modules/semver}/preload.js +0 -0
  187. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/gtr.js +0 -0
  188. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/intersects.js +0 -0
  189. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/ltr.js +0 -0
  190. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/max-satisfying.js +0 -0
  191. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/min-satisfying.js +0 -0
  192. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/min-version.js +0 -0
  193. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/outside.js +0 -0
  194. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/simplify.js +0 -0
  195. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/subset.js +0 -0
  196. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/to-comparators.js +0 -0
  197. /package/node_modules/{semver → node-abi/node_modules/semver}/ranges/valid.js +0 -0
  198. /package/node_modules/{strip-json-comments → rc/node_modules/strip-json-comments}/index.js +0 -0
  199. /package/node_modules/{strip-json-comments → rc/node_modules/strip-json-comments}/license +0 -0
  200. /package/node_modules/{strip-json-comments → rc/node_modules/strip-json-comments}/package.json +0 -0
  201. /package/node_modules/{strip-json-comments → rc/node_modules/strip-json-comments}/readme.md +0 -0
@@ -1,9 +1,9 @@
1
- "use strict";var yt=Object.create;var ie=Object.defineProperty;var mt=Object.getOwnPropertyDescriptor;var ft=Object.getOwnPropertyNames;var vt=Object.getPrototypeOf,St=Object.prototype.hasOwnProperty;var x=(n,e)=>()=>(n&&(e=n(n=0)),e);var Ne=(n,e)=>{for(var t in e)ie(n,t,{get:e[t],enumerable:!0})},Ue=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ft(e))!St.call(n,i)&&i!==t&&ie(n,i,{get:()=>e[i],enumerable:!(r=mt(e,i))||r.enumerable});return n};var y=(n,e,t)=>(t=n!=null?yt(vt(n)):{},Ue(e||!n||!n.__esModule?ie(t,"default",{value:n,enumerable:!0}):t,n)),wt=n=>Ue(ie({},"__esModule",{value:!0}),n);function bt(n,e){if(e instanceof Error){let t={name:e.name,message:e.message};e.stack&&(t.stack=e.stack);for(let r of Object.keys(e))r in t||(t[r]=e[r]);return t}return e}function ge(n){return new N(n)}var V,se,Le,$e,N,a,We=x(()=>{"use strict";V=y(require("fs")),se=y(require("path")),Le=y(require("os")),$e={debug:0,info:1,warn:2,error:3};N=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=se.dirname(this.logFile);V.existsSync(e)||V.mkdirSync(e,{recursive:!0})}}shouldLog(e){return $e[e]>=$e[this.level]}formatMessage(e,t,r){let i=new Date().toISOString(),s=e.toUpperCase().padEnd(5),o=`[${i}] [${s}] [${this.name}] ${t}`;return r!==void 0&&(r instanceof Error?(o+=` ${r.name}: ${r.message}`,r.stack&&(o+=`
2
- ${r.stack}`)):typeof r=="object"?o+=` ${JSON.stringify(r,bt)}`:o+=` ${r}`),o}log(e,t,r){if(!this.shouldLog(e))return;let i=this.formatMessage(e,t,r);if(this.logFile)try{V.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}};a=new N({name:"codevibe-core",logFile:se.join(Le.tmpdir(),"codevibe-core.log"),level:"info"})});var U=x(()=>{"use strict";We()});function kt(n){for(let e of n)try{process.stderr.write(e+`
4
- `)}catch{}}function It(){he=me.join(Me.homedir(),".codevibe");try{_.mkdirSync(he,{recursive:!0,mode:448})}catch{}$="file"}function Et(){if($!==null||ye!==null)return;let optedIn=process.env.CODEVIBE_ALLOW_FILE_KEYCHAIN==="1";if(optedIn){kt(["","\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).",""]),a.warn("[keychain-backend] Using file-based storage at ~/.codevibe (CODEVIBE_ALLOW_FILE_KEYCHAIN=1 explicit opt-in)"),It();return}let keytarLoadError=null;try{let nodeRequire=eval("require");D=nodeRequire("keytar")}catch(n){keytarLoadError=n instanceof Error?n.message:String(n),D=null}if(D){$="keytar",a.info("[keychain-backend] Using keytar (OS-native keyring)");return}ye=new oe(["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 At(n){return n.replace(/[^a-zA-Z0-9._-]/g,"_")}function Be(n){return me.join(he,`${At(n)}.json`)}function fe(n){try{let e=_.readFileSync(Be(n),"utf-8"),t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function Fe(n,e){let t=Be(n);_.writeFileSync(t,JSON.stringify(e,null,2),{mode:384});try{_.chmodSync(t,384)}catch{}}function ve(){if(Et(),$===null)throw ye??new oe("Keychain backend not initialized")}async function Se(n,e){return ve(),$==="keytar"&&D?D.getPassword(n,e):fe(n)[e]??null}async function we(n,e,t){if(ve(),$==="keytar"&&D){await D.setPassword(n,e,t);return}let r=fe(n);r[e]=t,Fe(n,r)}async function be(n,e){if(ve(),$==="keytar"&&D)return D.deletePassword(n,e);let t=fe(n);return e in t?(delete t[e],Fe(n,t),!0):!1}var Me,me,_,oe,$,D,he,ye,qe=x(()=>{"use strict";Me=y(require("os")),me=y(require("path")),_=y(require("fs"));U();oe=class extends Error{constructor(e){super(e),this.name="KeychainBackendUnavailableError"}},$=null,D=null,he="",ye=null});var A,L,ke,Ct,J,k,He=x(()=>{"use strict";A=y(require("crypto")),L=class extends Error{constructor(e){super(e),this.name="CryptoError"}},ke=1,Ct="CodeVibe E2E v1",J=class n{constructor(){}static getInstance(){return n.instance||(n.instance=new n),n.instance}generateKeyPair(){let e=A.createECDH("prime256v1");e.generateKeys();let r=e.getPublicKey().subarray(1).toString("base64");return{privateKey:e.getPrivateKey().toString("base64"),publicKey:r}}generateSessionKey(){return A.randomBytes(32).toString("base64")}deriveSharedKey(e,t){try{let r=A.createECDH("prime256v1"),i=Buffer.from(e,"base64");r.setPrivateKey(i);let s=Buffer.concat([Buffer.from([4]),Buffer.from(t,"base64")]),o=r.computeSecret(s),c=A.hkdfSync("sha256",o,Buffer.alloc(0),Buffer.from(Ct,"utf8"),32);return Buffer.from(c)}catch(r){throw new L(`Failed to derive shared key: ${r}`)}}encryptSessionKey(e,t){let r=this.generateKeyPair(),i=this.deriveSharedKey(r.privateKey,t),s=Buffer.from(e,"base64");return{encryptedKey:this.encrypt(s,i).toString("base64"),ephemeralPublicKey:r.publicKey}}decryptSessionKey(e,t){let r=this.deriveSharedKey(t,e.ephemeralPublicKey),i=Buffer.from(e.encryptedKey,"base64");return this.decrypt(i,r).toString("base64")}encryptContent(e,t){let r=Buffer.from(t,"base64"),i=Buffer.from(e,"utf8");return this.encrypt(i,r).toString("base64")}decryptContent(e,t){let r=Buffer.from(t,"base64"),i=Buffer.from(e,"base64");return this.decrypt(i,r).toString("utf8")}encryptMetadata(e,t){let r=JSON.stringify(e);return this.encryptContent(r,t)}decryptMetadata(e,t){let r=this.decryptContent(e,t);return JSON.parse(r)}encryptData(e,t){let r=Buffer.from(t,"base64");return this.encrypt(e,r)}decryptData(e,t){let r=Buffer.from(t,"base64");return this.decrypt(e,r)}encrypt(e,t){let r=A.randomBytes(12),i=A.createCipheriv("aes-256-gcm",t,r),s=Buffer.concat([i.update(e),i.final()]),o=i.getAuthTag();return Buffer.concat([r,s,o])}decrypt(e,t){let r=e.subarray(0,12),i=e.subarray(e.length-16),s=e.subarray(12,e.length-16),o=A.createDecipheriv("aes-256-gcm",t,r);o.setAuthTag(i);try{return Buffer.concat([o.update(s),o.final()])}catch{throw new L("Decryption failed: Invalid ciphertext or authentication tag")}}serializePrivateKey(e){return e}deserializePrivateKey(e){return e}},k=J.getInstance()});var X=x(()=>{"use strict";He()});function I(){let n=process.env.ENVIRONMENT;return n==="development"||n==="production"?n:"production"}function ce(n){let e=n||I();return ae={...W[e],aws:{...W[e].aws,region:process.env.AWS_REGION||W[e].aws.region,appsyncUrl:process.env.APPSYNC_URL||W[e].aws.appsyncUrl,cognitoUserPoolId:process.env.COGNITO_USER_POOL_ID||W[e].aws.cognitoUserPoolId,cognitoClientId:process.env.COGNITO_CLIENT_ID||W[e].aws.cognitoClientId,cognitoDomain:process.env.COGNITO_DOMAIN||W[e].aws.cognitoDomain}},Ve=!0,ae}function f(){return(!Ve||!ae)&&ce(),ae}var Z,Q,W,ae,Ve,Je=x(()=>{"use strict";Z=y(require("os")),Q=y(require("path")),W={development:{environment:"development",aws:{region:"us-east-1",appsyncUrl:"https://api-dev.codevibe.quantiya.ai/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(Z.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:Q.default.join(Z.default.homedir(),".gemini","tmp")}},production:{environment:"production",aws:{region:"us-east-1",appsyncUrl:"https://api.codevibe.quantiya.ai/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(Z.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:Q.default.join(Z.default.homedir(),".gemini","tmp")}}},ae=null,Ve=!1});var j=x(()=>{"use strict";Je()});var de,je,K,Ie,xt,M,g,ze=x(()=>{"use strict";de=y(require("os")),je=require("uuid");qe();X();j();U();K=class extends Error{constructor(e){super(e),this.name="KeychainError"}},Ie="device-identity",xt="tokens-",M=class n{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 n.instance||(n.instance=new n),n.instance}async getDeviceIdentity(){if(this.deviceIdentity)return this.deviceIdentity;let e=await Se(this.serviceName,Ie);return e?(this.deviceIdentity=JSON.parse(e),a.info(`[KeychainManager] Loaded device identity: ${this.deviceIdentity.deviceId}`),this.deviceIdentity):null}async setDeviceIdentity(e){try{await we(this.serviceName,Ie,JSON.stringify(e)),this.deviceIdentity=e,a.info(`[KeychainManager] Saved device identity: ${e.deviceId}`)}catch(t){throw a.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=k.generateKeyPair();return e={deviceId:(0,je.v4)().toUpperCase(),privateKey:t.privateKey,publicKey:t.publicKey,createdAt:new Date().toISOString()},await this.setDeviceIdentity(e),a.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 be(this.serviceName,Ie),this.deviceIdentity=null,this.sessionKeyCache.clear(),this.isRegistered=!1,a.info("[KeychainManager] Deleted device identity")}catch(e){throw a.error(`[KeychainManager] Failed to delete device identity: ${e}`),new K(`Failed to delete device identity: ${e}`)}}getTokenAccount(e){return`${xt}${e}`}async getTokens(e="production"){let t=await Se(this.serviceName,this.getTokenAccount(e));if(!t)return null;let r=JSON.parse(t);return a.debug(`[KeychainManager] Loaded tokens for ${e}`),r}async setTokens(e,t="production"){try{await we(this.serviceName,this.getTokenAccount(t),JSON.stringify(e)),a.info(`[KeychainManager] Saved tokens for ${t}`,{userId:e.userId,email:e.email})}catch(r){throw a.error(`[KeychainManager] Failed to save tokens: ${r}`),new K(`Failed to save tokens: ${r}`)}}async deleteTokens(e="production"){try{let t=await be(this.serviceName,this.getTokenAccount(e));return t&&a.info(`[KeychainManager] Deleted tokens for ${e}`),t}catch(t){return a.error(`[KeychainManager] Failed to delete tokens: ${t}`),!1}}isTokenExpired(e){return Date.now()>=e.expiresAt-3e5}async getSessionKey(e,t){let r=this.sessionKeyCache.get(e);if(r)return r;if(!t||t.length===0)return null;let i=await this.getDeviceId(),s=t.find(d=>d.deviceId===i);if(!s)return a.warn(`[KeychainManager] Device ${i} not found in encryptedKeys`),null;let o=await this.getDevicePrivateKey(),c=k.decryptSessionKey(s,o);return this.sessionKeyCache.set(e,c),a.info(`[KeychainManager] Decrypted and cached session key for ${e}`),c}createSessionKey(e){let t=k.generateSessionKey(),r=e.map(i=>{let s=k.encryptSessionKey(t,i.publicKey);return{deviceId:i.deviceId,encryptedKey:s.encryptedKey,ephemeralPublicKey:s.ephemeralPublicKey}});return a.info(`[KeychainManager] Created session key for ${e.length} devices`),{sessionKey:t,encryptedKeys:r}}cacheSessionKey(e,t){this.sessionKeyCache.set(e,t)}getCachedSessionKey(e){return this.sessionKeyCache.get(e)??null}getCachedSessionIds(){return Array.from(this.sessionKeyCache.keys())}clearSessionKey(e){this.sessionKeyCache.delete(e)}clearAllSessionKeys(){this.sessionKeyCache.clear()}getIsRegistered(){return this.isRegistered}setIsRegistered(e){this.isRegistered=e}getDeviceName(){return de.hostname()||"CLI Client"}getDevicePlatform(){let e=de.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,a.info("[KeychainManager] Cleared all data")}},g=M.getInstance()});var Ge={};Ne(Ge,{KeychainError:()=>K,KeychainManager:()=>M,keychainManager:()=>g});var P=x(()=>{"use strict";ze()});var Yt={};Ne(Yt,{AgentType:()=>et,AppSyncClient:()=>ee,AuthService:()=>G,CryptoError:()=>L,CryptoService:()=>J,DeliveryStatus:()=>Qe,ENCRYPTION_VERSION:()=>ke,EventSource:()=>Ee,EventType:()=>Ze,KeychainError:()=>K,KeychainManager:()=>M,Logger:()=>N,SessionStatus:()=>le,authService:()=>R,createLogger:()=>ge,cryptoService:()=>k,errorWasBeaconed:()=>re,fireAuthCompletedBeacon:()=>te,fireAuthFailedBeacon:()=>S,getConfig:()=>f,getEnvironment:()=>I,getErrorReason:()=>Te,keychainManager:()=>g,loadConfig:()=>ce,logger:()=>a,markErrorBeaconed:()=>E,mutations:()=>C,normalizeSnapshot:()=>Re,parseInteractivePrompt:()=>pt,prepareSessionEncryption:()=>ue,queries:()=>O,registerDeviceEncryptionKey:()=>Oe,rekeySessionForNewDevices:()=>H,resumeOrCreateSession:()=>_e,runAuthCli:()=>pe,startDeviceKeyWatcher:()=>Pe,subscriptions:()=>B});module.exports=wt(Yt);P();X();var F=y(require("ws")),q=require("uuid");j();U();P();var Ye=y(require("dns")),Xe=y(require("fs"));if(Dt())try{Ye.setDefaultResultOrder("ipv4first")}catch{}function Dt(){if(process.platform!=="linux")return!1;try{let n=Xe.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(n)}catch{return!1}}async function z(n,e,t){try{return await fetch(n,e)}catch(r){let i=r?.cause?.code,s=r?.cause?.message,o=i||s||r?.message||"unknown",c=Kt(i),d=t?`${t}: `:"",l=`Node ${process.version} on ${process.platform}`,h=[`${d}Cannot reach ${n}`,` Underlying error: ${o}`];c&&h.push(` Suggested fix: ${c}`),h.push(` Platform: ${l}`);let u=new Error(h.join(`
6
- `));throw u.cause=r,u}}function Kt(n){if(!n)return null;switch(n){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 O={getSession:`
1
+ "use strict";var It=Object.create;var ce=Object.defineProperty;var At=Object.getOwnPropertyDescriptor;var Tt=Object.getOwnPropertyNames;var Ct=Object.getPrototypeOf,Dt=Object.prototype.hasOwnProperty;var D=(n,e)=>()=>(n&&(e=n(n=0)),e);var Me=(n,e)=>{for(var t in e)ce(n,t,{get:e[t],enumerable:!0})},Be=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Tt(e))!Dt.call(n,i)&&i!==t&&ce(n,i,{get:()=>e[i],enumerable:!(r=At(e,i))||r.enumerable});return n};var v=(n,e,t)=>(t=n!=null?It(Ct(n)):{},Be(e||!n||!n.__esModule?ce(t,"default",{value:n,enumerable:!0}):t,n)),xt=n=>Be(ce({},"__esModule",{value:!0}),n);function _t(n,e){if(e instanceof Error){let t={name:e.name,message:e.message};e.stack&&(t.stack=e.stack);for(let r of Object.keys(e))r in t||(t[r]=e[r]);return t}return e}function ve(n){return new W(n)}var G,de,qe,Fe,W,c,He=D(()=>{"use strict";G=v(require("fs")),de=v(require("path")),qe=v(require("os")),Fe={debug:0,info:1,warn:2,error:3};W=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=de.dirname(this.logFile);G.existsSync(e)||G.mkdirSync(e,{recursive:!0})}}shouldLog(e){return Fe[e]>=Fe[this.level]}formatMessage(e,t,r){let i=new Date().toISOString(),s=e.toUpperCase().padEnd(5),o=`[${i}] [${s}] [${this.name}] ${t}`;return r!==void 0&&(r instanceof Error?(o+=` ${r.name}: ${r.message}`,r.stack&&(o+=`
2
+ ${r.stack}`)):typeof r=="object"?o+=` ${JSON.stringify(r,_t)}`:o+=` ${r}`),o}log(e,t,r){if(!this.shouldLog(e))return;let i=this.formatMessage(e,t,r);if(this.logFile)try{G.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 W({name:"codevibe-core",logFile:de.join(qe.tmpdir(),"codevibe-core.log"),level:"info"})});var M=D(()=>{"use strict";He()});function Kt(n){for(let e of n)try{process.stderr.write(e+`
4
+ `)}catch{}}function Rt(){Se=ke.join(Ve.homedir(),".codevibe");try{N.mkdirSync(Se,{recursive:!0,mode:448})}catch{}B="file"}function Pt(){if(B!==null||we!==null)return;let optedIn=process.env.CODEVIBE_ALLOW_FILE_KEYCHAIN==="1";if(optedIn){Kt(["","\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)"),Rt();return}let keytarLoadError=null;try{let nodeRequire=eval("require");x=nodeRequire("keytar")}catch(n){keytarLoadError=n instanceof Error?n.message:String(n),x=null}if(x){B="keytar",c.info("[keychain-backend] Using keytar (OS-native keyring)");return}we=new le(["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 Ot(n){return n.replace(/[^a-zA-Z0-9._-]/g,"_")}function Je(n){return ke.join(Se,`${Ot(n)}.json`)}function be(n){try{let e=N.readFileSync(Je(n),"utf-8"),t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function je(n,e){let t=Je(n);N.writeFileSync(t,JSON.stringify(e,null,2),{mode:384});try{N.chmodSync(t,384)}catch{}}function Ee(){if(Pt(),B===null)throw we??new le("Keychain backend not initialized")}async function Ie(n,e){return Ee(),B==="keytar"&&x?x.getPassword(n,e):be(n)[e]??null}async function Ae(n,e,t){if(Ee(),B==="keytar"&&x){await x.setPassword(n,e,t);return}let r=be(n);r[e]=t,je(n,r)}async function Te(n,e){if(Ee(),B==="keytar"&&x)return x.deletePassword(n,e);let t=be(n);return e in t?(delete t[e],je(n,t),!0):!1}var Ve,ke,N,le,B,x,Se,we,Ge=D(()=>{"use strict";Ve=v(require("os")),ke=v(require("path")),N=v(require("fs"));M();le=class extends Error{constructor(e){super(e),this.name="KeychainBackendUnavailableError"}},B=null,x=null,Se="",we=null});var T,_,Ce,Ut,z,E,ze=D(()=>{"use strict";T=v(require("crypto")),_=class extends Error{constructor(e){super(e),this.name="CryptoError"}},Ce=1,Ut="CodeVibe E2E v1",z=class n{constructor(){}static getInstance(){return n.instance||(n.instance=new n),n.instance}generateKeyPair(){let e=T.createECDH("prime256v1");e.generateKeys();let r=e.getPublicKey().subarray(1).toString("base64");return{privateKey:e.getPrivateKey().toString("base64"),publicKey:r}}generateSessionKey(){return T.randomBytes(32).toString("base64")}deriveSharedKey(e,t){try{let r=T.createECDH("prime256v1"),i=Buffer.from(e,"base64");r.setPrivateKey(i);let s=Buffer.concat([Buffer.from([4]),Buffer.from(t,"base64")]),o=r.computeSecret(s),a=T.hkdfSync("sha256",o,Buffer.alloc(0),Buffer.from(Ut,"utf8"),32);return Buffer.from(a)}catch(r){throw new _(`Failed to derive shared key: ${r}`)}}encryptSessionKey(e,t){let r=this.generateKeyPair(),i=this.deriveSharedKey(r.privateKey,t),s=Buffer.from(e,"base64");return{encryptedKey:this.encrypt(s,i).toString("base64"),ephemeralPublicKey:r.publicKey}}decryptSessionKey(e,t){let r=this.deriveSharedKey(t,e.ephemeralPublicKey),i=Buffer.from(e.encryptedKey,"base64");return this.decrypt(i,r).toString("base64")}encryptContent(e,t){let r=Buffer.from(t,"base64"),i=Buffer.from(e,"utf8");return this.encrypt(i,r).toString("base64")}decryptContent(e,t){let r=Buffer.from(t,"base64"),i=Buffer.from(e,"base64");return this.decrypt(i,r).toString("utf8")}encryptMetadata(e,t){let r=JSON.stringify(e);return this.encryptContent(r,t)}decryptMetadata(e,t){let r=this.decryptContent(e,t);return JSON.parse(r)}encryptData(e,t){let r=Buffer.from(t,"base64");return this.encrypt(e,r)}decryptData(e,t){let r=Buffer.from(t,"base64");return this.decrypt(e,r)}encrypt(e,t){let r=T.randomBytes(12),i=T.createCipheriv("aes-256-gcm",t,r),s=Buffer.concat([i.update(e),i.final()]),o=i.getAuthTag();return Buffer.concat([r,s,o])}decrypt(e,t){let r=e.subarray(0,12),i=e.subarray(e.length-16),s=e.subarray(12,e.length-16),o=T.createDecipheriv("aes-256-gcm",t,r);o.setAuthTag(i);try{return Buffer.concat([o.update(s),o.final()])}catch{throw new _("Decryption failed: Invalid ciphertext or authentication tag")}}serializePrivateKey(e){return e}deserializePrivateKey(e){return e}},E=z.getInstance()});var ee=D(()=>{"use strict";ze()});function I(){let n=process.env.ENVIRONMENT;return n==="development"||n==="production"?n:"production"}function ue(n){let e=n||I();return pe={...F[e],aws:{...F[e].aws,region:process.env.AWS_REGION||F[e].aws.region,appsyncUrl:process.env.APPSYNC_URL||F[e].aws.appsyncUrl,cognitoUserPoolId:process.env.COGNITO_USER_POOL_ID||F[e].aws.cognitoUserPoolId,cognitoClientId:process.env.COGNITO_CLIENT_ID||F[e].aws.cognitoClientId,cognitoDomain:process.env.COGNITO_DOMAIN||F[e].aws.cognitoDomain}},Ye=!0,pe}function w(){return(!Ye||!pe)&&ue(),pe}var te,re,F,pe,Ye,Xe=D(()=>{"use strict";te=v(require("os")),re=v(require("path")),F={development:{environment:"development",aws:{region:"us-east-1",appsyncUrl:"https://api-dev.codevibe.quantiya.ai/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:re.default.join(te.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:re.default.join(te.default.homedir(),".gemini","tmp")}},production:{environment:"production",aws:{region:"us-east-1",appsyncUrl:"https://api.codevibe.quantiya.ai/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:re.default.join(te.default.homedir(),".codex","sessions"),approvalTimeoutMs:5e3},gemini:{command:"gemini",defaultTimeout:6e4,transcriptDir:re.default.join(te.default.homedir(),".gemini","tmp")}}},pe=null,Ye=!1});var Y=D(()=>{"use strict";Xe()});var ye,Ze,K,De,$t,q,y,Qe=D(()=>{"use strict";ye=v(require("os")),Ze=require("uuid");Ge();ee();Y();M();K=class extends Error{constructor(e){super(e),this.name="KeychainError"}},De="device-identity",$t="tokens-",q=class n{constructor(){this.deviceIdentity=null;this.sessionKeyCache=new Map;this.isRegistered=!1;this._serviceName=null}get serviceName(){return this._serviceName||(this._serviceName=w().keychain.serviceName),this._serviceName}static getInstance(){return n.instance||(n.instance=new n),n.instance}async getDeviceIdentity(){if(this.deviceIdentity)return this.deviceIdentity;let e=await Ie(this.serviceName,De);return e?(this.deviceIdentity=JSON.parse(e),c.info(`[KeychainManager] Loaded device identity: ${this.deviceIdentity.deviceId}`),this.deviceIdentity):null}async setDeviceIdentity(e){try{await Ae(this.serviceName,De,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=E.generateKeyPair();return e={deviceId:(0,Ze.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 Te(this.serviceName,De),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`${$t}${e}`}async getTokens(e="production"){let t=await Ie(this.serviceName,this.getTokenAccount(e));if(!t)return null;let r=JSON.parse(t);return c.debug(`[KeychainManager] Loaded tokens for ${e}`),r}async setTokens(e,t="production"){try{await Ae(this.serviceName,this.getTokenAccount(t),JSON.stringify(e)),c.info(`[KeychainManager] Saved tokens for ${t}`,{userId:e.userId,email:e.email})}catch(r){throw c.error(`[KeychainManager] Failed to save tokens: ${r}`),new K(`Failed to save tokens: ${r}`)}}async deleteTokens(e="production"){try{let t=await Te(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 r=this.sessionKeyCache.get(e);if(r)return r;if(!t||t.length===0)return null;let i=await this.getDeviceId(),s=t.find(d=>d.deviceId===i);if(!s)return c.warn(`[KeychainManager] Device ${i} not found in encryptedKeys`),null;let o=await this.getDevicePrivateKey(),a=E.decryptSessionKey(s,o);return this.sessionKeyCache.set(e,a),c.info(`[KeychainManager] Decrypted and cached session key for ${e}`),a}createSessionKey(e,t){let r=E.generateSessionKey(),i=[],s=[];for(let o of e)try{let a=E.encryptSessionKey(r,o.publicKey);i.push({deviceId:o.deviceId,encryptedKey:a.encryptedKey,ephemeralPublicKey:a.ephemeralPublicKey})}catch(a){c.warn("[KeychainManager] Skipping device with invalid public key",{deviceId:o.deviceId,error:a instanceof Error?a.message:String(a)}),s.push(o.deviceId);try{t?.onDeviceSkipped?.(s.length)}catch{}}if(i.length===0)throw new _(`Failed to encrypt session key for any of ${e.length} devices`);return c.info("[KeychainManager] Created session key",{encryptedCount:i.length,skippedCount:s.length,totalCount:e.length}),{sessionKey:r,encryptedKeys:i,skippedDeviceIds:s}}cacheSessionKey(e,t){this.sessionKeyCache.set(e,t)}getCachedSessionKey(e){return this.sessionKeyCache.get(e)??null}getCachedSessionIds(){return Array.from(this.sessionKeyCache.keys())}clearSessionKey(e){this.sessionKeyCache.delete(e)}clearAllSessionKeys(){this.sessionKeyCache.clear()}getIsRegistered(){return this.isRegistered}setIsRegistered(e){this.isRegistered=e}getDeviceName(){return ye.hostname()||"CLI Client"}getDevicePlatform(){let e=ye.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")}},y=q.getInstance()});var et={};Me(et,{KeychainError:()=>K,KeychainManager:()=>q,keychainManager:()=>y});var R=D(()=>{"use strict";Qe()});var sr={};Me(sr,{AgentType:()=>st,AppSyncClient:()=>ne,AuthService:()=>Q,CryptoError:()=>_,CryptoService:()=>z,DeliveryStatus:()=>it,ENCRYPTION_VERSION:()=>Ce,EventSource:()=>xe,EventType:()=>nt,KeychainError:()=>K,KeychainManager:()=>q,Logger:()=>W,SessionStatus:()=>he,authService:()=>P,createLogger:()=>ve,cryptoService:()=>E,errorWasBeaconed:()=>se,fireAuthCompletedBeacon:()=>ie,fireAuthFailedBeacon:()=>b,getConfig:()=>w,getEnvironment:()=>I,getErrorReason:()=>Re,keychainManager:()=>y,loadConfig:()=>ue,logger:()=>c,markErrorBeaconed:()=>A,mutations:()=>C,normalizeSnapshot:()=>$e,parseInteractivePrompt:()=>St,prepareSessionEncryption:()=>fe,queries:()=>U,registerDeviceEncryptionKey:()=>ae,rekeySessionForNewDevices:()=>j,resumeOrCreateSession:()=>Le,runAuthCli:()=>me,startDeviceKeyWatcher:()=>We,subscriptions:()=>H});module.exports=xt(sr);R();ee();var V=v(require("ws")),J=require("uuid");Y();M();R();var tt=v(require("dns")),rt=v(require("fs"));if(Lt())try{tt.setDefaultResultOrder("ipv4first")}catch{}function Lt(){if(process.platform!=="linux")return!1;try{let n=rt.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(n)}catch{return!1}}async function X(n,e,t){try{return await fetch(n,e)}catch(r){let i=r?.cause?.code,s=r?.cause?.message,o=i||s||r?.message||"unknown",a=Wt(i),d=t?`${t}: `:"",l=`Node ${process.version} on ${process.platform}`,h=[`${d}Cannot reach ${n}`,` Underlying error: ${o}`];a&&h.push(` Suggested fix: ${a}`),h.push(` Platform: ${l}`);let p=new Error(h.join(`
6
+ `));throw p.cause=r,p}}function Wt(n){if(!n)return null;switch(n){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 U={getSession:`
7
7
  query GetSession($sessionId: ID!) {
8
8
  getSession(sessionId: $sessionId) {
9
9
  sessionId
@@ -155,7 +155,7 @@ ${r.stack}`)):typeof r=="object"?o+=` ${JSON.stringify(r,bt)}`:o+=` ${r}`),o}log
155
155
  expiresAt
156
156
  }
157
157
  }
158
- `},B={onEventCreated:`
158
+ `},H={onEventCreated:`
159
159
  subscription OnEventCreated($sessionId: ID!) {
160
160
  onEventCreated(sessionId: $sessionId) {
161
161
  eventId
@@ -202,7 +202,7 @@ ${r.stack}`)):typeof r=="object"?o+=` ${JSON.stringify(r,bt)}`:o+=` ${r}`),o}log
202
202
  updatedAt
203
203
  }
204
204
  }
205
- `};var Ze=(c=>(c.USER_PROMPT="USER_PROMPT",c.ASSISTANT_RESPONSE="ASSISTANT_RESPONSE",c.TOOL_USE="TOOL_USE",c.NOTIFICATION="NOTIFICATION",c.INTERACTIVE_PROMPT="INTERACTIVE_PROMPT",c.PROMPT_RESPONSE="PROMPT_RESPONSE",c.REASONING="REASONING",c))(Ze||{}),Ee=(t=>(t.DESKTOP="DESKTOP",t.MOBILE="MOBILE",t))(Ee||{}),Qe=(r=>(r.SENT="SENT",r.DELIVERED="DELIVERED",r.EXECUTED="EXECUTED",r))(Qe||{});var le=(r=>(r.ACTIVE="ACTIVE",r.INACTIVE="INACTIVE",r.PAUSED="PAUSED",r))(le||{}),et=(r=>(r.CLAUDE="CLAUDE",r.GEMINI="GEMINI",r.CODEX="CODEX",r))(et||{});var v={urgentMaxAttempts:10,baseDelayMs:1e3,maxDelayMs:6e4,backoffMultiplier:2,persistentDelayMs:300*1e3},ee=class n{constructor(){this.authenticated=!1;this.currentUserId=null;this.currentEmail=null;this.tokens=null;this.activeSubscriptions=new Map;this.pendingRefresh=null;this.lastRefreshFailureAt=null;this.deviceKeyWatcher=null;this.sessionUpdateWatchers=new Map;this.heartbeatTimers=new Map;this.environment=I(),a.info("[AppSyncClient] Initialized",{environment:this.environment})}static{this.REFRESH_BACKOFF_MS=3e4}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 a.debug("[AppSyncClient] No stored tokens found"),!1;if(a.info("[AppSyncClient] Found stored OAuth tokens",{userId:e.userId,email:e.email,expired:g.isTokenExpired(e)}),g.isTokenExpired(e)){if(a.info("[AppSyncClient] Tokens expired, attempting refresh..."),!await this.refreshTokens(e))return a.warn("[AppSyncClient] Token refresh failed"),!1}else this.tokens=e;return this.currentUserId=this.tokens.userId,this.currentEmail=this.tokens.email,this.authenticated=!0,a.info("[AppSyncClient] Authenticated successfully",{userId:this.currentUserId,email:this.currentEmail}),!0}catch(e){return a.error("[AppSyncClient] Authentication failed:",e),!1}}async refreshTokens(e){if(this.pendingRefresh)return this.pendingRefresh;if(this.lastRefreshFailureAt!==null&&Date.now()-this.lastRefreshFailureAt<n.REFRESH_BACKOFF_MS)return!1;this.pendingRefresh=this.performRefresh(e);try{return await this.pendingRefresh}finally{this.pendingRefresh=null}}async performRefresh(e){let t=await this.callCognitoRefresh(e.refreshToken);if(t!==null)return this.applyRefreshedTokens(e,t);let r=null;try{r=await g.getTokens(this.environment)}catch(i){a.warn("[AppSyncClient] Failed to re-read tokens from storage during refresh recovery",{error:i instanceof Error?i.message:String(i)})}if(r&&r.refreshToken&&r.refreshToken!==e.refreshToken){a.info("[AppSyncClient] In-memory refresh token rejected; retrying with storage-backed token (likely out-of-band re-auth)");let i=await this.callCognitoRefresh(r.refreshToken);if(i!==null)return this.applyRefreshedTokens(r,i)}return this.lastRefreshFailureAt=Date.now(),!1}async callCognitoRefresh(e){try{let t=f(),r=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e}),s=await z(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},"Token refresh");return s.ok?await s.json():(a.error("[AppSyncClient] Token refresh failed",{status:s.status}),null)}catch(t){return a.error("[AppSyncClient] Token refresh error:",t),null}}async applyRefreshedTokens(e,t){let r={...e,accessToken:t.access_token,idToken:t.id_token,expiresAt:Date.now()+t.expires_in*1e3};this.tokens=r,this.lastRefreshFailureAt=null;try{await g.setTokens(r,this.environment),a.info("[AppSyncClient] Tokens refreshed",{expiresAt:new Date(r.expiresAt).toISOString()})}catch(i){a.warn("[AppSyncClient] Tokens refreshed but persistence failed; daemon keeps using fresh tokens in memory. A restart while persistence is still broken would lose them.",{error:i instanceof Error?i.message:String(i),expiresAt:new Date(r.expiresAt).toISOString()})}return!0}isAuthenticated(){return this.authenticated}signOut(){this.authenticated=!1,this.tokens=null,this.currentUserId=null,this.currentEmail=null,this.cleanupSubscriptions(),a.info("[AppSyncClient] Signed out")}async graphqlRequest(e,t,r=!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 z(i.aws.appsyncUrl,{method:"POST",headers:s,body:JSON.stringify({query:e,variables:t})},"AppSync GraphQL request"),c=await o.json();if(o.status===401&&!r&&this.tokens){if(a.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(c.errors?.length)throw new Error(`GraphQL error: ${c.errors[0].message}`);return c}async createSession(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},r=await this.graphqlRequest(C.createSession,{input:t});return a.info("[AppSyncClient] Session created",{sessionId:r.data.createSession.sessionId}),r.data.createSession}async updateSession(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},r=await this.graphqlRequest(C.updateSession,{input:t});return a.debug("[AppSyncClient] Session updated",{sessionId:r.data.updateSession.sessionId}),r.data.updateSession}async getSession(e){return(await this.graphqlRequest(O.getSession,{sessionId:e})).data.getSession}async createEvent(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},r=await this.graphqlRequest(C.createEvent,{input:t});return a.debug("[AppSyncClient] Event created",{eventId:r.data.createEvent.eventId,type:r.data.createEvent.type}),r.data.createEvent}async updateEventStatus(e){return(await this.graphqlRequest(C.updateEventStatus,{input:e})).data.updateEventStatus}async listEvents(e,t,r){return(await this.graphqlRequest(O.listEvents,{sessionId:e,source:t,limit:r})).data.listEvents.items}async listSessions(e=100){if(!this.currentUserId)throw new Error("Not authenticated");let t=[],r=null;do{let s=(await this.graphqlRequest(O.listSessions,{userId:this.currentUserId,limit:e,nextToken:r})).data?.listSessions;s?.items&&t.push(...s.items),r=s?.nextToken??null}while(r);return t}async sweepOrphanSessions(e){let t=e.staleThresholdMs??9e5,r=new Set(e.excludeSessionIds??[]),i=Date.now(),s;try{s=await this.listSessions()}catch(c){return a.warn("[AppSyncClient] OrphanSweep: listSessions failed, skipping sweep",{agentType:e.agentType,error:c instanceof Error?c.message:String(c)}),0}let o=0;for(let c of s){if(c.agentType!==e.agentType||c.status!=="ACTIVE"||r.has(c.sessionId)||!c.lastHeartbeatAt)continue;let d=i-new Date(c.lastHeartbeatAt).getTime();if(!(d<t)){a.warn("[AppSyncClient] OrphanSweep: marking stale session INACTIVE",{sessionId:c.sessionId,agentType:c.agentType,lastHeartbeatAt:c.lastHeartbeatAt,heartbeatAgeMinutes:Math.round(d/6e4)});try{await this.updateSession({sessionId:c.sessionId,status:"INACTIVE"}),o++}catch(l){a.warn("[AppSyncClient] OrphanSweep: updateSession failed, leaving row as-is",{sessionId:c.sessionId,error:l instanceof Error?l.message:String(l)})}}}return o>0&&a.info("[AppSyncClient] OrphanSweep complete",{agentType:e.agentType,swept:o}),o}async listUserDeviceKeys(){return(await this.graphqlRequest(O.listUserDeviceKeys,{})).data.listUserDeviceKeys||[]}async registerDeviceKey(e,t,r,i){let s={deviceId:e,publicKey:t,platform:r,deviceName:i};await this.graphqlRequest(C.registerDeviceKey,{input:s}),a.info("[AppSyncClient] Device key registered",{deviceId:e,platform:r})}async grantSessionKey(e){await this.graphqlRequest(C.grantSessionKey,{input:e}),a.info("[AppSyncClient] Session key granted",{sessionId:e.sessionId,deviceId:e.deviceId})}async getAttachmentDownloadUrl(e){return(await this.graphqlRequest(C.getAttachmentDownloadUrl,{s3Key:e})).data.getAttachmentDownloadUrl}subscribeToEvents(e,t,r){a.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,q.v4)(),sessionId:e,onEvent:t,onError:r,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=new URL(e.aws.appsyncUrl),i=/\.appsync-api\.[^.]+\.amazonaws\.com$/.test(t.host)?e.aws.appsyncUrl.replace("https://","wss://").replace("appsync-api","appsync-realtime-api"):`wss://${t.host}/graphql/realtime`,s={host:t.host};this.tokens?.idToken&&(s.Authorization=this.tokens.idToken);let o=Buffer.from(JSON.stringify(s)).toString("base64"),c=Buffer.from(JSON.stringify({})).toString("base64");return`${i}?header=${o}&payload=${c}`}createSubscription(e){let{sessionId:t,subscriptionId:r,onEvent:i,onError:s}=e;try{let o=this.buildRealtimeUrl(),c=new F.default(o,["graphql-ws"]);c.on("open",()=>{a.info("[AppSyncClient] WebSocket connected",{sessionId:t}),c.send(JSON.stringify({type:"connection_init"}))}),c.on("message",d=>{try{let l=JSON.parse(d.toString());switch(l.type){case"connection_ack":this.sendSubscriptionStart(c,e);break;case"start_ack":a.info("[AppSyncClient] Subscription started",{sessionId:t}),e.isReconnecting=!1,e.reconnectAttempts=0,this.startHeartbeat(t);break;case"data":this.resetKeepAliveTimer(e);let h=l.payload?.data?.onEventCreated;h&&h.source==="MOBILE"&&i(h);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){a.error("[AppSyncClient] Failed to parse message",{error:l})}}),c.on("error",d=>{a.error("[AppSyncClient] WebSocket error",{sessionId:t,error:d.message}),this.handleSubscriptionError(e,d)}),c.on("close",(d,l)=>{a.info("[AppSyncClient] WebSocket closed",{sessionId:t,code:d}),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),!e.destroyed&&this.activeSubscriptions.get(t)===e&&this.handleSubscriptionError(e,new Error(`WebSocket closed: ${d}`))}),e.ws=c,this.resetKeepAliveTimer(e)}catch(o){this.handleSubscriptionError(e,o)}}sendSubscriptionStart(e,t){let r=f(),{sessionId:i,subscriptionId:s}=t,o={host:new URL(r.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:s,type:"start",payload:{data:JSON.stringify({query:B.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:r,onError:i}=e;if(e.isReconnecting||!this.activeSubscriptions.has(r))return;e.isReconnecting=!0,e.reconnectAttempts++,this.stopHeartbeat(r);let s=e.reconnectAttempts<=v.urgentMaxAttempts,o;if(s?o=Math.min(v.baseDelayMs*Math.pow(v.backoffMultiplier,e.reconnectAttempts-1),v.maxDelayMs):(o=v.persistentDelayMs,e.reconnectAttempts===v.urgentMaxAttempts+1&&a.info("[AppSyncClient] Switching to persistent reconnect (every 5min)",{sessionId:r})),a.info("[AppSyncClient] Scheduling reconnect",{sessionId:r,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(r)!==e){a.info("[AppSyncClient] Reconnect skipped \u2014 state is no longer canonical",{sessionId:r});return}try{let c=await g.getTokens(this.environment);c&&(g.isTokenExpired(c)?await this.refreshTokens(c)&&a.info("[AppSyncClient] Tokens refreshed before reconnect",{sessionId:r}):this.tokens=c)}catch{a.warn("[AppSyncClient] Token refresh failed before reconnect, using existing tokens",{sessionId:r})}if(e.destroyed||this.activeSubscriptions.get(r)!==e){a.info("[AppSyncClient] Reconnect skipped after token refresh \u2014 state no longer canonical",{sessionId:r});return}e.subscriptionId=(0,q.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===F.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}}subscribeToDeviceKeyRegistered(e,t,r,i){a.info("[AppSyncClient] Subscribing to device key registrations",{userId:e}),this.deviceKeyWatcher&&this.stopDeviceKeyWatcherInternal();let s={userId:e,subscriptionId:(0,q.v4)(),ws:null,onNewDevice:t,onReconnect:r,onError:i,reconnectAttempts:0,isReconnecting:!1,destroyed:!1};return this.deviceKeyWatcher=s,this.createDeviceKeyWatcherConnection(s),()=>{this.stopDeviceKeyWatcherInternal()}}stopDeviceKeyWatcher(){this.stopDeviceKeyWatcherInternal()}stopDeviceKeyWatcherInternal(){let e=this.deviceKeyWatcher;if(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===F.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}this.deviceKeyWatcher=null,a.info("[AppSyncClient] Device key watcher stopped")}}createDeviceKeyWatcherConnection(e){try{let t=this.buildRealtimeUrl(),r=new F.default(t,["graphql-ws"]);r.on("open",()=>{a.info("[AppSyncClient] Device key watcher WebSocket connected",{userId:e.userId}),r.send(JSON.stringify({type:"connection_init"}))}),r.on("message",i=>{try{let s=JSON.parse(i.toString());switch(s.type){case"connection_ack":this.sendDeviceKeyWatcherStart(r,e);break;case"start_ack":a.info("[AppSyncClient] Device key watcher subscription started",{userId:e.userId});let o=e.isReconnecting;if(e.isReconnecting=!1,e.reconnectAttempts=0,o&&e.onReconnect)try{e.onReconnect()}catch(l){a.warn("[AppSyncClient] Device key watcher onReconnect handler threw",{error:l})}break;case"data":this.resetDeviceKeyWatcherKeepAlive(e);let c=s.payload?.data?.onDeviceKeyRegistered;if(c){a.info("[AppSyncClient] Device key registration observed",{userId:e.userId,newDeviceId:c.deviceId,platform:c.platform});try{e.onNewDevice(c)}catch(l){a.warn("[AppSyncClient] Device key watcher onNewDevice handler threw",{error:l})}}break;case"ka":this.resetDeviceKeyWatcherKeepAlive(e);break;case"error":let d=s.payload?.errors?.[0]?.message||"Unknown error";this.handleDeviceKeyWatcherError(e,new Error(d));break}}catch(s){a.error("[AppSyncClient] Failed to parse device key watcher message",{error:s})}}),r.on("error",i=>{a.error("[AppSyncClient] Device key watcher WebSocket error",{userId:e.userId,error:i.message}),this.handleDeviceKeyWatcherError(e,i)}),r.on("close",i=>{a.info("[AppSyncClient] Device key watcher WebSocket closed",{userId:e.userId,code:i}),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),!e.destroyed&&this.deviceKeyWatcher===e&&this.handleDeviceKeyWatcherError(e,new Error(`WebSocket closed: ${i}`))}),e.ws=r,this.resetDeviceKeyWatcherKeepAlive(e)}catch(t){this.handleDeviceKeyWatcherError(e,t)}}sendDeviceKeyWatcherStart(e,t){let r=f(),{userId:i,subscriptionId:s}=t,o={host:new URL(r.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:s,type:"start",payload:{data:JSON.stringify({query:B.onDeviceKeyRegistered,variables:{userId:i}}),extensions:{authorization:o}}}))}resetDeviceKeyWatcherKeepAlive(e){e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.keepAliveTimer=setTimeout(()=>{this.handleDeviceKeyWatcherError(e,new Error("Device key watcher keep-alive timeout"))},300*1e3)}handleDeviceKeyWatcherError(e,t){if(e.isReconnecting||e.destroyed||this.deviceKeyWatcher!==e)return;if(e.isReconnecting=!0,e.reconnectAttempts++,e.onError)try{e.onError(t)}catch{}if(e.ws){try{e.ws.removeAllListeners()}catch{}try{e.ws.close(1e3)}catch{}e.ws=null}e.keepAliveTimer&&(clearTimeout(e.keepAliveTimer),e.keepAliveTimer=void 0);let i=e.reconnectAttempts<=v.urgentMaxAttempts?Math.min(v.baseDelayMs*Math.pow(v.backoffMultiplier,e.reconnectAttempts-1),v.maxDelayMs):v.persistentDelayMs;a.warn("[AppSyncClient] Device key watcher reconnect scheduled",{userId:e.userId,attempts:e.reconnectAttempts,delayMs:i,error:t.message}),e.reconnectTimer=setTimeout(async()=>{if(e.isReconnecting=!1,e.destroyed||this.deviceKeyWatcher!==e){a.info("[AppSyncClient] Device key watcher reconnect skipped \u2014 state no longer canonical",{userId:e.userId});return}try{let s=await g.getTokens(this.environment);s&&(g.isTokenExpired(s)?await this.refreshTokens(s)&&a.info("[AppSyncClient] Tokens refreshed before device key watcher reconnect",{userId:e.userId}):this.tokens=s)}catch{a.warn("[AppSyncClient] Token refresh failed before device key watcher reconnect, using existing tokens",{userId:e.userId})}e.destroyed||this.deviceKeyWatcher!==e||(e.subscriptionId=(0,q.v4)(),this.createDeviceKeyWatcherConnection(e))},i)}watchForMobileEnd(e,t){a.info("[AppSyncClient] Starting mobile-end watcher",{sessionId:e});let r=this.sessionUpdateWatchers.get(e);r&&(a.info("[AppSyncClient] Replacing existing mobile-end watcher",{sessionId:e}),this.cleanupSessionUpdateWatcherState(r),this.sessionUpdateWatchers.delete(e));let i={sessionId:e,subscriptionId:(0,q.v4)(),ws:null,onMobileEndRequested:t,priorStatus:"ACTIVE",firedOnce:!1,reconnectAttempts:0,isReconnecting:!1,destroyed:!1};return this.sessionUpdateWatchers.set(e,i),this.createSessionUpdateWatcherConnection(i),{stop:()=>{this.sessionUpdateWatchers.get(e)===i&&(this.cleanupSessionUpdateWatcherState(i),this.sessionUpdateWatchers.delete(e),a.info("[AppSyncClient] Mobile-end watcher stopped",{sessionId:e}))}}}createSessionUpdateWatcherConnection(e){try{let t=this.buildRealtimeUrl(),r=new F.default(t,["graphql-ws"]);r.on("open",()=>{a.info("[AppSyncClient] Mobile-end watcher WebSocket connected",{sessionId:e.sessionId}),r.send(JSON.stringify({type:"connection_init"}))}),r.on("message",i=>{try{let s=JSON.parse(i.toString());switch(s.type){case"connection_ack":this.sendSessionUpdateWatcherStart(r,e);break;case"start_ack":a.info("[AppSyncClient] Mobile-end watcher subscription started",{sessionId:e.sessionId}),e.isReconnecting=!1,e.reconnectAttempts=0;break;case"data":this.resetSessionUpdateWatcherKeepAlive(e),this.handleSessionUpdatePayload(e,s.payload);break;case"ka":this.resetSessionUpdateWatcherKeepAlive(e);break;case"error":let o=s.payload?.errors?.[0]?.message||"Unknown error";this.handleSessionUpdateWatcherError(e,new Error(o));break}}catch(s){a.error("[AppSyncClient] Failed to parse mobile-end watcher message",{error:s})}}),r.on("error",i=>{a.error("[AppSyncClient] Mobile-end watcher WebSocket error",{sessionId:e.sessionId,error:i.message}),this.handleSessionUpdateWatcherError(e,i)}),r.on("close",i=>{a.info("[AppSyncClient] Mobile-end watcher WebSocket closed",{sessionId:e.sessionId,code:i}),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),!e.destroyed&&this.sessionUpdateWatchers.get(e.sessionId)===e&&this.handleSessionUpdateWatcherError(e,new Error(`WebSocket closed: ${i}`))}),e.ws=r,this.resetSessionUpdateWatcherKeepAlive(e)}catch(t){this.handleSessionUpdateWatcherError(e,t)}}handleSessionUpdatePayload(e,t){let r=t?.data?.onSessionUpdated;if(!r){a.warn("[AppSyncClient] Mobile-end watcher received malformed payload",{sessionId:e.sessionId});return}if(e.firedOnce)return;let i=r.status;if(i==null){a.debug("[AppSyncClient] Mobile-end watcher skipped non-status payload",{sessionId:e.sessionId});return}if(e.priorStatus==="ACTIVE"&&i==="INACTIVE"){e.firedOnce=!0,e.priorStatus="INACTIVE",a.info("[AppSyncClient] Mobile end requested for session",{sessionId:e.sessionId}),Promise.resolve().then(()=>e.onMobileEndRequested()).catch(s=>{a.warn("[AppSyncClient] Mobile-end callback threw",{sessionId:e.sessionId,error:s})});return}e.priorStatus=i}sendSessionUpdateWatcherStart(e,t){let r=f(),{sessionId:i,subscriptionId:s}=t,o={host:new URL(r.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:s,type:"start",payload:{data:JSON.stringify({query:B.onSessionUpdated,variables:{sessionId:i}}),extensions:{authorization:o}}}))}resetSessionUpdateWatcherKeepAlive(e){e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.keepAliveTimer=setTimeout(()=>{this.handleSessionUpdateWatcherError(e,new Error("Mobile-end watcher keep-alive timeout"))},300*1e3)}handleSessionUpdateWatcherError(e,t){if(e.isReconnecting||e.destroyed||this.sessionUpdateWatchers.get(e.sessionId)!==e)return;if(e.isReconnecting=!0,e.reconnectAttempts++,e.ws){try{e.ws.removeAllListeners()}catch{}try{e.ws.close(1e3)}catch{}e.ws=null}e.keepAliveTimer&&(clearTimeout(e.keepAliveTimer),e.keepAliveTimer=void 0);let i=e.reconnectAttempts<=v.urgentMaxAttempts?Math.min(v.baseDelayMs*Math.pow(v.backoffMultiplier,e.reconnectAttempts-1),v.maxDelayMs):v.persistentDelayMs;a.warn("[AppSyncClient] Mobile-end watcher reconnect scheduled",{sessionId:e.sessionId,attempts:e.reconnectAttempts,delayMs:i,error:t.message}),e.reconnectTimer=setTimeout(async()=>{if(e.isReconnecting=!1,!(e.destroyed||this.sessionUpdateWatchers.get(e.sessionId)!==e)){try{let s=await g.getTokens(this.environment);s&&(g.isTokenExpired(s)?await this.refreshTokens(s):this.tokens=s)}catch{a.warn("[AppSyncClient] Token refresh failed before mobile-end watcher reconnect",{sessionId:e.sessionId})}e.destroyed||this.sessionUpdateWatchers.get(e.sessionId)!==e||(e.subscriptionId=(0,q.v4)(),this.createSessionUpdateWatcherConnection(e))}},i)}cleanupSessionUpdateWatcherState(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===F.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 r=setInterval(()=>{this.sendHeartbeat(e)},t);this.heartbeatTimers.set(e,r),a.info("[AppSyncClient] Heartbeat started",{sessionId:e,intervalMs:t})}stopHeartbeat(e){let t=this.heartbeatTimers.get(e);t&&(clearInterval(t),this.heartbeatTimers.delete(e),a.info("[AppSyncClient] Heartbeat stopped",{sessionId:e}))}async sendHeartbeat(e){try{await this.updateSession({sessionId:e,lastHeartbeatAt:new Date().toISOString()}),a.debug("[AppSyncClient] Heartbeat sent",{sessionId:e})}catch(t){a.warn("[AppSyncClient] Heartbeat failed",{sessionId:e,error:t})}}cleanupSubscriptions(){this.activeSubscriptions.forEach(e=>{this.cleanupSubscriptionState(e)}),this.activeSubscriptions.clear(),this.stopDeviceKeyWatcherInternal(),this.sessionUpdateWatchers.forEach(e=>{this.cleanupSessionUpdateWatcherState(e)}),this.sessionUpdateWatchers.clear(),this.heartbeatTimers.forEach(e=>clearInterval(e)),this.heartbeatTimers.clear()}};var at=y(require("crypto")),ct=y(require("fs")),xe=y(require("http")),dt=require("child_process");j();P();U();var tt=y(require("crypto")),rt=y(require("https")),nt=y(require("os")),Rt="G-GS74YEQTB8",_t="lAfOF6OxRzSQ-NsLBRjhAg",Pt="www.google-analytics.com",Ot=`/mp/collect?measurement_id=${Rt}&api_secret=${_t}`,Nt={port_in_use:"server_start",server_listen_failed:"server_start",browser_open_failed:"browser_open",login_timeout:"awaiting_callback",cognito_rejected:"awaiting_callback",state_mismatch:"awaiting_callback",no_authorization_code:"awaiting_callback",token_exchange_failed:"exchanging_code",token_exchange_network_error:"exchanging_code",keychain_write_failed:"storing_tokens",user_aborted:"unknown",unknown:"unknown"};function Ut(){let n=typeof process.getuid=="function"?process.getuid():0;return tt.createHash("sha256").update(`${nt.hostname()}-${n}`).digest("hex").substring(0,36)}function it(){return{platform:process.platform,source:process.env.CODEVIBE_TELEMETRY_SOURCE||"production"}}async function st(n,e){try{let t=JSON.stringify({client_id:Ut(),events:[{name:n,params:e}]});await new Promise(r=>{let i=rt.request({hostname:Pt,path:Ot,method:"POST",headers:{"Content-Type":"application/json"}},()=>r());i.on("error",()=>r()),i.write(t),i.end(),setTimeout(r,2e3)})}catch{}}async function te(n){await st("auth_completed",{...it(),user_id:n})}async function S(n,e){let t={...it(),reason:n,stage:e?.stage??Nt[n]};if(typeof e?.httpStatus=="number"&&(t.http_status=e.httpStatus),e?.errorFragment){let{homedir:r}=await import("os"),i=e.errorFragment.replace(/\x1b\[[0-9;]*[a-zA-Z]/g,"").replace(/\\/g,"/").replace(/[\n\r\t"]/g," ").replace(/[^\x20-\x7E]/g,"").trim(),s=[process.env.HOME,process.env.USERPROFILE,(()=>{try{return r()}catch{return}})()].filter(d=>typeof d=="string"&&d.length>0).map(d=>d.replace(/\\/g,"/"));for(let d of s){let l=d.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");i=i.replace(new RegExp(l,"g"),"~")}i=i.replace(/\/Users\/[^/ ]+/g,"/Users/<user>").replace(/\/home\/[^/ ]+/g,"/home/<user>").replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,"<email>");let o=i.substring(0,100),c=i.substring(100,200);o&&(t.error_fragment=o),c&&(t.error_fragment_2=c)}await st("auth_failed",t)}var Ae=Symbol.for("codevibe.auth.beaconed"),ot=Symbol.for("codevibe.auth.failureReason");function E(n,e){try{Object.defineProperty(n,Ae,{value:!0,enumerable:!1,configurable:!0,writable:!1}),Object.defineProperty(n,ot,{value:e,enumerable:!1,configurable:!0,writable:!1})}catch{}return n}function re(n){return!!(n&&typeof n=="object"&&n[Ae])}function Te(n){if(n&&typeof n=="object"&&n[Ae]){let e=n[ot];if(typeof e=="string")return e}}var ne=8080,lt="/callback",Ce=`http://localhost:${ne}${lt}`,G=class n{constructor(){}static getInstance(){return n.instance||(n.instance=new n),n.instance}openBrowser(e){console.error(""),console.error("Opening your browser for sign-in..."),this.isRunningInWSL()?console.error("If your browser does not open, paste this URL in your Windows browser:"):console.error("If your browser does not open automatically, visit this URL:"),console.error(` ${e}`),console.error("");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=ct.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(e)}catch{return!1}}tryBrowserCommand(e,t,r){if(r>=e.length){a.debug("[AuthService] No browser-opening command succeeded. User must open the sign-in URL manually (printed to stderr above)."),console.error(""),console.error("\u26A0\uFE0F Could not open browser automatically."),this.isRunningInWSL()?console.error(" WSL detected \u2014 paste this URL in your Windows browser:"):console.error(" Please copy and paste this URL into your browser:"),console.error(` ${t}`),console.error("");return}let i=e[r],s=[...i.fixedArgs,t],o=!1,c=u=>{o||(o=!0,a.debug(`[AuthService] Browser command '${i.cmd}' ${u}; trying next fallback`),this.tryBrowserCommand(e,t,r+1))},d=u=>{o||(o=!0,a.debug(`[AuthService] Browser command '${i.cmd}' ${u}`))},l;try{l=(0,dt.spawn)(i.cmd,s,{detached:!0,stdio:"ignore"})}catch(u){c(`threw synchronously: ${u?.message||u}`);return}l.on("error",u=>{c(`failed to spawn: ${u?.message||u}`)}),l.on("exit",(u,w)=>{u===0?d("exited successfully"):c(w?`terminated by signal ${w}`:`exited with code ${u}`)}),setTimeout(()=>{d("still running after 3s, assuming success")},3e3).unref(),l.unref()}generateState(){return at.randomBytes(32).toString("hex")}buildAuthUrl(e){let t=f(),r=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?${r.toString()}`}async exchangeCodeForTokens(e){let t=f(),r=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"authorization_code",client_id:t.aws.cognitoClientId,code:e,redirect_uri:Ce}),s;try{s=await z(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},"Token exchange")}catch(c){throw await S("token_exchange_network_error"),E(c,"token_exchange_network_error"),c}if(!s.ok){let c=await s.text(),d=new Error(`Token exchange failed: ${s.status} ${c}`);throw await S("token_exchange_failed",{httpStatus:s.status}),E(d,"token_exchange_failed"),d}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(),r=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e}),s=await z(r,{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(I());if(e&&!g.isTokenExpired(e))return e;let t=this.generateState(),r=this.buildAuthUrl(t);return new Promise((i,s)=>{let o=xe.createServer(async(c,d)=>{if(!c.url?.startsWith(lt)){d.writeHead(404),d.end("Not found");return}try{let l=new URL(c.url,`http://localhost:${ne}`),h=l.searchParams.get("code"),u=l.searchParams.get("state"),w=l.searchParams.get("error");if(w){let T=new Error(`OAuth error: ${w}`);throw await S("cognito_rejected"),E(T,"cognito_rejected"),T}if(u!==t){let T=new Error("State mismatch");throw await S("state_mismatch"),E(T,"state_mismatch"),T}if(!h){let T=new Error("No authorization code");throw await S("no_authorization_code"),E(T,"no_authorization_code"),T}let b=await this.exchangeCodeForTokens(h),Y=this.decodeJwt(b.idToken),m={accessToken:b.accessToken,idToken:b.idToken,refreshToken:b.refreshToken,expiresAt:Date.now()+b.expiresIn*1e3,userId:Y.sub,email:Y.email||"unknown"};try{await g.setTokens(m,I())}catch(T){throw await S("keychain_write_failed"),E(T,"keychain_write_failed"),T}d.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),d.end(`
205
+ `};var nt=(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))(nt||{}),xe=(t=>(t.DESKTOP="DESKTOP",t.MOBILE="MOBILE",t))(xe||{}),it=(r=>(r.SENT="SENT",r.DELIVERED="DELIVERED",r.EXECUTED="EXECUTED",r))(it||{});var he=(r=>(r.ACTIVE="ACTIVE",r.INACTIVE="INACTIVE",r.PAUSED="PAUSED",r))(he||{}),st=(r=>(r.CLAUDE="CLAUDE",r.GEMINI="GEMINI",r.CODEX="CODEX",r))(st||{});var k={urgentMaxAttempts:10,baseDelayMs:1e3,maxDelayMs:6e4,backoffMultiplier:2,persistentDelayMs:300*1e3},ne=class n{constructor(){this.authenticated=!1;this.currentUserId=null;this.currentEmail=null;this.tokens=null;this.activeSubscriptions=new Map;this.pendingRefresh=null;this.lastRefreshFailureAt=null;this.deviceKeyWatcher=null;this.sessionUpdateWatchers=new Map;this.heartbeatTimers=new Map;this.environment=I(),c.info("[AppSyncClient] Initialized",{environment:this.environment})}static{this.REFRESH_BACKOFF_MS=3e4}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 y.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:y.isTokenExpired(e)}),y.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){if(this.pendingRefresh)return this.pendingRefresh;if(this.lastRefreshFailureAt!==null&&Date.now()-this.lastRefreshFailureAt<n.REFRESH_BACKOFF_MS)return!1;this.pendingRefresh=this.performRefresh(e);try{return await this.pendingRefresh}finally{this.pendingRefresh=null}}async performRefresh(e){let t=await this.callCognitoRefresh(e.refreshToken);if(t!==null)return this.applyRefreshedTokens(e,t);let r=null;try{r=await y.getTokens(this.environment)}catch(i){c.warn("[AppSyncClient] Failed to re-read tokens from storage during refresh recovery",{error:i instanceof Error?i.message:String(i)})}if(r&&r.refreshToken&&r.refreshToken!==e.refreshToken){c.info("[AppSyncClient] In-memory refresh token rejected; retrying with storage-backed token (likely out-of-band re-auth)");let i=await this.callCognitoRefresh(r.refreshToken);if(i!==null)return this.applyRefreshedTokens(r,i)}return this.lastRefreshFailureAt=Date.now(),!1}async callCognitoRefresh(e){try{let t=w(),r=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e}),s=await X(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},"Token refresh");return s.ok?await s.json():(c.error("[AppSyncClient] Token refresh failed",{status:s.status}),null)}catch(t){return c.error("[AppSyncClient] Token refresh error:",t),null}}async applyRefreshedTokens(e,t){let r={...e,accessToken:t.access_token,idToken:t.id_token,expiresAt:Date.now()+t.expires_in*1e3};this.tokens=r,this.lastRefreshFailureAt=null;try{await y.setTokens(r,this.environment),c.info("[AppSyncClient] Tokens refreshed",{expiresAt:new Date(r.expiresAt).toISOString()})}catch(i){c.warn("[AppSyncClient] Tokens refreshed but persistence failed; daemon keeps using fresh tokens in memory. A restart while persistence is still broken would lose them.",{error:i instanceof Error?i.message:String(i),expiresAt:new Date(r.expiresAt).toISOString()})}return!0}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,r=!1){let i=w();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 X(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&&!r&&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},r=await this.graphqlRequest(C.createSession,{input:t});return c.info("[AppSyncClient] Session created",{sessionId:r.data.createSession.sessionId}),r.data.createSession}async updateSession(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},r=await this.graphqlRequest(C.updateSession,{input:t});return c.debug("[AppSyncClient] Session updated",{sessionId:r.data.updateSession.sessionId}),r.data.updateSession}async getSession(e){return(await this.graphqlRequest(U.getSession,{sessionId:e})).data.getSession}async createEvent(e){let t={...e,metadata:e.metadata?JSON.stringify(e.metadata):void 0},r=await this.graphqlRequest(C.createEvent,{input:t});return c.debug("[AppSyncClient] Event created",{eventId:r.data.createEvent.eventId,type:r.data.createEvent.type}),r.data.createEvent}async updateEventStatus(e){return(await this.graphqlRequest(C.updateEventStatus,{input:e})).data.updateEventStatus}async listEvents(e,t,r){return(await this.graphqlRequest(U.listEvents,{sessionId:e,source:t,limit:r})).data.listEvents.items}async listSessions(e=100){if(!this.currentUserId)throw new Error("Not authenticated");let t=[],r=null;do{let s=(await this.graphqlRequest(U.listSessions,{userId:this.currentUserId,limit:e,nextToken:r})).data?.listSessions;s?.items&&t.push(...s.items),r=s?.nextToken??null}while(r);return t}async sweepOrphanSessions(e){let t=e.staleThresholdMs??9e5,r=new Set(e.excludeSessionIds??[]),i=Date.now(),s;try{s=await this.listSessions()}catch(a){return c.warn("[AppSyncClient] OrphanSweep: listSessions failed, skipping sweep",{agentType:e.agentType,error:a instanceof Error?a.message:String(a)}),0}let o=0;for(let a of s){if(a.agentType!==e.agentType||a.status!=="ACTIVE"||r.has(a.sessionId)||!a.lastHeartbeatAt)continue;let d=i-new Date(a.lastHeartbeatAt).getTime();if(!(d<t)){c.warn("[AppSyncClient] OrphanSweep: marking stale session INACTIVE",{sessionId:a.sessionId,agentType:a.agentType,lastHeartbeatAt:a.lastHeartbeatAt,heartbeatAgeMinutes:Math.round(d/6e4)});try{await this.updateSession({sessionId:a.sessionId,status:"INACTIVE"}),o++}catch(l){c.warn("[AppSyncClient] OrphanSweep: updateSession failed, leaving row as-is",{sessionId:a.sessionId,error:l instanceof Error?l.message:String(l)})}}}return o>0&&c.info("[AppSyncClient] OrphanSweep complete",{agentType:e.agentType,swept:o}),o}async listUserDeviceKeys(){return(await this.graphqlRequest(U.listUserDeviceKeys,{})).data.listUserDeviceKeys||[]}async registerDeviceKey(e,t,r,i){let s={deviceId:e,publicKey:t,platform:r,deviceName:i};await this.graphqlRequest(C.registerDeviceKey,{input:s}),c.info("[AppSyncClient] Device key registered",{deviceId:e,platform:r})}async grantSessionKey(e){await this.graphqlRequest(C.grantSessionKey,{input:e}),c.info("[AppSyncClient] Session key granted",{sessionId:e.sessionId,deviceId:e.deviceId})}async getAttachmentDownloadUrl(e){return(await this.graphqlRequest(C.getAttachmentDownloadUrl,{s3Key:e})).data.getAttachmentDownloadUrl}subscribeToEvents(e,t,r){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,J.v4)(),sessionId:e,onEvent:t,onError:r,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=w(),t=new URL(e.aws.appsyncUrl),i=/\.appsync-api\.[^.]+\.amazonaws\.com$/.test(t.host)?e.aws.appsyncUrl.replace("https://","wss://").replace("appsync-api","appsync-realtime-api"):`wss://${t.host}/graphql/realtime`,s={host:t.host};this.tokens?.idToken&&(s.Authorization=this.tokens.idToken);let o=Buffer.from(JSON.stringify(s)).toString("base64"),a=Buffer.from(JSON.stringify({})).toString("base64");return`${i}?header=${o}&payload=${a}`}createSubscription(e){let{sessionId:t,subscriptionId:r,onEvent:i,onError:s}=e;try{let o=this.buildRealtimeUrl(),a=new V.default(o,["graphql-ws"]);a.on("open",()=>{c.info("[AppSyncClient] WebSocket connected",{sessionId:t}),a.send(JSON.stringify({type:"connection_init"}))}),a.on("message",d=>{try{let l=JSON.parse(d.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 h=l.payload?.data?.onEventCreated;h&&h.source==="MOBILE"&&i(h);break;case"ka":this.resetKeepAliveTimer(e);break;case"error":let p=l.payload?.errors?.[0]?.message||"Unknown error";this.handleSubscriptionError(e,new Error(p));break}}catch(l){c.error("[AppSyncClient] Failed to parse message",{error:l})}}),a.on("error",d=>{c.error("[AppSyncClient] WebSocket error",{sessionId:t,error:d.message}),this.handleSubscriptionError(e,d)}),a.on("close",(d,l)=>{c.info("[AppSyncClient] WebSocket closed",{sessionId:t,code:d}),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),!e.destroyed&&this.activeSubscriptions.get(t)===e&&this.handleSubscriptionError(e,new Error(`WebSocket closed: ${d}`))}),e.ws=a,this.resetKeepAliveTimer(e)}catch(o){this.handleSubscriptionError(e,o)}}sendSubscriptionStart(e,t){let r=w(),{sessionId:i,subscriptionId:s}=t,o={host:new URL(r.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:s,type:"start",payload:{data:JSON.stringify({query:H.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:r,onError:i}=e;if(e.isReconnecting||!this.activeSubscriptions.has(r))return;e.isReconnecting=!0,e.reconnectAttempts++,this.stopHeartbeat(r);let s=e.reconnectAttempts<=k.urgentMaxAttempts,o;if(s?o=Math.min(k.baseDelayMs*Math.pow(k.backoffMultiplier,e.reconnectAttempts-1),k.maxDelayMs):(o=k.persistentDelayMs,e.reconnectAttempts===k.urgentMaxAttempts+1&&c.info("[AppSyncClient] Switching to persistent reconnect (every 5min)",{sessionId:r})),c.info("[AppSyncClient] Scheduling reconnect",{sessionId:r,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(r)!==e){c.info("[AppSyncClient] Reconnect skipped \u2014 state is no longer canonical",{sessionId:r});return}try{let a=await y.getTokens(this.environment);a&&(y.isTokenExpired(a)?await this.refreshTokens(a)&&c.info("[AppSyncClient] Tokens refreshed before reconnect",{sessionId:r}):this.tokens=a)}catch{c.warn("[AppSyncClient] Token refresh failed before reconnect, using existing tokens",{sessionId:r})}if(e.destroyed||this.activeSubscriptions.get(r)!==e){c.info("[AppSyncClient] Reconnect skipped after token refresh \u2014 state no longer canonical",{sessionId:r});return}e.subscriptionId=(0,J.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===V.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}}subscribeToDeviceKeyRegistered(e,t,r,i){c.info("[AppSyncClient] Subscribing to device key registrations",{userId:e}),this.deviceKeyWatcher&&this.stopDeviceKeyWatcherInternal();let s={userId:e,subscriptionId:(0,J.v4)(),ws:null,onNewDevice:t,onReconnect:r,onError:i,reconnectAttempts:0,isReconnecting:!1,destroyed:!1};return this.deviceKeyWatcher=s,this.createDeviceKeyWatcherConnection(s),()=>{this.stopDeviceKeyWatcherInternal()}}stopDeviceKeyWatcher(){this.stopDeviceKeyWatcherInternal()}stopDeviceKeyWatcherInternal(){let e=this.deviceKeyWatcher;if(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===V.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}this.deviceKeyWatcher=null,c.info("[AppSyncClient] Device key watcher stopped")}}createDeviceKeyWatcherConnection(e){try{let t=this.buildRealtimeUrl(),r=new V.default(t,["graphql-ws"]);r.on("open",()=>{c.info("[AppSyncClient] Device key watcher WebSocket connected",{userId:e.userId}),r.send(JSON.stringify({type:"connection_init"}))}),r.on("message",i=>{try{let s=JSON.parse(i.toString());switch(s.type){case"connection_ack":this.sendDeviceKeyWatcherStart(r,e);break;case"start_ack":c.info("[AppSyncClient] Device key watcher subscription started",{userId:e.userId});let o=e.isReconnecting;if(e.isReconnecting=!1,e.reconnectAttempts=0,o&&e.onReconnect)try{e.onReconnect()}catch(l){c.warn("[AppSyncClient] Device key watcher onReconnect handler threw",{error:l})}break;case"data":this.resetDeviceKeyWatcherKeepAlive(e);let a=s.payload?.data?.onDeviceKeyRegistered;if(a){c.info("[AppSyncClient] Device key registration observed",{userId:e.userId,newDeviceId:a.deviceId,platform:a.platform});try{e.onNewDevice(a)}catch(l){c.warn("[AppSyncClient] Device key watcher onNewDevice handler threw",{error:l})}}break;case"ka":this.resetDeviceKeyWatcherKeepAlive(e);break;case"error":let d=s.payload?.errors?.[0]?.message||"Unknown error";this.handleDeviceKeyWatcherError(e,new Error(d));break}}catch(s){c.error("[AppSyncClient] Failed to parse device key watcher message",{error:s})}}),r.on("error",i=>{c.error("[AppSyncClient] Device key watcher WebSocket error",{userId:e.userId,error:i.message}),this.handleDeviceKeyWatcherError(e,i)}),r.on("close",i=>{c.info("[AppSyncClient] Device key watcher WebSocket closed",{userId:e.userId,code:i}),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),!e.destroyed&&this.deviceKeyWatcher===e&&this.handleDeviceKeyWatcherError(e,new Error(`WebSocket closed: ${i}`))}),e.ws=r,this.resetDeviceKeyWatcherKeepAlive(e)}catch(t){this.handleDeviceKeyWatcherError(e,t)}}sendDeviceKeyWatcherStart(e,t){let r=w(),{userId:i,subscriptionId:s}=t,o={host:new URL(r.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:s,type:"start",payload:{data:JSON.stringify({query:H.onDeviceKeyRegistered,variables:{userId:i}}),extensions:{authorization:o}}}))}resetDeviceKeyWatcherKeepAlive(e){e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.keepAliveTimer=setTimeout(()=>{this.handleDeviceKeyWatcherError(e,new Error("Device key watcher keep-alive timeout"))},300*1e3)}handleDeviceKeyWatcherError(e,t){if(e.isReconnecting||e.destroyed||this.deviceKeyWatcher!==e)return;if(e.isReconnecting=!0,e.reconnectAttempts++,e.onError)try{e.onError(t)}catch{}if(e.ws){try{e.ws.removeAllListeners()}catch{}try{e.ws.close(1e3)}catch{}e.ws=null}e.keepAliveTimer&&(clearTimeout(e.keepAliveTimer),e.keepAliveTimer=void 0);let i=e.reconnectAttempts<=k.urgentMaxAttempts?Math.min(k.baseDelayMs*Math.pow(k.backoffMultiplier,e.reconnectAttempts-1),k.maxDelayMs):k.persistentDelayMs;c.warn("[AppSyncClient] Device key watcher reconnect scheduled",{userId:e.userId,attempts:e.reconnectAttempts,delayMs:i,error:t.message}),e.reconnectTimer=setTimeout(async()=>{if(e.isReconnecting=!1,e.destroyed||this.deviceKeyWatcher!==e){c.info("[AppSyncClient] Device key watcher reconnect skipped \u2014 state no longer canonical",{userId:e.userId});return}try{let s=await y.getTokens(this.environment);s&&(y.isTokenExpired(s)?await this.refreshTokens(s)&&c.info("[AppSyncClient] Tokens refreshed before device key watcher reconnect",{userId:e.userId}):this.tokens=s)}catch{c.warn("[AppSyncClient] Token refresh failed before device key watcher reconnect, using existing tokens",{userId:e.userId})}e.destroyed||this.deviceKeyWatcher!==e||(e.subscriptionId=(0,J.v4)(),this.createDeviceKeyWatcherConnection(e))},i)}watchForMobileEnd(e,t){c.info("[AppSyncClient] Starting mobile-end watcher",{sessionId:e});let r=this.sessionUpdateWatchers.get(e);r&&(c.info("[AppSyncClient] Replacing existing mobile-end watcher",{sessionId:e}),this.cleanupSessionUpdateWatcherState(r),this.sessionUpdateWatchers.delete(e));let i={sessionId:e,subscriptionId:(0,J.v4)(),ws:null,onMobileEndRequested:t,priorStatus:"ACTIVE",firedOnce:!1,reconnectAttempts:0,isReconnecting:!1,destroyed:!1};return this.sessionUpdateWatchers.set(e,i),this.createSessionUpdateWatcherConnection(i),{stop:()=>{this.sessionUpdateWatchers.get(e)===i&&(this.cleanupSessionUpdateWatcherState(i),this.sessionUpdateWatchers.delete(e),c.info("[AppSyncClient] Mobile-end watcher stopped",{sessionId:e}))}}}createSessionUpdateWatcherConnection(e){try{let t=this.buildRealtimeUrl(),r=new V.default(t,["graphql-ws"]);r.on("open",()=>{c.info("[AppSyncClient] Mobile-end watcher WebSocket connected",{sessionId:e.sessionId}),r.send(JSON.stringify({type:"connection_init"}))}),r.on("message",i=>{try{let s=JSON.parse(i.toString());switch(s.type){case"connection_ack":this.sendSessionUpdateWatcherStart(r,e);break;case"start_ack":c.info("[AppSyncClient] Mobile-end watcher subscription started",{sessionId:e.sessionId}),e.isReconnecting=!1,e.reconnectAttempts=0;break;case"data":this.resetSessionUpdateWatcherKeepAlive(e),this.handleSessionUpdatePayload(e,s.payload);break;case"ka":this.resetSessionUpdateWatcherKeepAlive(e);break;case"error":let o=s.payload?.errors?.[0]?.message||"Unknown error";this.handleSessionUpdateWatcherError(e,new Error(o));break}}catch(s){c.error("[AppSyncClient] Failed to parse mobile-end watcher message",{error:s})}}),r.on("error",i=>{c.error("[AppSyncClient] Mobile-end watcher WebSocket error",{sessionId:e.sessionId,error:i.message}),this.handleSessionUpdateWatcherError(e,i)}),r.on("close",i=>{c.info("[AppSyncClient] Mobile-end watcher WebSocket closed",{sessionId:e.sessionId,code:i}),e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),!e.destroyed&&this.sessionUpdateWatchers.get(e.sessionId)===e&&this.handleSessionUpdateWatcherError(e,new Error(`WebSocket closed: ${i}`))}),e.ws=r,this.resetSessionUpdateWatcherKeepAlive(e)}catch(t){this.handleSessionUpdateWatcherError(e,t)}}handleSessionUpdatePayload(e,t){let r=t?.data?.onSessionUpdated;if(!r){c.warn("[AppSyncClient] Mobile-end watcher received malformed payload",{sessionId:e.sessionId});return}if(e.firedOnce)return;let i=r.status;if(i==null){c.debug("[AppSyncClient] Mobile-end watcher skipped non-status payload",{sessionId:e.sessionId});return}if(e.priorStatus==="ACTIVE"&&i==="INACTIVE"){e.firedOnce=!0,e.priorStatus="INACTIVE",c.info("[AppSyncClient] Mobile end requested for session",{sessionId:e.sessionId}),Promise.resolve().then(()=>e.onMobileEndRequested()).catch(s=>{c.warn("[AppSyncClient] Mobile-end callback threw",{sessionId:e.sessionId,error:s})});return}e.priorStatus=i}sendSessionUpdateWatcherStart(e,t){let r=w(),{sessionId:i,subscriptionId:s}=t,o={host:new URL(r.aws.appsyncUrl).host};this.tokens?.idToken&&(o.Authorization=this.tokens.idToken),e.send(JSON.stringify({id:s,type:"start",payload:{data:JSON.stringify({query:H.onSessionUpdated,variables:{sessionId:i}}),extensions:{authorization:o}}}))}resetSessionUpdateWatcherKeepAlive(e){e.keepAliveTimer&&clearTimeout(e.keepAliveTimer),e.keepAliveTimer=setTimeout(()=>{this.handleSessionUpdateWatcherError(e,new Error("Mobile-end watcher keep-alive timeout"))},300*1e3)}handleSessionUpdateWatcherError(e,t){if(e.isReconnecting||e.destroyed||this.sessionUpdateWatchers.get(e.sessionId)!==e)return;if(e.isReconnecting=!0,e.reconnectAttempts++,e.ws){try{e.ws.removeAllListeners()}catch{}try{e.ws.close(1e3)}catch{}e.ws=null}e.keepAliveTimer&&(clearTimeout(e.keepAliveTimer),e.keepAliveTimer=void 0);let i=e.reconnectAttempts<=k.urgentMaxAttempts?Math.min(k.baseDelayMs*Math.pow(k.backoffMultiplier,e.reconnectAttempts-1),k.maxDelayMs):k.persistentDelayMs;c.warn("[AppSyncClient] Mobile-end watcher reconnect scheduled",{sessionId:e.sessionId,attempts:e.reconnectAttempts,delayMs:i,error:t.message}),e.reconnectTimer=setTimeout(async()=>{if(e.isReconnecting=!1,!(e.destroyed||this.sessionUpdateWatchers.get(e.sessionId)!==e)){try{let s=await y.getTokens(this.environment);s&&(y.isTokenExpired(s)?await this.refreshTokens(s):this.tokens=s)}catch{c.warn("[AppSyncClient] Token refresh failed before mobile-end watcher reconnect",{sessionId:e.sessionId})}e.destroyed||this.sessionUpdateWatchers.get(e.sessionId)!==e||(e.subscriptionId=(0,J.v4)(),this.createSessionUpdateWatcherConnection(e))}},i)}cleanupSessionUpdateWatcherState(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===V.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 r=setInterval(()=>{this.sendHeartbeat(e)},t);this.heartbeatTimers.set(e,r),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.stopDeviceKeyWatcherInternal(),this.sessionUpdateWatchers.forEach(e=>{this.cleanupSessionUpdateWatcherState(e)}),this.sessionUpdateWatchers.clear(),this.heartbeatTimers.forEach(e=>clearInterval(e)),this.heartbeatTimers.clear()}};var gt=v(require("crypto")),mt=v(require("fs")),Oe=v(require("http")),ft=require("child_process");Y();R();M();var _e=v(require("crypto")),ot=v(require("https")),at=v(require("os")),Mt="G-GS74YEQTB8",Bt="lAfOF6OxRzSQ-NsLBRjhAg",Ft="www.google-analytics.com",qt=`/mp/collect?measurement_id=${Mt}&api_secret=${Bt}`,Ht={port_in_use:"server_start",server_listen_failed:"server_start",browser_open_failed:"browser_open",login_timeout:"awaiting_callback",cognito_rejected:"awaiting_callback",state_mismatch:"awaiting_callback",no_authorization_code:"awaiting_callback",token_exchange_failed:"exchanging_code",token_exchange_network_error:"exchanging_code",keychain_write_failed:"storing_tokens",user_aborted:"unknown",unknown:"unknown"};function Vt(){let n=typeof process.getuid=="function"?process.getuid():0;return _e.createHash("sha256").update(`${at.hostname()}-${n}`).digest("hex").substring(0,36)}function $(){return{platform:process.platform,source:process.env.CODEVIBE_TELEMETRY_SOURCE||"production"}}async function L(n,e){try{let t=JSON.stringify({client_id:Vt(),events:[{name:n,params:e}]});await new Promise(r=>{let i=ot.request({hostname:Ft,path:qt,method:"POST",headers:{"Content-Type":"application/json"}},()=>r());i.on("error",()=>r()),i.write(t),i.end(),setTimeout(r,2e3)})}catch{}}async function ie(n){await L("auth_completed",{...$(),user_id:n})}async function b(n,e){let t={...$(),reason:n,stage:e?.stage??Ht[n]};if(typeof e?.httpStatus=="number"&&(t.http_status=e.httpStatus),e?.errorFragment){let{homedir:r}=await import("os"),i=e.errorFragment.replace(/\x1b\[[0-9;]*[a-zA-Z]/g,"").replace(/\\/g,"/").replace(/[\n\r\t"]/g," ").replace(/[^\x20-\x7E]/g,"").trim(),s=[process.env.HOME,process.env.USERPROFILE,(()=>{try{return r()}catch{return}})()].filter(d=>typeof d=="string"&&d.length>0).map(d=>d.replace(/\\/g,"/"));for(let d of s){let l=d.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");i=i.replace(new RegExp(l,"g"),"~")}i=i.replace(/\/Users\/[^/ ]+/g,"/Users/<user>").replace(/\/home\/[^/ ]+/g,"/home/<user>").replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,"<email>");let o=i.substring(0,100),a=i.substring(100,200);o&&(t.error_fragment=o),a&&(t.error_fragment_2=a)}await L("auth_failed",t)}var Ke=Symbol.for("codevibe.auth.beaconed"),ct=Symbol.for("codevibe.auth.failureReason");function A(n,e){try{Object.defineProperty(n,Ke,{value:!0,enumerable:!1,configurable:!0,writable:!1}),Object.defineProperty(n,ct,{value:e,enumerable:!1,configurable:!0,writable:!1})}catch{}return n}function se(n){return!!(n&&typeof n=="object"&&n[Ke])}function Re(n){if(n&&typeof n=="object"&&n[Ke]){let e=n[ct];if(typeof e=="string")return e}}function Z(n){return n<=0?"0":n===1?"1":n<=5?"2-5":"6+"}function ge(n){return _e.createHash("sha256").update(n).digest("hex").slice(0,8)}async function dt(n){return L("session_encryption_device_skipped",{...$(),...n})}async function lt(n){return L("session_encryption_partial_success",{...$(),...n})}async function pt(n){return L("session_encryption_catch_up_grant",{...$(),...n})}async function ut(n){return L("session_encryption_self_rekey_request",{...$(),...n})}async function yt(n){return L("session_encryption_self_rekey_success",{...$(),...n})}async function ht(n){return L("session_encryption_self_rekey_timeout",{...$(),...n})}var oe=8080,vt="/callback",Pe=`http://localhost:${oe}${vt}`,Q=class n{constructor(){}static getInstance(){return n.instance||(n.instance=new n),n.instance}openBrowser(e){console.error(""),console.error("Opening your browser for sign-in..."),this.isRunningInWSL()?console.error("If your browser does not open, paste this URL in your Windows browser:"):console.error("If your browser does not open automatically, visit this URL:"),console.error(` ${e}`),console.error("");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=mt.readFileSync("/proc/sys/kernel/osrelease","utf8");return/microsoft|wsl/i.test(e)}catch{return!1}}tryBrowserCommand(e,t,r){if(r>=e.length){c.debug("[AuthService] No browser-opening command succeeded. User must open the sign-in URL manually (printed to stderr above)."),console.error(""),console.error("\u26A0\uFE0F Could not open browser automatically."),this.isRunningInWSL()?console.error(" WSL detected \u2014 paste this URL in your Windows browser:"):console.error(" Please copy and paste this URL into your browser:"),console.error(` ${t}`),console.error("");return}let i=e[r],s=[...i.fixedArgs,t],o=!1,a=p=>{o||(o=!0,c.debug(`[AuthService] Browser command '${i.cmd}' ${p}; trying next fallback`),this.tryBrowserCommand(e,t,r+1))},d=p=>{o||(o=!0,c.debug(`[AuthService] Browser command '${i.cmd}' ${p}`))},l;try{l=(0,ft.spawn)(i.cmd,s,{detached:!0,stdio:"ignore"})}catch(p){a(`threw synchronously: ${p?.message||p}`);return}l.on("error",p=>{a(`failed to spawn: ${p?.message||p}`)}),l.on("exit",(p,g)=>{p===0?d("exited successfully"):a(g?`terminated by signal ${g}`:`exited with code ${p}`)}),setTimeout(()=>{d("still running after 3s, assuming success")},3e3).unref(),l.unref()}generateState(){return gt.randomBytes(32).toString("hex")}buildAuthUrl(e){let t=w(),r=new URLSearchParams({client_id:t.aws.cognitoClientId,response_type:"code",scope:"email openid profile",redirect_uri:Pe,state:e});return`https://${t.aws.cognitoDomain}/oauth2/authorize?${r.toString()}`}async exchangeCodeForTokens(e){let t=w(),r=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"authorization_code",client_id:t.aws.cognitoClientId,code:e,redirect_uri:Pe}),s;try{s=await X(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},"Token exchange")}catch(a){throw await b("token_exchange_network_error"),A(a,"token_exchange_network_error"),a}if(!s.ok){let a=await s.text(),d=new Error(`Token exchange failed: ${s.status} ${a}`);throw await b("token_exchange_failed",{httpStatus:s.status}),A(d,"token_exchange_failed"),d}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=w(),r=`https://${t.aws.cognitoDomain}/oauth2/token`,i=new URLSearchParams({grant_type:"refresh_token",client_id:t.aws.cognitoClientId,refresh_token:e}),s=await X(r,{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 y.getTokens(I());if(e&&!y.isTokenExpired(e))return e;let t=this.generateState(),r=this.buildAuthUrl(t);return new Promise((i,s)=>{let o=Oe.createServer(async(a,d)=>{if(!a.url?.startsWith(vt)){d.writeHead(404),d.end("Not found");return}try{let l=new URL(a.url,`http://localhost:${oe}`),h=l.searchParams.get("code"),p=l.searchParams.get("state"),g=l.searchParams.get("error");if(g){let S=new Error(`OAuth error: ${g}`);throw await b("cognito_rejected"),A(S,"cognito_rejected"),S}if(p!==t){let S=new Error("State mismatch");throw await b("state_mismatch"),A(S,"state_mismatch"),S}if(!h){let S=new Error("No authorization code");throw await b("no_authorization_code"),A(S,"no_authorization_code"),S}let f=await this.exchangeCodeForTokens(h),O=this.decodeJwt(f.idToken),m={accessToken:f.accessToken,idToken:f.idToken,refreshToken:f.refreshToken,expiresAt:Date.now()+f.expiresIn*1e3,userId:O.sub,email:O.email||"unknown"};try{await y.setTokens(m,I())}catch(S){throw await b("keychain_write_failed"),A(S,"keychain_write_failed"),S}d.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),d.end(`
206
206
  <!DOCTYPE html>
207
207
  <html>
208
208
  <head><title>Success</title></head>
@@ -221,7 +221,7 @@ ${r.stack}`)):typeof r=="object"?o+=` ${JSON.stringify(r,bt)}`:o+=` ${r}`),o}log
221
221
  <p style="text-align: center; color: #71717a; margin-top: 24px;">You can close this window and try again in your terminal.</p>
222
222
  </body>
223
223
  </html>
224
- `),setTimeout(()=>{o.close(()=>s(l))},500)}});o.on("error",async c=>{if(c.code==="EADDRINUSE"){let d=new Error(`Port ${ne} is in use`);await S("port_in_use"),E(d,"port_in_use"),s(d)}else await S("server_listen_failed"),E(c,"server_listen_failed"),s(c)}),o.listen(ne,"localhost",()=>{a.info("[AuthService] Callback server started"),this.openBrowser(r)}),setTimeout(async()=>{let c=new Error("Login timeout");await S("login_timeout"),E(c,"login_timeout"),o.close(()=>s(c))},120*1e3)})}async logout(){let e=f(),t=await g.deleteTokens(I());return t&&new Promise(r=>{let i=xe.createServer((s,o)=>{s.url?.startsWith("/signout")?(o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(`
224
+ `),setTimeout(()=>{o.close(()=>s(l))},500)}});o.on("error",async a=>{if(a.code==="EADDRINUSE"){let d=new Error(`Port ${oe} is in use`);await b("port_in_use"),A(d,"port_in_use"),s(d)}else await b("server_listen_failed"),A(a,"server_listen_failed"),s(a)}),o.listen(oe,"localhost",()=>{c.info("[AuthService] Callback server started"),this.openBrowser(r)}),setTimeout(async()=>{let a=new Error("Login timeout");await b("login_timeout"),A(a,"login_timeout"),o.close(()=>s(a))},120*1e3)})}async logout(){let e=w(),t=await y.deleteTokens(I());return t&&new Promise(r=>{let i=Oe.createServer((s,o)=>{s.url?.startsWith("/signout")?(o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(`
225
225
  <!DOCTYPE html>
226
226
  <html>
227
227
  <head><title>Signed Out</title></head>
@@ -230,27 +230,27 @@ ${r.stack}`)):typeof r=="object"?o+=` ${JSON.stringify(r,bt)}`:o+=` ${r}`),o}log
230
230
  <p>You can close this window.</p>
231
231
  </body>
232
232
  </html>
233
- `),setTimeout(()=>{i.close(()=>r(!0))},500)):(o.writeHead(404),o.end("Not found"))});i.on("error",()=>{r(!0)}),i.listen(ne,"localhost",()=>{let s=`https://${e.aws.cognitoDomain}/logout?client_id=${e.aws.cognitoClientId}&logout_uri=${encodeURIComponent(Ce.replace("/callback","/signout"))}`;this.openBrowser(s)}),setTimeout(()=>{i.close(()=>r(!0))},30*1e3)})}async getStatus(){let e=await g.getTokens(I());return e?{authenticated:!g.isTokenExpired(e),tokens:e}:{authenticated:!1}}},R=G.getInstance();j();var p={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m"};async function $t(){console.log(`${p.cyan}CodeVibe Login${p.reset}
234
- `);try{let n=await R.getStatus();if(n.authenticated&&n.tokens){console.log(`${p.yellow}Already logged in as: ${n.tokens.email}${p.reset}`),console.log(`Token expires: ${new Date(n.tokens.expiresAt).toLocaleString()}`),console.log(`
235
- Run '${p.dim}codevibe logout${p.reset}' to sign out first.`),process.exit(0);return}console.log("Opening browser for authentication..."),console.log(`${p.dim}Waiting for callback...${p.reset}
236
- `);let e=await R.login();e&&(console.log(`
237
- ${p.green}\u2713 Authentication successful!${p.reset}`),console.log(` User: ${e.email}`),console.log(` User ID: ${e.userId}`),console.log(` Expires: ${new Date(e.expiresAt).toLocaleString()}`),await te(e.userId)),process.exit(0)}catch(n){let e=(()=>{let t=n?.message;return typeof t=="string"&&t.length>0?t:n==null?"(null/undefined error)":`[no_message ctor=${n?.constructor?.name??typeof n}] ${String(n).substring(0,80)}`})();console.error(`
238
- ${p.red}\u2717 Authentication failed${p.reset}`),console.error(` Error: ${e}`),re(n)||await S("unknown",{errorFragment:e}),process.exit(1)}}async function Lt(){console.log(`${p.cyan}CodeVibe Logout${p.reset}
239
- `);try{let n=await R.getStatus();if(!n.authenticated){console.log(`${p.yellow}Not logged in.${p.reset}`),process.exit(0);return}let e=n.tokens?.email;await R.logout()?(console.log(`${p.green}\u2713 Logged out successfully.${p.reset}`),console.log(` Previous user: ${e}`),console.log(`
240
- ${p.dim}Clearing browser session...${p.reset}`)):console.log(`${p.red}\u2717 Failed to log out.${p.reset}`),process.exit(0)}catch(n){console.error(`${p.red}\u2717 Logout failed: ${n.message}${p.reset}`),process.exit(1)}}async function Wt(){console.log(`${p.cyan}CodeVibe Auth Status${p.reset}
241
- `);try{let n=await R.getStatus();if(!n.tokens){console.log(`${p.yellow}Not authenticated.${p.reset}`),console.log(`
242
- Run '${p.dim}codevibe login${p.reset}' to sign in.`),process.exit(0);return}let e=!n.authenticated;console.log(e?`${p.yellow}\u26A0 Token expired${p.reset}`:`${p.green}\u2713 Authenticated${p.reset}`),console.log(` User: ${n.tokens.email}`),console.log(` User ID: ${n.tokens.userId}`),console.log(` Expires: ${new Date(n.tokens.expiresAt).toLocaleString()}`),e&&console.log(`
243
- ${p.dim}Token will be refreshed automatically.${p.reset}`),process.exit(0)}catch(n){console.error(`${p.red}\u2717 Status check failed: ${n.message}${p.reset}`),process.exit(1)}}async function Mt(){console.log(`${p.cyan}CodeVibe Reset Device${p.reset}
244
- `),console.log(`${p.red}\u26A0 WARNING: This will delete your device identity.${p.reset}`),console.log(`${p.red} Old encrypted sessions will become inaccessible.${p.reset}
245
- `);let{keychainManager:n}=await Promise.resolve().then(()=>(P(),Ge));try{await n.clearAllData(),console.log(`${p.green}\u2713 Device reset complete.${p.reset}`),console.log(` Run '${p.dim}codevibe login${p.reset}' to set up again.`),process.exit(0)}catch(e){console.error(`${p.red}\u2717 Reset failed: ${e.message}${p.reset}`),process.exit(1)}}function Bt(){console.log(`CodeVibe Authentication
233
+ `),setTimeout(()=>{i.close(()=>r(!0))},500)):(o.writeHead(404),o.end("Not found"))});i.on("error",()=>{r(!0)}),i.listen(oe,"localhost",()=>{let s=`https://${e.aws.cognitoDomain}/logout?client_id=${e.aws.cognitoClientId}&logout_uri=${encodeURIComponent(Pe.replace("/callback","/signout"))}`;this.openBrowser(s)}),setTimeout(()=>{i.close(()=>r(!0))},30*1e3)})}async getStatus(){let e=await y.getTokens(I());return e?{authenticated:!y.isTokenExpired(e),tokens:e}:{authenticated:!1}}},P=Q.getInstance();Y();var u={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m"};async function Jt(){console.log(`${u.cyan}CodeVibe Login${u.reset}
234
+ `);try{let n=await P.getStatus();if(n.authenticated&&n.tokens){console.log(`${u.yellow}Already logged in as: ${n.tokens.email}${u.reset}`),console.log(`Token expires: ${new Date(n.tokens.expiresAt).toLocaleString()}`),console.log(`
235
+ Run '${u.dim}codevibe logout${u.reset}' to sign out first.`),process.exit(0);return}console.log("Opening browser for authentication..."),console.log(`${u.dim}Waiting for callback...${u.reset}
236
+ `);let e=await P.login();e&&(console.log(`
237
+ ${u.green}\u2713 Authentication successful!${u.reset}`),console.log(` User: ${e.email}`),console.log(` User ID: ${e.userId}`),console.log(` Expires: ${new Date(e.expiresAt).toLocaleString()}`),await ie(e.userId)),process.exit(0)}catch(n){let e=(()=>{let t=n?.message;return typeof t=="string"&&t.length>0?t:n==null?"(null/undefined error)":`[no_message ctor=${n?.constructor?.name??typeof n}] ${String(n).substring(0,80)}`})();console.error(`
238
+ ${u.red}\u2717 Authentication failed${u.reset}`),console.error(` Error: ${e}`),se(n)||await b("unknown",{errorFragment:e}),process.exit(1)}}async function jt(){console.log(`${u.cyan}CodeVibe Logout${u.reset}
239
+ `);try{let n=await P.getStatus();if(!n.authenticated){console.log(`${u.yellow}Not logged in.${u.reset}`),process.exit(0);return}let e=n.tokens?.email;await P.logout()?(console.log(`${u.green}\u2713 Logged out successfully.${u.reset}`),console.log(` Previous user: ${e}`),console.log(`
240
+ ${u.dim}Clearing browser session...${u.reset}`)):console.log(`${u.red}\u2717 Failed to log out.${u.reset}`),process.exit(0)}catch(n){console.error(`${u.red}\u2717 Logout failed: ${n.message}${u.reset}`),process.exit(1)}}async function Gt(){console.log(`${u.cyan}CodeVibe Auth Status${u.reset}
241
+ `);try{let n=await P.getStatus();if(!n.tokens){console.log(`${u.yellow}Not authenticated.${u.reset}`),console.log(`
242
+ Run '${u.dim}codevibe login${u.reset}' to sign in.`),process.exit(0);return}let e=!n.authenticated;console.log(e?`${u.yellow}\u26A0 Token expired${u.reset}`:`${u.green}\u2713 Authenticated${u.reset}`),console.log(` User: ${n.tokens.email}`),console.log(` User ID: ${n.tokens.userId}`),console.log(` Expires: ${new Date(n.tokens.expiresAt).toLocaleString()}`),e&&console.log(`
243
+ ${u.dim}Token will be refreshed automatically.${u.reset}`),process.exit(0)}catch(n){console.error(`${u.red}\u2717 Status check failed: ${n.message}${u.reset}`),process.exit(1)}}async function zt(){console.log(`${u.cyan}CodeVibe Reset Device${u.reset}
244
+ `),console.log(`${u.red}\u26A0 WARNING: This will delete your device identity.${u.reset}`),console.log(`${u.red} Old encrypted sessions will become inaccessible.${u.reset}
245
+ `);let{keychainManager:n}=await Promise.resolve().then(()=>(R(),et));try{await n.clearAllData(),console.log(`${u.green}\u2713 Device reset complete.${u.reset}`),console.log(` Run '${u.dim}codevibe login${u.reset}' to set up again.`),process.exit(0)}catch(e){console.error(`${u.red}\u2717 Reset failed: ${e.message}${u.reset}`),process.exit(1)}}function Yt(){console.log(`CodeVibe Authentication
246
246
  `),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(`
247
- Environment:`),console.log(' Set ENVIRONMENT env var to "development" or "production" (default)'),console.log(" Example: ENVIRONMENT=development codevibe login")}async function pe(n){let e=I();console.log(`${p.dim}Environment: ${e}${p.reset}
248
- `);let r=n.slice(2).filter(i=>!i.startsWith("--"))[0];switch(r){case"login":await $t();break;case"logout":await Lt();break;case"status":await Wt();break;case"reset-device":await Mt();break;default:Bt(),process.exit(r?1:0)}}require.main===module&&pe(process.argv).catch(n=>{console.error("Error:",n),process.exit(1)});j();U();var Ft=/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;function pt(n){let e=Re(n);if(!e)return null;let t=qt(e);if(t)return t;let r=Ht(e);return r||null}function Re(n){return n.replace(/\r/g,`
249
- `).replace(Ft,"").replace(/[│┌┐└┘─├┤┬┴┼╌╎╭╮╯╰║═╔╗╚╝╠╣╦╩╬]/g," ").replace(/[ \t]+\n/g,`
247
+ Environment:`),console.log(' Set ENVIRONMENT env var to "development" or "production" (default)'),console.log(" Example: ENVIRONMENT=development codevibe login")}async function me(n){let e=I();console.log(`${u.dim}Environment: ${e}${u.reset}
248
+ `);let r=n.slice(2).filter(i=>!i.startsWith("--"))[0];switch(r){case"login":await Jt();break;case"logout":await jt();break;case"status":await Gt();break;case"reset-device":await zt();break;default:Yt(),process.exit(r?1:0)}}require.main===module&&me(process.argv).catch(n=>{console.error("Error:",n),process.exit(1)});Y();M();var Xt=/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;function St(n){let e=$e(n);if(!e)return null;let t=Zt(e);if(t)return t;let r=Qt(e);return r||null}function $e(n){return n.replace(/\r/g,`
249
+ `).replace(Xt,"").replace(/[│┌┐└┘─├┤┬┴┼╌╎╭╮╯╰║═╔╗╚╝╠╣╦╩╬]/g," ").replace(/[ \t]+\n/g,`
250
250
  `).replace(/\n{3,}/g,`
251
251
 
252
- `).trim()}function qt(n){let e=n.split(`
253
- `).map(h=>h.trim()),t=Vt(e,h=>/\[(?:y\/n|Y\/n|y\/N)\]/.test(h)),r=t>=0?e[t]:null;if(!r)return null;let i=gt(e,t),s=i.length>0?i.join(`
254
- `):r,o=s.toLowerCase(),c=o.includes("what to change")||o.includes("what should")||o.includes("provide")||o.includes("instructions");return{kind:"yes_no",promptText:s,options:c?[{number:"1",text:"Yes"},{number:"2",text:"No, provide instructions"}]:[{number:"1",text:"Yes"},{number:"2",text:"No"}],submitMap:{1:"y",2:"n"},requiresFollowUpText:c}}function Ht(n){let e=n.split(`
255
- `).map(d=>d.trim()),t=Jt(e);if(t.length<2)return null;let r=t.map(({line:d})=>ut(d)).filter(d=>!!d),i={};for(let d of r)i[d.number]=d.number;let s=t[0]?.index??-1,o=gt(e,s-1);return{kind:"numbered",promptText:o.length>0?o.join(`
256
- `):"Select an option",options:r,submitMap:i}}function Vt(n,e){for(let t=n.length-1;t>=0;t-=1)if(e(n[t]))return t;return-1}function ut(n){let e=n.match(/^(?:[>›❯▸▶➜➤*●]\s*)?(\d+)\.\s+(.*)$/);return e?{number:e[1],text:e[2]}:null}function Jt(n){let e=n.map((r,i)=>({index:i,line:r,parsed:ut(r)})).filter(r=>!!r.parsed);if(e.length===0)return[];let t=[e[e.length-1]];for(let r=e.length-2;r>=0;r-=1){let i=e[r],s=t[0];if(i.index!==s.index-1)break;t.unshift(i)}return t.map(({index:r,line:i})=>({index:r,line:i}))}function gt(n,e){if(e<0)return[];let t=De(n,e);if(t<0)return[];let{start:r,end:i}=Ke(n,t),s=n.slice(r,i+1).filter(Boolean);if(zt(s)){let u=jt(n,r-1);return u.length>0?u:s}if(r<=1)return s;let o=r-1;if(o=De(n,o),o<0||o===r-1)return s;let{start:c,end:d}=Ke(n,o),l=n.slice(c,d+1).filter(Boolean);return l.some(ht)?[...l,...s]:s}function ht(n){return/^(?:would you like to|do you want to|the model would like to|action required|confirm)\b/i.test(n)}function De(n,e){let t=e;for(;t>=0&&!n[t];)t-=1;return t}function Ke(n,e){let t=e;for(;t>=0&&n[t];)t-=1;return{start:t+1,end:e}}function jt(n,e){let t=[],r=e;for(;r>=0&&t.length<2&&(r=De(n,r),!(r<0));){let{start:s,end:o}=Ke(n,r),c=n.slice(s,o+1).filter(Boolean);c.length>0&&t.unshift(c),r=s-1}if(t.length===0)return[];let i=t.findIndex(s=>s.some(ht));return i>=0?t.slice(i).flat():t[t.length-1]}function zt(n){return n.length===0?!1:n.filter(Gt).length>=Math.max(2,Math.ceil(n.length/2))}function Gt(n){return/^\d+\s/.test(n)}X();P();X();U();async function H(n,e,t,r={}){let i;try{i=await t.getSession(n)}catch(u){return a.warn("[SessionRekey] Failed to fetch session state for re-key",{sessionId:n,error:u instanceof Error?u.message:String(u)}),0}if(!i)return a.warn("[SessionRekey] Session not found, skipping re-key",{sessionId:n}),0;if(!i.isEncrypted)return 0;let s=i.encryptedKeys||[],o=new Set(s.map(u=>u.deviceId)),c=r.forceDeviceIds??new Set,d;try{d=await t.listUserDeviceKeys()}catch(u){return a.warn("[SessionRekey] Failed to fetch user device keys",{sessionId:n,error:u instanceof Error?u.message:String(u)}),0}let l=d.filter(u=>!o.has(u.deviceId)||c.has(u.deviceId));if(l.length===0)return 0;a.info("[SessionRekey] Granting session key to devices",{sessionId:n,existingDeviceCount:s.length,grantCount:l.length,grantDeviceIds:l.map(u=>u.deviceId),forceCount:c.size});let h=0;for(let u of l)try{let w=k.encryptSessionKey(e,u.publicKey);await t.grantSessionKey({sessionId:n,deviceId:u.deviceId,encryptedKey:w.encryptedKey,ephemeralPublicKey:w.ephemeralPublicKey}),h++,a.info("[SessionRekey] Granted session key to device",{sessionId:n,deviceId:u.deviceId,platform:u.platform})}catch(w){a.warn("[SessionRekey] Failed to grant session key to device",{sessionId:n,deviceId:u.deviceId,error:w instanceof Error?w.message:String(w)})}return h>0&&a.info("[SessionRekey] Re-key complete",{sessionId:n,grantedCount:h,requestedCount:l.length}),h}async function ue(n,e,t){try{let r=await e.listUserDeviceKeys();if(r.length===0)return t.info("No device keys found, session will not be encrypted"),null;t.info("Preparing session encryption",{sessionId:n,deviceCount:r.length});let{sessionKey:i,encryptedKeys:s}=g.createSessionKey(r);return t.info("Session encryption prepared",{sessionId:n,deviceCount:s.length}),{sessionKey:i,encryptedKeys:s}}catch(r){return t.warn("Failed to prepare session encryption:",r),null}}async function _e(n,e,t){let{sessionId:r,userId:i,agentType:s,projectPath:o,metadata:c}=n,d=null;try{d=await e.getSession(r)}catch(b){t.warn("Failed to get session (will attempt to create new)",{sessionId:r,error:b})}if(d){t.info("Session exists in backend - reactivating",{sessionId:r,previousStatus:d.status});try{await e.updateSession({sessionId:r,status:"ACTIVE"})}catch(m){t.warn("Failed to reactivate existing session, will continue",{sessionId:r,error:m})}let b=null,Y=d.encryptedKeys;if(d.isEncrypted&&Y?.length)try{let m=await g.getSessionKey(r,Y);m?(b=m,g.cacheSessionKey(r,m),t.info("Session key retrieved for resumed session",{sessionId:r})):t.warn("No encrypted key for this device; proceeding without decryption",{sessionId:r})}catch(m){t.warn("Failed to retrieve session key for resumed session",{sessionId:r,error:m})}if(b)try{let m=await H(r,b,e);m>0&&t.info("Session re-keyed for newly registered devices on resume",{sessionId:r,newDeviceCount:m})}catch(m){t.warn("Session re-key on resume failed (non-fatal)",{sessionId:r,error:m instanceof Error?m.message:String(m)})}return{resumed:!0,sessionKey:b}}let l=await ue(r,e,t),h=o,u=c;l&&(h=k.encryptContent(o,l.sessionKey),u&&Object.keys(u).length>0&&(u={encrypted:k.encryptMetadata(u,l.sessionKey)}),t.info("Session data encrypted",{sessionId:r})),t.info("Creating new session in backend",{sessionId:r,userId:i,agentType:s,isEncrypted:!!l}),await e.createSession({sessionId:r,userId:i,agentType:s,projectPath:h,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 w=l?.sessionKey||null;return l&&g.cacheSessionKey(r,l.sessionKey),t.info("Session created",{sessionId:r,userId:i,isEncrypted:!!l}),{resumed:!1,sessionKey:w}}P();function Pe(n,e){let t=n.getCurrentUserId(),r=async(s,o)=>{let c=g.getCachedSessionIds();if(c.length===0){e.info("[DeviceKeyWatcher] No active sessions to re-key",{reason:s});return}e.info("[DeviceKeyWatcher] Running re-key pass",{reason:s,activeSessionCount:c.length,forceDeviceCount:o?.size??0});for(let d of c){let l=g.getCachedSessionKey(d);if(l)try{let h=await H(d,l,n,o?{forceDeviceIds:o}:void 0);h>0&&e.info("[DeviceKeyWatcher] Session re-keyed",{sessionId:d,newDeviceCount:h,reason:s})}catch(h){e.warn("[DeviceKeyWatcher] Re-key failed for session (non-fatal)",{sessionId:d,reason:s,error:h instanceof Error?h.message:String(h)})}}},i=n.subscribeToDeviceKeyRegistered(t,s=>{e.info("[DeviceKeyWatcher] New device observed, triggering re-key",{userId:t,newDeviceId:s.deviceId,platform:s.platform,deviceName:s.deviceName}),r(`new-device:${s.deviceId}`,new Set([s.deviceId]))},()=>{r("watcher-reconnect")},s=>{e.warn("[DeviceKeyWatcher] Subscription error (will retry)",{error:s instanceof Error?s.message:String(s)})});return e.info("[DeviceKeyWatcher] Started",{userId:t}),i}P();async function Oe(n,e){try{let t=await g.getDeviceId(),r=await g.getDevicePublicKey(),i=g.getDevicePlatform(),s=g.getDeviceName();e.info("Registering device encryption key",{deviceId:t,platform:i,deviceName:s}),await n.registerDeviceKey(t,r,i,s),g.setIsRegistered(!0),e.info("Device encryption key registered successfully",{deviceId:t})}catch(t){e.warn("Failed to register device encryption key (E2E encryption may not work):",t)}}0&&(module.exports={AgentType,AppSyncClient,AuthService,CryptoError,CryptoService,DeliveryStatus,ENCRYPTION_VERSION,EventSource,EventType,KeychainError,KeychainManager,Logger,SessionStatus,authService,createLogger,cryptoService,errorWasBeaconed,fireAuthCompletedBeacon,fireAuthFailedBeacon,getConfig,getEnvironment,getErrorReason,keychainManager,loadConfig,logger,markErrorBeaconed,mutations,normalizeSnapshot,parseInteractivePrompt,prepareSessionEncryption,queries,registerDeviceEncryptionKey,rekeySessionForNewDevices,resumeOrCreateSession,runAuthCli,startDeviceKeyWatcher,subscriptions});
252
+ `).trim()}function Zt(n){let e=n.split(`
253
+ `).map(h=>h.trim()),t=er(e,h=>/\[(?:y\/n|Y\/n|y\/N)\]/.test(h)),r=t>=0?e[t]:null;if(!r)return null;let i=kt(e,t),s=i.length>0?i.join(`
254
+ `):r,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 Qt(n){let e=n.split(`
255
+ `).map(d=>d.trim()),t=tr(e);if(t.length<2)return null;let r=t.map(({line:d})=>wt(d)).filter(d=>!!d),i={};for(let d of r)i[d.number]=d.number;let s=t[0]?.index??-1,o=kt(e,s-1);return{kind:"numbered",promptText:o.length>0?o.join(`
256
+ `):"Select an option",options:r,submitMap:i}}function er(n,e){for(let t=n.length-1;t>=0;t-=1)if(e(n[t]))return t;return-1}function wt(n){let e=n.match(/^(?:[>›❯▸▶➜➤*●]\s*)?(\d+)\.\s+(.*)$/);return e?{number:e[1],text:e[2]}:null}function tr(n){let e=n.map((r,i)=>({index:i,line:r,parsed:wt(r)})).filter(r=>!!r.parsed);if(e.length===0)return[];let t=[e[e.length-1]];for(let r=e.length-2;r>=0;r-=1){let i=e[r],s=t[0];if(i.index!==s.index-1)break;t.unshift(i)}return t.map(({index:r,line:i})=>({index:r,line:i}))}function kt(n,e){if(e<0)return[];let t=Ne(n,e);if(t<0)return[];let{start:r,end:i}=Ue(n,t),s=n.slice(r,i+1).filter(Boolean);if(nr(s)){let p=rr(n,r-1);return p.length>0?p:s}if(r<=1)return s;let o=r-1;if(o=Ne(n,o),o<0||o===r-1)return s;let{start:a,end:d}=Ue(n,o),l=n.slice(a,d+1).filter(Boolean);return l.some(bt)?[...l,...s]:s}function bt(n){return/^(?:would you like to|do you want to|the model would like to|action required|confirm)\b/i.test(n)}function Ne(n,e){let t=e;for(;t>=0&&!n[t];)t-=1;return t}function Ue(n,e){let t=e;for(;t>=0&&n[t];)t-=1;return{start:t+1,end:e}}function rr(n,e){let t=[],r=e;for(;r>=0&&t.length<2&&(r=Ne(n,r),!(r<0));){let{start:s,end:o}=Ue(n,r),a=n.slice(s,o+1).filter(Boolean);a.length>0&&t.unshift(a),r=s-1}if(t.length===0)return[];let i=t.findIndex(s=>s.some(bt));return i>=0?t.slice(i).flat():t[t.length-1]}function nr(n){return n.length===0?!1:n.filter(ir).length>=Math.max(2,Math.ceil(n.length/2))}function ir(n){return/^\d+\s/.test(n)}ee();R();ee();R();M();async function j(n,e,t,r={}){let i;try{i=await t.getSession(n)}catch(p){return c.warn("[SessionRekey] Failed to fetch session state for re-key",{sessionId:n,error:p instanceof Error?p.message:String(p)}),0}if(!i)return c.warn("[SessionRekey] Session not found, skipping re-key",{sessionId:n}),0;if(!i.isEncrypted)return 0;let s=i.encryptedKeys||[],o=new Set(s.map(p=>p.deviceId)),a=r.forceDeviceIds??new Set,d;try{d=await t.listUserDeviceKeys()}catch(p){return c.warn("[SessionRekey] Failed to fetch user device keys",{sessionId:n,error:p instanceof Error?p.message:String(p)}),0}let l=d.filter(p=>!o.has(p.deviceId)||a.has(p.deviceId));if(l.length===0)return 0;c.info("[SessionRekey] Granting session key to devices",{sessionId:n,existingDeviceCount:s.length,grantCount:l.length,grantDeviceIds:l.map(p=>p.deviceId),forceCount:a.size});let h=0;for(let p of l)try{let g=E.encryptSessionKey(e,p.publicKey);await t.grantSessionKey({sessionId:n,deviceId:p.deviceId,encryptedKey:g.encryptedKey,ephemeralPublicKey:g.ephemeralPublicKey}),h++,c.info("[SessionRekey] Granted session key to device",{sessionId:n,deviceId:p.deviceId,platform:p.platform})}catch(g){c.warn("[SessionRekey] Failed to grant session key to device",{sessionId:n,deviceId:p.deviceId,error:g instanceof Error?g.message:String(g)})}return h>0&&c.info("[SessionRekey] Re-key complete",{sessionId:n,grantedCount:h,requestedCount:l.length}),h}async function Et(n,e){let t=e.pollIntervalMs??5e3,r=e.maxAttempts??6,i,s;try{i=await y.getDeviceId(),s=await y.getDevicePrivateKey()}catch(o){c.warn("[SessionRekey] A1 pre-loop keychain read failed",{sessionId:n,error:o instanceof Error?o.message:String(o)});try{e.onTimeout?.(0)}catch{}return null}for(let o=1;o<=r;o++){o>1&&await new Promise(g=>setTimeout(g,t));let a;try{a=await e.appSyncClient.getSession(n)}catch(g){c.warn("[SessionRekey] A1 getSession failed during poll, will retry",{sessionId:n,attempt:o,error:g instanceof Error?g.message:String(g)});continue}let d=a?.encryptedKeys??[],l=d.filter(g=>g.deviceId===i);if(l.length===0){c.info("[SessionRekey] A1 our deviceId still not in encryptedKeys",{sessionId:n,attempt:o,freshDeviceCount:d.length});continue}let h=null,p=[];for(let g=l.length-1;g>=0;g--)try{h=E.decryptSessionKey(l[g],s);break}catch(f){p.push(f instanceof Error?f.message:String(f))}if(h){y.cacheSessionKey(n,h);try{e.onSuccess?.(o)}catch{}return c.info("[SessionRekey] A1 self-rekey successful",{sessionId:n,attempt:o,entriesTriedToDecrypt:l.length}),h}c.warn("[SessionRekey] A1 found entries but all decrypt-failed, will retry",{sessionId:n,attempt:o,entriesTried:l.length,errors:p})}try{e.onTimeout?.(r)}catch{}return c.warn("[SessionRekey] A1 self-rekey exhausted maxAttempts",{sessionId:n,maxAttempts:r}),null}R();async function ae(n,e){try{let t=await y.getDeviceId(),r=await y.getDevicePublicKey(),i=y.getDevicePlatform(),s=y.getDeviceName();e.info("Registering device encryption key",{deviceId:t,platform:i,deviceName:s}),await n.registerDeviceKey(t,r,i,s),y.setIsRegistered(!0),e.info("Device encryption key registered successfully",{deviceId:t})}catch(t){e.warn("Failed to register device encryption key (E2E encryption may not work):",t)}}async function fe(n,e,t){try{let r=await e.listUserDeviceKeys();if(r.length===0)return t.info("No device keys found, session will not be encrypted"),null;t.info("Preparing session encryption",{sessionId:n,deviceCount:r.length});let i=ge(n),{sessionKey:s,encryptedKeys:o,skippedDeviceIds:a}=y.createSessionKey(r,{onDeviceSkipped:d=>{dt({skipped_count_bucket:Z(d),session_hash:i}).catch(()=>{})}});return a.length>0&&lt({session_hash:i,encrypted_count_bucket:Z(o.length),skipped_count_bucket:Z(a.length)}).catch(()=>{}),t.info("Session encryption prepared",{sessionId:n,deviceCount:o.length,skippedCount:a.length}),{sessionKey:s,encryptedKeys:o,skippedDeviceIds:a}}catch(r){return t.warn("Failed to prepare session encryption:",r),null}}async function Le(n,e,t){let{sessionId:r,userId:i,agentType:s,projectPath:o,metadata:a}=n,d=null;try{d=await e.getSession(r)}catch(f){t.warn("Failed to get session (will attempt to create new)",{sessionId:r,error:f})}if(d){t.info("Session exists in backend - reactivating",{sessionId:r,previousStatus:d.status});try{await e.updateSession({sessionId:r,status:"ACTIVE"})}catch(m){t.warn("Failed to reactivate existing session, will continue",{sessionId:r,error:m})}let f=null,O=d.encryptedKeys??[];if(d.isEncrypted){if(O.length>0){try{let m=await y.getSessionKey(r,O);m&&(f=m,y.cacheSessionKey(r,m),t.info("Session key retrieved for resumed session",{sessionId:r}))}catch(m){t.warn("Failed to retrieve session key for resumed session",{sessionId:r,error:m})}if(!f){let m=ge(r);t.info("Self-rekey: re-registering device key + awaiting grant",{sessionId:r,otherDeviceCount:O.length}),ut({session_hash:m,other_device_count_bucket:Z(O.length)}).catch(()=>{});try{await ae(e,t),f=await Et(r,{appSyncClient:e,onSuccess:S=>{yt({session_hash:m,attempt_count:S}).catch(()=>{})},onTimeout:S=>{ht({session_hash:m,attempt_count:S}).catch(()=>{})}})}catch(S){t.warn("Self-rekey path failed",{sessionId:r,error:S instanceof Error?S.message:String(S)})}}}else t.warn("Encrypted session has empty encryptedKeys; cannot self-rekey",{sessionId:r});if(!f){let m=new Error(`Cannot resume encrypted session ${r}: `+(O.length===0?"session is marked encrypted but session.encryptedKeys is empty (corrupt state). Cannot self-rekey without a peer device. Start a new session.":"this device's key is not in session.encryptedKeys and self-rekey did not complete within 30s. This typically means the device key was rotated and mobile has not yet granted access to this device. Open the mobile app to refresh device keys, then retry."));throw m.code="ENCRYPTED_SESSION_NO_KEY",m}}if(f)try{let m=await j(r,f,e);m>0&&(t.info("Session re-keyed for newly registered devices on resume",{sessionId:r,newDeviceCount:m}),pt({session_hash:ge(r),granted_count_bucket:Z(m)}).catch(()=>{}))}catch(m){t.warn("Session re-key on resume failed (non-fatal)",{sessionId:r,error:m instanceof Error?m.message:String(m)})}return{resumed:!0,sessionKey:f}}let l=await fe(r,e,t),h=o,p=a;l&&(h=E.encryptContent(o,l.sessionKey),p&&Object.keys(p).length>0&&(p={encrypted:E.encryptMetadata(p,l.sessionKey)}),t.info("Session data encrypted",{sessionId:r})),t.info("Creating new session in backend",{sessionId:r,userId:i,agentType:s,isEncrypted:!!l}),await e.createSession({sessionId:r,userId:i,agentType:s,projectPath:h,status:"ACTIVE",metadata:p,isEncrypted:l?!0:void 0,creatorDeviceId:l?await y.getDeviceId():void 0,encryptionVersion:l?1:void 0,encryptedKeys:l?.encryptedKeys});let g=l?.sessionKey||null;return l&&y.cacheSessionKey(r,l.sessionKey),t.info("Session created",{sessionId:r,userId:i,isEncrypted:!!l}),{resumed:!1,sessionKey:g}}R();function We(n,e){let t=n.getCurrentUserId(),r=async(s,o)=>{let a=y.getCachedSessionIds();if(a.length===0){e.info("[DeviceKeyWatcher] No active sessions to re-key",{reason:s});return}e.info("[DeviceKeyWatcher] Running re-key pass",{reason:s,activeSessionCount:a.length,forceDeviceCount:o?.size??0});for(let d of a){let l=y.getCachedSessionKey(d);if(l)try{let h=await j(d,l,n,o?{forceDeviceIds:o}:void 0);h>0&&e.info("[DeviceKeyWatcher] Session re-keyed",{sessionId:d,newDeviceCount:h,reason:s})}catch(h){e.warn("[DeviceKeyWatcher] Re-key failed for session (non-fatal)",{sessionId:d,reason:s,error:h instanceof Error?h.message:String(h)})}}},i=n.subscribeToDeviceKeyRegistered(t,s=>{e.info("[DeviceKeyWatcher] New device observed, triggering re-key",{userId:t,newDeviceId:s.deviceId,platform:s.platform,deviceName:s.deviceName}),r(`new-device:${s.deviceId}`,new Set([s.deviceId]))},()=>{r("watcher-reconnect")},s=>{e.warn("[DeviceKeyWatcher] Subscription error (will retry)",{error:s instanceof Error?s.message:String(s)})});return e.info("[DeviceKeyWatcher] Started",{userId:t}),i}0&&(module.exports={AgentType,AppSyncClient,AuthService,CryptoError,CryptoService,DeliveryStatus,ENCRYPTION_VERSION,EventSource,EventType,KeychainError,KeychainManager,Logger,SessionStatus,authService,createLogger,cryptoService,errorWasBeaconed,fireAuthCompletedBeacon,fireAuthFailedBeacon,getConfig,getEnvironment,getErrorReason,keychainManager,loadConfig,logger,markErrorBeaconed,mutations,normalizeSnapshot,parseInteractivePrompt,prepareSessionEncryption,queries,registerDeviceEncryptionKey,rekeySessionForNewDevices,resumeOrCreateSession,runAuthCli,startDeviceKeyWatcher,subscriptions});
@@ -91,14 +91,28 @@ export declare class KeychainManager {
91
91
  */
92
92
  getSessionKey(sessionId: string, encryptedKeys?: EncryptedSessionKey[]): Promise<string | null>;
93
93
  /**
94
- * Generate and encrypt a new session key for all devices
94
+ * Generate and encrypt a new session key for all devices.
95
+ *
96
+ * Per-device try/catch (task #331 Bug B): one bad publicKey (corrupted
97
+ * base64, wrong curve, ECDH derive failure) does NOT abort the whole
98
+ * call — that device is skipped and reported in `skippedDeviceIds`. The
99
+ * caller decides what to do (telemetry, partial-success UX). Throw only
100
+ * if NO device succeeded, preserving the existing "no encryption"
101
+ * fallback at `prepareSessionEncryption`.
102
+ *
103
+ * Optional `onDeviceSkipped` callback fires per-skip for telemetry —
104
+ * intentionally a callback rather than a direct beacon import so this
105
+ * module stays free of analytics dependencies.
95
106
  */
96
107
  createSessionKey(devicePublicKeys: Array<{
97
108
  deviceId: string;
98
109
  publicKey: string;
99
- }>): {
110
+ }>, options?: {
111
+ onDeviceSkipped?: (totalSkippedSoFar: number) => void;
112
+ }): {
100
113
  sessionKey: string;
101
114
  encryptedKeys: EncryptedSessionKey[];
115
+ skippedDeviceIds: string[];
102
116
  };
103
117
  /**
104
118
  * Cache a session key
@@ -36,3 +36,43 @@ export interface RekeyOptions {
36
36
  * @returns The number of new grants that succeeded.
37
37
  */
38
38
  export declare function rekeySessionForNewDevices(sessionId: string, sessionKey: string, appSyncClient: AppSyncClient, options?: RekeyOptions): Promise<number>;
39
+ /**
40
+ * Options for {@link awaitOwnSessionKeyGrant}.
41
+ */
42
+ export interface AwaitOwnGrantOptions {
43
+ /** Poll interval in ms. Default 5000. */
44
+ pollIntervalMs?: number;
45
+ /** Max poll attempts. Default 6 (30s total at 5s intervals). */
46
+ maxAttempts?: number;
47
+ /** Authenticated AppSyncClient. */
48
+ appSyncClient: AppSyncClient;
49
+ /** Fired on successful decrypt. Telemetry-only — never thrown. */
50
+ onSuccess?: (attemptCount: number) => void;
51
+ /** Fired after maxAttempts exhausted. Telemetry-only — never thrown. */
52
+ onTimeout?: (attemptCount: number) => void;
53
+ }
54
+ /**
55
+ * Wait for this device's deviceId to appear in `session.encryptedKeys`.
56
+ *
57
+ * Triggered when {@link keychainManager.getSessionKey} returned null on
58
+ * resume AND at least one other device IS in encryptedKeys (so some other
59
+ * device can mint a grant for us via grantSessionKey). Caller must have
60
+ * already invoked {@link registerDeviceEncryptionKey} BEFORE this helper —
61
+ * that's what causes mobile's DeviceKeyWatcher subscription to fire and
62
+ * grant the session key to our (possibly rotated) pubKey.
63
+ *
64
+ * This helper deliberately bypasses {@link keychainManager.getSessionKey}
65
+ * (which has a cache short-circuit) and instead:
66
+ * 1. Calls {@link AppSyncClient.getSession} each poll for fresh
67
+ * `encryptedKeys`.
68
+ * 2. Looks for our `deviceId` in the fresh list.
69
+ * 3. If found, calls {@link cryptoService.decryptSessionKey} directly.
70
+ * 4. On success, populates the keychain cache (so subsequent
71
+ * `getSessionKey` calls hit the cache). The cache is NEVER populated
72
+ * on failure — there's no null sentinel.
73
+ *
74
+ * Returns the decrypted session key on success, or `null` after timeout.
75
+ * Errors are swallowed inside the loop (best-effort polling); telemetry
76
+ * surfaces success vs timeout via the optional callbacks.
77
+ */
78
+ export declare function awaitOwnSessionKeyGrant(sessionId: string, options: AwaitOwnGrantOptions): Promise<string | null>;
@@ -36,6 +36,7 @@ export interface ResumeOrCreateSessionResult {
36
36
  export declare function prepareSessionEncryption(sessionId: string, appSyncClient: AppSyncClient, logger: Logger): Promise<{
37
37
  sessionKey: string;
38
38
  encryptedKeys: EncryptedSessionKey[];
39
+ skippedDeviceIds: string[];
39
40
  } | null>;
40
41
  /**
41
42
  * Resume an existing session or create a new one.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
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",
@@ -17,18 +17,18 @@ before trusting. For example, `req.body.foo.toString()` may fail in multiple
17
17
  ways, for example the `foo` property may not be there or may not be a string,
18
18
  and `toString` may not be a function and instead a string or other user input.
19
19
 
20
- [Learn about the anatomy of an HTTP transaction in Node.js](https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/).
20
+ [Learn about the anatomy of an HTTP transaction in Node.js](https://nodejs.org/en/learn/http/anatomy-of-an-http-transaction).
21
21
 
22
22
  _This does not handle multipart bodies_, due to their complex and typically
23
23
  large nature. For multipart bodies, you may be interested in the following
24
24
  modules:
25
25
 
26
- * [busboy](https://www.npmjs.org/package/busboy#readme) and
27
- [connect-busboy](https://www.npmjs.org/package/connect-busboy#readme)
28
- * [multiparty](https://www.npmjs.org/package/multiparty#readme) and
29
- [connect-multiparty](https://www.npmjs.org/package/connect-multiparty#readme)
30
- * [formidable](https://www.npmjs.org/package/formidable#readme)
31
- * [multer](https://www.npmjs.org/package/multer#readme)
26
+ * [busboy](https://www.npmjs.com/package/busboy#readme) and
27
+ [connect-busboy](https://www.npmjs.com/package/connect-busboy#readme)
28
+ * [multiparty](https://www.npmjs.com/package/multiparty#readme) and
29
+ [connect-multiparty](https://www.npmjs.com/package/connect-multiparty#readme)
30
+ * [formidable](https://www.npmjs.com/package/formidable#readme)
31
+ * [multer](https://www.npmjs.com/package/multer#readme)
32
32
 
33
33
  This module provides the following parsers:
34
34
 
@@ -39,8 +39,8 @@ This module provides the following parsers:
39
39
 
40
40
  Other body parsers you might be interested in:
41
41
 
42
- - [body](https://www.npmjs.org/package/body#readme)
43
- - [co-body](https://www.npmjs.org/package/co-body#readme)
42
+ - [body](https://www.npmjs.com/package/body#readme)
43
+ - [co-body](https://www.npmjs.com/package/co-body#readme)
44
44
 
45
45
  ## Installation
46
46
 
@@ -109,7 +109,7 @@ accept anything `JSON.parse` accepts. Defaults to `true`.
109
109
  The `type` option is used to determine what media type the middleware will
110
110
  parse. This option can be a string, array of strings, or a function. If not a
111
111
  function, `type` option is passed directly to the
112
- [type-is](https://www.npmjs.org/package/type-is#readme) library and this can
112
+ [type-is](https://www.npmjs.com/package/type-is#readme) library and this can
113
113
  be an extension name (like `json`), a mime type (like `application/json`), or
114
114
  a mime type with a wildcard (like `*/*` or `*/json`). If a function, the `type`
115
115
  option is called as `fn(req)` and the request is parsed if it returns a truthy
@@ -154,7 +154,7 @@ to `'100kb'`.
154
154
  The `type` option is used to determine what media type the middleware will
155
155
  parse. This option can be a string, array of strings, or a function.
156
156
  If not a function, `type` option is passed directly to the
157
- [type-is](https://www.npmjs.org/package/type-is#readme) library and this
157
+ [type-is](https://www.npmjs.com/package/type-is#readme) library and this
158
158
  can be an extension name (like `bin`), a mime type (like
159
159
  `application/octet-stream`), or a mime type with a wildcard (like `*/*` or
160
160
  `application/*`). If a function, the `type` option is called as `fn(req)`
@@ -205,7 +205,7 @@ to `'100kb'`.
205
205
  The `type` option is used to determine what media type the middleware will
206
206
  parse. This option can be a string, array of strings, or a function. If not
207
207
  a function, `type` option is passed directly to the
208
- [type-is](https://www.npmjs.org/package/type-is#readme) library and this can
208
+ [type-is](https://www.npmjs.com/package/type-is#readme) library and this can
209
209
  be an extension name (like `txt`), a mime type (like `text/plain`), or a mime
210
210
  type with a wildcard (like `*/*` or `text/*`). If a function, the `type`
211
211
  option is called as `fn(req)` and the request is parsed if it returns a
@@ -221,8 +221,8 @@ encoding of the request. The parsing can be aborted by throwing an error.
221
221
 
222
222
  Returns middleware that only parses `urlencoded` bodies and only looks at
223
223
  requests where the `Content-Type` header matches the `type` option. This
224
- parser accepts only UTF-8 encoding of the body and supports automatic
225
- inflation of `gzip`, `br` (brotli) and `deflate` encodings.
224
+ parser accepts only UTF-8 and ISO-8859-1 encodings of the body and supports
225
+ automatic inflation of `gzip`, `br` (brotli) and `deflate` encodings.
226
226
 
227
227
  A new `body` object containing the parsed data is populated on the `request`
228
228
  object after the middleware (i.e. `req.body`). This object will contain
@@ -239,7 +239,7 @@ any of the following keys:
239
239
  The "extended" syntax allows for rich objects and arrays to be encoded into the
240
240
  URL-encoded format, allowing for a JSON-like experience with URL-encoded. For
241
241
  more information, please [see the qs
242
- library](https://www.npmjs.org/package/qs#readme).
242
+ library](https://www.npmjs.com/package/qs#readme).
243
243
 
244
244
  Defaults to `false`.
245
245
 
@@ -266,7 +266,7 @@ than this value, a 413 will be returned to the client. Defaults to `1000`.
266
266
  The `type` option is used to determine what media type the middleware will
267
267
  parse. This option can be a string, array of strings, or a function. If not
268
268
  a function, `type` option is passed directly to the
269
- [type-is](https://www.npmjs.org/package/type-is#readme) library and this can
269
+ [type-is](https://www.npmjs.com/package/type-is#readme) library and this can
270
270
  be an extension name (like `urlencoded`), a mime type (like
271
271
  `application/x-www-form-urlencoded`), or a mime type with a wildcard (like
272
272
  `*/x-www-form-urlencoded`). If a function, the `type` option is called as
@@ -488,7 +488,7 @@ app.use(bodyParser.text({ type: 'text/html' }))
488
488
  [coveralls-image]: https://img.shields.io/coverallsCoverage/github/expressjs/body-parser?branch=master
489
489
  [coveralls-url]: https://coveralls.io/r/expressjs/body-parser?branch=master
490
490
  [npm-downloads-image]: https://img.shields.io/npm/dm/body-parser
491
- [npm-url]: https://npmjs.org/package/body-parser
491
+ [npm-url]: https://npmjs.com/package/body-parser
492
492
  [npm-version-image]: https://img.shields.io/npm/v/body-parser
493
493
  [ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/body-parser/badge
494
- [ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/body-parser
494
+ [ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/body-parser