ummaya 0.2.9 → 0.2.11
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/CheckExistingSecretStep.tsx +3 -3
- package/tui/src/commands/install-github-app/ExistingWorkflowStep.tsx +3 -3
- package/tui/src/commands/install-github-app/InstallAppStep.tsx +1 -1
- package/tui/src/commands/install-github-app/SuccessStep.tsx +2 -10
- package/tui/src/commands/install-github-app/install-github-app.tsx +21 -22
- package/tui/src/commands/install-github-app/setupGitHubActions.ts +21 -27
- 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 +3 -3
- package/tui/src/components/messages/AssistantTextMessage.tsx +1 -2
- package/tui/src/constants/github-app.ts +26 -38
- 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 -6
- 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
|
@@ -28,12 +28,12 @@ function isDevMode(): boolean {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Builds a deep link URL for
|
|
32
|
-
* Format:
|
|
33
|
-
* In dev mode:
|
|
31
|
+
* Builds a deep link URL for UMMAYA Desktop to resume a CLI session.
|
|
32
|
+
* Format: ummaya://resume?session={sessionId}&cwd={cwd}
|
|
33
|
+
* In dev mode: ummaya-dev://resume?session={sessionId}&cwd={cwd}
|
|
34
34
|
*/
|
|
35
35
|
function buildDesktopDeepLink(sessionId: string): string {
|
|
36
|
-
const protocol = isDevMode() ? '
|
|
36
|
+
const protocol = isDevMode() ? 'ummaya-dev' : 'ummaya'
|
|
37
37
|
const url = new URL(`${protocol}://resume`)
|
|
38
38
|
url.searchParams.set('session', sessionId)
|
|
39
39
|
url.searchParams.set('cwd', getCwd())
|
|
@@ -41,9 +41,9 @@ function buildDesktopDeepLink(sessionId: string): string {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* Check if
|
|
45
|
-
* On macOS, checks for /Applications/
|
|
46
|
-
* On Linux, checks if xdg-open can handle
|
|
44
|
+
* Check if UMMAYA Desktop app is installed.
|
|
45
|
+
* On macOS, checks for /Applications/UMMAYA.app.
|
|
46
|
+
* On Linux, checks if xdg-open can handle ummaya:// protocol.
|
|
47
47
|
* On Windows, checks if the protocol handler exists.
|
|
48
48
|
* In dev mode, always returns true (assumes dev Desktop is running).
|
|
49
49
|
*/
|
|
@@ -56,22 +56,22 @@ async function isDesktopInstalled(): Promise<boolean> {
|
|
|
56
56
|
const platform = process.platform
|
|
57
57
|
|
|
58
58
|
if (platform === 'darwin') {
|
|
59
|
-
// Check for
|
|
60
|
-
return pathExists('/Applications/
|
|
59
|
+
// Check for UMMAYA.app in /Applications
|
|
60
|
+
return pathExists('/Applications/UMMAYA.app')
|
|
61
61
|
} else if (platform === 'linux') {
|
|
62
|
-
// Check if xdg-mime can find a handler for
|
|
62
|
+
// Check if xdg-mime can find a handler for ummaya://
|
|
63
63
|
// Note: xdg-mime returns exit code 0 even with no handler, so check stdout too
|
|
64
64
|
const { code, stdout } = await execFileNoThrow('xdg-mime', [
|
|
65
65
|
'query',
|
|
66
66
|
'default',
|
|
67
|
-
'x-scheme-handler/
|
|
67
|
+
'x-scheme-handler/ummaya',
|
|
68
68
|
])
|
|
69
69
|
return code === 0 && stdout.trim().length > 0
|
|
70
70
|
} else if (platform === 'win32') {
|
|
71
71
|
// On Windows, try to query the registry for the protocol handler
|
|
72
72
|
const { code } = await execFileNoThrow('reg', [
|
|
73
73
|
'query',
|
|
74
|
-
'HKEY_CLASSES_ROOT\\
|
|
74
|
+
'HKEY_CLASSES_ROOT\\ummaya',
|
|
75
75
|
'/ve',
|
|
76
76
|
])
|
|
77
77
|
return code === 0
|
|
@@ -81,7 +81,7 @@ async function isDesktopInstalled(): Promise<boolean> {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* Detect the installed
|
|
84
|
+
* Detect the installed UMMAYA Desktop version.
|
|
85
85
|
* On macOS, reads CFBundleShortVersionString from the app plist.
|
|
86
86
|
* On Windows, finds the highest app-X.Y.Z directory in the Squirrel install.
|
|
87
87
|
* Returns null if version cannot be determined.
|
|
@@ -92,7 +92,7 @@ async function getDesktopVersion(): Promise<string | null> {
|
|
|
92
92
|
if (platform === 'darwin') {
|
|
93
93
|
const { code, stdout } = await execFileNoThrow('defaults', [
|
|
94
94
|
'read',
|
|
95
|
-
'/Applications/
|
|
95
|
+
'/Applications/UMMAYA.app/Contents/Info.plist',
|
|
96
96
|
'CFBundleShortVersionString',
|
|
97
97
|
])
|
|
98
98
|
if (code !== 0) {
|
|
@@ -105,7 +105,7 @@ async function getDesktopVersion(): Promise<string | null> {
|
|
|
105
105
|
if (!localAppData) {
|
|
106
106
|
return null
|
|
107
107
|
}
|
|
108
|
-
const installDir = join(localAppData, '
|
|
108
|
+
const installDir = join(localAppData, 'UMMAYA')
|
|
109
109
|
try {
|
|
110
110
|
const entries = await readdir(installDir)
|
|
111
111
|
const versions = entries
|
|
@@ -200,7 +200,7 @@ async function openDeepLink(deepLinkUrl: string): Promise<boolean> {
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
/**
|
|
203
|
-
* Build and open a deep link to resume the current session in
|
|
203
|
+
* Build and open a deep link to resume the current session in UMMAYA Desktop.
|
|
204
204
|
* Returns an object with success status and any error message.
|
|
205
205
|
*/
|
|
206
206
|
export async function openCurrentSessionInDesktop(): Promise<{
|
|
@@ -216,7 +216,7 @@ export async function openCurrentSessionInDesktop(): Promise<{
|
|
|
216
216
|
return {
|
|
217
217
|
success: false,
|
|
218
218
|
error:
|
|
219
|
-
'
|
|
219
|
+
'UMMAYA Desktop is not installed. See https://ummaya-docs.pages.dev/ for setup instructions.',
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
|
|
@@ -227,7 +227,7 @@ export async function openCurrentSessionInDesktop(): Promise<{
|
|
|
227
227
|
if (!opened) {
|
|
228
228
|
return {
|
|
229
229
|
success: false,
|
|
230
|
-
error: 'Failed to open
|
|
230
|
+
error: 'Failed to open UMMAYA Desktop. Please try opening it manually.',
|
|
231
231
|
deepLinkUrl,
|
|
232
232
|
}
|
|
233
233
|
}
|
|
@@ -90,7 +90,7 @@ export function getFastModeUnavailableReason(): string | null {
|
|
|
90
90
|
!isInBundledMode() &&
|
|
91
91
|
getFeatureValue_CACHED_MAY_BE_STALE('tengu_marble_sandcastle', false)
|
|
92
92
|
) {
|
|
93
|
-
return 'Fast mode requires the native binary · Install from: https://
|
|
93
|
+
return 'Fast mode requires the native UMMAYA binary · Install from: https://ummaya-docs.pages.dev/'
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// Not available in the SDK unless explicitly opted in via --settings.
|
package/tui/src/utils/http.ts
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
handleOAuth401Error,
|
|
11
11
|
isClaudeAISubscriber,
|
|
12
12
|
} from './auth.js'
|
|
13
|
-
import { getClaudeCodeUserAgent } from './userAgent.js'
|
|
14
13
|
import { getWorkload } from './workloadContext.js'
|
|
15
14
|
|
|
16
15
|
// WARNING: We rely on `claude-cli` in the user agent for log filtering.
|
|
@@ -49,12 +48,8 @@ export function getMCPUserAgent(): string {
|
|
|
49
48
|
return `claude-code/${MACRO.VERSION}${suffix}`
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
// User-Agent for WebFetch requests to arbitrary sites. `Claude-User` is
|
|
53
|
-
// Anthropic's publicly documented agent for user-initiated fetches (what site
|
|
54
|
-
// operators match in robots.txt); the claude-code suffix lets them distinguish
|
|
55
|
-
// local CLI traffic from claude.ai server-side fetches.
|
|
56
51
|
export function getWebFetchUserAgent(): string {
|
|
57
|
-
return `
|
|
52
|
+
return `UMMAYA-User (ummaya/${MACRO.VERSION}; +https://ummaya-docs.pages.dev/)`
|
|
58
53
|
}
|
|
59
54
|
|
|
60
55
|
export type AuthHeaders = {
|
package/tui/src/utils/ide.ts
CHANGED
|
@@ -1419,9 +1419,11 @@ async function installFromArtifactory(command: string): Promise<string> {
|
|
|
1419
1419
|
throw new Error('No artifactory auth token found in ~/.npmrc')
|
|
1420
1420
|
}
|
|
1421
1421
|
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
'
|
|
1422
|
+
const vsixBaseUrl = process.env.UMMAYA_VSCODE_EXTENSION_BASE_URL?.trim()
|
|
1423
|
+
if (!vsixBaseUrl) {
|
|
1424
|
+
throw new Error('UMMAYA_VSCODE_EXTENSION_BASE_URL is not configured')
|
|
1425
|
+
}
|
|
1426
|
+
const versionUrl = `${vsixBaseUrl}/stable`
|
|
1425
1427
|
|
|
1426
1428
|
try {
|
|
1427
1429
|
const versionResponse = await axios.get(versionUrl, {
|
|
@@ -1435,8 +1437,7 @@ async function installFromArtifactory(command: string): Promise<string> {
|
|
|
1435
1437
|
throw new Error('No version found in artifactory response')
|
|
1436
1438
|
}
|
|
1437
1439
|
|
|
1438
|
-
|
|
1439
|
-
const vsixUrl = `https://artifactory.infra.ant.dev/artifactory/armorcode-claude-code-internal/claude-vscode-releases/${version}/claude-code.vsix`
|
|
1440
|
+
const vsixUrl = `${vsixBaseUrl}/${version}/ummaya.vsix`
|
|
1440
1441
|
const tempVsixPath = join(
|
|
1441
1442
|
os.tmpdir(),
|
|
1442
1443
|
`claude-code-${version}-${Date.now()}.vsix`,
|
|
@@ -17,22 +17,18 @@ export function getAPIProviderForStatsig(): AnalyticsMetadata_I_VERIFIED_THIS_IS
|
|
|
17
17
|
return getAPIProvider() as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
* Check if ANTHROPIC_BASE_URL is a first-party Anthropic API URL.
|
|
22
|
-
* Returns true if not set (default API) or points to api.anthropic.com
|
|
23
|
-
* (or api-staging.anthropic.com for ant users).
|
|
24
|
-
*/
|
|
20
|
+
/** Check if ANTHROPIC_BASE_URL points to an operator-approved first-party API. */
|
|
25
21
|
export function isFirstPartyAnthropicBaseUrl(): boolean {
|
|
26
22
|
const baseUrl = process.env.ANTHROPIC_BASE_URL
|
|
27
23
|
if (!baseUrl) {
|
|
28
|
-
return
|
|
24
|
+
return false
|
|
29
25
|
}
|
|
30
26
|
try {
|
|
31
27
|
const host = new URL(baseUrl).host
|
|
32
|
-
const allowedHosts =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
const allowedHosts = (process.env.UMMAYA_FIRST_PARTY_API_HOSTS ?? '')
|
|
29
|
+
.split(',')
|
|
30
|
+
.map(value => value.trim())
|
|
31
|
+
.filter(Boolean)
|
|
36
32
|
return allowedHosts.includes(host)
|
|
37
33
|
} catch {
|
|
38
34
|
return false
|
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
type ModelShortName,
|
|
24
24
|
} from './model/model.js'
|
|
25
25
|
|
|
26
|
-
// @see https://platform.claude.com/docs/en/about-claude/pricing
|
|
27
26
|
export type ModelCosts = {
|
|
28
27
|
inputTokens: number
|
|
29
28
|
outputTokens: number
|
|
@@ -99,7 +98,6 @@ export function getOpus46CostTier(fastMode: boolean): ModelCosts {
|
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
// @[MODEL LAUNCH]: Add a pricing entry for the new model below.
|
|
102
|
-
// Costs from https://platform.claude.com/docs/en/about-claude/pricing
|
|
103
101
|
// Web search cost: $10 per 1000 requests = $0.01 per request
|
|
104
102
|
export const MODEL_COSTS: Record<ModelShortName, ModelCosts> = {
|
|
105
103
|
[firstPartyNameToCanonical(CLAUDE_3_5_HAIKU_CONFIG.firstParty)]:
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Download functionality for native installer
|
|
3
|
-
*
|
|
4
|
-
* Handles downloading Claude binaries from various sources:
|
|
5
|
-
* - Artifactory NPM packages
|
|
6
|
-
* - GCS bucket
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { feature } from 'bun:bundle'
|
|
10
2
|
import axios from 'axios'
|
|
11
3
|
import { createHash } from 'crypto'
|
|
@@ -23,9 +15,10 @@ import { jsonStringify, writeFileSync_DEPRECATED } from '../slowOperations.js'
|
|
|
23
15
|
import { getBinaryName, getPlatform } from './installer.js'
|
|
24
16
|
|
|
25
17
|
const GCS_BUCKET_URL =
|
|
26
|
-
|
|
18
|
+
process.env.UMMAYA_NATIVE_DOWNLOAD_BASE_URL?.trim()
|
|
27
19
|
export const ARTIFACTORY_REGISTRY_URL =
|
|
28
|
-
|
|
20
|
+
process.env.UMMAYA_NATIVE_NPM_REGISTRY_URL?.trim() ??
|
|
21
|
+
'https://registry.npmjs.org/'
|
|
29
22
|
|
|
30
23
|
export async function getLatestVersionFromArtifactory(
|
|
31
24
|
tag: string = 'latest',
|
|
@@ -144,7 +137,9 @@ export async function getLatestVersion(
|
|
|
144
137
|
return getLatestVersionFromArtifactory(npmTag)
|
|
145
138
|
}
|
|
146
139
|
|
|
147
|
-
|
|
140
|
+
if (!GCS_BUCKET_URL) {
|
|
141
|
+
throw new Error('UMMAYA_NATIVE_DOWNLOAD_BASE_URL is not configured')
|
|
142
|
+
}
|
|
148
143
|
return getLatestVersionFromBinaryRepo(channel, GCS_BUCKET_URL)
|
|
149
144
|
}
|
|
150
145
|
|
|
@@ -488,11 +483,12 @@ export async function downloadVersion(
|
|
|
488
483
|
version: string,
|
|
489
484
|
stagingPath: string,
|
|
490
485
|
): Promise<'npm' | 'binary'> {
|
|
491
|
-
// Test-fixture versions route to the private sentinel bucket. DCE'd in all
|
|
492
|
-
// shipped builds — the string 'claude-code-ci-sentinel' and the gcloud call
|
|
493
|
-
// never exist in compiled binaries. Same gcloud-token pattern as
|
|
494
|
-
// remoteSkillLoader.ts:175-195.
|
|
495
486
|
if (feature('ALLOW_TEST_VERSIONS') && /^99\.99\./.test(version)) {
|
|
487
|
+
const testDownloadBaseUrl =
|
|
488
|
+
process.env.UMMAYA_NATIVE_TEST_DOWNLOAD_BASE_URL?.trim()
|
|
489
|
+
if (!testDownloadBaseUrl) {
|
|
490
|
+
throw new Error('UMMAYA_NATIVE_TEST_DOWNLOAD_BASE_URL is not configured')
|
|
491
|
+
}
|
|
496
492
|
const { stdout } = await execFileNoThrowWithCwd('gcloud', [
|
|
497
493
|
'auth',
|
|
498
494
|
'print-access-token',
|
|
@@ -500,7 +496,7 @@ export async function downloadVersion(
|
|
|
500
496
|
await downloadVersionFromBinaryRepo(
|
|
501
497
|
version,
|
|
502
498
|
stagingPath,
|
|
503
|
-
|
|
499
|
+
testDownloadBaseUrl,
|
|
504
500
|
{ headers: { Authorization: `Bearer ${stdout.trim()}` } },
|
|
505
501
|
)
|
|
506
502
|
return 'binary'
|
|
@@ -512,7 +508,9 @@ export async function downloadVersion(
|
|
|
512
508
|
return 'npm'
|
|
513
509
|
}
|
|
514
510
|
|
|
515
|
-
|
|
511
|
+
if (!GCS_BUCKET_URL) {
|
|
512
|
+
throw new Error('UMMAYA_NATIVE_DOWNLOAD_BASE_URL is not configured')
|
|
513
|
+
}
|
|
516
514
|
await downloadVersionFromBinaryRepo(version, stagingPath, GCS_BUCKET_URL)
|
|
517
515
|
return 'binary'
|
|
518
516
|
}
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin install counts data layer
|
|
3
|
-
*
|
|
4
|
-
* This module fetches and caches plugin install counts from the official
|
|
5
|
-
* Claude plugins statistics repository. The cache is refreshed if older
|
|
6
|
-
* than 24 hours.
|
|
7
|
-
*
|
|
8
|
-
* Cache location: ~/.claude/plugins/install-counts-cache.json
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
1
|
import axios from 'axios'
|
|
12
2
|
import { randomBytes } from 'crypto'
|
|
13
3
|
import { readFile, rename, unlink, writeFile } from 'fs/promises'
|
|
@@ -23,7 +13,7 @@ import { getPluginsDirectory } from './pluginDirectories.js'
|
|
|
23
13
|
const INSTALL_COUNTS_CACHE_VERSION = 1
|
|
24
14
|
const INSTALL_COUNTS_CACHE_FILENAME = 'install-counts-cache.json'
|
|
25
15
|
const INSTALL_COUNTS_URL =
|
|
26
|
-
|
|
16
|
+
process.env.UMMAYA_PLUGIN_INSTALL_COUNTS_URL?.trim()
|
|
27
17
|
const CACHE_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours in milliseconds
|
|
28
18
|
|
|
29
19
|
/**
|
|
@@ -184,6 +174,9 @@ async function saveInstallCountsCache(
|
|
|
184
174
|
async function fetchInstallCountsFromGitHub(): Promise<
|
|
185
175
|
Array<{ plugin: string; unique_installs: number }>
|
|
186
176
|
> {
|
|
177
|
+
if (!INSTALL_COUNTS_URL) {
|
|
178
|
+
return []
|
|
179
|
+
}
|
|
187
180
|
logForDebugging(`Fetching install counts from ${INSTALL_COUNTS_URL}`)
|
|
188
181
|
|
|
189
182
|
const started = performance.now()
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* inc-5046: fetch the official marketplace from a GCS mirror instead of
|
|
3
|
-
* git-cloning GitHub on every startup.
|
|
4
|
-
*
|
|
5
|
-
* Backend (anthropic#317037) publishes a marketplace-only zip alongside the
|
|
6
|
-
* titanium squashfs, keyed by base repo SHA. This module fetches the `latest`
|
|
7
|
-
* pointer, compares against a local sentinel, and downloads+extracts the zip
|
|
8
|
-
* when there's a new SHA. Callers decide fallback behavior on failure.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
1
|
import axios from 'axios'
|
|
12
2
|
import { chmod, mkdir, readFile, rename, rm, writeFile } from 'fs/promises'
|
|
13
3
|
import { dirname, join, resolve, sep } from 'path'
|
|
@@ -20,13 +10,7 @@ import { errorMessage, getErrnoCode } from '../errors.js'
|
|
|
20
10
|
|
|
21
11
|
type SafeString = AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
|
|
22
12
|
|
|
23
|
-
|
|
24
|
-
// binary ships from — nativeInstaller/download.ts:24 uses the raw GCS URL).
|
|
25
|
-
// `{sha}.zip` is content-addressed so CDN can cache it indefinitely;
|
|
26
|
-
// `latest` has Cache-Control: max-age=300 so CDN staleness is bounded.
|
|
27
|
-
// Backend (anthropic#317037) populates this prefix.
|
|
28
|
-
const GCS_BASE =
|
|
29
|
-
'https://downloads.claude.ai/claude-code-releases/plugins/claude-plugins-official'
|
|
13
|
+
const GCS_BASE = process.env.UMMAYA_OFFICIAL_MARKETPLACE_BASE_URL?.trim()
|
|
30
14
|
|
|
31
15
|
// Zip arc paths are seed-dir-relative (marketplaces/claude-plugins-official/…)
|
|
32
16
|
// so the titanium seed machinery can use the same zip. Strip this prefix when
|
|
@@ -48,6 +32,9 @@ export async function fetchOfficialMarketplaceFromGcs(
|
|
|
48
32
|
installLocation: string,
|
|
49
33
|
marketplacesCacheDir: string,
|
|
50
34
|
): Promise<string | null> {
|
|
35
|
+
if (!GCS_BASE) {
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
51
38
|
// Defense in depth: this function does `rm(installLocation, {recursive})`
|
|
52
39
|
// during the atomic swap. A corrupted known_marketplaces.json (gh-32793 —
|
|
53
40
|
// Windows path read on WSL, literal tilde, manual edit) could point at the
|
|
@@ -158,7 +145,7 @@ export async function fetchOfficialMarketplaceFromGcs(
|
|
|
158
145
|
// values below are static enums or a git SHA — not code/filepaths/PII.
|
|
159
146
|
logEvent('tengu_plugin_remote_fetch', {
|
|
160
147
|
source: 'marketplace_gcs' as SafeString,
|
|
161
|
-
host:
|
|
148
|
+
host: new URL(GCS_BASE).host as SafeString,
|
|
162
149
|
is_official: true,
|
|
163
150
|
outcome: outcome as SafeString,
|
|
164
151
|
duration_ms: Math.round(performance.now() - start),
|
|
@@ -26,9 +26,9 @@ const MAX_RELEASE_NOTES_SHOWN = 5
|
|
|
26
26
|
* 3. Next time the user starts Claude, the cached changelog is available immediately
|
|
27
27
|
*/
|
|
28
28
|
export const CHANGELOG_URL =
|
|
29
|
-
'https://github.com/
|
|
29
|
+
'https://github.com/umyunsang/UMMAYA/blob/main/CHANGELOG.md'
|
|
30
30
|
const RAW_CHANGELOG_URL =
|
|
31
|
-
'https://raw.githubusercontent.com/
|
|
31
|
+
'https://raw.githubusercontent.com/umyunsang/UMMAYA/refs/heads/main/CHANGELOG.md'
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Get the path for the cached changelog file.
|
|
@@ -887,7 +887,7 @@ export const SettingsSchema = lazySchema(() =>
|
|
|
887
887
|
.string()
|
|
888
888
|
.optional()
|
|
889
889
|
.describe(
|
|
890
|
-
'Display name for the assistant, shown in the
|
|
890
|
+
'Display name for the assistant, shown in the UMMAYA remote session list',
|
|
891
891
|
),
|
|
892
892
|
}
|
|
893
893
|
: {}),
|
|
@@ -125,13 +125,13 @@ const bothAuthMethodsNotice: StatusNoticeDefinition = {
|
|
|
125
125
|
<Box flexDirection="column" marginLeft={3}>
|
|
126
126
|
<Text color="warning">
|
|
127
127
|
· Trying to use{' '}
|
|
128
|
-
{authTokenInfo.source === 'claude.ai' ? '
|
|
128
|
+
{authTokenInfo.source === 'claude.ai' ? 'UMMAYA remote auth' : authTokenInfo.source}
|
|
129
129
|
?{' '}
|
|
130
|
-
{apiKeySource === 'ANTHROPIC_API_KEY' ? 'Unset the ANTHROPIC_API_KEY environment variable, or
|
|
130
|
+
{apiKeySource === 'ANTHROPIC_API_KEY' ? 'Unset the ANTHROPIC_API_KEY environment variable, or run ummaya /logout then say "No" to the API key approval before login.' : apiKeySource === 'apiKeyHelper' ? 'Unset the apiKeyHelper setting.' : 'ummaya /logout'}
|
|
131
131
|
</Text>
|
|
132
132
|
<Text color="warning">
|
|
133
133
|
· Trying to use {apiKeySource}?{' '}
|
|
134
|
-
{authTokenInfo.source === 'claude.ai' ? '
|
|
134
|
+
{authTokenInfo.source === 'claude.ai' ? 'ummaya /logout to sign out of UMMAYA remote auth.' : `Unset the ${authTokenInfo.source} environment variable.`}
|
|
135
135
|
</Text>
|
|
136
136
|
</Box>
|
|
137
137
|
</Box>;
|
|
@@ -37,25 +37,26 @@ type InternalMetricsPayload = {
|
|
|
37
37
|
metrics: Metric[]
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function getMetricsExportEndpoint(): string | undefined {
|
|
41
|
+
const baseUrl =
|
|
42
|
+
process.env.UMMAYA_METRICS_BASE_URL ??
|
|
43
|
+
(process.env.USER_TYPE === 'ant'
|
|
44
|
+
? process.env.ANT_CLAUDE_CODE_METRICS_ENDPOINT
|
|
45
|
+
: undefined)
|
|
46
|
+
const trimmed = baseUrl?.trim()
|
|
47
|
+
return trimmed
|
|
48
|
+
? `${trimmed.replace(/\/$/, '')}/api/claude_code/metrics`
|
|
49
|
+
: undefined
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
export class BigQueryMetricsExporter implements PushMetricExporter {
|
|
41
|
-
private readonly endpoint: string
|
|
53
|
+
private readonly endpoint: string | undefined
|
|
42
54
|
private readonly timeout: number
|
|
43
55
|
private pendingExports: Promise<void>[] = []
|
|
44
56
|
private isShutdown = false
|
|
45
57
|
|
|
46
58
|
constructor(options: { timeout?: number } = {}) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
process.env.USER_TYPE === 'ant' &&
|
|
51
|
-
process.env.ANT_CLAUDE_CODE_METRICS_ENDPOINT
|
|
52
|
-
) {
|
|
53
|
-
this.endpoint =
|
|
54
|
-
process.env.ANT_CLAUDE_CODE_METRICS_ENDPOINT +
|
|
55
|
-
'/api/claude_code/metrics'
|
|
56
|
-
} else {
|
|
57
|
-
this.endpoint = defaultEndpoint
|
|
58
|
-
}
|
|
59
|
+
this.endpoint = getMetricsExportEndpoint()
|
|
59
60
|
|
|
60
61
|
this.timeout = options.timeout || 5000
|
|
61
62
|
}
|
|
@@ -101,6 +102,12 @@ export class BigQueryMetricsExporter implements PushMetricExporter {
|
|
|
101
102
|
return
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
if (!this.endpoint) {
|
|
106
|
+
logForDebugging('BigQuery metrics export: endpoint not configured')
|
|
107
|
+
resultCallback({ code: ExportResultCode.SUCCESS })
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
104
111
|
// Check organization-level metrics opt-out
|
|
105
112
|
const metricsStatus = await checkMetricsEnabled()
|
|
106
113
|
if (!metricsStatus.enabled) {
|