ummaya 0.2.8 → 0.2.10

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 (63) hide show
  1. package/npm-shrinkwrap.json +2 -2
  2. package/package.json +1 -1
  3. package/pyproject.toml +2 -2
  4. package/tui/package.json +1 -1
  5. package/tui/src/bridge/bridgeEnabled.ts +1 -1
  6. package/tui/src/commands/chrome/chrome.tsx +3 -4
  7. package/tui/src/commands/createMovedToPluginCommand.ts +1 -1
  8. package/tui/src/commands/extra-usage/extra-usage-core.ts +2 -4
  9. package/tui/src/commands/insights.ts +5 -4
  10. package/tui/src/commands/install-github-app/ApiKeyStep.tsx +1 -2
  11. package/tui/src/commands/install-github-app/ExistingWorkflowStep.tsx +1 -1
  12. package/tui/src/commands/install-github-app/InstallAppStep.tsx +1 -1
  13. package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
  14. package/tui/src/commands/install-github-app/setupGitHubActions.ts +2 -2
  15. package/tui/src/commands/install-slack-app/install-slack-app.ts +1 -1
  16. package/tui/src/commands/mobile/mobile.tsx +3 -3
  17. package/tui/src/commands/stickers/stickers.ts +1 -1
  18. package/tui/src/commands/upgrade/upgrade.tsx +3 -4
  19. package/tui/src/components/ClaudeInChromeOnboarding.tsx +2 -3
  20. package/tui/src/components/Feedback.tsx +8 -2
  21. package/tui/src/components/FeedbackSurvey/submitTranscriptShare.ts +7 -2
  22. package/tui/src/components/Passes/Passes.tsx +1 -1
  23. package/tui/src/components/WorkflowMultiselectDialog.tsx +1 -1
  24. package/tui/src/components/messages/AssistantTextMessage.tsx +1 -2
  25. package/tui/src/constants/github-app.ts +19 -26
  26. package/tui/src/constants/oauth.ts +28 -59
  27. package/tui/src/constants/product.ts +6 -6
  28. package/tui/src/entrypoints/sdk/coreSchemas.ts +1 -1
  29. package/tui/src/services/analytics/firstPartyEventLogger.ts +0 -3
  30. package/tui/src/services/analytics/firstPartyEventLoggingExporter.ts +34 -12
  31. package/tui/src/services/analytics/growthbook.ts +17 -16
  32. package/tui/src/services/api/filesApi.ts +4 -14
  33. package/tui/src/services/api/metricsOptOut.ts +20 -1
  34. package/tui/src/services/mcp/channelNotification.ts +1 -1
  35. package/tui/src/services/mcp/officialRegistry.ts +5 -1
  36. package/tui/src/services/mcp/useManageMCPConnections.ts +1 -1
  37. package/tui/src/services/mcp/utils.ts +2 -2
  38. package/tui/src/services/tokenEstimation.ts +0 -1
  39. package/tui/src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts +6 -6
  40. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +1 -1
  41. package/tui/src/tools/RemoteTriggerTool/RemoteTriggerTool.ts +1 -1
  42. package/tui/src/tools/RemoteTriggerTool/prompt.ts +2 -2
  43. package/tui/src/tools/WebFetchTool/preapproved.ts +0 -4
  44. package/tui/src/tools/WebFetchTool/utils.ts +15 -11
  45. package/tui/src/upstreamproxy/upstreamproxy.ts +9 -15
  46. package/tui/src/utils/autoUpdater.ts +4 -1
  47. package/tui/src/utils/claudeInChrome/mcpServer.ts +1 -1
  48. package/tui/src/utils/claudeInChrome/setup.ts +1 -1
  49. package/tui/src/utils/claudeInChrome/toolRendering.tsx +1 -2
  50. package/tui/src/utils/desktopDeepLink.ts +18 -18
  51. package/tui/src/utils/fastMode.ts +1 -1
  52. package/tui/src/utils/http.ts +1 -5
  53. package/tui/src/utils/ide.ts +6 -5
  54. package/tui/src/utils/model/providers.ts +6 -10
  55. package/tui/src/utils/modelCost.ts +0 -2
  56. package/tui/src/utils/nativeInstaller/download.ts +15 -17
  57. package/tui/src/utils/plugins/installCounts.ts +4 -11
  58. package/tui/src/utils/plugins/officialMarketplaceGcs.ts +5 -18
  59. package/tui/src/utils/releaseNotes.ts +2 -2
  60. package/tui/src/utils/settings/types.ts +1 -1
  61. package/tui/src/utils/statusNoticeDefinitions.tsx +3 -3
  62. package/tui/src/utils/telemetry/bigqueryExporter.ts +20 -13
  63. package/uv.lock +1 -1
@@ -100,7 +100,7 @@ export function AssistantTextMessage(t0) {
100
100
  {
101
101
  let t2;
102
102
  if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
103
- t2 = <MessageResponse height={1}><Text color="error">Credit balance too low · Add funds: https://platform.claude.com/settings/billing</Text></MessageResponse>;
103
+ t2 = <MessageResponse height={1}><Text color="error">Credit balance too low · Configure FriendliAI billing: https://ummaya-docs.pages.dev/</Text></MessageResponse>;
104
104
  $[5] = t2;
105
105
  } else {
106
106
  t2 = $[5];
@@ -267,4 +267,3 @@ export function AssistantTextMessage(t0) {
267
267
  }
268
268
  }
269
269
  }
270
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJUZXh0QmxvY2tQYXJhbSIsIlJlYWN0IiwidXNlQ29udGV4dCIsIkVSUk9SX01FU1NBR0VfVVNFUl9BQk9SVCIsImlzUmF0ZUxpbWl0RXJyb3JNZXNzYWdlIiwiQkxBQ0tfQ0lSQ0xFIiwiQm94IiwiTm9TZWxlY3QiLCJUZXh0IiwiQVBJX0VSUk9SX01FU1NBR0VfUFJFRklYIiwiQVBJX1RJTUVPVVRfRVJST1JfTUVTU0FHRSIsIkNSRURJVF9CQUxBTkNFX1RPT19MT1dfRVJST1JfTUVTU0FHRSIsIkNVU1RPTV9PRkZfU1dJVENIX01FU1NBR0UiLCJJTlZBTElEX0FQSV9LRVlfRVJST1JfTUVTU0FHRSIsIklOVkFMSURfQVBJX0tFWV9FUlJPUl9NRVNTQUdFX0VYVEVSTkFMIiwiT1JHX0RJU0FCTEVEX0VSUk9SX01FU1NBR0VfRU5WX0tFWSIsIk9SR19ESVNBQkxFRF9FUlJPUl9NRVNTQUdFX0VOVl9LRVlfV0lUSF9PQVVUSCIsIlBST01QVF9UT09fTE9OR19FUlJPUl9NRVNTQUdFIiwic3RhcnRzV2l0aEFwaUVycm9yUHJlZml4IiwiVE9LRU5fUkVWT0tFRF9FUlJPUl9NRVNTQUdFIiwiaXNFbXB0eU1lc3NhZ2VUZXh0IiwiTk9fUkVTUE9OU0VfUkVRVUVTVEVEIiwiZ2V0VXBncmFkZU1lc3NhZ2UiLCJnZXREZWZhdWx0U29ubmV0TW9kZWwiLCJyZW5kZXJNb2RlbE5hbWUiLCJpc01hY09zS2V5Y2hhaW5Mb2NrZWQiLCJDdHJsT1RvRXhwYW5kIiwiSW50ZXJydXB0ZWRCeVVzZXIiLCJNYXJrZG93biIsIk1lc3NhZ2VSZXNwb25zZSIsIk1lc3NhZ2VBY3Rpb25zU2VsZWN0ZWRDb250ZXh0IiwiUmF0ZUxpbWl0TWVzc2FnZSIsIk1BWF9BUElfRVJST1JfQ0hBUlMiLCJQcm9wcyIsInBhcmFtIiwiYWRkTWFyZ2luIiwic2hvdWxkU2hvd0RvdCIsInZlcmJvc2UiLCJ3aWR0aCIsIm9uT3BlblJhdGVMaW1pdE9wdGlvbnMiLCJJbnZhbGlkQXBpS2V5TWVzc2FnZSIsIiQiLCJfYyIsInQwIiwiU3ltYm9sIiwiZm9yIiwiaXNLZXljaGFpbkxvY2tlZCIsInQxIiwiQXNzaXN0YW50VGV4dE1lc3NhZ2UiLCJ0ZXh0IiwiaXNTZWxlY3RlZCIsInQyIiwidXBncmFkZUhpbnQiLCJ0MyIsInByb2Nlc3MiLCJlbnYiLCJBUElfVElNRU9VVF9NUyIsInRydW5jYXRlZCIsImxlbmd0aCIsInNsaWNlIiwidDQiLCJ0NSIsInVuZGVmaW5lZCIsInQ2IiwidDciXSwic291cmNlcyI6WyJBc3Npc3RhbnRUZXh0TWVzc2FnZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBUZXh0QmxvY2tQYXJhbSB9IGZyb20gJ0BhbnRocm9waWMtYWkvc2RrL3Jlc291cmNlcy9pbmRleC5tanMnXG5pbXBvcnQgUmVhY3QsIHsgdXNlQ29udGV4dCB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgRVJST1JfTUVTU0FHRV9VU0VSX0FCT1JUIH0gZnJvbSAnc3JjL3NlcnZpY2VzL2NvbXBhY3QvY29tcGFjdC5qcydcbmltcG9ydCB7IGlzUmF0ZUxpbWl0RXJyb3JNZXNzYWdlIH0gZnJvbSAnc3JjL3NlcnZpY2VzL3JhdGVMaW1pdE1lc3NhZ2VzLmpzJ1xuaW1wb3J0IHsgQkxBQ0tfQ0lSQ0xFIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzL2ZpZ3VyZXMuanMnXG5pbXBvcnQgeyBCb3gsIE5vU2VsZWN0LCBUZXh0IH0gZnJvbSAnLi4vLi4vaW5rLmpzJ1xuaW1wb3J0IHtcbiAgQVBJX0VSUk9SX01FU1NBR0VfUFJFRklYLFxuICBBUElfVElNRU9VVF9FUlJPUl9NRVNTQUdFLFxuICBDUkVESVRfQkFMQU5DRV9UT09fTE9XX0VSUk9SX01FU1NBR0UsXG4gIENVU1RPTV9PRkZfU1dJVENIX01FU1NBR0UsXG4gIElOVkFMSURfQVBJX0tFWV9FUlJPUl9NRVNTQUdFLFxuICBJTlZBTElEX0FQSV9LRVlfRVJST1JfTUVTU0FHRV9FWFRFUk5BTCxcbiAgT1JHX0RJU0FCTEVEX0VSUk9SX01FU1NBR0VfRU5WX0tFWSxcbiAgT1JHX0RJU0FCTEVEX0VSUk9SX01FU1NBR0VfRU5WX0tFWV9XSVRIX09BVVRILFxuICBQUk9NUFRfVE9PX0xPTkdfRVJST1JfTUVTU0FHRSxcbiAgc3RhcnRzV2l0aEFwaUVycm9yUHJlZml4LFxuICBUT0tFTl9SRVZPS0VEX0VSUk9SX01FU1NBR0UsXG59IGZyb20gJy4uLy4uL3NlcnZpY2VzL2FwaS9lcnJvcnMuanMnXG5pbXBvcnQge1xuICBpc0VtcHR5TWVzc2FnZVRleHQsXG4gIE5PX1JFU1BPTlNFX1JFUVVFU1RFRCxcbn0gZnJvbSAnLi4vLi4vdXRpbHMvbWVzc2FnZXMuanMnXG5pbXBvcnQgeyBnZXRVcGdyYWRlTWVzc2FnZSB9IGZyb20gJy4uLy4uL3V0aWxzL21vZGVsL2NvbnRleHRXaW5kb3dVcGdyYWRlQ2hlY2suanMnXG5pbXBvcnQge1xuICBnZXREZWZhdWx0U29ubmV0TW9kZWwsXG4gIHJlbmRlck1vZGVsTmFtZSxcbn0gZnJvbSAnLi4vLi4vdXRpbHMvbW9kZWwvbW9kZWwuanMnXG5pbXBvcnQgeyBpc01hY09zS2V5Y2hhaW5Mb2NrZWQgfSBmcm9tICcuLi8uLi91dGlscy9zZWN1cmVTdG9yYWdlL21hY09zS2V5Y2hhaW5TdG9yYWdlLmpzJ1xuaW1wb3J0IHsgQ3RybE9Ub0V4cGFuZCB9IGZyb20gJy4uL0N0cmxPVG9FeHBhbmQuanMnXG5pbXBvcnQgeyBJbnRlcnJ1cHRlZEJ5VXNlciB9IGZyb20gJy4uL0ludGVycnVwdGVkQnlVc2VyLmpzJ1xuaW1wb3J0IHsgTWFya2Rvd24gfSBmcm9tICcuLi9NYXJrZG93bi5qcydcbmltcG9ydCB7IE1lc3NhZ2VSZXNwb25zZSB9IGZyb20gJy4uL01lc3NhZ2VSZXNwb25zZS5qcydcbmltcG9ydCB7IE1lc3NhZ2VBY3Rpb25zU2VsZWN0ZWRDb250ZXh0IH0gZnJvbSAnLi4vbWVzc2FnZUFjdGlvbnMuanMnXG5pbXBvcnQgeyBSYXRlTGltaXRNZXNzYWdlIH0gZnJvbSAnLi9SYXRlTGltaXRNZXNzYWdlLmpzJ1xuXG5jb25zdCBNQVhfQVBJX0VSUk9SX0NIQVJTID0gMTAwMFxuXG50eXBlIFByb3BzID0ge1xuICBwYXJhbTogVGV4dEJsb2NrUGFyYW1cbiAgYWRkTWFyZ2luOiBib29sZWFuXG4gIHNob3VsZFNob3dEb3Q6IGJvb2xlYW5cbiAgdmVyYm9zZTogYm9vbGVhblxuICB3aWR0aD86IG51bWJlciB8IHN0cmluZ1xuICBvbk9wZW5SYXRlTGltaXRPcHRpb25zPzogKCkgPT4gdm9pZFxufVxuXG5mdW5jdGlvbiBJbnZhbGlkQXBpS2V5TWVzc2FnZSgpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBpc0tleWNoYWluTG9ja2VkID0gaXNNYWNPc0tleWNoYWluTG9ja2VkKClcblxuICByZXR1cm4gKFxuICAgIDxNZXNzYWdlUmVzcG9uc2U+XG4gICAgICA8Qm94IGZsZXhEaXJlY3Rpb249XCJjb2x1bW5cIj5cbiAgICAgICAgPFRleHQgY29sb3I9XCJlcnJvclwiPntJTlZBTElEX0FQSV9LRVlfRVJST1JfTUVTU0FHRX08L1RleHQ+XG4gICAgICAgIHtpc0tleWNoYWluTG9ja2VkICYmIChcbiAgICAgICAgICA8VGV4dCBkaW1Db2xvcj5cbiAgICAgICAgICAgIMK3IFJ1biBpbiBhbm90aGVyIHRlcm1pbmFsOiBzZWN1cml0eSB1bmxvY2sta2V5Y2hhaW5cbiAgICAgICAgICA8L1RleHQ+XG4gICAgICAgICl9XG4gICAgICA8L0JveD5cbiAgICA8L01lc3NhZ2VSZXNwb25zZT5cbiAgKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gQXNzaXN0YW50VGV4dE1lc3NhZ2Uoe1xuICBwYXJhbTogeyB0ZXh0IH0sXG4gIGFkZE1hcmdpbixcbiAgc2hvdWxkU2hvd0RvdCxcbiAgdmVyYm9zZSxcbiAgb25PcGVuUmF0ZUxpbWl0T3B0aW9ucyxcbn06IFByb3BzKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgY29uc3QgaXNTZWxlY3RlZCA9IHVzZUNvbnRleHQoTWVzc2FnZUFjdGlvbnNTZWxlY3RlZENvbnRleHQpXG4gIGlmIChpc0VtcHR5TWVzc2FnZVRleHQodGV4dCkpIHtcbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbiAgLy8gSGFuZGxlIGFsbCByYXRlIGxpbWl0IGVycm9yIG1lc3NhZ2VzIGZyb20gZ2V0UmF0ZUxpbWl0RXJyb3JNZXNzYWdlXG4gIC8vIFVzZSB0aGUgZXhwb3J0ZWQgZnVuY3Rpb24gdG8gYXZvaWQgZnJhZ2lsZSBzdHJpbmcgY291cGxpbmdcbiAgaWYgKGlzUmF0ZUxpbWl0RXJyb3JNZXNzYWdlKHRleHQpKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxSYXRlTGltaXRNZXNzYWdlXG4gICAgICAgIHRleHQ9e3RleHR9XG4gICAgICAgIG9uT3BlblJhdGVMaW1pdE9wdGlvbnM9e29uT3BlblJhdGVMaW1pdE9wdGlvbnN9XG4gICAgICAvPlxuICAgIClcbiAgfVxuXG4gIHN3aXRjaCAodGV4dCkge1xuICAgIC8vIExvY2FsIEpTWCBjb21tYW5kcyBkb24ndCBuZWVkIGEgcmVzcG9uc2UsIGJ1dCB3ZSBzdGlsbCB3YW50IENsYXVkZSB0byBzZWUgdGhlbVxuICAgIC8vIFRvb2wgcmVzdWx0cyByZW5kZXIgdGhlaXIgb3duIGludGVycnVwdCBtZXNzYWdlc1xuICAgIGNhc2UgTk9fUkVTUE9OU0VfUkVRVUVTVEVEOlxuICAgICAgcmV0dXJuIG51bGxcblxuICAgIGNhc2UgUFJPTVBUX1RPT19MT05HX0VSUk9SX01FU1NBR0U6IHtcbiAgICAgIGNvbnN0IHVwZ3JhZGVIaW50ID0gZ2V0VXBncmFkZU1lc3NhZ2UoJ3dhcm5pbmcnKVxuICAgICAgcmV0dXJuIChcbiAgICAgICAgPE1lc3NhZ2VSZXNwb25zZSBoZWlnaHQ9ezF9PlxuICAgICAgICAgIDxUZXh0IGNvbG9yPVwiZXJyb3JcIj5cbiAgICAgICAgICAgIENvbnRleHQgbGltaXQgcmVhY2hlZCDCtyAvY29tcGFjdCBvciAvY2xlYXIgdG8gY29udGludWVcbiAgICAgICAgICAgIHt1cGdyYWRlSGludCA/IGAgwrcgJHt1cGdyYWRlSGludH1gIDogJyd9XG4gICAgICAgICAgPC9UZXh0PlxuICAgICAgICA8L01lc3NhZ2VSZXNwb25zZT5cbiAgICAgIClcbiAgICB9XG5cbiAgICBjYXNlIENSRURJVF9CQUxBTkNFX1RPT19MT1dfRVJST1JfTUVTU0FHRTpcbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxNZXNzYWdlUmVzcG9uc2UgaGVpZ2h0PXsxfT5cbiAgICAgICAgICA8VGV4dCBjb2xvcj1cImVycm9yXCI+XG4gICAgICAgICAgICBDcmVkaXQgYmFsYW5jZSB0b28gbG93ICZtaWRkb3Q7IEFkZCBmdW5kczpcbiAgICAgICAgICAgIGh0dHBzOi8vcGxhdGZvcm0uY2xhdWRlLmNvbS9zZXR0aW5ncy9iaWxsaW5nXG4gICAgICAgICAgPC9UZXh0PlxuICAgICAgICA8L01lc3NhZ2VSZXNwb25zZT5cbiAgICAgIClcblxuICAgIGNhc2UgSU5WQUxJRF9BUElfS0VZX0VSUk9SX01FU1NBR0U6XG4gICAgICByZXR1cm4gPEludmFsaWRBcGlLZXlNZXNzYWdlIC8+XG5cbiAgICBjYXNlIElOVkFMSURfQVBJX0tFWV9FUlJPUl9NRVNTQUdFX0VYVEVSTkFMOlxuICAgICAgcmV0dXJuIChcbiAgICAgICAgPE1lc3NhZ2VSZXNwb25zZSBoZWlnaHQ9ezF9PlxuICAgICAgICAgIDxUZXh0IGNvbG9yPVwiZXJyb3JcIj57SU5WQUxJRF9BUElfS0VZX0VSUk9SX01FU1NBR0VfRVhURVJOQUx9PC9UZXh0PlxuICAgICAgICA8L01lc3NhZ2VSZXNwb25zZT5cbiAgICAgIClcblxuICAgIGNhc2UgT1JHX0RJU0FCTEVEX0VSUk9SX01FU1NBR0VfRU5WX0tFWTpcbiAgICBjYXNlIE9SR19ESVNBQkxFRF9FUlJPUl9NRVNTQUdFX0VOVl9LRVlfV0lUSF9PQVVUSDpcbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxNZXNzYWdlUmVzcG9uc2U+XG4gICAgICAgICAgPFRleHQgY29sb3I9XCJlcnJvclwiPnt0ZXh0fTwvVGV4dD5cbiAgICAgICAgPC9NZXNzYWdlUmVzcG9uc2U+XG4gICAgICApXG5cbiAgICBjYXNlIFRPS0VOX1JFVk9LRURfRVJST1JfTUVTU0FHRTpcbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxNZXNzYWdlUmVzcG9uc2UgaGVpZ2h0PXsxfT5cbiAgICAgICAgICA8VGV4dCBjb2xvcj1cImVycm9yXCI+e1RPS0VOX1JFVk9LRURfRVJST1JfTUVTU0FHRX08L1RleHQ+XG4gICAgICAgIDwvTWVzc2FnZVJlc3BvbnNlPlxuICAgICAgKVxuXG4gICAgY2FzZSBBUElfVElNRU9VVF9FUlJPUl9NRVNTQUdFOlxuICAgICAgcmV0dXJuIChcbiAgICAgICAgPE1lc3NhZ2VSZXNwb25zZSBoZWlnaHQ9ezF9PlxuICAgICAgICAgIDxUZXh0IGNvbG9yPVwiZXJyb3JcIj5cbiAgICAgICAgICAgIHtBUElfVElNRU9VVF9FUlJPUl9NRVNTQUdFfVxuICAgICAgICAgICAge3Byb2Nlc3MuZW52LkFQSV9USU1FT1VUX01TICYmIChcbiAgICAgICAgICAgICAgPD5cbiAgICAgICAgICAgICAgICB7JyAnfVxuICAgICAgICAgICAgICAgIChBUElfVElNRU9VVF9NUz17cHJvY2Vzcy5lbnYuQVBJX1RJTUVPVVRfTVN9bXMsIHRyeSBpbmNyZWFzaW5nXG4gICAgICAgICAgICAgICAgaXQpXG4gICAgICAgICAgICAgIDwvPlxuICAgICAgICAgICAgKX1cbiAgICAgICAgICA8L1RleHQ+XG4gICAgICAgIDwvTWVzc2FnZVJlc3BvbnNlPlxuICAgICAgKVxuXG4gICAgY2FzZSBDVVNUT01fT0ZGX1NXSVRDSF9NRVNTQUdFOlxuICAgICAgcmV0dXJuIChcbiAgICAgICAgPE1lc3NhZ2VSZXNwb25zZT5cbiAgICAgICAgICA8Qm94IGZsZXhEaXJlY3Rpb249XCJjb2x1bW5cIiBnYXA9ezF9PlxuICAgICAgICAgICAgPFRleHQgY29sb3I9XCJlcnJvclwiPlxuICAgICAgICAgICAgICBXZSBhcmUgZXhwZXJpZW5jaW5nIGhpZ2ggZGVtYW5kIGZvciBPcHVzIDQuXG4gICAgICAgICAgICA8L1RleHQ+XG4gICAgICAgICAgICA8VGV4dD5cbiAgICAgICAgICAgICAgVG8gY29udGludWUgaW1tZWRpYXRlbHksIHVzZSAvbW9kZWwgdG8gc3dpdGNoIHRveycgJ31cbiAgICAgICAgICAgICAge3JlbmRlck1vZGVsTmFtZShnZXREZWZhdWx0U29ubmV0TW9kZWwoKSl9IGFuZCBjb250aW51ZSBjb2RpbmcuXG4gICAgICAgICAgICA8L1RleHQ+XG4gICAgICAgICAgPC9Cb3g+XG4gICAgICAgIDwvTWVzc2FnZVJlc3BvbnNlPlxuICAgICAgKVxuXG4gICAgLy8gVE9ETzogTW92ZSB0aGlzIHRvIGEgdXNlciB0dXJuXG4gICAgY2FzZSBFUlJPUl9NRVNTQUdFX1VTRVJfQUJPUlQ6XG4gICAgICByZXR1cm4gKFxuICAgICAgICA8TWVzc2FnZVJlc3BvbnNlIGhlaWdodD17MX0+XG4gICAgICAgICAgPEludGVycnVwdGVkQnlVc2VyIC8+XG4gICAgICAgIDwvTWVzc2FnZVJlc3BvbnNlPlxuICAgICAgKVxuXG4gICAgZGVmYXVsdDpcbiAgICAgIGlmIChzdGFydHNXaXRoQXBpRXJyb3JQcmVmaXgodGV4dCkpIHtcbiAgICAgICAgY29uc3QgdHJ1bmNhdGVkID0gIXZlcmJvc2UgJiYgdGV4dC5sZW5ndGggPiBNQVhfQVBJX0VSUk9SX0NIQVJTXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgPE1lc3NhZ2VSZXNwb25zZT5cbiAgICAgICAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiPlxuICAgICAgICAgICAgICA8VGV4dCBjb2xvcj1cImVycm9yXCI+XG4gICAgICAgICAgICAgICAge3RleHQgPT09IEFQSV9FUlJPUl9NRVNTQUdFX1BSRUZJWFxuICAgICAgICAgICAgICAgICAgPyBgJHtBUElfRVJST1JfTUVTU0FHRV9QUkVGSVh9OiBQbGVhc2Ugd2FpdCBhIG1vbWVudCBhbmQgdHJ5IGFnYWluLmBcbiAgICAgICAgICAgICAgICAgIDogdHJ1bmNhdGVkXG4gICAgICAgICAgICAgICAgICAgID8gdGV4dC5zbGljZSgwLCBNQVhfQVBJX0VSUk9SX0NIQVJTKSArICfigKYnXG4gICAgICAgICAgICAgICAgICAgIDogdGV4dH1cbiAgICAgICAgICAgICAgPC9UZXh0PlxuICAgICAgICAgICAgICB7dHJ1bmNhdGVkICYmIDxDdHJsT1RvRXhwYW5kIC8+fVxuICAgICAgICAgICAgPC9Cb3g+XG4gICAgICAgICAgPC9NZXNzYWdlUmVzcG9uc2U+XG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxCb3hcbiAgICAgICAgICBhbGlnbkl0ZW1zPVwiZmxleC1zdGFydFwiXG4gICAgICAgICAgZmxleERpcmVjdGlvbj1cInJvd1wiXG4gICAgICAgICAganVzdGlmeUNvbnRlbnQ9XCJzcGFjZS1iZXR3ZWVuXCJcbiAgICAgICAgICBtYXJnaW5Ub3A9e2FkZE1hcmdpbiA/IDEgOiAwfVxuICAgICAgICAgIHdpZHRoPVwiMTAwJVwiXG4gICAgICAgICAgYmFja2dyb3VuZENvbG9yPXtpc1NlbGVjdGVkID8gJ21lc3NhZ2VBY3Rpb25zQmFja2dyb3VuZCcgOiB1bmRlZmluZWR9XG4gICAgICAgID5cbiAgICAgICAgICA8Qm94IGZsZXhEaXJlY3Rpb249XCJyb3dcIj5cbiAgICAgICAgICAgIHtzaG91bGRTaG93RG90ICYmIChcbiAgICAgICAgICAgICAgPE5vU2VsZWN0IGZyb21MZWZ0RWRnZSBtaW5XaWR0aD17Mn0+XG4gICAgICAgICAgICAgICAgPFRleHQgY29sb3I9e2lzU2VsZWN0ZWQgPyAnc3VnZ2VzdGlvbicgOiAndGV4dCd9PlxuICAgICAgICAgICAgICAgICAge0JMQUNLX0NJUkNMRX1cbiAgICAgICAgICAgICAgICA8L1RleHQ+XG4gICAgICAgICAgICAgIDwvTm9TZWxlY3Q+XG4gICAgICAgICAgICApfVxuICAgICAgICAgICAgPEJveCBmbGV4RGlyZWN0aW9uPVwiY29sdW1uXCI+XG4gICAgICAgICAgICAgIDxNYXJrZG93bj57dGV4dH08L01hcmtkb3duPlxuICAgICAgICAgICAgPC9Cb3g+XG4gICAgICAgICAgPC9Cb3g+XG4gICAgICAgIDwvQm94PlxuICAgICAgKVxuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7QUFBQSxjQUFjQSxjQUFjLFFBQVEsdUNBQXVDO0FBQzNFLE9BQU9DLEtBQUssSUFBSUMsVUFBVSxRQUFRLE9BQU87QUFDekMsU0FBU0Msd0JBQXdCLFFBQVEsaUNBQWlDO0FBQzFFLFNBQVNDLHVCQUF1QixRQUFRLG1DQUFtQztBQUMzRSxTQUFTQyxZQUFZLFFBQVEsNEJBQTRCO0FBQ3pELFNBQVNDLEdBQUcsRUFBRUMsUUFBUSxFQUFFQyxJQUFJLFFBQVEsY0FBYztBQUNsRCxTQUNFQyx3QkFBd0IsRUFDeEJDLHlCQUF5QixFQUN6QkMsb0NBQW9DLEVBQ3BDQyx5QkFBeUIsRUFDekJDLDZCQUE2QixFQUM3QkMsc0NBQXNDLEVBQ3RDQyxrQ0FBa0MsRUFDbENDLDZDQUE2QyxFQUM3Q0MsNkJBQTZCLEVBQzdCQyx3QkFBd0IsRUFDeEJDLDJCQUEyQixRQUN0Qiw4QkFBOEI7QUFDckMsU0FDRUMsa0JBQWtCLEVBQ2xCQyxxQkFBcUIsUUFDaEIseUJBQXlCO0FBQ2hDLFNBQVNDLGlCQUFpQixRQUFRLGdEQUFnRDtBQUNsRixTQUNFQyxxQkFBcUIsRUFDckJDLGVBQWUsUUFDViw0QkFBNEI7QUFDbkMsU0FBU0MscUJBQXFCLFFBQVEsbURBQW1EO0FBQ3pGLFNBQVNDLGFBQWEsUUFBUSxxQkFBcUI7QUFDbkQsU0FBU0MsaUJBQWlCLFFBQVEseUJBQXlCO0FBQzNELFNBQVNDLFFBQVEsUUFBUSxnQkFBZ0I7QUFDekMsU0FBU0MsZUFBZSxRQUFRLHVCQUF1QjtBQUN2RCxTQUFTQyw2QkFBNkIsUUFBUSxzQkFBc0I7QUFDcEUsU0FBU0MsZ0JBQWdCLFFBQVEsdUJBQXVCO0FBRXhELE1BQU1DLG1CQUFtQixHQUFHLElBQUk7QUFFaEMsS0FBS0MsS0FBSyxHQUFHO0VBQ1hDLEtBQUssRUFBRWxDLGNBQWM7RUFDckJtQyxTQUFTLEVBQUUsT0FBTztFQUNsQkMsYUFBYSxFQUFFLE9BQU87RUFDdEJDLE9BQU8sRUFBRSxPQUFPO0VBQ2hCQyxLQUFLLENBQUMsRUFBRSxNQUFNLEdBQUcsTUFBTTtFQUN2QkMsc0JBQXNCLENBQUMsRUFBRSxHQUFHLEdBQUcsSUFBSTtBQUNyQyxDQUFDO0FBRUQsU0FBQUMscUJBQUE7RUFBQSxNQUFBQyxDQUFBLEdBQUFDLEVBQUE7RUFBQSxJQUFBQyxFQUFBO0VBQUEsSUFBQUYsQ0FBQSxRQUFBRyxNQUFBLENBQUFDLEdBQUE7SUFDMkJGLEVBQUEsR0FBQWxCLHFCQUFxQixDQUFDLENBQUM7SUFBQWdCLENBQUEsTUFBQUUsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUYsQ0FBQTtFQUFBO0VBQWhELE1BQUFLLGdCQUFBLEdBQXlCSCxFQUF1QjtFQUFBLElBQUFJLEVBQUE7RUFBQSxJQUFBTixDQUFBLFFBQUFHLE1BQUEsQ0FBQUMsR0FBQTtJQUc5Q0UsRUFBQSxJQUFDLGVBQWUsQ0FDZCxDQUFDLEdBQUcsQ0FBZSxhQUFRLENBQVIsUUFBUSxDQUN6QixDQUFDLElBQUksQ0FBTyxLQUFPLENBQVAsT0FBTyxDQUFFbEMsOEJBQTRCLENBQUUsRUFBbEQsSUFBSSxDQUNKLENBQUFpQyxnQkFJQSxJQUhDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBUixLQUFPLENBQUMsQ0FBQyxtREFFZixFQUZDLElBQUksQ0FHUCxDQUNGLEVBUEMsR0FBRyxDQVFOLEVBVEMsZUFBZSxDQVNFO0lBQUFMLENBQUEsTUFBQU0sRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQU4sQ0FBQTtFQUFBO0VBQUEsT0FUbEJNLEVBU2tCO0FBQUE7QUFJdEIsT0FBTyxTQUFBQyxxQkFBQUwsRUFBQTtFQUFBLE1BQUFGLENBQUEsR0FBQUMsRUFBQTtFQUE4QjtJQUFBUixLQUFBLEVBQUFhLEVBQUE7SUFBQVosU0FBQTtJQUFBQyxhQUFBO0lBQUFDLE9BQUE7SUFBQUU7RUFBQSxJQUFBSSxFQU03QjtFQUxDO0lBQUFNO0VBQUEsSUFBQUYsRUFBUTtFQU1mLE1BQUFHLFVBQUEsR0FBbUJoRCxVQUFVLENBQUM0Qiw2QkFBNkIsQ0FBQztFQUM1RCxJQUFJVixrQkFBa0IsQ0FBQzZCLElBQUksQ0FBQztJQUFBLE9BQ25CLElBQUk7RUFBQTtFQUtiLElBQUk3Qyx1QkFBdUIsQ0FBQzZDLElBQUksQ0FBQztJQUFBLElBQUFFLEVBQUE7SUFBQSxJQUFBVixDQUFBLFFBQUFGLHNCQUFBLElBQUFFLENBQUEsUUFBQVEsSUFBQTtNQUU3QkUsRUFBQSxJQUFDLGdCQUFnQixDQUNURixJQUFJLENBQUpBLEtBQUcsQ0FBQyxDQUNjVixzQkFBc0IsQ0FBdEJBLHVCQUFxQixDQUFDLEdBQzlDO01BQUFFLENBQUEsTUFBQUYsc0JBQUE7TUFBQUUsQ0FBQSxNQUFBUSxJQUFBO01BQUFSLENBQUEsTUFBQVUsRUFBQTtJQUFBO01BQUFBLEVBQUEsR0FBQVYsQ0FBQTtJQUFBO0lBQUEsT0FIRlUsRUFHRTtFQUFBO0VBSU4sUUFBUUYsSUFBSTtJQUFBLEtBR0w1QixxQkFBcUI7TUFBQTtRQUFBLE9BQ2pCLElBQUk7TUFBQTtJQUFBLEtBRVJKLDZCQUE2QjtNQUFBO1FBQUEsSUFBQWtDLEVBQUE7UUFBQSxJQUFBVixDQUFBLFFBQUFHLE1BQUEsQ0FBQUMsR0FBQTtVQUNaTSxFQUFBLEdBQUE3QixpQkFBaUIsQ0FBQyxTQUFTLENBQUM7VUFBQW1CLENBQUEsTUFBQVUsRUFBQTtRQUFBO1VBQUFBLEVBQUEsR0FBQVYsQ0FBQTtRQUFBO1FBQWhELE1BQUFXLFdBQUEsR0FBb0JELEVBQTRCO1FBQUEsSUFBQUUsRUFBQTtRQUFBLElBQUFaLENBQUEsUUFBQUcsTUFBQSxDQUFBQyxHQUFBO1VBRTlDUSxFQUFBLElBQUMsZUFBZSxDQUFTLE1BQUMsQ0FBRCxHQUFDLENBQ3hCLENBQUMsSUFBSSxDQUFPLEtBQU8sQ0FBUCxPQUFPLENBQUMsc0RBRWpCLENBQUFELFdBQVcsR0FBWCxNQUFvQkEsV0FBVyxFQUFPLEdBQXRDLEVBQXFDLENBQ3hDLEVBSEMsSUFBSSxDQUlQLEVBTEMsZUFBZSxDQUtFO1VBQUFYLENBQUEsTUFBQVksRUFBQTtRQUFBO1VBQUFBLEVBQUEsR0FBQVosQ0FBQTtRQUFBO1FBQUEsT0FMbEJZLEVBS2tCO01BQUE7SUFBQSxLQUlqQjFDLG9DQUFvQztNQUFBO1FBQUEsSUFBQXdDLEVBQUE7UUFBQSxJQUFBVixDQUFBLFFBQUFHLE1BQUEsQ0FBQUMsR0FBQTtVQUVyQ00sRUFBQSxJQUFDLGVBQWUsQ0FBUyxNQUFDLENBQUQsR0FBQyxDQUN4QixDQUFDLElBQUksQ0FBTyxLQUFPLENBQVAsT0FBTyxDQUFDLGdGQUdwQixFQUhDLElBQUksQ0FJUCxFQUxDLGVBQWUsQ0FLRTtVQUFBVixDQUFBLE1BQUFVLEVBQUE7UUFBQTtVQUFBQSxFQUFBLEdBQUFWLENBQUE7UUFBQTtRQUFBLE9BTGxCVSxFQUtrQjtNQUFBO0lBQUEsS0FHakJ0Qyw2QkFBNkI7TUFBQTtRQUFBLElBQUFzQyxFQUFBO1FBQUEsSUFBQVYsQ0FBQSxRQUFBRyxNQUFBLENBQUFDLEdBQUE7VUFDekJNLEVBQUEsSUFBQyxvQkFBb0IsR0FBRztVQUFBVixDQUFBLE1BQUFVLEVBQUE7UUFBQTtVQUFBQSxFQUFBLEdBQUFWLENBQUE7UUFBQTtRQUFBLE9BQXhCVSxFQUF3QjtNQUFBO0lBQUEsS0FFNUJyQyxzQ0FBc0M7TUFBQTtRQUFBLElBQUFxQyxFQUFBO1FBQUEsSUFBQVYsQ0FBQSxRQUFBRyxNQUFBLENBQUFDLEdBQUE7VUFFdkNNLEVBQUEsSUFBQyxlQUFlLENBQVMsTUFBQyxDQUFELEdBQUMsQ0FDeEIsQ0FBQyxJQUFJLENBQU8sS0FBTyxDQUFQLE9BQU8sQ0FBRXJDLHVDQUFxQyxDQUFFLEVBQTNELElBQUksQ0FDUCxFQUZDLGVBQWUsQ0FFRTtVQUFBMkIsQ0FBQSxNQUFBVSxFQUFBO1FBQUE7VUFBQUEsRUFBQSxHQUFBVixDQUFBO1FBQUE7UUFBQSxPQUZsQlUsRUFFa0I7TUFBQTtJQUFBLEtBR2pCcEMsa0NBQWtDO0lBQUEsS0FDbENDLDZDQUE2QztNQUFBO1FBQUEsSUFBQW1DLEVBQUE7UUFBQSxJQUFBVixDQUFBLFFBQUFRLElBQUE7VUFFOUNFLEVBQUEsSUFBQyxlQUFlLENBQ2QsQ0FBQyxJQUFJLENBQU8sS0FBTyxDQUFQLE9BQU8sQ0FBRUYsS0FBRyxDQUFFLEVBQXpCLElBQUksQ0FDUCxFQUZDLGVBQWUsQ0FFRTtVQUFBUixDQUFBLE1BQUFRLElBQUE7VUFBQVIsQ0FBQSxNQUFBVSxFQUFBO1FBQUE7VUFBQUEsRUFBQSxHQUFBVixDQUFBO1FBQUE7UUFBQSxPQUZsQlUsRUFFa0I7TUFBQTtJQUFBLEtBR2pCaEMsMkJBQTJCO01BQUE7UUFBQSxJQUFBZ0MsRUFBQTtRQUFBLElBQUFWLENBQUEsU0FBQUcsTUFBQSxDQUFBQyxHQUFBO1VBRTVCTSxFQUFBLElBQUMsZUFBZSxDQUFTLE1BQUMsQ0FBRCxHQUFDLENBQ3hCLENBQUMsSUFBSSxDQUFPLEtBQU8sQ0FBUCxPQUFPLENBQUVoQyw0QkFBMEIsQ0FBRSxFQUFoRCxJQUFJLENBQ1AsRUFGQyxlQUFlLENBRUU7VUFBQXNCLENBQUEsT0FBQVUsRUFBQTtRQUFBO1VBQUFBLEVBQUEsR0FBQVYsQ0FBQTtRQUFBO1FBQUEsT0FGbEJVLEVBRWtCO01BQUE7SUFBQSxLQUdqQnpDLHlCQUF5QjtNQUFBO1FBQUEsSUFBQXlDLEVBQUE7UUFBQSxJQUFBVixDQUFBLFNBQUFHLE1BQUEsQ0FBQUMsR0FBQTtVQUUxQk0sRUFBQSxJQUFDLGVBQWUsQ0FBUyxNQUFDLENBQUQsR0FBQyxDQUN4QixDQUFDLElBQUksQ0FBTyxLQUFPLENBQVAsT0FBTyxDQUNoQnpDLDBCQUF3QixDQUN4QixDQUFBNEMsT0FBTyxDQUFBQyxHQUFJLENBQUFDLGNBTVgsSUFOQSxFQUVJLElBQUUsQ0FBRSxnQkFDWSxDQUFBRixPQUFPLENBQUFDLEdBQUksQ0FBQUMsY0FBYyxDQUFFLHNCQUU5QyxHQUNGLENBQ0YsRUFUQyxJQUFJLENBVVAsRUFYQyxlQUFlLENBV0U7VUFBQWYsQ0FBQSxPQUFBVSxFQUFBO1FBQUE7VUFBQUEsRUFBQSxHQUFBVixDQUFBO1FBQUE7UUFBQSxPQVhsQlUsRUFXa0I7TUFBQTtJQUFBLEtBR2pCdkMseUJBQXlCO01BQUE7UUFBQSxJQUFBdUMsRUFBQTtRQUFBLElBQUFWLENBQUEsU0FBQUcsTUFBQSxDQUFBQyxHQUFBO1VBSXRCTSxFQUFBLElBQUMsSUFBSSxDQUFPLEtBQU8sQ0FBUCxPQUFPLENBQUMsMkNBRXBCLEVBRkMsSUFBSSxDQUVFO1VBQUFWLENBQUEsT0FBQVUsRUFBQTtRQUFBO1VBQUFBLEVBQUEsR0FBQVYsQ0FBQTtRQUFBO1FBQUEsSUFBQVksRUFBQTtRQUFBLElBQUFaLENBQUEsU0FBQUcsTUFBQSxDQUFBQyxHQUFBO1VBSlhRLEVBQUEsSUFBQyxlQUFlLENBQ2QsQ0FBQyxHQUFHLENBQWUsYUFBUSxDQUFSLFFBQVEsQ0FBTSxHQUFDLENBQUQsR0FBQyxDQUNoQyxDQUFBRixFQUVNLENBQ04sQ0FBQyxJQUFJLENBQUMsZ0RBQzZDLElBQUUsQ0FDbEQsQ0FBQTNCLGVBQWUsQ0FBQ0QscUJBQXFCLENBQUMsQ0FBQyxFQUFFLHFCQUM1QyxFQUhDLElBQUksQ0FJUCxFQVJDLEdBQUcsQ0FTTixFQVZDLGVBQWUsQ0FVRTtVQUFBa0IsQ0FBQSxPQUFBWSxFQUFBO1FBQUE7VUFBQUEsRUFBQSxHQUFBWixDQUFBO1FBQUE7UUFBQSxPQVZsQlksRUFVa0I7TUFBQTtJQUFBLEtBSWpCbEQsd0JBQXdCO01BQUE7UUFBQSxJQUFBZ0QsRUFBQTtRQUFBLElBQUFWLENBQUEsU0FBQUcsTUFBQSxDQUFBQyxHQUFBO1VBRXpCTSxFQUFBLElBQUMsZUFBZSxDQUFTLE1BQUMsQ0FBRCxHQUFDLENBQ3hCLENBQUMsaUJBQWlCLEdBQ3BCLEVBRkMsZUFBZSxDQUVFO1VBQUFWLENBQUEsT0FBQVUsRUFBQTtRQUFBO1VBQUFBLEVBQUEsR0FBQVYsQ0FBQTtRQUFBO1FBQUEsT0FGbEJVLEVBRWtCO01BQUE7SUFBQTtNQUFBO1FBSXBCLElBQUlqQyx3QkFBd0IsQ0FBQytCLElBQUksQ0FBQztVQUNoQyxNQUFBUSxTQUFBLEdBQWtCLENBQUNwQixPQUE0QyxJQUFqQ1ksSUFBSSxDQUFBUyxNQUFPLEdBQUcxQixtQkFBbUI7VUFLdEQsTUFBQW1CLEVBQUEsR0FBQUYsSUFBSSxLQUFLeEMsd0JBSUEsR0FKVCxHQUNNQSx3QkFBd0IsdUNBR3JCLEdBRk5nRCxTQUFTLEdBQ1BSLElBQUksQ0FBQVUsS0FBTSxDQUFDLENBQUMsRUFBRTNCLG1CQUFtQixDQUFDLEdBQUcsUUFDakMsR0FGTmlCLElBRU07VUFBQSxJQUFBSSxFQUFBO1VBQUEsSUFBQVosQ0FBQSxTQUFBVSxFQUFBO1lBTFpFLEVBQUEsSUFBQyxJQUFJLENBQU8sS0FBTyxDQUFQLE9BQU8sQ0FDaEIsQ0FBQUYsRUFJUSxDQUNYLEVBTkMsSUFBSSxDQU1FO1lBQUFWLENBQUEsT0FBQVUsRUFBQTtZQUFBVixDQUFBLE9BQUFZLEVBQUE7VUFBQTtZQUFBQSxFQUFBLEdBQUFaLENBQUE7VUFBQTtVQUFBLElBQUFtQixFQUFBO1VBQUEsSUFBQW5CLENBQUEsU0FBQWdCLFNBQUE7WUFDTkcsRUFBQSxHQUFBSCxTQUE4QixJQUFqQixDQUFDLGFBQWEsR0FBRztZQUFBaEIsQ0FBQSxPQUFBZ0IsU0FBQTtZQUFBaEIsQ0FBQSxPQUFBbUIsRUFBQTtVQUFBO1lBQUFBLEVBQUEsR0FBQW5CLENBQUE7VUFBQTtVQUFBLElBQUFvQixFQUFBO1VBQUEsSUFBQXBCLENBQUEsU0FBQVksRUFBQSxJQUFBWixDQUFBLFNBQUFtQixFQUFBO1lBVG5DQyxFQUFBLElBQUMsZUFBZSxDQUNkLENBQUMsR0FBRyxDQUFlLGFBQVEsQ0FBUixRQUFRLENBQ3pCLENBQUFSLEVBTU0sQ0FDTCxDQUFBTyxFQUE2QixDQUNoQyxFQVRDLEdBQUcsQ0FVTixFQVhDLGVBQWUsQ0FXRTtZQUFBbkIsQ0FBQSxPQUFBWSxFQUFBO1lBQUFaLENBQUEsT0FBQW1CLEVBQUE7WUFBQW5CLENBQUEsT0FBQW9CLEVBQUE7VUFBQTtZQUFBQSxFQUFBLEdBQUFwQixDQUFBO1VBQUE7VUFBQSxPQVhsQm9CLEVBV2tCO1FBQUE7UUFRUCxNQUFBVixFQUFBLEdBQUFoQixTQUFTLEdBQVQsQ0FBaUIsR0FBakIsQ0FBaUI7UUFFWCxNQUFBa0IsRUFBQSxHQUFBSCxVQUFVLEdBQVYsMEJBQW1ELEdBQW5EWSxTQUFtRDtRQUFBLElBQUFGLEVBQUE7UUFBQSxJQUFBbkIsQ0FBQSxTQUFBUyxVQUFBLElBQUFULENBQUEsU0FBQUwsYUFBQTtVQUdqRXdCLEVBQUEsR0FBQXhCLGFBTUEsSUFMQyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQVosS0FBVyxDQUFDLENBQVcsUUFBQyxDQUFELEdBQUMsQ0FDaEMsQ0FBQyxJQUFJLENBQVEsS0FBa0MsQ0FBbEMsQ0FBQWMsVUFBVSxHQUFWLFlBQWtDLEdBQWxDLE1BQWlDLENBQUMsQ0FDNUM3QyxhQUFXLENBQ2QsRUFGQyxJQUFJLENBR1AsRUFKQyxRQUFRLENBS1Y7VUFBQW9DLENBQUEsT0FBQVMsVUFBQTtVQUFBVCxDQUFBLE9BQUFMLGFBQUE7VUFBQUssQ0FBQSxPQUFBbUIsRUFBQTtRQUFBO1VBQUFBLEVBQUEsR0FBQW5CLENBQUE7UUFBQTtRQUFBLElBQUFvQixFQUFBO1FBQUEsSUFBQXBCLENBQUEsU0FBQVEsSUFBQTtVQUNEWSxFQUFBLElBQUMsR0FBRyxDQUFlLGFBQVEsQ0FBUixRQUFRLENBQ3pCLENBQUMsUUFBUSxDQUFFWixLQUFHLENBQUUsRUFBZixRQUFRLENBQ1gsRUFGQyxHQUFHLENBRUU7VUFBQVIsQ0FBQSxPQUFBUSxJQUFBO1VBQUFSLENBQUEsT0FBQW9CLEVBQUE7UUFBQTtVQUFBQSxFQUFBLEdBQUFwQixDQUFBO1FBQUE7UUFBQSxJQUFBc0IsRUFBQTtRQUFBLElBQUF0QixDQUFBLFNBQUFtQixFQUFBLElBQUFuQixDQUFBLFNBQUFvQixFQUFBO1VBVlJFLEVBQUEsSUFBQyxHQUFHLENBQWUsYUFBSyxDQUFMLEtBQUssQ0FDckIsQ0FBQUgsRUFNRCxDQUNBLENBQUFDLEVBRUssQ0FDUCxFQVhDLEdBQUcsQ0FXRTtVQUFBcEIsQ0FBQSxPQUFBbUIsRUFBQTtVQUFBbkIsQ0FBQSxPQUFBb0IsRUFBQTtVQUFBcEIsQ0FBQSxPQUFBc0IsRUFBQTtRQUFBO1VBQUFBLEVBQUEsR0FBQXRCLENBQUE7UUFBQTtRQUFBLElBQUF1QixFQUFBO1FBQUEsSUFBQXZCLENBQUEsU0FBQVUsRUFBQSxJQUFBVixDQUFBLFNBQUFZLEVBQUEsSUFBQVosQ0FBQSxTQUFBc0IsRUFBQTtVQW5CUkMsRUFBQSxJQUFDLEdBQUcsQ0FDUyxVQUFZLENBQVosWUFBWSxDQUNULGFBQUssQ0FBTCxLQUFLLENBQ0osY0FBZSxDQUFmLGVBQWUsQ0FDbkIsU0FBaUIsQ0FBakIsQ0FBQWIsRUFBZ0IsQ0FBQyxDQUN0QixLQUFNLENBQU4sTUFBTSxDQUNLLGVBQW1ELENBQW5ELENBQUFFLEVBQWtELENBQUMsQ0FFcEUsQ0FBQVUsRUFXSyxDQUNQLEVBcEJDLEdBQUcsQ0FvQkU7VUFBQXRCLENBQUEsT0FBQVUsRUFBQTtVQUFBVixDQUFBLE9BQUFZLEVBQUE7VUFBQVosQ0FBQSxPQUFBc0IsRUFBQTtVQUFBdEIsQ0FBQSxPQUFBdUIsRUFBQTtRQUFBO1VBQUFBLEVBQUEsR0FBQXZCLENBQUE7UUFBQTtRQUFBLE9BcEJOdUIsRUFvQk07TUFBQTtFQUVaO0FBQUMiLCJpZ25vcmVMaXN0IjpbXX0=
@@ -1,7 +1,7 @@
1
1
  export const PR_TITLE = 'Add UMMAYA GitHub Workflow'
2
2
 
3
3
  export const GITHUB_ACTION_SETUP_DOCS_URL =
4
- 'https://github.com/anthropics/claude-code-action/blob/main/docs/setup.md'
4
+ 'https://ummaya-docs.pages.dev/en/'
5
5
 
6
6
  export const WORKFLOW_CONTENT = `name: UMMAYA
7
7
 
@@ -35,23 +35,16 @@ jobs:
35
35
  with:
36
36
  fetch-depth: 1
37
37
 
38
- - name: Run UMMAYA
39
- id: claude
40
- uses: anthropics/claude-code-action@v1
41
- with:
42
- friendli_api_key: \${{ secrets.FRIENDLI_TOKEN }}
43
-
44
- # This is an optional setting that allows UMMAYA to read CI results on PRs
45
- additional_permissions: |
46
- actions: read
38
+ - name: Install UMMAYA
39
+ run: npm install -g ummaya
47
40
 
48
- # Optional: Give a custom prompt to UMMAYA. If this is not specified, UMMAYA will perform the instructions specified in the comment that tagged it.
49
- # prompt: 'Update the pull request description to include a summary of changes.'
41
+ - name: Verify UMMAYA
42
+ id: ummaya
43
+ env:
44
+ FRIENDLI_TOKEN: \${{ secrets.FRIENDLI_TOKEN }}
45
+ run: ummaya --version
50
46
 
51
- # Optional: Add ummaya_args to customize behavior and configuration
52
- # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
53
- # or https://ummaya-docs.pages.dev/en/ for available options
54
- # ummaya_args: '--allowed-tools Bash(gh pr:*)'
47
+ # See https://ummaya-docs.pages.dev/en/ for available options
55
48
 
56
49
  `
57
50
 
@@ -130,15 +123,15 @@ jobs:
130
123
  with:
131
124
  fetch-depth: 1
132
125
 
133
- - name: Run UMMAYA Review
134
- id: claude-review
135
- uses: anthropics/claude-code-action@v1
136
- with:
137
- friendli_api_key: \${{ secrets.FRIENDLI_TOKEN }}
138
- plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
139
- plugins: 'code-review@ummaya-plugins'
140
- prompt: '/code-review:code-review \${{ github.repository }}/pull/\${{ github.event.pull_request.number }}'
141
- # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
142
- # or https://ummaya-docs.pages.dev/en/ for available options
126
+ - name: Install UMMAYA
127
+ run: npm install -g ummaya
128
+
129
+ - name: Verify UMMAYA Review Runtime
130
+ id: ummaya-review
131
+ env:
132
+ FRIENDLI_TOKEN: \${{ secrets.FRIENDLI_TOKEN }}
133
+ run: ummaya --version
134
+
135
+ # See https://ummaya-docs.pages.dev/en/ for available options
143
136
 
144
137
  `
@@ -34,6 +34,9 @@ export const CLAUDE_AI_INFERENCE_SCOPE = 'user:inference' as const
34
34
  export const CLAUDE_AI_PROFILE_SCOPE = 'user:profile' as const
35
35
  const CONSOLE_SCOPE = 'org:create_api_key' as const
36
36
  export const OAUTH_BETA_HEADER = 'oauth-2025-04-20' as const
37
+ const UMMAYA_DISABLED_OAUTH_BASE_URL =
38
+ 'http://127.0.0.1:9/ummaya-disabled-oauth' as const
39
+ const UMMAYA_DOCS_ORIGIN = 'https://ummaya-docs.pages.dev' as const
37
40
 
38
41
  // Console OAuth scopes - for API key creation via Console
39
42
  export const CONSOLE_OAUTH_SCOPES = [
@@ -61,12 +64,6 @@ type OauthConfig = {
61
64
  BASE_API_URL: string
62
65
  CONSOLE_AUTHORIZE_URL: string
63
66
  CLAUDE_AI_AUTHORIZE_URL: string
64
- /**
65
- * The claude.ai web origin. Separate from CLAUDE_AI_AUTHORIZE_URL because
66
- * that now routes through claude.com/cai/* for attribution — deriving
67
- * .origin from it would give claude.com, breaking links to /code,
68
- * /settings/connectors, and other claude.ai web pages.
69
- */
70
67
  CLAUDE_AI_ORIGIN: string
71
68
  TOKEN_URL: string
72
69
  API_KEY_URL: string
@@ -80,26 +77,24 @@ type OauthConfig = {
80
77
  MCP_PROXY_PATH: string
81
78
  }
82
79
 
83
- // Production OAuth configuration - Used in normal operation
80
+ // Production OAuth configuration. UMMAYA uses FriendliAI API-key login, so
81
+ // OAuth-shaped endpoints fail closed unless an explicit operator override is
82
+ // configured below.
84
83
  const PROD_OAUTH_CONFIG = {
85
- BASE_API_URL: 'https://api.anthropic.com',
86
- CONSOLE_AUTHORIZE_URL: 'https://platform.claude.com/oauth/authorize',
87
- // Bounces through claude.com/cai/* so CLI sign-ins connect to claude.com
88
- // visits for attribution. 307s to claude.ai/oauth/authorize in two hops.
89
- CLAUDE_AI_AUTHORIZE_URL: 'https://claude.com/cai/oauth/authorize',
90
- CLAUDE_AI_ORIGIN: 'https://claude.ai',
91
- TOKEN_URL: 'https://platform.claude.com/v1/oauth/token',
92
- API_KEY_URL: 'https://api.anthropic.com/api/oauth/claude_cli/create_api_key',
93
- ROLES_URL: 'https://api.anthropic.com/api/oauth/claude_cli/roles',
94
- CONSOLE_SUCCESS_URL:
95
- 'https://platform.claude.com/buy_credits?returnUrl=/oauth/code/success%3Fapp%3Dclaude-code',
96
- CLAUDEAI_SUCCESS_URL:
97
- 'https://platform.claude.com/oauth/code/success?app=claude-code',
98
- MANUAL_REDIRECT_URL: 'https://platform.claude.com/oauth/code/callback',
84
+ BASE_API_URL: UMMAYA_DISABLED_OAUTH_BASE_URL,
85
+ CONSOLE_AUTHORIZE_URL: `${UMMAYA_DISABLED_OAUTH_BASE_URL}/oauth/authorize`,
86
+ CLAUDE_AI_AUTHORIZE_URL: `${UMMAYA_DISABLED_OAUTH_BASE_URL}/oauth/authorize`,
87
+ CLAUDE_AI_ORIGIN: UMMAYA_DOCS_ORIGIN,
88
+ TOKEN_URL: `${UMMAYA_DISABLED_OAUTH_BASE_URL}/v1/oauth/token`,
89
+ API_KEY_URL: `${UMMAYA_DISABLED_OAUTH_BASE_URL}/api/oauth/ummaya_cli/create_api_key`,
90
+ ROLES_URL: `${UMMAYA_DISABLED_OAUTH_BASE_URL}/api/oauth/ummaya_cli/roles`,
91
+ CONSOLE_SUCCESS_URL: `${UMMAYA_DOCS_ORIGIN}/en/`,
92
+ CLAUDEAI_SUCCESS_URL: `${UMMAYA_DOCS_ORIGIN}/en/`,
93
+ MANUAL_REDIRECT_URL: `${UMMAYA_DISABLED_OAUTH_BASE_URL}/oauth/code/callback`,
99
94
  CLIENT_ID: '9d1c250a-e61b-44d9-88ed-5944d1962f5e',
100
95
  // No suffix for production config
101
96
  OAUTH_FILE_SUFFIX: '',
102
- MCP_PROXY_URL: 'https://mcp-proxy.anthropic.com',
97
+ MCP_PROXY_URL: UMMAYA_DISABLED_OAUTH_BASE_URL,
103
98
  MCP_PROXY_PATH: '/v1/mcp/{server_id}',
104
99
  } as const
105
100
 
@@ -107,44 +102,22 @@ const PROD_OAUTH_CONFIG = {
107
102
  * Client ID Metadata Document URL for MCP OAuth (CIMD / SEP-991).
108
103
  * When an MCP auth server advertises client_id_metadata_document_supported: true,
109
104
  * Claude Code uses this URL as its client_id instead of Dynamic Client Registration.
110
- * The URL must point to a JSON document hosted by Anthropic.
105
+ * The URL must point to a JSON document hosted by the runtime operator. UMMAYA
106
+ * disables this by default because there is no public hosted OAuth metadata
107
+ * endpoint for the FriendliAI API-key login path.
111
108
  * See: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-client-id-metadata-document-00
112
109
  */
113
110
  export const MCP_CLIENT_METADATA_URL =
114
- 'https://claude.ai/oauth/claude-code-client-metadata'
111
+ `${UMMAYA_DISABLED_OAUTH_BASE_URL}/oauth/ummaya-client-metadata`
115
112
 
116
- // Staging OAuth configuration - only included in ant builds with staging flag
117
- // Uses literal check for dead code elimination
118
113
  const STAGING_OAUTH_CONFIG =
119
114
  process.env.USER_TYPE === 'ant'
120
115
  ? ({
121
- BASE_API_URL: 'https://api-staging.anthropic.com',
122
- CONSOLE_AUTHORIZE_URL:
123
- 'https://platform.staging.ant.dev/oauth/authorize',
124
- CLAUDE_AI_AUTHORIZE_URL:
125
- 'https://claude-ai.staging.ant.dev/oauth/authorize',
126
- CLAUDE_AI_ORIGIN: 'https://claude-ai.staging.ant.dev',
127
- TOKEN_URL: 'https://platform.staging.ant.dev/v1/oauth/token',
128
- API_KEY_URL:
129
- 'https://api-staging.anthropic.com/api/oauth/claude_cli/create_api_key',
130
- ROLES_URL:
131
- 'https://api-staging.anthropic.com/api/oauth/claude_cli/roles',
132
- CONSOLE_SUCCESS_URL:
133
- 'https://platform.staging.ant.dev/buy_credits?returnUrl=/oauth/code/success%3Fapp%3Dclaude-code',
134
- CLAUDEAI_SUCCESS_URL:
135
- 'https://platform.staging.ant.dev/oauth/code/success?app=claude-code',
136
- MANUAL_REDIRECT_URL:
137
- 'https://platform.staging.ant.dev/oauth/code/callback',
138
- CLIENT_ID: '22422756-60c9-4084-8eb7-27705fd5cf9a',
116
+ ...PROD_OAUTH_CONFIG,
139
117
  OAUTH_FILE_SUFFIX: '-staging-oauth',
140
- MCP_PROXY_URL: 'https://mcp-proxy-staging.anthropic.com',
141
- MCP_PROXY_PATH: '/v1/mcp/{server_id}',
142
118
  } as const)
143
119
  : undefined
144
120
 
145
- // Three local dev servers: :8000 api-proxy (`api dev start -g ccr`),
146
- // :4000 claude-ai frontend, :3000 Console frontend. Env vars let
147
- // scripts/claude-localhost override if your layout differs.
148
121
  function getLocalOauthConfig(): OauthConfig {
149
122
  const api =
150
123
  process.env.CLAUDE_LOCAL_OAUTH_API_BASE?.replace(/\/$/, '') ??
@@ -173,14 +146,12 @@ function getLocalOauthConfig(): OauthConfig {
173
146
  }
174
147
  }
175
148
 
176
- // Allowed base URLs for CLAUDE_CODE_CUSTOM_OAUTH_URL override.
177
- // Only FedStart/PubSec deployments are permitted to prevent OAuth tokens
178
- // from being sent to arbitrary endpoints.
179
- const ALLOWED_OAUTH_BASE_URLS = [
180
- 'https://beacon.claude-ai.staging.ant.dev',
181
- 'https://claude.fedstart.com',
182
- 'https://claude-staging.fedstart.com',
183
- ]
149
+ const ALLOWED_OAUTH_BASE_URLS = (
150
+ process.env.UMMAYA_ALLOWED_OAUTH_BASE_URLS ?? ''
151
+ )
152
+ .split(',')
153
+ .map(url => url.trim().replace(/\/$/, ''))
154
+ .filter(Boolean)
184
155
 
185
156
  // Default to prod config, override with test/staging if enabled
186
157
  export function getOauthConfig(): OauthConfig {
@@ -195,8 +166,6 @@ export function getOauthConfig(): OauthConfig {
195
166
  }
196
167
  })()
197
168
 
198
- // Allow overriding all OAuth URLs to point to an approved FedStart deployment.
199
- // Only allowlisted base URLs are accepted to prevent credential leakage.
200
169
  const oauthBaseUrl = process.env.CLAUDE_CODE_CUSTOM_OAUTH_URL
201
170
  if (oauthBaseUrl) {
202
171
  const base = oauthBaseUrl.replace(/\/$/, '')
@@ -1,8 +1,8 @@
1
- export const PRODUCT_URL = 'https://claude.com/claude-code'
1
+ export const PRODUCT_URL = 'https://ummaya-docs.pages.dev/'
2
2
 
3
- // Claude Code Remote session URLs
4
- export const CLAUDE_AI_BASE_URL = 'https://claude.ai'
5
- export const CLAUDE_AI_STAGING_BASE_URL = 'https://claude-ai.staging.ant.dev'
3
+ // UMMAYA remote session URLs
4
+ export const CLAUDE_AI_BASE_URL = 'https://ummaya-docs.pages.dev'
5
+ export const CLAUDE_AI_STAGING_BASE_URL = 'https://ummaya-docs.pages.dev'
6
6
  export const CLAUDE_AI_LOCAL_BASE_URL = 'http://localhost:4000'
7
7
 
8
8
  /**
@@ -34,7 +34,7 @@ export function isRemoteSessionLocal(
34
34
  }
35
35
 
36
36
  /**
37
- * Get the base URL for Claude AI based on environment.
37
+ * Get the base URL for UMMAYA remote sessions based on environment.
38
38
  */
39
39
  export function getClaudeAiBaseUrl(
40
40
  sessionId?: string,
@@ -54,7 +54,7 @@ export function getClaudeAiBaseUrl(
54
54
  *
55
55
  * The cse_→session_ translation is a temporary shim gated by
56
56
  * tengu_bridge_repl_v2_cse_shim_enabled (see isCseShimEnabled). Worker
57
- * endpoints (/v1/code/sessions/{id}/worker/*) want `cse_*` but the claude.ai
57
+ * endpoints (/v1/code/sessions/{id}/worker/*) want `cse_*` but the remote
58
58
  * frontend currently routes on `session_*` (compat/convert.go:27 validates
59
59
  * TagSession). Same UUID body, different tag prefix. Once the server tags by
60
60
  * environment_kind and the frontend accepts `cse_*` directly, flip the gate
@@ -1341,7 +1341,7 @@ export const SDKRateLimitInfoSchema = lazySchema(() =>
1341
1341
  isUsingOverage: z.boolean().optional(),
1342
1342
  surpassedThreshold: z.number().optional(),
1343
1343
  })
1344
- .describe('Rate limit information for claude.ai subscription users.'),
1344
+ .describe('Rate limit information for UMMAYA remote subscription users.'),
1345
1345
  )
1346
1346
 
1347
1347
  export const SDKAssistantMessageSchema = lazySchema(() =>
@@ -239,9 +239,6 @@ export type GrowthBookExperimentData = {
239
239
  experimentMetadata?: Record<string, unknown>
240
240
  }
241
241
 
242
- // api.anthropic.com only serves the "production" GrowthBook environment
243
- // (see starling/starling/cli/cli.py DEFAULT_ENVIRONMENTS). Staging and
244
- // development environments are not exported to the prod API.
245
242
  function getEnvironmentForGrowthBook(): string {
246
243
  return 'production'
247
244
  }
@@ -55,6 +55,17 @@ type FirstPartyEventLoggingPayload = {
55
55
  events: FirstPartyEventLoggingEvent[]
56
56
  }
57
57
 
58
+ function getFirstPartyEventBaseUrl(
59
+ configuredBaseUrl: string | undefined,
60
+ ): string | undefined {
61
+ const baseUrl =
62
+ configuredBaseUrl ??
63
+ process.env.UMMAYA_FIRST_PARTY_EVENT_BASE_URL ??
64
+ process.env.ANTHROPIC_BASE_URL
65
+ const trimmed = baseUrl?.trim()
66
+ return trimmed ? trimmed.replace(/\/$/, '') : undefined
67
+ }
68
+
58
69
  /**
59
70
  * Exporter for 1st-party event logging to /api/event_logging/batch.
60
71
  *
@@ -71,7 +82,7 @@ type FirstPartyEventLoggingPayload = {
71
82
  * - Auth fallback: retries without auth on 401 errors
72
83
  */
73
84
  export class FirstPartyEventLoggingExporter implements LogRecordExporter {
74
- private readonly endpoint: string
85
+ private readonly endpoint: string | undefined
75
86
  private readonly timeout: number
76
87
  private readonly maxBatchSize: number
77
88
  private readonly skipAuth: boolean
@@ -109,15 +120,10 @@ export class FirstPartyEventLoggingExporter implements LogRecordExporter {
109
120
  schedule?: (fn: () => Promise<void>, delayMs: number) => () => void
110
121
  } = {},
111
122
  ) {
112
- // Default: prod, except when ANTHROPIC_BASE_URL is explicitly staging.
113
- // Overridable via tengu_1p_event_batch_config.baseUrl.
114
- const baseUrl =
115
- options.baseUrl ||
116
- (process.env.ANTHROPIC_BASE_URL === 'https://api-staging.anthropic.com'
117
- ? 'https://api-staging.anthropic.com'
118
- : 'https://api.anthropic.com')
119
-
120
- this.endpoint = `${baseUrl}${options.path || '/api/event_logging/batch'}`
123
+ const baseUrl = getFirstPartyEventBaseUrl(options.baseUrl)
124
+ this.endpoint = baseUrl
125
+ ? `${baseUrl}${options.path || '/api/event_logging/batch'}`
126
+ : undefined
121
127
 
122
128
  this.timeout = options.timeout || 10000
123
129
  this.maxBatchSize = options.maxBatchSize || 200
@@ -134,8 +140,10 @@ export class FirstPartyEventLoggingExporter implements LogRecordExporter {
134
140
  return () => clearTimeout(t)
135
141
  })
136
142
 
137
- // Retry any failed events from previous runs of this session (in background)
138
- void this.retryPreviousBatches()
143
+ if (this.endpoint) {
144
+ // Retry any failed events from previous runs of this session (in background)
145
+ void this.retryPreviousBatches()
146
+ }
139
147
  }
140
148
 
141
149
  // Expose for testing
@@ -327,6 +335,11 @@ export class FirstPartyEventLoggingExporter implements LogRecordExporter {
327
335
  return
328
336
  }
329
337
 
338
+ if (!this.endpoint) {
339
+ resultCallback({ code: ExportResultCode.SUCCESS })
340
+ return
341
+ }
342
+
330
343
  if (this.attempts >= this.maxAttempts) {
331
344
  resultCallback({
332
345
  code: ExportResultCode.FAILED,
@@ -467,6 +480,11 @@ export class FirstPartyEventLoggingExporter implements LogRecordExporter {
467
480
  }
468
481
 
469
482
  private async retryFailedEvents(): Promise<void> {
483
+ if (!this.endpoint) {
484
+ this.resetBackoff()
485
+ return
486
+ }
487
+
470
488
  const filePath = this.getCurrentBatchFilePath()
471
489
 
472
490
  // Keep retrying while there are events and endpoint is healthy
@@ -527,6 +545,10 @@ export class FirstPartyEventLoggingExporter implements LogRecordExporter {
527
545
  private async sendBatchWithRetry(
528
546
  payload: FirstPartyEventLoggingPayload,
529
547
  ): Promise<void> {
548
+ if (!this.endpoint) {
549
+ return
550
+ }
551
+
530
552
  if (this.isKilled()) {
531
553
  // Throw so the caller short-circuits remaining batches and queues
532
554
  // everything to disk. Zero network traffic while killed; the backoff
@@ -421,27 +421,31 @@ function syncRemoteEvalToDisk(): void {
421
421
  */
422
422
  function isGrowthBookEnabled(): boolean {
423
423
  // GrowthBook depends on 1P event logging.
424
- return is1PEventLoggingEnabled()
424
+ return is1PEventLoggingEnabled() && getGrowthBookApiHost() !== undefined
425
+ }
426
+
427
+ function getGrowthBookApiHost(): string | undefined {
428
+ const baseUrl =
429
+ process.env.USER_TYPE === 'ant'
430
+ ? process.env.CLAUDE_CODE_GB_BASE_URL
431
+ : process.env.UMMAYA_GROWTHBOOK_BASE_URL
432
+ const trimmed = baseUrl?.trim()
433
+ return trimmed ? trimmed : undefined
425
434
  }
426
435
 
427
436
  /**
428
- * Hostname of ANTHROPIC_BASE_URL when it points at a non-Anthropic proxy.
429
- *
430
- * Enterprise-proxy deployments (Epic, Marble, etc.) typically use
431
- * apiKeyHelper auth, which means isAnthropicAuthEnabled() returns false and
432
- * organizationUUID/accountUUID/email are all absent from GrowthBook
433
- * attributes. Without this, there's no stable attribute to target them on
434
- * — only per-device IDs. See src/utils/auth.ts isAnthropicAuthEnabled().
435
- *
436
- * Returns undefined for unset/default (api.anthropic.com) so the attribute
437
- * is absent for direct-API users. Hostname only — no path/query/creds.
437
+ * Hostname of ANTHROPIC_BASE_URL when it points at an operator-approved proxy.
438
438
  */
439
439
  export function getApiBaseUrlHost(): string | undefined {
440
440
  const baseUrl = process.env.ANTHROPIC_BASE_URL
441
441
  if (!baseUrl) return undefined
442
442
  try {
443
443
  const host = new URL(baseUrl).host
444
- if (host === 'api.anthropic.com') return undefined
444
+ const firstPartyHosts = (process.env.UMMAYA_FIRST_PARTY_API_HOSTS ?? '')
445
+ .split(',')
446
+ .map(value => value.trim())
447
+ .filter(Boolean)
448
+ if (firstPartyHosts.includes(host)) return undefined
445
449
  return host
446
450
  } catch {
447
451
  return undefined
@@ -500,10 +504,7 @@ const getGrowthBookClient = memoize(
500
504
  `GrowthBook: Creating client with clientKey=${clientKey}, attributes: ${jsonStringify(attributes)}`,
501
505
  )
502
506
  }
503
- const baseUrl =
504
- process.env.USER_TYPE === 'ant'
505
- ? process.env.CLAUDE_CODE_GB_BASE_URL || 'https://api.anthropic.com/'
506
- : 'https://api.anthropic.com/'
507
+ const baseUrl = getGrowthBookApiHost() ?? 'http://127.0.0.1:9'
507
508
 
508
509
  // Skip auth if trust hasn't been established yet
509
510
  // This prevents executing apiKeyHelper commands before the trust dialog
@@ -1,12 +1,3 @@
1
- /**
2
- * Files API client for managing files
3
- *
4
- * This module provides functionality to download and upload files to Anthropic Public Files API.
5
- * Used by the Claude Code agent to download file attachments at session startup.
6
- *
7
- * API Reference: https://docs.anthropic.com/en/api/files-content
8
- */
9
-
10
1
  import axios from 'axios'
11
2
  import { randomUUID } from 'crypto'
12
3
  import * as fs from 'fs/promises'
@@ -27,13 +18,12 @@ import {
27
18
  const FILES_API_BETA_HEADER = 'files-api-2025-04-14,oauth-2025-04-20'
28
19
  const ANTHROPIC_VERSION = '2023-06-01'
29
20
 
30
- // API base URL - uses ANTHROPIC_BASE_URL set by env-manager for the appropriate environment
31
- // Falls back to public API for standalone usage
32
21
  function getDefaultApiBaseUrl(): string {
33
22
  return (
23
+ process.env.UMMAYA_FILES_API_BASE_URL ||
34
24
  process.env.ANTHROPIC_BASE_URL ||
35
25
  process.env.CLAUDE_CODE_API_BASE_URL ||
36
- 'https://api.anthropic.com'
26
+ 'http://127.0.0.1:9/ummaya-disabled-files-api'
37
27
  )
38
28
  }
39
29
 
@@ -60,7 +50,7 @@ export type File = {
60
50
  export type FilesApiConfig = {
61
51
  /** OAuth token for authentication (from session JWT) */
62
52
  oauthToken: string
63
- /** Base URL for the API (default: https://api.anthropic.com) */
53
+ /** Base URL for the API. Defaults to a disabled local endpoint. */
64
54
  baseUrl?: string
65
55
  /** Session ID for creating session-specific directories */
66
56
  sessionId: string
@@ -123,7 +113,7 @@ async function retryWithBackoff<T>(
123
113
  }
124
114
 
125
115
  /**
126
- * Downloads a single file from the Anthropic Public Files API
116
+ * Downloads a single file from the configured runtime Files API.
127
117
  *
128
118
  * @param fileId - The file ID (e.g., "file_011CNha8iCJcU1wXNR6q4V8w")
129
119
  * @param config - Files API configuration
@@ -26,6 +26,18 @@ const CACHE_TTL_MS = 60 * 60 * 1000
26
26
  // N `claude -p` invocations into ~1 API call/day.
27
27
  const DISK_CACHE_TTL_MS = 24 * 60 * 60 * 1000
28
28
 
29
+ function getMetricsEnabledEndpoint(): string | undefined {
30
+ const baseUrl =
31
+ process.env.UMMAYA_METRICS_BASE_URL ??
32
+ process.env.ANT_CLAUDE_CODE_METRICS_ENDPOINT ??
33
+ process.env.ANTHROPIC_BASE_URL ??
34
+ process.env.CLAUDE_CODE_API_BASE_URL
35
+ const trimmed = baseUrl?.trim()
36
+ return trimmed
37
+ ? `${trimmed.replace(/\/$/, '')}/api/claude_code/organizations/metrics_enabled`
38
+ : undefined
39
+ }
40
+
29
41
  /**
30
42
  * Internal function to call the API and check if metrics are enabled
31
43
  * This is wrapped by memoizeWithTTLAsync to add caching behavior
@@ -42,7 +54,10 @@ async function _fetchMetricsEnabled(): Promise<MetricsEnabledResponse> {
42
54
  ...authResult.headers,
43
55
  }
44
56
 
45
- const endpoint = `https://api.anthropic.com/api/claude_code/organizations/metrics_enabled`
57
+ const endpoint = getMetricsEnabledEndpoint()
58
+ if (!endpoint) {
59
+ throw new Error('Metrics opt-out endpoint is not configured for UMMAYA')
60
+ }
46
61
  const response = await axios.get<MetricsEnabledResponse>(endpoint, {
47
62
  headers,
48
63
  timeout: 5000,
@@ -58,6 +73,10 @@ async function _checkMetricsEnabledAPI(): Promise<MetricsStatus> {
58
73
  return { enabled: false, hasError: false }
59
74
  }
60
75
 
76
+ if (!getMetricsEnabledEndpoint()) {
77
+ return { enabled: false, hasError: false }
78
+ }
79
+
61
80
  try {
62
81
  const data = await withOAuth401Retry(_fetchMetricsEnabled, {
63
82
  also403Revoked: true,
@@ -223,7 +223,7 @@ export function gateChannelServer(
223
223
  return {
224
224
  action: 'skip',
225
225
  kind: 'auth',
226
- reason: 'channels requires claude.ai authentication (run /login)',
226
+ reason: 'channels requires UMMAYA remote authentication (run /login)',
227
227
  }
228
228
  }
229
229
 
@@ -34,10 +34,14 @@ export async function prefetchOfficialMcpUrls(): Promise<void> {
34
34
  if (process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC) {
35
35
  return
36
36
  }
37
+ const registryUrl = process.env.UMMAYA_MCP_REGISTRY_URL?.trim()
38
+ if (!registryUrl) {
39
+ return
40
+ }
37
41
 
38
42
  try {
39
43
  const response = await axios.get<RegistryResponse>(
40
- 'https://api.anthropic.com/mcp-registry/v0/servers?version=latest&visibility=commercial',
44
+ registryUrl,
41
45
  { timeout: 5000 },
42
46
  )
43
47
 
@@ -597,7 +597,7 @@ export function useManageMCPConnections(
597
597
  gate.kind === 'disabled'
598
598
  ? 'Channels are not currently available'
599
599
  : gate.kind === 'auth'
600
- ? 'Channels require claude.ai authentication · run /login'
600
+ ? 'Channels require UMMAYA remote authentication · run /login'
601
601
  : gate.kind === 'policy'
602
602
  ? 'Channels are not enabled for your org · have an administrator set channelsEnabled: true in managed settings'
603
603
  : gate.reason
@@ -273,7 +273,7 @@ export function describeMcpConfigFilePath(scope: ConfigScope): string {
273
273
  case 'enterprise':
274
274
  return getEnterpriseMcpFilePath()
275
275
  case 'claudeai':
276
- return 'claude.ai'
276
+ return 'UMMAYA remote'
277
277
  default:
278
278
  return scope
279
279
  }
@@ -292,7 +292,7 @@ export function getScopeLabel(scope: ConfigScope): string {
292
292
  case 'enterprise':
293
293
  return 'Enterprise config (managed by your organization)'
294
294
  case 'claudeai':
295
- return 'claude.ai config'
295
+ return 'UMMAYA remote config'
296
296
  default:
297
297
  return scope
298
298
  }
@@ -398,7 +398,6 @@ function roughTokenCountEstimationForBlock(
398
398
  return roughTokenCountEstimation(block.text)
399
399
  }
400
400
  if (block.type === 'image' || block.type === 'document') {
401
- // https://platform.claude.com/docs/en/build-with-claude/vision#calculate-image-costs
402
401
  // tokens = (width px * height px)/750
403
402
  // Images are resized to max 2000x2000 (5333 tokens). Use a conservative
404
403
  // estimate that matches microCompact's IMAGE_MAX_TOKEN_SIZE to avoid