ummaya 0.2.9 → 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.
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/pyproject.toml +2 -2
- package/tui/package.json +1 -1
- package/tui/src/bridge/bridgeEnabled.ts +1 -1
- package/tui/src/commands/chrome/chrome.tsx +3 -4
- package/tui/src/commands/createMovedToPluginCommand.ts +1 -1
- package/tui/src/commands/extra-usage/extra-usage-core.ts +2 -4
- package/tui/src/commands/insights.ts +5 -4
- package/tui/src/commands/install-github-app/ApiKeyStep.tsx +1 -2
- package/tui/src/commands/install-github-app/ExistingWorkflowStep.tsx +1 -1
- package/tui/src/commands/install-github-app/InstallAppStep.tsx +1 -1
- package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
- package/tui/src/commands/install-github-app/setupGitHubActions.ts +2 -2
- package/tui/src/commands/install-slack-app/install-slack-app.ts +1 -1
- package/tui/src/commands/mobile/mobile.tsx +3 -3
- package/tui/src/commands/stickers/stickers.ts +1 -1
- package/tui/src/commands/upgrade/upgrade.tsx +3 -4
- package/tui/src/components/ClaudeInChromeOnboarding.tsx +2 -3
- package/tui/src/components/Feedback.tsx +8 -2
- package/tui/src/components/FeedbackSurvey/submitTranscriptShare.ts +7 -2
- package/tui/src/components/Passes/Passes.tsx +1 -1
- package/tui/src/components/WorkflowMultiselectDialog.tsx +1 -1
- package/tui/src/components/messages/AssistantTextMessage.tsx +1 -2
- package/tui/src/constants/github-app.ts +19 -26
- package/tui/src/constants/oauth.ts +28 -59
- package/tui/src/constants/product.ts +6 -6
- package/tui/src/entrypoints/sdk/coreSchemas.ts +1 -1
- package/tui/src/services/analytics/firstPartyEventLogger.ts +0 -3
- package/tui/src/services/analytics/firstPartyEventLoggingExporter.ts +34 -12
- package/tui/src/services/analytics/growthbook.ts +17 -16
- package/tui/src/services/api/filesApi.ts +4 -14
- package/tui/src/services/api/metricsOptOut.ts +20 -1
- package/tui/src/services/mcp/channelNotification.ts +1 -1
- package/tui/src/services/mcp/officialRegistry.ts +5 -1
- package/tui/src/services/mcp/useManageMCPConnections.ts +1 -1
- package/tui/src/services/mcp/utils.ts +2 -2
- package/tui/src/services/tokenEstimation.ts +0 -1
- package/tui/src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts +6 -6
- package/tui/src/tools/McpAuthTool/McpAuthTool.ts +1 -1
- package/tui/src/tools/RemoteTriggerTool/RemoteTriggerTool.ts +1 -1
- package/tui/src/tools/RemoteTriggerTool/prompt.ts +2 -2
- package/tui/src/tools/WebFetchTool/preapproved.ts +0 -4
- package/tui/src/tools/WebFetchTool/utils.ts +15 -11
- package/tui/src/upstreamproxy/upstreamproxy.ts +9 -15
- package/tui/src/utils/autoUpdater.ts +4 -1
- package/tui/src/utils/claudeInChrome/mcpServer.ts +1 -1
- package/tui/src/utils/claudeInChrome/setup.ts +1 -1
- package/tui/src/utils/claudeInChrome/toolRendering.tsx +1 -2
- package/tui/src/utils/desktopDeepLink.ts +18 -18
- package/tui/src/utils/fastMode.ts +1 -1
- package/tui/src/utils/http.ts +1 -5
- package/tui/src/utils/ide.ts +6 -5
- package/tui/src/utils/model/providers.ts +6 -10
- package/tui/src/utils/modelCost.ts +0 -2
- package/tui/src/utils/nativeInstaller/download.ts +15 -17
- package/tui/src/utils/plugins/installCounts.ts +4 -11
- package/tui/src/utils/plugins/officialMarketplaceGcs.ts +5 -18
- package/tui/src/utils/releaseNotes.ts +2 -2
- package/tui/src/utils/settings/types.ts +1 -1
- package/tui/src/utils/statusNoticeDefinitions.tsx +3 -3
- package/tui/src/utils/telemetry/bigqueryExporter.ts +20 -13
- 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 ·
|
|
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+XG4gICAgICAgIDwvQm94PlxuICAgICAgKVxuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7QUFBQSxjQUFjQSxjQUFjLFFBQVEsdUNBQXVDO0FBQzNFLE9BQU9DLEtBQUssSUFBSUMsVUFBVSxRQUFRLE9BQU87QUFDekMsU0FBU0Msd0JBQXdCLFFBQVEsaUNBQWlDO0FBQzFFLFNBQVNDLHVCQUF1QixRQUFRLG1DQUFtQztBQUMzRSxTQUFTQyxZQUFZLFFBQVEsNEJBQTRCO0FBQ3pELFNBQVNDLEdBQUcsRUFBRUMsUUFBUSxFQUFFQyxJQUFJLFFBQVEsY0FBYztBQUNsRCxTQUNFQyx3QkFBd0IsRUFDeEJDLHlCQUF5QixFQUN6QkMsb0NBQW9DLEVBQ3BDQyx5QkFBeUIsRUFDekJDLDZCQUE2QixFQUM3QkMsc0NBQXNDLEVBQ3RDQyxrQ0FBa0MsRUFDbENDLDZDQUE2QyxFQUM3Q0MsNkJBQTZCLEVBQzdCQyx3QkFBd0IsRUFDeEJDLDJCQUEyQixRQUN0Qiw4QkFBOEI7QUFDckMsU0FDRUMsa0JBQWtCLEVBQ2xCQyxxQkFBcUIsUUFDaEIseUJBQXlCO0FBQ2hDLFNBQVNDLGlCQUFpQixRQUFRLGdEQUFnRDtBQUNsRixTQUNFQyxxQkFBcUIsRUFDckJDLGVBQWUsUUFDViw0QkFBNEI7QUFDbkMsU0FBU0MscUJBQXFCLFFBQVEsbURBQW1EO0FBQ3pGLFNBQVNDLGFBQWEsUUFBUSxxQkFBcUI7QUFDbkQsU0FBU0MsaUJBQWlCLFFBQVEseUJBQXlCO0FBQzNELFNBQVNDLFFBQVEsUUFBUSxnQkFBZ0I7QUFDekMsU0FBU0MsZUFBZSxRQUFRLHVCQUF1QjtBQUN2RCxTQUFTQyw2QkFBNkIsUUFBUSxzQkFBc0I7QUFDcEUsU0FBU0MsZ0JBQWdCLFFBQVEsdUJBQXVCO0FBRXhELE1BQU1DLG1CQUFtQixHQUFHLElBQUk7QUFFaEMsS0FBS0MsS0FBSyxHQUFHO0VBQ1hDLEtBQUssRUFBRWxDLGNBQWM7RUFDckJtQyxTQUFTLEVBQUUsT0FBTztF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
|
|
@@ -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://
|
|
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:
|
|
39
|
-
|
|
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
|
-
|
|
49
|
-
|
|
41
|
+
- name: Verify UMMAYA
|
|
42
|
+
id: ummaya
|
|
43
|
+
env:
|
|
44
|
+
FRIENDLI_TOKEN: \${{ secrets.FRIENDLI_TOKEN }}
|
|
45
|
+
run: ummaya --version
|
|
50
46
|
|
|
51
|
-
|
|
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:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
|
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:
|
|
86
|
-
CONSOLE_AUTHORIZE_URL:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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://
|
|
1
|
+
export const PRODUCT_URL = 'https://ummaya-docs.pages.dev/'
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
export const CLAUDE_AI_BASE_URL = 'https://
|
|
5
|
-
export const CLAUDE_AI_STAGING_BASE_URL = 'https://
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
138
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
'
|
|
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
|
|
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
|
|
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 =
|
|
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,
|
|
@@ -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
|
-
|
|
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
|
|
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 '
|
|
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 '
|
|
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
|