@myagentroam/node 0.9.62 → 0.9.65

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 (161) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +4 -0
  3. package/dist/capabilities.js +110 -2
  4. package/dist/claude-agent-sdk.js +330 -2
  5. package/dist/claude-channel.js +44 -2
  6. package/dist/codex-app-server.js +510 -2
  7. package/dist/config.js +106 -2
  8. package/dist/connector/node-connector-options.js +1 -2
  9. package/dist/connector/node-operation-router.js +22 -2
  10. package/dist/connector.js +1736 -2
  11. package/dist/control-outbound-scheduler.js +153 -2
  12. package/dist/database.js +639 -2
  13. package/dist/fake-runner.js +129 -2
  14. package/dist/git-askpass.js +12 -0
  15. package/dist/git-execution-helper.js +266 -0
  16. package/dist/health.js +3 -2
  17. package/dist/main.js +57 -2
  18. package/dist/mcp-installation-model.js +1 -2
  19. package/dist/migrations/v004.js +55 -3
  20. package/dist/migrations/v005.js +13 -3
  21. package/dist/migrations/v006.js +90 -3
  22. package/dist/migrations/v007.js +22 -3
  23. package/dist/migrations/v008.js +18 -3
  24. package/dist/migrations/v009.js +70 -4
  25. package/dist/migrations/v010.js +43 -3
  26. package/dist/migrations/v011.js +20 -3
  27. package/dist/migrations/v012.js +8 -0
  28. package/dist/native-jsonl-reader.js +186 -2
  29. package/dist/native-session-history.js +1143 -2
  30. package/dist/opencode-runtime.js +80 -2
  31. package/dist/opencode-server.js +259 -2
  32. package/dist/operational.js +122 -2
  33. package/dist/process-tree.js +18 -2
  34. package/dist/ripgrep-binary.js +31 -2
  35. package/dist/rotating-log.js +67 -2
  36. package/dist/runner/abstract-runner.js +260 -2
  37. package/dist/runner/claude/managed-run-controller.js +355 -2
  38. package/dist/runner/claude/tool-normalizer.js +120 -2
  39. package/dist/runner/claude-code-runner.js +303 -2
  40. package/dist/runner/codex/composer-image-markers.js +8 -2
  41. package/dist/runner/codex/conversation-parser.js +913 -2
  42. package/dist/runner/codex/managed-run-controller.js +494 -2
  43. package/dist/runner/codex/tool-normalizer.js +214 -2
  44. package/dist/runner/codex-runner.js +585 -2
  45. package/dist/runner/fake-test-runner.js +47 -2
  46. package/dist/runner/mar-agent/conversation-normalizer.js +644 -2
  47. package/dist/runner/mar-agent/executor-stdio-client-transport.js +139 -2
  48. package/dist/runner/mar-agent/generated-images.js +41 -2
  49. package/dist/runner/mar-agent/history-projection.js +106 -2
  50. package/dist/runner/mar-agent/hosted-conversation-runtime.js +446 -2
  51. package/dist/runner/mar-agent/managed-run-controller.js +785 -2
  52. package/dist/runner/mar-agent/mcp-client-pool.js +233 -2
  53. package/dist/runner/mar-agent/runtime-model-factory.js +326 -2
  54. package/dist/runner/mar-agent-runner.js +458 -2
  55. package/dist/runner/opencode/conversation-parser.js +221 -2
  56. package/dist/runner/opencode/managed-run-controller.js +588 -2
  57. package/dist/runner/opencode/tool-normalizer.js +80 -2
  58. package/dist/runner/opencode-runner.js +426 -2
  59. package/dist/runner/runner-registry.js +87 -2
  60. package/dist/runner-command-engine.js +71 -2
  61. package/dist/runner-profiles.js +323 -2
  62. package/dist/runner-usage.js +190 -2
  63. package/dist/runtime-command-detector.js +73 -2
  64. package/dist/runtime-model.js +1 -2
  65. package/dist/runtime-state.js +1509 -2
  66. package/dist/service/attachment-domain-state.js +7 -2
  67. package/dist/service/bubblewrap-sandbox-executor.js +543 -2
  68. package/dist/service/continuous-run-coordinator.js +425 -2
  69. package/dist/service/conversation-history-service.js +552 -2
  70. package/dist/service/conversation-hosting-capability-service.js +61 -2
  71. package/dist/service/conversation-hosting-enablement-service.js +91 -2
  72. package/dist/service/conversation-hosting-maintenance-service.js +174 -2
  73. package/dist/service/conversation-segment-service.js +162 -2
  74. package/dist/service/conversation-template-node-service.js +992 -2
  75. package/dist/service/external-session-resume-service.js +152 -2
  76. package/dist/service/fake-managed-run-service.js +60 -2
  77. package/dist/service/git-execution-service.js +418 -0
  78. package/dist/service/git-operation-service.js +57 -0
  79. package/dist/service/hosted-conversation-node-service.js +1982 -2
  80. package/dist/service/hosted-conversation-store.js +1405 -2
  81. package/dist/service/managed-runner-session-service.js +35 -2
  82. package/dist/service/mar-agent-model-transport-test-service.js +88 -2
  83. package/dist/service/mcp-installation-verifier.js +87 -2
  84. package/dist/service/mcp-node-operation-service.js +90 -2
  85. package/dist/service/mission-mcp-server.js +124 -2
  86. package/dist/service/mission-mcp-stdio.js +40 -2
  87. package/dist/service/mission-runtime.js +142 -2
  88. package/dist/service/native-session-projection-service.js +274 -2
  89. package/dist/service/native-session-watch-service.js +683 -2
  90. package/dist/service/node-connection-lifecycle-service.js +88 -2
  91. package/dist/service/node-control-channel.js +85 -2
  92. package/dist/service/node-control-message-service.js +109 -2
  93. package/dist/service/node-request-service.js +62 -2
  94. package/dist/service/node-run-event-bridge.js +88 -2
  95. package/dist/service/node-terminal-channel.js +202 -2
  96. package/dist/service/node-upgrade-coordinator.js +137 -2
  97. package/dist/service/node-workspace-coordinator.js +97 -2
  98. package/dist/service/recent-run-projection-service.js +99 -2
  99. package/dist/service/run-attachment-service.js +321 -2
  100. package/dist/service/run-domain-state.js +4 -2
  101. package/dist/service/run-event-service.js +246 -2
  102. package/dist/service/run-ownership-policy.js +22 -2
  103. package/dist/service/run-workbench-service.js +120 -2
  104. package/dist/service/runner-channel-message-service.js +20 -2
  105. package/dist/service/runner-interaction-service.js +243 -2
  106. package/dist/service/runner-service.js +69 -2
  107. package/dist/service/runtime-credential-control-service.js +95 -2
  108. package/dist/service/session-catalog-service.js +404 -2
  109. package/dist/service/session-command-service.js +125 -2
  110. package/dist/service/session-context-service.js +128 -2
  111. package/dist/service/session-domain-state.js +9 -2
  112. package/dist/service/session-identity-service.js +86 -2
  113. package/dist/service/session-lifecycle-service.js +248 -2
  114. package/dist/service/session-message-service.js +270 -2
  115. package/dist/service/session-presentation-service.js +43 -2
  116. package/dist/service/session-query-service.js +82 -2
  117. package/dist/service/session-watch-slot-coordinator.js +21 -2
  118. package/dist/service/skill-directory-service.js +238 -2
  119. package/dist/service/skill-install-service.js +434 -2
  120. package/dist/service/skill-node-operation-service.js +206 -2
  121. package/dist/service/terminal-relay-state.js +3 -2
  122. package/dist/service/terminal-service.js +90 -2
  123. package/dist/service/web-search-error.js +40 -2
  124. package/dist/service/workbench-event-service.js +21 -2
  125. package/dist/service/workbench-manifest-service.js +69 -2
  126. package/dist/service/workspace-change-service.js +290 -2
  127. package/dist/service/workspace-content-search-service.js +457 -2
  128. package/dist/service/workspace-domain-state.js +41 -2
  129. package/dist/service/workspace-file-service.js +150 -2
  130. package/dist/service/workspace-git-exclude-service.js +119 -2
  131. package/dist/service/workspace-queue-workbench-service.js +176 -2
  132. package/dist/service/workspace-service.js +92 -2
  133. package/dist/service/workspace-session-service.js +154 -2
  134. package/dist/service/workspace-upload-service.js +262 -2
  135. package/dist/service/workspace-watch-controller.js +68 -2
  136. package/dist/service/workspace-watch-service.js +170 -2
  137. package/dist/service/workspace-watch-snapshot-service.js +218 -2
  138. package/dist/service/workspace-workbench-service.js +239 -2
  139. package/dist/service.js +91 -2
  140. package/dist/storage.js +32 -2
  141. package/dist/supervisor.js +136 -2
  142. package/dist/terminal.js +496 -2
  143. package/dist/util/git-credential-client.js +32 -0
  144. package/dist/util/node-operation-data.js +9 -2
  145. package/dist/util/node-operation-parsers.js +382 -2
  146. package/dist/util/personal-instructions.js +34 -2
  147. package/dist/util/runner-error.js +70 -2
  148. package/dist/util/runner-native-session-parsers.js +510 -2
  149. package/dist/util/safe-error.js +8 -2
  150. package/dist/util/secret-environment.js +25 -2
  151. package/dist/workspace.js +1793 -2
  152. package/package.json +11 -8
  153. package/vendor/ripgrep/darwin-arm64/rg +0 -0
  154. package/vendor/ripgrep/darwin-x64/rg +0 -0
  155. package/vendor/ripgrep/manifest.json +12 -0
  156. package/README.md +0 -42
  157. package/dist/event-buffer.js +0 -2
  158. package/dist/migrations/v001.js +0 -107
  159. package/dist/migrations/v002.js +0 -2
  160. package/dist/migrations/v003.js +0 -2
  161. package/dist/service/mcp-package-installer.js +0 -2
@@ -1,2 +1,152 @@
1
- /* mar-release-protected */
2
- const _0xff519d=_0x50f4;function _0x5176(){const _0x5c92dd=['y2XLyxjgywLSDxjL','CMvZB2X2zq','ChjVzhvJDa','zwzMB3j0','ChjVAMvJDgLVBKzVCG','zw5ZDxjLq29UzMLNDxjHDgLVBG','CMvZDw1L','z2v0','y29Kzq','mtu5mdiZnZL2BwLQy3q','rvHurvjoquW','DhjHBNnPDgLVBNm','C2v0rMfPBhvYzq','C2v0','rvHurvjoquXFqunusvzf','CNvUBMvY','zMfPBhvYzurLDgfPBa','z2v0qwDLBNrtzxnZAw9U','nJaWmJqYngncAvLdAa','ywn0AxzPDhK','BwvZC2fNzuzHAwX1CMvdB2rL','n2PhAg1lqW','y3jLyxrLqwDLBNrtzxnZAw9U','CMvTzw1IzxjoyxrPDMu','nte3mJu5nurhDvrizW','BwvZC2fNzvjLC3vTzuzHAwX1CMvZ','CMvZB2X2zuzVCK1LC3nHz2u','C2vZC2LVBG','CMvZDw1LrxH0zxjUywW','DgHLBG','zMfPBhvYzvrPBwvYCW','CMvZDw1Lzej5rgLYzwn0swq','CMvZDw1LrMfPBhvYzurLDgfPBhm','mJy1nZy2mwfwr2T4wG','neTduMHnyq','uLvotKvsx1voqvzbsuXbqKXf','u0vtu0LptL9srvnvtuvFuKvkrunuruq','tufsx01btKfhruq','nda5ndqXyunUwgHU','CMvZDw1LvgfZA3m','Bw9KzwW','zgvSAxzLCNK','ywnJzxnZ','zxH0zxjUywXby3rPDML0Eq','ywrK','C3rHDgu','B3b0Aw9UCW','rvHurvjoquXFu0vtu0LptL9bq1rjvKu','u0vtu0LptL9ot1rFrK9vtKq','D29YA3nWywnLswq','ywnJzxb0rM9YtwvZC2fNzq','CNvUDgLTzq','uKvkrunuruq','BMf0AxzLq29UDhjVBa','uKvtvu1bqKXf','mtCYmdK4nffcwwLMwG','y29UzMLNDxjHDgLVBG','zgvSzxrL','CMvZDw1LrMfPBhvYzxm','C2v0tMf0AxzLq29UDhjVBa','BwfUywDLzefSAwfZrM9Y','AgfZ','zMfPBhvYzunVzgu','C3rHz2u','zxH0zxjUywXtzxnZAw9Uswq','CNvUBMvYCW','CgvYzM9YBvjLC3vTzq','DhjHBNnPDgLVBMLUzW','yxzHAwXHyMXL','mZqZmdG3nKH6sunhCW','Dw5Yzwy','zMfPBhvYzq','D29YA3nWywnLugf0Aa','CNvUBMvYvgL0Bgu','y3vZDg9TvgL0Bgu','y3DK'];_0x5176=function(){return _0x5c92dd;};return _0x5176();}(function(_0x7d1319,_0x4b05de){const _0x48716b=_0x50f4,_0x36e5de=_0x7d1319();while(!![]){try{const _0x53f089=parseInt(_0x48716b(0x1b1))/(0x14b7+-0x24cc+-0x8e*-0x1d)*(-parseInt(_0x48716b(0x1ad))/(-0x2*0x16f+0x59d*-0x5+0x1ef1))+-parseInt(_0x48716b(0x1ac))/(-0xe8e*-0x1+-0xf16+-0x1*-0x8b)+parseInt(_0x48716b(0x184))/(0x1d*-0x77+-0xa*-0x329+-0x3*0x609)+-parseInt(_0x48716b(0x1a3))/(-0x1*-0x71+-0x1*0x28e+-0x1*-0x222)+parseInt(_0x48716b(0x19d))/(0x227*-0x7+-0x1*0xbe9+0x1b00)+parseInt(_0x48716b(0x1a0))/(-0xb5a*-0x3+0x1103+-0x1*0x330a)*(-parseInt(_0x48716b(0x1c2))/(0x83f*0x2+-0xaf*-0x13+0x15*-0x167))+parseInt(_0x48716b(0x194))/(-0x25ed+-0x9ae+0x2fa4);if(_0x53f089===_0x4b05de)break;else _0x36e5de['push'](_0x36e5de['shift']());}catch(_0x5ae765){_0x36e5de['push'](_0x36e5de['shift']());}}}(_0x5176,-0x2*0x83064+0x8b169+0xd*0x160da));function _0x50f4(_0x2f3e4d,_0x3fbddc){_0x2f3e4d=_0x2f3e4d-(0x617*0x5+0x1e6d*-0x1+0x17d);const _0x34d2fc=_0x5176();let _0x3b27fa=_0x34d2fc[_0x2f3e4d];if(_0x50f4['pQyKaw']===undefined){var _0x22a94a=function(_0x26681d){const _0x5333ef='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x3dd715='',_0xb4d914='';for(let _0x471e42=0xacc+0x713+-0x393*0x5,_0x3287b6,_0xfb3c7d,_0x5be23b=-0x139*0x10+-0x83*-0x37+0x1*-0x895;_0xfb3c7d=_0x26681d['charAt'](_0x5be23b++);~_0xfb3c7d&&(_0x3287b6=_0x471e42%(-0x13da+0x537+0xea7)?_0x3287b6*(0x6a*-0x14+-0x1672+0x1efa)+_0xfb3c7d:_0xfb3c7d,_0x471e42++%(-0x20b0+0x1f5+0x1ebf))?_0x3dd715+=String['fromCharCode'](-0xb26*0x3+0x1e16+0xdf*0x5&_0x3287b6>>(-(0x2*-0x1205+-0x7*0xd0+0x29bc)*_0x471e42&0xc9a+-0x3*-0x8a9+0x1*-0x268f)):-0xbed*0x2+-0x1*0x19cd+0x29d*0x13){_0xfb3c7d=_0x5333ef['indexOf'](_0xfb3c7d);}for(let _0x34b529=-0x8a9+-0xe87+0x10*0x173,_0xe900f7=_0x3dd715['length'];_0x34b529<_0xe900f7;_0x34b529++){_0xb4d914+='%'+('00'+_0x3dd715['charCodeAt'](_0x34b529)['toString'](-0xb*0x1f3+-0x298*0xf+0x3c69))['slice'](-(-0x43*-0x3b+-0x3d5*-0x1+-0x1344));}return decodeURIComponent(_0xb4d914);};_0x50f4['UJamzR']=_0x22a94a,_0x50f4['egDBsm']={},_0x50f4['pQyKaw']=!![];}const _0x36dd66=_0x34d2fc[0x2026+0x96c+0x11*-0x272];_0x50f4['IcFexQ']!==_0x36dd66&&(_0x50f4['egDBsm']={},_0x50f4['IcFexQ']=_0x36dd66);const _0x3b23a4=_0x50f4['egDBsm'][_0x2f3e4d];return _0x3b23a4===undefined?(_0x3b27fa=_0x50f4['UJamzR'](_0x3b27fa),_0x50f4['egDBsm'][_0x2f3e4d]=_0x3b27fa):_0x3b27fa=_0x3b23a4,_0x3b27fa;}const RESUME_FAILURE_TTL_MS=(-0x767+0xf84+0x7ff*-0x1)*(-0x10fb3+0x1*0x15e97+0x9b7c);export class ExternalSessionResumeService{[_0xff519d(0x1b9)];[_0xff519d(0x196)]=new Set();[_0xff519d(0x1b2)]=new Map();constructor(_0x360d47){const _0x31dde1=_0xff519d;this[_0x31dde1(0x1b9)]=_0x360d47;}[_0xff519d(0x1ce)](_0x7ed60a){const _0x362fd3=_0xff519d;return this[_0x362fd3(0x196)][_0x362fd3(0x1c8)](_0x7ed60a);}async[_0xff519d(0x191)](_0x2d861b){const _0x4d3d40=_0xff519d,_0x1c1d4c=this[_0x4d3d40(0x1b2)][_0x4d3d40(0x192)](_0x2d861b['id']);if(_0x1c1d4c!==undefined)return _0x1c1d4c;const _0x2594af=this[_0x4d3d40(0x1cd)](_0x2d861b);this[_0x4d3d40(0x1b2)][_0x4d3d40(0x198)](_0x2d861b['id'],_0x2594af);try{return await _0x2594af;}finally{if(this[_0x4d3d40(0x1b2)][_0x4d3d40(0x192)](_0x2d861b['id'])===_0x2594af)this[_0x4d3d40(0x1b2)][_0x4d3d40(0x1c4)](_0x2d861b['id']);}}async[_0xff519d(0x1cd)](_0x144bb5){const _0x34c0c8=_0xff519d;this[_0x34c0c8(0x18b)](_0x144bb5['id']);const _0x438c0d=this[_0x34c0c8(0x1b9)][_0x34c0c8(0x1b8)][_0x34c0c8(0x1aa)][_0x34c0c8(0x192)](_0x144bb5['id']),_0x4c0d6a=_0x438c0d===undefined?undefined:this[_0x34c0c8(0x1b9)][_0x34c0c8(0x1be)][_0x34c0c8(0x19c)](_0x438c0d);if(_0x4c0d6a!==undefined)return this[_0x34c0c8(0x1b9)][_0x34c0c8(0x190)](_0x4c0d6a);const _0x1b94cc=this[_0x34c0c8(0x1b9)][_0x34c0c8(0x1cc)][_0x34c0c8(0x18d)](_0x144bb5[_0x34c0c8(0x19a)]);if(_0x1b94cc===undefined)return this[_0x34c0c8(0x197)](_0x144bb5['id'],_0x34c0c8(0x1ae)),undefined;this[_0x34c0c8(0x196)][_0x34c0c8(0x1b7)](_0x144bb5['id']);let _0x1de049;try{_0x1de049=await _0x1b94cc[_0x34c0c8(0x1a7)](_0x144bb5,{'available':this[_0x34c0c8(0x1b9)][_0x34c0c8(0x183)](_0x144bb5[_0x34c0c8(0x19a)]),'projectionFor':this[_0x34c0c8(0x1b9)][_0x34c0c8(0x18f)],'managedAliasFor':this[_0x34c0c8(0x1b9)][_0x34c0c8(0x1c7)],'currentResumed':_0x7cb731=>{const _0x3b83df=_0x34c0c8,_0x321327=this[_0x3b83df(0x1b9)][_0x3b83df(0x1b8)][_0x3b83df(0x1aa)][_0x3b83df(0x192)](_0x7cb731);return _0x321327===undefined?undefined:this[_0x3b83df(0x1b9)][_0x3b83df(0x1be)][_0x3b83df(0x19c)](_0x321327);},'promote':_0x2cd972=>{const _0x5eaa03=_0x34c0c8;return this[_0x5eaa03(0x1b9)][_0x5eaa03(0x1be)][_0x5eaa03(0x1c6)](_0x2cd972,_0x5eaa03(0x1b0)),this[_0x5eaa03(0x1b9)][_0x5eaa03(0x1be)][_0x5eaa03(0x19c)](_0x2cd972);},'ensureConfiguration':this[_0x34c0c8(0x1b9)][_0x34c0c8(0x190)],'create':_0x2c0680=>{const _0x50f2e9=_0x34c0c8,_0xc85b81=this[_0x50f2e9(0x1b9)][_0x50f2e9(0x1c3)](_0x2c0680);return this[_0x50f2e9(0x1b9)][_0x50f2e9(0x1be)][_0x50f2e9(0x1a1)]({'workspaceId':_0x2c0680[_0x50f2e9(0x1bc)],'runner':_0x2c0680[_0x50f2e9(0x19a)],..._0x2c0680[_0x50f2e9(0x1cb)]===null?{}:{'externalSessionId':_0x2c0680[_0x50f2e9(0x1cb)]},'nativeControl':_0x50f2e9(0x1b0),'cwd':_0x2c0680[_0x50f2e9(0x18a)],'model':_0xc85b81[_0x50f2e9(0x1b3)],'effort':_0xc85b81[_0x50f2e9(0x18e)],'access':_0xc85b81[_0x50f2e9(0x1b5)],..._0x2c0680[_0x50f2e9(0x188)]===null?{}:{'title':_0x2c0680[_0x50f2e9(0x188)]},..._0x2c0680[_0x50f2e9(0x189)]===null?{}:{'customTitle':_0x2c0680[_0x50f2e9(0x189)]}});},'workspacePath':this[_0x34c0c8(0x1b9)][_0x34c0c8(0x187)],'rememberManagedNative':this[_0x34c0c8(0x1b9)][_0x34c0c8(0x1a2)]});}finally{this[_0x34c0c8(0x196)][_0x34c0c8(0x1c4)](_0x144bb5['id']);}if(_0x1de049[_0x34c0c8(0x19e)]!==undefined)this[_0x34c0c8(0x1b9)][_0x34c0c8(0x1b8)][_0x34c0c8(0x1b6)][_0x34c0c8(0x198)](_0x144bb5['id'],_0x1de049[_0x34c0c8(0x19e)]);if(_0x1de049[_0x34c0c8(0x1a6)]!==undefined)return this[_0x34c0c8(0x1b9)][_0x34c0c8(0x1b8)][_0x34c0c8(0x1aa)][_0x34c0c8(0x198)](_0x144bb5['id'],_0x1de049[_0x34c0c8(0x1a6)]['id']),_0x1de049[_0x34c0c8(0x1a6)];return this[_0x34c0c8(0x197)](_0x144bb5['id'],_0x1de049[_0x34c0c8(0x1c9)]??_0x34c0c8(0x1af),_0x1de049[_0x34c0c8(0x19b)]),this[_0x34c0c8(0x1b9)][_0x34c0c8(0x1b8)][_0x34c0c8(0x1a4)][_0x34c0c8(0x198)](_0x144bb5['id'],_0x1de049[_0x34c0c8(0x19f)]??_0x1de049[_0x34c0c8(0x1c9)]??_0x34c0c8(0x1af)),undefined;}[_0xff519d(0x186)](_0x6ddef4){const _0x3d0d85=_0xff519d,_0x54687e=this[_0x3d0d85(0x1b9)][_0x3d0d85(0x1b8)][_0x3d0d85(0x1c5)][_0x3d0d85(0x192)](_0x6ddef4)??_0x3d0d85(0x1af),_0x343b87=this[_0x3d0d85(0x1b9)][_0x3d0d85(0x1b8)][_0x3d0d85(0x1ab)][_0x3d0d85(0x192)](_0x6ddef4);return _0x343b87===undefined?{'code':_0x54687e}:{'code':_0x54687e,'detail':_0x343b87};}async[_0xff519d(0x1a5)](_0xcdd6e1){const _0x47baf6=_0xff519d,_0x268eb7=this[_0x47baf6(0x1b9)][_0x47baf6(0x1b8)][_0x47baf6(0x1aa)][_0x47baf6(0x192)](_0xcdd6e1),_0x59e4f6=this[_0x47baf6(0x1b9)][_0x47baf6(0x1be)][_0x47baf6(0x19c)](_0x268eb7??_0xcdd6e1)??await this[_0x47baf6(0x1b9)][_0x47baf6(0x18c)](_0xcdd6e1);if(_0x59e4f6===undefined)throw new Error(_0x47baf6(0x1bb));if(_0x59e4f6[_0x47baf6(0x1c0)]!==_0x47baf6(0x195))return _0x59e4f6;const _0x4cefd6=await this[_0x47baf6(0x191)](_0x59e4f6);if(_0x4cefd6!==undefined)return _0x4cefd6;if(this[_0x47baf6(0x1b9)][_0x47baf6(0x1b8)][_0x47baf6(0x1b6)][_0x47baf6(0x192)](_0x59e4f6['id'])===_0x47baf6(0x199))throw new Error(_0x47baf6(0x1ba));throw new Error(this[_0x47baf6(0x1b9)][_0x47baf6(0x1b8)][_0x47baf6(0x1a4)][_0x47baf6(0x192)](_0x59e4f6['id'])??this[_0x47baf6(0x186)](_0x59e4f6['id'])[_0x47baf6(0x193)]);}async[_0xff519d(0x1bd)](_0x3b3b4c){const _0x4a07c7=_0xff519d,_0x28beb2=this[_0x4a07c7(0x1b9)][_0x4a07c7(0x1b8)][_0x4a07c7(0x1aa)][_0x4a07c7(0x192)](_0x3b3b4c),_0x375480=this[_0x4a07c7(0x1b9)][_0x4a07c7(0x1be)][_0x4a07c7(0x19c)](_0x28beb2??_0x3b3b4c)??await this[_0x4a07c7(0x1b9)][_0x4a07c7(0x18c)](_0x3b3b4c);if(_0x375480===undefined)throw new Error(_0x4a07c7(0x1bb));if(_0x375480[_0x4a07c7(0x1c0)]!==_0x4a07c7(0x195))return{'session':_0x375480,'ready':Promise[_0x4a07c7(0x18c)](_0x375480),'deferred':![]};const _0x3aeecc=this[_0x4a07c7(0x1b9)][_0x4a07c7(0x18f)](_0x375480)??this[_0x4a07c7(0x1b9)][_0x4a07c7(0x1ca)](_0x375480),_0x3d5c5c=this[_0x4a07c7(0x191)](_0x375480)[_0x4a07c7(0x1a8)](_0x28672f=>{const _0x341a8b=_0x4a07c7;if(_0x28672f!==undefined)return _0x28672f;if(this[_0x341a8b(0x1b9)][_0x341a8b(0x1b8)][_0x341a8b(0x1b6)][_0x341a8b(0x192)](_0x375480['id'])===_0x341a8b(0x199))throw new Error(_0x341a8b(0x1ba));throw new Error(this[_0x341a8b(0x1b9)][_0x341a8b(0x1b8)][_0x341a8b(0x1a4)][_0x341a8b(0x192)](_0x375480['id'])??this[_0x341a8b(0x186)](_0x375480['id'])[_0x341a8b(0x193)]);});return{'session':_0x3aeecc,'ready':_0x3d5c5c,'deferred':!![]};}[_0xff519d(0x1b4)](_0x7dadb6){const _0x4328e0=_0xff519d;return _0x7dadb6[_0x4328e0(0x1c0)]===_0x4328e0(0x195)&&_0x7dadb6[_0x4328e0(0x1cb)]!==null?_0x4328e0(0x1c1):_0x4328e0(0x1bf);}[_0xff519d(0x18b)](_0x3f1132){const _0x1d6b35=_0xff519d,_0x4f665b=this[_0x1d6b35(0x1b9)][_0x1d6b35(0x1b8)][_0x1d6b35(0x1a9)][_0x1d6b35(0x192)](_0x3f1132);if(_0x4f665b!==undefined)clearTimeout(_0x4f665b);this[_0x1d6b35(0x1b9)][_0x1d6b35(0x1b8)][_0x1d6b35(0x1a9)][_0x1d6b35(0x1c4)](_0x3f1132),this[_0x1d6b35(0x1b9)][_0x1d6b35(0x1b8)][_0x1d6b35(0x1c5)][_0x1d6b35(0x1c4)](_0x3f1132),this[_0x1d6b35(0x1b9)][_0x1d6b35(0x1b8)][_0x1d6b35(0x1ab)][_0x1d6b35(0x1c4)](_0x3f1132),this[_0x1d6b35(0x1b9)][_0x1d6b35(0x1b8)][_0x1d6b35(0x1a4)][_0x1d6b35(0x1c4)](_0x3f1132);}[_0xff519d(0x197)](_0x1c201f,_0x352a6d,_0x219ebd){const _0x43f017=_0xff519d;this[_0x43f017(0x18b)](_0x1c201f),this[_0x43f017(0x1b9)][_0x43f017(0x1b8)][_0x43f017(0x1c5)][_0x43f017(0x198)](_0x1c201f,_0x352a6d);if(_0x219ebd===undefined)this[_0x43f017(0x1b9)][_0x43f017(0x1b8)][_0x43f017(0x1ab)][_0x43f017(0x1c4)](_0x1c201f);else this[_0x43f017(0x1b9)][_0x43f017(0x1b8)][_0x43f017(0x1ab)][_0x43f017(0x198)](_0x1c201f,_0x219ebd);const _0x570d12=setTimeout(()=>this[_0x43f017(0x18b)](_0x1c201f),RESUME_FAILURE_TTL_MS);_0x570d12[_0x43f017(0x185)](),this[_0x43f017(0x1b9)][_0x43f017(0x1b8)][_0x43f017(0x1a9)][_0x43f017(0x198)](_0x1c201f,_0x570d12);}}
1
+ const RESUME_FAILURE_TTL_MS = 30 * 60_000;
2
+ export class ExternalSessionResumeService {
3
+ options;
4
+ transitions = new Set();
5
+ resumeTasks = new Map();
6
+ constructor(options) {
7
+ this.options = options;
8
+ }
9
+ transitioning(sessionId) {
10
+ return this.transitions.has(sessionId);
11
+ }
12
+ async resume(external) {
13
+ const existing = this.resumeTasks.get(external.id);
14
+ if (existing !== undefined)
15
+ return existing;
16
+ const task = this.performResume(external);
17
+ this.resumeTasks.set(external.id, task);
18
+ try {
19
+ return await task;
20
+ }
21
+ finally {
22
+ if (this.resumeTasks.get(external.id) === task)
23
+ this.resumeTasks.delete(external.id);
24
+ }
25
+ }
26
+ async performResume(external) {
27
+ this.clearFailure(external.id);
28
+ const priorId = this.options.state.resumedByDirectId.get(external.id);
29
+ const prior = priorId === undefined ? undefined : this.options.runtime.getAgentSession(priorId);
30
+ if (prior !== undefined)
31
+ return this.options.ensureConfiguration(prior);
32
+ const runner = this.options.runners.product(external.runner);
33
+ if (runner === undefined) {
34
+ this.setFailure(external.id, 'RUNNER_UNAVAILABLE');
35
+ return undefined;
36
+ }
37
+ this.transitions.add(external.id);
38
+ let result;
39
+ try {
40
+ result = await runner.resumeExternal(external, {
41
+ available: this.options.available(external.runner),
42
+ projectionFor: this.options.projectionFor,
43
+ managedAliasFor: this.options.managedAliasFor,
44
+ currentResumed: (sessionId) => {
45
+ const resumedId = this.options.state.resumedByDirectId.get(sessionId);
46
+ return resumedId === undefined
47
+ ? undefined
48
+ : this.options.runtime.getAgentSession(resumedId);
49
+ },
50
+ promote: (sessionId) => {
51
+ this.options.runtime.setNativeControl(sessionId, 'MAR_MANAGED');
52
+ return this.options.runtime.getAgentSession(sessionId);
53
+ },
54
+ ensureConfiguration: this.options.ensureConfiguration,
55
+ create: (session) => {
56
+ const configuration = this.options.configuration(session);
57
+ return this.options.runtime.createAgentSession({
58
+ workspaceId: session.workspaceId,
59
+ runner: session.runner,
60
+ ...(session.externalSessionId === null
61
+ ? {}
62
+ : { externalSessionId: session.externalSessionId }),
63
+ nativeControl: 'MAR_MANAGED',
64
+ cwd: session.cwd,
65
+ model: configuration.model,
66
+ effort: configuration.effort,
67
+ access: configuration.access,
68
+ ...(session.runnerTitle === null ? {} : { title: session.runnerTitle }),
69
+ ...(session.customTitle === null ? {} : { customTitle: session.customTitle })
70
+ });
71
+ },
72
+ workspacePath: this.options.workspacePath,
73
+ rememberManagedNative: this.options.rememberNative
74
+ });
75
+ }
76
+ finally {
77
+ this.transitions.delete(external.id);
78
+ }
79
+ if (result.activity !== undefined)
80
+ this.options.state.externalActivity.set(external.id, result.activity);
81
+ if (result.session !== undefined) {
82
+ this.options.state.resumedByDirectId.set(external.id, result.session.id);
83
+ return result.session;
84
+ }
85
+ this.setFailure(external.id, result.failureCode ?? 'SESSION_RESUME_REJECTED', result.failureDetail);
86
+ this.options.state.messageResumeFailures.set(external.id, result.messageFailureCode ?? result.failureCode ?? 'SESSION_RESUME_REJECTED');
87
+ return undefined;
88
+ }
89
+ failure(sessionId) {
90
+ const code = this.options.state.resumeFailures.get(sessionId) ?? 'SESSION_RESUME_REJECTED';
91
+ const detail = this.options.state.resumeFailureDetails.get(sessionId);
92
+ return detail === undefined ? { code } : { code, detail };
93
+ }
94
+ async resolveForMessage(sessionId) {
95
+ const resumedId = this.options.state.resumedByDirectId.get(sessionId);
96
+ const current = this.options.runtime.getAgentSession(resumedId ?? sessionId) ??
97
+ (await this.options.resolve(sessionId));
98
+ if (current === undefined)
99
+ throw new Error('SESSION_NOT_FOUND');
100
+ if (current.nativeControl !== 'EXTERNAL')
101
+ return current;
102
+ const resumed = await this.resume(current);
103
+ if (resumed !== undefined)
104
+ return resumed;
105
+ if (this.options.state.externalActivity.get(current.id) === 'EXTERNAL_ACTIVE')
106
+ throw new Error('EXTERNAL_SESSION_ACTIVE');
107
+ throw new Error(this.options.state.messageResumeFailures.get(current.id) ?? this.failure(current.id).code);
108
+ }
109
+ async acceptForMessage(sessionId) {
110
+ const resumedId = this.options.state.resumedByDirectId.get(sessionId);
111
+ const current = this.options.runtime.getAgentSession(resumedId ?? sessionId) ??
112
+ (await this.options.resolve(sessionId));
113
+ if (current === undefined)
114
+ throw new Error('SESSION_NOT_FOUND');
115
+ if (current.nativeControl !== 'EXTERNAL')
116
+ return { session: current, ready: Promise.resolve(current), deferred: false };
117
+ const staged = this.options.projectionFor(current) ?? this.options.stage(current);
118
+ const ready = this.resume(current).then((session) => {
119
+ if (session !== undefined)
120
+ return session;
121
+ if (this.options.state.externalActivity.get(current.id) === 'EXTERNAL_ACTIVE')
122
+ throw new Error('EXTERNAL_SESSION_ACTIVE');
123
+ throw new Error(this.options.state.messageResumeFailures.get(current.id) ?? this.failure(current.id).code);
124
+ });
125
+ return { session: staged, ready, deferred: true };
126
+ }
127
+ delivery(session) {
128
+ return session.nativeControl === 'EXTERNAL' && session.externalSessionId !== null
129
+ ? 'RESUMABLE'
130
+ : 'REJECTED';
131
+ }
132
+ clearFailure(sessionId) {
133
+ const timer = this.options.state.failureTimers.get(sessionId);
134
+ if (timer !== undefined)
135
+ clearTimeout(timer);
136
+ this.options.state.failureTimers.delete(sessionId);
137
+ this.options.state.resumeFailures.delete(sessionId);
138
+ this.options.state.resumeFailureDetails.delete(sessionId);
139
+ this.options.state.messageResumeFailures.delete(sessionId);
140
+ }
141
+ setFailure(sessionId, code, detail) {
142
+ this.clearFailure(sessionId);
143
+ this.options.state.resumeFailures.set(sessionId, code);
144
+ if (detail === undefined)
145
+ this.options.state.resumeFailureDetails.delete(sessionId);
146
+ else
147
+ this.options.state.resumeFailureDetails.set(sessionId, detail);
148
+ const timer = setTimeout(() => this.clearFailure(sessionId), RESUME_FAILURE_TTL_MS);
149
+ timer.unref();
150
+ this.options.state.failureTimers.set(sessionId, timer);
151
+ }
152
+ }
@@ -1,2 +1,60 @@
1
- /* mar-release-protected */
2
- function _0x210b(){const _0x4a04f6=['AgfZ','ywrVChrsDw4','ywn0AxzL','ywrK','CNvUDgLTzq','ndKYntaYmdvvvffOr20','nJa0nZC0mun3wvPzua','Aw5WDxq','mtG0nJKWA0rmzxz6','mtC1rhvqBhnk','C2nYAxb0','y3DK','BMfTzq','mtvsC29HtwK','y3jLyxrLqxbWCM92ywW','odm1odK2yKv6C1b4','C2vZC2LVBKLK','C3rHCNq','zMLUywXSEq','mJqYmJi2sfLnyKP2','C3rHDgu','Cgf5Bg9Hza','CNvUBMvY','D29YA3nWywnLswq','zw1PDfj1BG','CNvUswq','CNvUBMvYCW','mty0nZK2oeP1zvL5wa','mtGYmty3me9KAgDdwa','C3rYAw5N','zgvSzxrL','ChjVzhvJDa','zgLZy29UBMvJDa','ChvIBgLZAefWChjVDMfS','B3b0Aw9UCW'];_0x210b=function(){return _0x4a04f6;};return _0x210b();}const _0x1f1d35=_0x19e2;(function(_0x2e3a3d,_0x23469b){const _0x56f817=_0x19e2,_0x1989cc=_0x2e3a3d();while(!![]){try{const _0x3a2b5c=-parseInt(_0x56f817(0x149))/(-0x5ef+-0x25*0xc9+-0x2b1*-0xd)+parseInt(_0x56f817(0x135))/(-0x327*-0xb+-0x55*-0x8+0x1c7*-0x15)*(-parseInt(_0x56f817(0x13a))/(-0x20*-0x2+-0xfa7+-0xf6a*-0x1))+parseInt(_0x56f817(0x13c))/(-0x1*0x234c+0x8ce+0x27*0xae)+parseInt(_0x56f817(0x136))/(-0x1dae+0x1517+0x89c)*(-parseInt(_0x56f817(0x140))/(-0x1*0x1f01+-0x1a68+0x396f))+-parseInt(_0x56f817(0x156))/(0x1d*0x39+0x247d+0x2aeb*-0x1)+-parseInt(_0x56f817(0x148))/(-0xa33+-0x1*-0x2565+-0x1b2a)+parseInt(_0x56f817(0x155))/(0xb20+0x1*0x25b1+-0x37c*0xe);if(_0x3a2b5c===_0x23469b)break;else _0x1989cc['push'](_0x1989cc['shift']());}catch(_0x5dd9db){_0x1989cc['push'](_0x1989cc['shift']());}}}(_0x210b,0x8464a+-0x5cdee*-0x1+-0x19*0x138));function _0x19e2(_0xe97380,_0x3b2f17){_0xe97380=_0xe97380-(-0x7e+0x1683+-0x14d0);const _0x165ec1=_0x210b();let _0x2871cc=_0x165ec1[_0xe97380];if(_0x19e2['EROcBE']===undefined){var _0xc3b1b5=function(_0x21aa4b){const _0x33d98e='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x922bb1='',_0x5a034e='';for(let _0x32ee42=0x117+-0xf3b*0x1+-0x2d4*-0x5,_0x319500,_0xca65a4,_0x32a255=0x21fd+-0x1*0x11d9+-0x409*0x4;_0xca65a4=_0x21aa4b['charAt'](_0x32a255++);~_0xca65a4&&(_0x319500=_0x32ee42%(0xe66+-0x1df9*-0x1+-0x2c5b)?_0x319500*(0x476+-0x1e2b+0x19f5)+_0xca65a4:_0xca65a4,_0x32ee42++%(0x16fb+0x12*0x209+-0x3b99))?_0x922bb1+=String['fromCharCode'](-0x2384*0x1+-0x21bf+0x4642&_0x319500>>(-(0x336+0xd*0x2b3+-0x264b)*_0x32ee42&-0x7*0x10b+-0x70+0x7c3)):0x1294+-0x1*0x1aae+0x81a){_0xca65a4=_0x33d98e['indexOf'](_0xca65a4);}for(let _0xd98dfa=-0x1*-0x17db+-0x3d1*0x1+-0x140a,_0x442af6=_0x922bb1['length'];_0xd98dfa<_0x442af6;_0xd98dfa++){_0x5a034e+='%'+('00'+_0x922bb1['charCodeAt'](_0xd98dfa)['toString'](0x29*0x5b+0xaa9+-0x4*0x64b))['slice'](-(0x40c*0x1+0x3b*-0x1a+-0x4*-0x7d));}return decodeURIComponent(_0x5a034e);};_0x19e2['SLjorG']=_0xc3b1b5,_0x19e2['XvgkTH']={},_0x19e2['EROcBE']=!![];}const _0x1f5197=_0x165ec1[-0x207e+0x76e*0x5+0x12a*-0x4];_0x19e2['fShCKh']!==_0x1f5197&&(_0x19e2['XvgkTH']={},_0x19e2['fShCKh']=_0x1f5197);const _0x4837d8=_0x19e2['XvgkTH'][_0xe97380];return _0x4837d8===undefined?(_0x2871cc=_0x19e2['SLjorG'](_0x2871cc),_0x19e2['XvgkTH'][_0xe97380]=_0x2871cc):_0x2871cc=_0x4837d8,_0x2871cc;}import{isTerminalRunStatus}from'../runner/codex/conversation-parser.js';export class FakeManagedRunService{[_0x1f1d35(0x14f)];constructor(_0x372193){const _0x4d8514=_0x1f1d35;this[_0x4d8514(0x14f)]=_0x372193;}[_0x1f1d35(0x13e)](_0xf72524){const _0x30d22e=_0x1f1d35,_0x592bcb=_0xf72524[_0x30d22e(0x142)];if(typeof _0x592bcb[_0x30d22e(0x146)]!==_0x30d22e(0x14a)||this[_0x30d22e(0x14f)][_0x30d22e(0x141)][_0x30d22e(0x152)][_0x30d22e(0x150)](_0x592bcb[_0x30d22e(0x146)]))return;const _0x19e7e1=_0x592bcb[_0x30d22e(0x146)],_0xf36cd5=typeof _0x592bcb[_0x30d22e(0x138)]===_0x30d22e(0x14a)?_0x592bcb[_0x30d22e(0x138)]:undefined;if(typeof _0x592bcb[_0x30d22e(0x13d)]===_0x30d22e(0x14a)&&typeof _0x592bcb[_0x30d22e(0x143)]===_0x30d22e(0x14a)&&_0xf36cd5!==undefined){const _0x3a984c=this[_0x30d22e(0x14f)][_0x30d22e(0x147)][_0x30d22e(0x14c)](_0x592bcb[_0x30d22e(0x143)]);if(_0x3a984c===undefined)return;this[_0x30d22e(0x14f)][_0x30d22e(0x154)][_0x30d22e(0x151)]({'runId':_0x19e7e1,'sessionId':_0x592bcb[_0x30d22e(0x13d)],...typeof _0x592bcb[_0x30d22e(0x144)]===_0x30d22e(0x14a)?{'workspaceId':_0x592bcb[_0x30d22e(0x144)]}:{},'runner':_0x3a984c[_0x30d22e(0x139)],'cwd':_0xf36cd5});}this[_0x30d22e(0x14f)][_0x30d22e(0x141)][_0x30d22e(0x152)][_0x30d22e(0x153)](_0x19e7e1),void this[_0x30d22e(0x14f)][_0x30d22e(0x143)][_0x30d22e(0x13e)](_0x19e7e1,this[_0x30d22e(0x14f)][_0x30d22e(0x137)](_0x592bcb[_0x30d22e(0x157)],_0x19e7e1),{'event':(_0x2fa8ce,_0x5d0dff,_0x17c73a)=>{const _0x13d73d=_0x30d22e;this[_0x13d73d(0x14f)][_0x13d73d(0x145)](_0x19e7e1,_0x2fa8ce,_0x5d0dff,_0x17c73a),_0x17c73a!==undefined&&isTerminalRunStatus(_0x17c73a)&&this[_0x13d73d(0x14f)][_0x13d73d(0x141)][_0x13d73d(0x152)][_0x13d73d(0x14b)](_0x19e7e1);},'approval':(_0x4142e7,_0x54458e,_0x22e433)=>{const _0x403e44=_0x30d22e;try{this[_0x403e44(0x14f)][_0x403e44(0x154)][_0x403e44(0x13b)]({'runId':_0x19e7e1,'approvalId':_0x4142e7,'payload':_0x54458e,'expiresAt':_0x22e433});}catch{return;}this[_0x403e44(0x14f)][_0x403e44(0x14e)]({'runId':_0x19e7e1,'approvalId':_0x4142e7,'payload':_0x54458e,'expiresAt':_0x22e433});},'disconnect':this[_0x30d22e(0x14f)][_0x30d22e(0x14d)]})[_0x30d22e(0x13f)](()=>this[_0x30d22e(0x14f)][_0x30d22e(0x141)][_0x30d22e(0x152)][_0x30d22e(0x14b)](_0x19e7e1));}}
1
+ import { isTerminalRunStatus } from '../runner/codex/conversation-parser.js';
2
+ /** Test-only managed Run adapter; production Runner paths never depend on it. */
3
+ export class FakeManagedRunService {
4
+ options;
5
+ constructor(options) {
6
+ this.options = options;
7
+ }
8
+ start(envelope) {
9
+ const payload = envelope.payload;
10
+ if (typeof payload.runId !== 'string' || this.options.state.active.has(payload.runId))
11
+ return;
12
+ const runId = payload.runId;
13
+ const cwd = typeof payload.cwd === 'string' ? payload.cwd : undefined;
14
+ if (typeof payload.sessionId === 'string' &&
15
+ typeof payload.runner === 'string' &&
16
+ cwd !== undefined) {
17
+ const runner = this.options.runners.product(payload.runner);
18
+ if (runner === undefined)
19
+ return;
20
+ this.options.runtime.adoptRun({
21
+ runId,
22
+ sessionId: payload.sessionId,
23
+ ...(typeof payload.workspaceId === 'string' ? { workspaceId: payload.workspaceId } : {}),
24
+ runner: runner.name,
25
+ cwd
26
+ });
27
+ }
28
+ this.options.state.active.add(runId);
29
+ void this.options.runner
30
+ .start(runId, this.options.script(payload.input, runId), {
31
+ event: (eventType, eventPayload, status) => {
32
+ this.options.emitRun(runId, eventType, eventPayload, status);
33
+ if (status !== undefined && isTerminalRunStatus(status)) {
34
+ this.options.state.active.delete(runId);
35
+ }
36
+ },
37
+ approval: (approvalId, approvalPayload, expiresAt) => {
38
+ try {
39
+ this.options.runtime.createApproval({
40
+ runId,
41
+ approvalId,
42
+ payload: approvalPayload,
43
+ expiresAt
44
+ });
45
+ }
46
+ catch {
47
+ return;
48
+ }
49
+ this.options.publishApproval({
50
+ runId,
51
+ approvalId,
52
+ payload: approvalPayload,
53
+ expiresAt
54
+ });
55
+ },
56
+ disconnect: this.options.disconnect
57
+ })
58
+ .finally(() => this.options.state.active.delete(runId));
59
+ }
60
+ }
@@ -0,0 +1,418 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { execFile } from 'node:child_process';
3
+ import { existsSync } from 'node:fs';
4
+ import { chmod, lstat, mkdir, mkdtemp, readdir, rm, writeFile } from 'node:fs/promises';
5
+ import { createServer } from 'node:http';
6
+ import { homedir, tmpdir } from 'node:os';
7
+ import { delimiter, join } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { promisify } from 'node:util';
10
+ import { personalGitRuntimeSchema, selectGitCredential } from '@myagentroam/protocol';
11
+ const execute = promisify(execFile);
12
+ /** Owns only process-scoped Git credentials, never repository or global configuration. */
13
+ export class GitExecutionService {
14
+ options;
15
+ contexts = new Map();
16
+ tokens = new Map();
17
+ removals = new Set();
18
+ server;
19
+ starting;
20
+ root;
21
+ wrappers = new Map();
22
+ closed = false;
23
+ constructor(options = {}) {
24
+ this.options = options;
25
+ }
26
+ async acquire(userId, configuration, baseEnvironment = {}) {
27
+ if (this.closed)
28
+ throw new Error('GIT_EXECUTION_CLOSED');
29
+ if (!Number.isSafeInteger(userId) || userId < 1)
30
+ throw new Error('USER_AUTHORIZATION_REQUIRED');
31
+ const parsed = personalGitRuntimeSchema.safeParse(configuration);
32
+ if (!parsed.success)
33
+ throw new Error('GIT_CONFIGURATION_INVALID');
34
+ const key = createHash('sha256')
35
+ .update(JSON.stringify([
36
+ userId,
37
+ parsed.data,
38
+ Object.entries(baseEnvironment).sort(([a], [b]) => a.localeCompare(b))
39
+ ]))
40
+ .digest('hex');
41
+ const endpoint = await this.start();
42
+ if (this.closed)
43
+ throw new Error('GIT_EXECUTION_CLOSED');
44
+ let context = this.contexts.get(key);
45
+ if (context === undefined) {
46
+ const token = randomBytes(32).toString('hex');
47
+ const original = { ...process.env, ...baseEnvironment };
48
+ const binary = await gitExecutable(original);
49
+ const environment = {
50
+ ...baseEnvironment,
51
+ MAR_GIT_ENDPOINT: endpoint,
52
+ MAR_GIT_TOKEN: token
53
+ };
54
+ const count = Number(original.GIT_CONFIG_COUNT ?? 0);
55
+ if (!Number.isSafeInteger(count) || count < 0 || count > 128)
56
+ throw new Error('GIT_ENVIRONMENT_INVALID');
57
+ const entries = parsed.data.credentials.some((entry) => entry.protocol === 'HTTPS')
58
+ ? [
59
+ ['credential.helper', ''],
60
+ ['credential.helper', `!${helperCommand('git-execution-helper')} credential`],
61
+ ['credential.useHttpPath', 'true']
62
+ ]
63
+ : [];
64
+ if (entries.length > 0)
65
+ environment.GIT_CONFIG_COUNT = String(count + entries.length);
66
+ for (const [index, [name, value]] of entries.entries()) {
67
+ environment[`GIT_CONFIG_KEY_${count + index}`] = name;
68
+ environment[`GIT_CONFIG_VALUE_${count + index}`] = value;
69
+ }
70
+ if (parsed.data.credentials.some((entry) => entry.protocol === 'SSH')) {
71
+ environment.GIT_SSH_COMMAND = `${helperCommand('git-execution-helper')} ssh`;
72
+ environment.GIT_SSH_VARIANT = 'ssh';
73
+ }
74
+ const pathKey = process.platform === 'win32' && original.Path !== undefined ? 'Path' : 'PATH';
75
+ environment[pathKey] =
76
+ `${await this.gitWrapper(binary)}${delimiter}${original[pathKey] ?? ''}`;
77
+ const restore = Object.fromEntries(Object.keys(environment)
78
+ .filter((name) => environment[name] !== baseEnvironment[name] || name.startsWith('MAR_GIT_'))
79
+ .map((name) => [name, name.startsWith('MAR_GIT_') ? null : (original[name] ?? null)]));
80
+ context = {
81
+ key,
82
+ token,
83
+ configuration: parsed.data,
84
+ environment: Object.freeze(environment),
85
+ restore,
86
+ keys: new Map(),
87
+ references: 0
88
+ };
89
+ this.contexts.set(key, context);
90
+ this.tokens.set(token, context);
91
+ }
92
+ return { environment: context.environment, release: this.reference(context) };
93
+ }
94
+ retain(environment) {
95
+ if (environment.MAR_GIT_TOKEN === undefined)
96
+ return () => undefined;
97
+ const context = this.tokens.get(environment.MAR_GIT_TOKEN);
98
+ if (context === undefined || this.closed)
99
+ throw new Error('GIT_CREDENTIAL_CONTEXT_EXPIRED');
100
+ return this.reference(context);
101
+ }
102
+ reference(context) {
103
+ clearTimeout(context.timer);
104
+ delete context.timer;
105
+ context.references++;
106
+ let released = false;
107
+ return () => {
108
+ if (released)
109
+ return;
110
+ released = true;
111
+ if (--context.references !== 0 || this.closed)
112
+ return;
113
+ // This outlives the existing 60-second warm Runner window.
114
+ context.timer = setTimeout(() => this.retire(context), this.options.idleTimeoutMs ?? 70_000);
115
+ context.timer.unref();
116
+ };
117
+ }
118
+ retire(context) {
119
+ this.contexts.delete(context.key);
120
+ this.tokens.delete(context.token);
121
+ clearTimeout(context.timer);
122
+ const removal = Promise.allSettled(context.keys.values())
123
+ .then(async () => {
124
+ if (context.directory !== undefined)
125
+ await rm(await context.directory, { recursive: true, force: true });
126
+ })
127
+ .catch(() => undefined);
128
+ this.removals.add(removal);
129
+ void removal.finally(() => this.removals.delete(removal));
130
+ }
131
+ async close() {
132
+ this.closed = true;
133
+ await this.starting?.catch(() => undefined);
134
+ if (this.server !== undefined) {
135
+ this.server.closeAllConnections();
136
+ await new Promise((resolve) => this.server.close(() => resolve()));
137
+ }
138
+ for (const context of this.contexts.values())
139
+ this.retire(context);
140
+ await Promise.all(this.removals);
141
+ if (this.root !== undefined)
142
+ await rm(await this.root, { recursive: true, force: true });
143
+ }
144
+ start() {
145
+ this.starting ??= new Promise((resolve, reject) => {
146
+ const server = createServer((request, response) => {
147
+ void this.respond(request, response).catch(() => {
148
+ if (!response.headersSent)
149
+ response.writeHead(500, { 'content-type': 'application/json' });
150
+ response.end('{"error":"GIT_CREDENTIAL_UNAVAILABLE"}');
151
+ });
152
+ });
153
+ this.server = server;
154
+ server.requestTimeout = 10_000;
155
+ server.headersTimeout = 10_000;
156
+ server.on('error', reject);
157
+ server.listen(0, '127.0.0.1', () => {
158
+ const address = server.address();
159
+ if (address === null || typeof address === 'string')
160
+ return reject(new Error('GIT_CREDENTIAL_UNAVAILABLE'));
161
+ server.unref();
162
+ resolve(`http://127.0.0.1:${address.port}`);
163
+ });
164
+ });
165
+ return this.starting;
166
+ }
167
+ async respond(request, response) {
168
+ response.setHeader('content-type', 'application/json');
169
+ response.setHeader('cache-control', 'no-store');
170
+ const token = request.headers.authorization?.replace(/^Bearer /u, '');
171
+ const context = token === undefined ? undefined : this.tokens.get(token);
172
+ if (request.method !== 'POST' ||
173
+ request.headers.origin !== undefined ||
174
+ context === undefined ||
175
+ this.closed) {
176
+ response.writeHead(403).end('{"error":"GIT_CREDENTIAL_CONTEXT_EXPIRED"}');
177
+ return;
178
+ }
179
+ const release = this.reference(context);
180
+ try {
181
+ let body = '';
182
+ for await (const chunk of request) {
183
+ body += String(chunk);
184
+ if (Buffer.byteLength(body) > 64 * 1024) {
185
+ response.writeHead(413).end('{"error":"GIT_CREDENTIAL_REQUEST_INVALID"}');
186
+ return;
187
+ }
188
+ }
189
+ const input = JSON.parse(body);
190
+ if (input === null || typeof input !== 'object' || Array.isArray(input))
191
+ throw new Error('GIT_CREDENTIAL_REQUEST_INVALID');
192
+ if (request.url === '/restore') {
193
+ response.end(JSON.stringify({ restore: context.restore }));
194
+ return;
195
+ }
196
+ if (request.url === '/passphrase') {
197
+ const credential = context.configuration.credentials.find((candidate) => candidate.id === input.id && candidate.protocol === 'SSH');
198
+ response.end(JSON.stringify({ passphrase: credential?.passphrase ?? '' }));
199
+ return;
200
+ }
201
+ if (request.url === '/identity') {
202
+ const match = typeof input.remote === 'string'
203
+ ? matchRemoteCredential(context.configuration.credentials, input.remote)
204
+ : undefined;
205
+ if (match?.commitName) {
206
+ response.end(JSON.stringify({
207
+ matched: true,
208
+ name: match.commitName,
209
+ email: match.commitEmail
210
+ }));
211
+ }
212
+ else
213
+ response.end('{"matched":false}');
214
+ return;
215
+ }
216
+ if (request.url !== '/credential' && request.url !== '/ssh') {
217
+ response.writeHead(404).end('{}');
218
+ return;
219
+ }
220
+ const protocol = request.url === '/ssh' ? 'SSH' : 'HTTPS';
221
+ let match;
222
+ try {
223
+ if (protocol === 'HTTPS' && input.protocol !== 'https')
224
+ throw new Error('UNMATCHED');
225
+ if (typeof input.host !== 'string' || typeof input.path !== 'string')
226
+ throw new Error('UNMATCHED');
227
+ const address = new URL(`${protocol === 'SSH' ? 'ssh' : 'https'}://${input.host}`);
228
+ match = selectGitCredential(context.configuration.credentials, {
229
+ protocol,
230
+ host: address.hostname,
231
+ port: Number(input.port ?? (address.port || (protocol === 'SSH' ? 22 : 443))),
232
+ path: protocol === 'SSH' ? input.path : decodeURIComponent(input.path)
233
+ });
234
+ }
235
+ catch {
236
+ match = undefined;
237
+ }
238
+ if (match === undefined) {
239
+ response.end('{"matched":false}');
240
+ return;
241
+ }
242
+ if (protocol === 'HTTPS') {
243
+ response.end(JSON.stringify({ matched: true, username: match.username, password: match.secret }));
244
+ return;
245
+ }
246
+ let key = context.keys.get(match.id);
247
+ if (key === undefined) {
248
+ const credential = match;
249
+ key = (async () => {
250
+ context.directory ??= this.privateRoot().then(async (root) => {
251
+ const directory = await mkdtemp(join(root, 'context-'));
252
+ try {
253
+ await writeFile(join(directory, 'ssh_config'), '', { mode: 0o600, flag: 'wx' });
254
+ return directory;
255
+ }
256
+ catch (error) {
257
+ await rm(directory, { recursive: true, force: true });
258
+ throw error;
259
+ }
260
+ });
261
+ const file = join(await context.directory, `${randomBytes(16).toString('hex')}.key`);
262
+ await writeFile(file, `${credential.secret.trim()}\n`, { mode: 0o600, flag: 'wx' });
263
+ return file;
264
+ })();
265
+ context.keys.set(match.id, key);
266
+ }
267
+ response.end(JSON.stringify({
268
+ matched: true,
269
+ id: match.id,
270
+ username: match.username,
271
+ keyFile: await key,
272
+ configFile: join(await context.directory, 'ssh_config'),
273
+ knownHostsFile: this.options.knownHostsFile ?? join(homedir(), '.ssh', 'known_hosts'),
274
+ askpassImport: helperImport('git-askpass')
275
+ }));
276
+ }
277
+ finally {
278
+ release();
279
+ }
280
+ }
281
+ privateRoot() {
282
+ this.root ??= (async () => {
283
+ const parent = this.options.directory ?? tmpdir();
284
+ if (this.options.directory !== undefined) {
285
+ await mkdir(parent, { recursive: true, mode: 0o700 });
286
+ if ((await lstat(parent)).isSymbolicLink())
287
+ throw new Error('GIT_CREDENTIAL_DIRECTORY_INVALID');
288
+ for (const item of await readdir(parent, { withFileTypes: true })) {
289
+ const pid = /^mar-git-(\d+)-/u.exec(item.name)?.[1];
290
+ if (pid === undefined || !item.isDirectory())
291
+ continue;
292
+ try {
293
+ process.kill(Number(pid), 0);
294
+ }
295
+ catch (error) {
296
+ if (error.code === 'ESRCH')
297
+ await rm(join(parent, item.name), { recursive: true, force: true });
298
+ }
299
+ }
300
+ }
301
+ const root = await mkdtemp(join(parent, `mar-git-${process.pid}-`));
302
+ try {
303
+ if (process.platform === 'win32') {
304
+ const { stdout } = await execute('whoami', [], { windowsHide: true });
305
+ await execute('icacls', [root, '/inheritance:r', '/grant:r', `${stdout.trim()}:(OI)(CI)F`], { windowsHide: true });
306
+ }
307
+ else
308
+ await chmod(root, 0o700);
309
+ return root;
310
+ }
311
+ catch {
312
+ await rm(root, { recursive: true, force: true });
313
+ throw new Error('GIT_CREDENTIAL_DIRECTORY_INVALID');
314
+ }
315
+ })();
316
+ return this.root;
317
+ }
318
+ gitWrapper(binary) {
319
+ let wrapper = this.wrappers.get(binary);
320
+ if (wrapper !== undefined)
321
+ return wrapper;
322
+ wrapper = (async () => {
323
+ const directory = join(await this.privateRoot(), `bin-${createHash('sha256').update(binary).digest('hex').slice(0, 16)}`);
324
+ await mkdir(directory, { recursive: true, mode: 0o700 });
325
+ if (process.platform === 'win32') {
326
+ await writeFile(join(directory, 'git.cmd'), `@echo off\r\nset "MAR_GIT_BINARY=${windowsEnvironmentValue(binary)}"\r\n${windowsCommand([...helperArguments('git-execution-helper'), 'invoke'])} %*\r\n`, { mode: 0o700, flag: 'wx' });
327
+ }
328
+ else {
329
+ const executable = join(directory, 'git');
330
+ await writeFile(executable, `#!/bin/sh\nMAR_GIT_BINARY=${shellArgument(binary)}\nexport MAR_GIT_BINARY\nexec ${helperCommand('git-execution-helper')} invoke "$@"\n`, { mode: 0o700, flag: 'wx' });
331
+ await chmod(executable, 0o700);
332
+ }
333
+ return directory;
334
+ })();
335
+ this.wrappers.set(binary, wrapper);
336
+ return wrapper;
337
+ }
338
+ }
339
+ function matchRemoteCredential(credentials, remote) {
340
+ try {
341
+ if (remote.startsWith('https://')) {
342
+ const address = new URL(remote);
343
+ return selectGitCredential(credentials, {
344
+ protocol: 'HTTPS',
345
+ host: address.hostname,
346
+ port: Number(address.port || 443),
347
+ path: decodeURIComponent(address.pathname)
348
+ });
349
+ }
350
+ if (remote.startsWith('ssh://')) {
351
+ const address = new URL(remote);
352
+ return selectGitCredential(credentials, {
353
+ protocol: 'SSH',
354
+ host: address.hostname,
355
+ port: Number(address.port || 22),
356
+ path: decodeURIComponent(address.pathname)
357
+ });
358
+ }
359
+ const scp = /^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/u.exec(remote);
360
+ if (scp === null)
361
+ return undefined;
362
+ return selectGitCredential(credentials, {
363
+ protocol: 'SSH',
364
+ host: scp[1],
365
+ port: 22,
366
+ path: scp[2]
367
+ });
368
+ }
369
+ catch {
370
+ return undefined;
371
+ }
372
+ }
373
+ async function gitExecutable(environment) {
374
+ const command = process.platform === 'win32' ? 'where.exe' : '/bin/sh';
375
+ const args = process.platform === 'win32' ? ['git.exe'] : ['-lc', 'command -v git'];
376
+ const { stdout } = await execute(command, args, {
377
+ env: environment,
378
+ windowsHide: true,
379
+ maxBuffer: 64 * 1024
380
+ });
381
+ const executable = stdout
382
+ .split(/\r?\n/u)
383
+ .find((value) => value.trim() !== '')
384
+ ?.trim();
385
+ if (executable === undefined)
386
+ throw new Error('GIT_TRANSPORT_UNAVAILABLE');
387
+ return executable;
388
+ }
389
+ function helperLocation(name) {
390
+ const built = new URL(`../${name}.js`, import.meta.url);
391
+ return existsSync(built) ? built : new URL(`../${name}.ts`, import.meta.url);
392
+ }
393
+ function helperArguments(name) {
394
+ const url = helperLocation(name);
395
+ return [
396
+ process.execPath,
397
+ ...(url.pathname.endsWith('.ts') ? ['--import', import.meta.resolve('tsx/esm')] : []),
398
+ fileURLToPath(url)
399
+ ];
400
+ }
401
+ function helperImport(name) {
402
+ const url = helperLocation(name);
403
+ return `${url.pathname.endsWith('.ts') ? `--import ${JSON.stringify(import.meta.resolve('tsx/esm'))} ` : ''}--import ${JSON.stringify(url.href)}`;
404
+ }
405
+ function helperCommand(name) {
406
+ return helperArguments(name).map(shellArgument).join(' ');
407
+ }
408
+ function shellArgument(value) {
409
+ return `'${value.replaceAll("'", "'\\''").replaceAll('\\', '/')}'`;
410
+ }
411
+ function windowsCommand(args) {
412
+ return args.map((value) => `"${value.replaceAll('"', '""')}"`).join(' ');
413
+ }
414
+ function windowsEnvironmentValue(value) {
415
+ if (/[\r\n\0"]/u.test(value))
416
+ throw new Error('GIT_TRANSPORT_UNAVAILABLE');
417
+ return value.replaceAll('%', '%%');
418
+ }