init claude-code
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { logEvent } from 'src/services/analytics/index.js'
|
||||
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
|
||||
import { logError } from '../utils/log.js'
|
||||
import {
|
||||
getSettingsForSource,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
/**
|
||||
* Migration: Move user-set autoUpdates preference to settings.json env var
|
||||
* Only migrates if user explicitly disabled auto-updates (not for protection)
|
||||
* This preserves user intent while allowing native installations to auto-update
|
||||
*/
|
||||
export function migrateAutoUpdatesToSettings(): void {
|
||||
const globalConfig = getGlobalConfig()
|
||||
|
||||
// Only migrate if autoUpdates was explicitly set to false by user preference
|
||||
// (not automatically for native protection)
|
||||
if (
|
||||
globalConfig.autoUpdates !== false ||
|
||||
globalConfig.autoUpdatesProtectedForNative === true
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const userSettings = getSettingsForSource('userSettings') || {}
|
||||
|
||||
// Always set DISABLE_AUTOUPDATER to preserve user intent
|
||||
// We need to overwrite even if it exists, to ensure the migration is complete
|
||||
updateSettingsForSource('userSettings', {
|
||||
...userSettings,
|
||||
env: {
|
||||
...userSettings.env,
|
||||
DISABLE_AUTOUPDATER: '1',
|
||||
},
|
||||
})
|
||||
|
||||
logEvent('tengu_migrate_autoupdates_to_settings', {
|
||||
was_user_preference: true,
|
||||
already_had_env_var: !!userSettings.env?.DISABLE_AUTOUPDATER,
|
||||
})
|
||||
|
||||
// explicitly set, so this takes effect immediately
|
||||
process.env.DISABLE_AUTOUPDATER = '1'
|
||||
|
||||
// Remove autoUpdates from global config after successful migration
|
||||
saveGlobalConfig(current => {
|
||||
const {
|
||||
autoUpdates: _,
|
||||
autoUpdatesProtectedForNative: __,
|
||||
...updatedConfig
|
||||
} = current
|
||||
return updatedConfig
|
||||
})
|
||||
} catch (error) {
|
||||
logError(new Error(`Failed to migrate auto-updates: ${error}`))
|
||||
logEvent('tengu_migrate_autoupdates_error', {
|
||||
has_error: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { logEvent } from 'src/services/analytics/index.js'
|
||||
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
|
||||
import { logError } from '../utils/log.js'
|
||||
import {
|
||||
hasSkipDangerousModePermissionPrompt,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
|
||||
/**
|
||||
* Migration: Move bypassPermissionsModeAccepted from global config to settings.json
|
||||
* as skipDangerousModePermissionPrompt. This is a better home since settings.json
|
||||
* is the user-configurable settings file.
|
||||
*/
|
||||
export function migrateBypassPermissionsAcceptedToSettings(): void {
|
||||
const globalConfig = getGlobalConfig()
|
||||
|
||||
if (!globalConfig.bypassPermissionsModeAccepted) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
if (!hasSkipDangerousModePermissionPrompt()) {
|
||||
updateSettingsForSource('userSettings', {
|
||||
skipDangerousModePermissionPrompt: true,
|
||||
})
|
||||
}
|
||||
|
||||
logEvent('tengu_migrate_bypass_permissions_accepted', {})
|
||||
|
||||
saveGlobalConfig(current => {
|
||||
if (!('bypassPermissionsModeAccepted' in current)) return current
|
||||
const { bypassPermissionsModeAccepted: _, ...updatedConfig } = current
|
||||
return updatedConfig
|
||||
})
|
||||
} catch (error) {
|
||||
logError(
|
||||
new Error(`Failed to migrate bypass permissions accepted: ${error}`),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { logEvent } from 'src/services/analytics/index.js'
|
||||
import {
|
||||
getCurrentProjectConfig,
|
||||
saveCurrentProjectConfig,
|
||||
} from '../utils/config.js'
|
||||
import { logError } from '../utils/log.js'
|
||||
import {
|
||||
getSettingsForSource,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
|
||||
/**
|
||||
* Migration: Move MCP server approval fields from project config to local settings
|
||||
* This migrates both enableAllProjectMcpServers and enabledMcpjsonServers to the
|
||||
* settings system for better management and consistency.
|
||||
*/
|
||||
export function migrateEnableAllProjectMcpServersToSettings(): void {
|
||||
const projectConfig = getCurrentProjectConfig()
|
||||
|
||||
// Check if any field exists in project config
|
||||
const hasEnableAll = projectConfig.enableAllProjectMcpServers !== undefined
|
||||
const hasEnabledServers =
|
||||
projectConfig.enabledMcpjsonServers &&
|
||||
projectConfig.enabledMcpjsonServers.length > 0
|
||||
const hasDisabledServers =
|
||||
projectConfig.disabledMcpjsonServers &&
|
||||
projectConfig.disabledMcpjsonServers.length > 0
|
||||
|
||||
if (!hasEnableAll && !hasEnabledServers && !hasDisabledServers) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const existingSettings = getSettingsForSource('localSettings') || {}
|
||||
const updates: Partial<{
|
||||
enableAllProjectMcpServers: boolean
|
||||
enabledMcpjsonServers: string[]
|
||||
disabledMcpjsonServers: string[]
|
||||
}> = {}
|
||||
const fieldsToRemove: Array<
|
||||
| 'enableAllProjectMcpServers'
|
||||
| 'enabledMcpjsonServers'
|
||||
| 'disabledMcpjsonServers'
|
||||
> = []
|
||||
|
||||
// Migrate enableAllProjectMcpServers if it exists and hasn't been migrated
|
||||
if (
|
||||
hasEnableAll &&
|
||||
existingSettings.enableAllProjectMcpServers === undefined
|
||||
) {
|
||||
updates.enableAllProjectMcpServers =
|
||||
projectConfig.enableAllProjectMcpServers
|
||||
fieldsToRemove.push('enableAllProjectMcpServers')
|
||||
} else if (hasEnableAll) {
|
||||
// Already migrated, just mark for removal
|
||||
fieldsToRemove.push('enableAllProjectMcpServers')
|
||||
}
|
||||
|
||||
// Migrate enabledMcpjsonServers if it exists
|
||||
if (hasEnabledServers && projectConfig.enabledMcpjsonServers) {
|
||||
const existingEnabledServers =
|
||||
existingSettings.enabledMcpjsonServers || []
|
||||
// Merge the servers (avoiding duplicates)
|
||||
updates.enabledMcpjsonServers = [
|
||||
...new Set([
|
||||
...existingEnabledServers,
|
||||
...projectConfig.enabledMcpjsonServers,
|
||||
]),
|
||||
]
|
||||
fieldsToRemove.push('enabledMcpjsonServers')
|
||||
}
|
||||
|
||||
// Migrate disabledMcpjsonServers if it exists
|
||||
if (hasDisabledServers && projectConfig.disabledMcpjsonServers) {
|
||||
const existingDisabledServers =
|
||||
existingSettings.disabledMcpjsonServers || []
|
||||
// Merge the servers (avoiding duplicates)
|
||||
updates.disabledMcpjsonServers = [
|
||||
...new Set([
|
||||
...existingDisabledServers,
|
||||
...projectConfig.disabledMcpjsonServers,
|
||||
]),
|
||||
]
|
||||
fieldsToRemove.push('disabledMcpjsonServers')
|
||||
}
|
||||
|
||||
// Update settings if there are any updates
|
||||
if (Object.keys(updates).length > 0) {
|
||||
updateSettingsForSource('localSettings', updates)
|
||||
}
|
||||
|
||||
// Remove migrated fields from project config
|
||||
if (
|
||||
fieldsToRemove.includes('enableAllProjectMcpServers') ||
|
||||
fieldsToRemove.includes('enabledMcpjsonServers') ||
|
||||
fieldsToRemove.includes('disabledMcpjsonServers')
|
||||
) {
|
||||
saveCurrentProjectConfig(current => {
|
||||
const {
|
||||
enableAllProjectMcpServers: _enableAll,
|
||||
enabledMcpjsonServers: _enabledServers,
|
||||
disabledMcpjsonServers: _disabledServers,
|
||||
...configWithoutFields
|
||||
} = current
|
||||
return configWithoutFields
|
||||
})
|
||||
}
|
||||
|
||||
// Log the migration event
|
||||
logEvent('tengu_migrate_mcp_approval_fields_success', {
|
||||
migratedCount: fieldsToRemove.length,
|
||||
})
|
||||
} catch (e: unknown) {
|
||||
// Log migration failure but don't throw to avoid breaking startup
|
||||
logError(e)
|
||||
logEvent('tengu_migrate_mcp_approval_fields_error', {})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
getSettingsForSource,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
|
||||
/**
|
||||
* Migrate users on removed fennec model aliases to their new Opus 4.6 aliases.
|
||||
* - fennec-latest → opus
|
||||
* - fennec-latest[1m] → opus[1m]
|
||||
* - fennec-fast-latest → opus[1m] + fast mode
|
||||
* - opus-4-5-fast → opus + fast mode
|
||||
*
|
||||
* Only touches userSettings. Reading and writing the same source keeps this
|
||||
* idempotent without a completion flag. Fennec aliases in project/local/policy
|
||||
* settings are left alone — we can't rewrite those, and reading merged
|
||||
* settings here would cause infinite re-runs + silent global promotion.
|
||||
*/
|
||||
export function migrateFennecToOpus(): void {
|
||||
if (process.env.USER_TYPE !== 'ant') {
|
||||
return
|
||||
}
|
||||
|
||||
const settings = getSettingsForSource('userSettings')
|
||||
|
||||
const model = settings?.model
|
||||
if (typeof model === 'string') {
|
||||
if (model.startsWith('fennec-latest[1m]')) {
|
||||
updateSettingsForSource('userSettings', {
|
||||
model: 'opus[1m]',
|
||||
})
|
||||
} else if (model.startsWith('fennec-latest')) {
|
||||
updateSettingsForSource('userSettings', {
|
||||
model: 'opus',
|
||||
})
|
||||
} else if (
|
||||
model.startsWith('fennec-fast-latest') ||
|
||||
model.startsWith('opus-4-5-fast')
|
||||
) {
|
||||
updateSettingsForSource('userSettings', {
|
||||
model: 'opus[1m]',
|
||||
fastMode: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
logEvent,
|
||||
} from '../services/analytics/index.js'
|
||||
import { saveGlobalConfig } from '../utils/config.js'
|
||||
import { isLegacyModelRemapEnabled } from '../utils/model/model.js'
|
||||
import { getAPIProvider } from '../utils/model/providers.js'
|
||||
import {
|
||||
getSettingsForSource,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
|
||||
/**
|
||||
* Migrate first-party users off explicit Opus 4.0/4.1 model strings.
|
||||
*
|
||||
* The 'opus' alias already resolves to Opus 4.6 for 1P, so anyone still
|
||||
* on an explicit 4.0/4.1 string pinned it in settings before 4.5 launched.
|
||||
* parseUserSpecifiedModel now silently remaps these at runtime anyway —
|
||||
* this migration cleans up the settings file so /model shows the right
|
||||
* thing, and sets a timestamp so the REPL can show a one-time notification.
|
||||
*
|
||||
* Only touches userSettings. Legacy strings in project/local/policy settings
|
||||
* are left alone (we can't/shouldn't rewrite those) and are still remapped at
|
||||
* runtime by parseUserSpecifiedModel. Reading and writing the same source
|
||||
* keeps this idempotent without a completion flag, and avoids silently
|
||||
* promoting 'opus' to the global default for users who only pinned it in one
|
||||
* project.
|
||||
*/
|
||||
export function migrateLegacyOpusToCurrent(): void {
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isLegacyModelRemapEnabled()) {
|
||||
return
|
||||
}
|
||||
|
||||
const model = getSettingsForSource('userSettings')?.model
|
||||
if (
|
||||
model !== 'claude-opus-4-20250514' &&
|
||||
model !== 'claude-opus-4-1-20250805' &&
|
||||
model !== 'claude-opus-4-0' &&
|
||||
model !== 'claude-opus-4-1'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
updateSettingsForSource('userSettings', { model: 'opus' })
|
||||
saveGlobalConfig(current => ({
|
||||
...current,
|
||||
legacyOpusMigrationTimestamp: Date.now(),
|
||||
}))
|
||||
logEvent('tengu_legacy_opus_migration', {
|
||||
from_model:
|
||||
model as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { logEvent } from '../services/analytics/index.js'
|
||||
import {
|
||||
getDefaultMainLoopModelSetting,
|
||||
isOpus1mMergeEnabled,
|
||||
parseUserSpecifiedModel,
|
||||
} from '../utils/model/model.js'
|
||||
import {
|
||||
getSettingsForSource,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
|
||||
/**
|
||||
* Migrate users with 'opus' pinned in their settings to 'opus[1m]' when they
|
||||
* are eligible for the merged Opus 1M experience (Max/Team Premium on 1P).
|
||||
*
|
||||
* CLI invocations with --model opus are unaffected: that flag is a runtime
|
||||
* override and does not touch userSettings, so it continues to use plain Opus.
|
||||
*
|
||||
* Pro subscribers are skipped — they retain separate Opus and Opus 1M options.
|
||||
* 3P users are skipped — their model strings are full model IDs, not aliases.
|
||||
*
|
||||
* Idempotent: only writes if userSettings.model is exactly 'opus'.
|
||||
*/
|
||||
export function migrateOpusToOpus1m(): void {
|
||||
if (!isOpus1mMergeEnabled()) {
|
||||
return
|
||||
}
|
||||
|
||||
const model = getSettingsForSource('userSettings')?.model
|
||||
if (model !== 'opus') {
|
||||
return
|
||||
}
|
||||
|
||||
const migrated = 'opus[1m]'
|
||||
const modelToSet =
|
||||
parseUserSpecifiedModel(migrated) ===
|
||||
parseUserSpecifiedModel(getDefaultMainLoopModelSetting())
|
||||
? undefined
|
||||
: migrated
|
||||
updateSettingsForSource('userSettings', { model: modelToSet })
|
||||
|
||||
logEvent('tengu_opus_to_opus1m_migration', {})
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { saveGlobalConfig } from '../utils/config.js'
|
||||
|
||||
/**
|
||||
* Migrate the `replBridgeEnabled` config key to `remoteControlAtStartup`.
|
||||
*
|
||||
* The old key was an implementation detail that leaked into user-facing config.
|
||||
* This migration copies the value to the new key and removes the old one.
|
||||
* Idempotent — only acts when the old key exists and the new one doesn't.
|
||||
*/
|
||||
export function migrateReplBridgeEnabledToRemoteControlAtStartup(): void {
|
||||
saveGlobalConfig(prev => {
|
||||
// The old key is no longer in the GlobalConfig type, so access it via
|
||||
// an untyped cast. Only migrate if the old key exists and the new key
|
||||
// hasn't been set yet.
|
||||
const oldValue = (prev as Record<string, unknown>)['replBridgeEnabled']
|
||||
if (oldValue === undefined) return prev
|
||||
if (prev.remoteControlAtStartup !== undefined) return prev
|
||||
const next = { ...prev, remoteControlAtStartup: Boolean(oldValue) }
|
||||
delete (next as Record<string, unknown>)['replBridgeEnabled']
|
||||
return next
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
getMainLoopModelOverride,
|
||||
setMainLoopModelOverride,
|
||||
} from '../bootstrap/state.js'
|
||||
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
|
||||
import {
|
||||
getSettingsForSource,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
|
||||
/**
|
||||
* Migrate users who had "sonnet[1m]" saved to the explicit "sonnet-4-5-20250929[1m]".
|
||||
*
|
||||
* The "sonnet" alias now resolves to Sonnet 4.6, so users who previously set
|
||||
* "sonnet[1m]" (targeting Sonnet 4.5 with 1M context) need to be pinned to the
|
||||
* explicit version to preserve their intended model.
|
||||
*
|
||||
* This is needed because Sonnet 4.6 1M was offered to a different group of users than
|
||||
* Sonnet 4.5 1M, so we needed to pin existing sonnet[1m] users to Sonnet 4.5 1M.
|
||||
*
|
||||
* Reads from userSettings specifically (not merged settings) so we don't
|
||||
* promote a project-scoped "sonnet[1m]" to the global default. Runs once,
|
||||
* tracked by a completion flag in global config.
|
||||
*/
|
||||
export function migrateSonnet1mToSonnet45(): void {
|
||||
const config = getGlobalConfig()
|
||||
if (config.sonnet1m45MigrationComplete) {
|
||||
return
|
||||
}
|
||||
|
||||
const model = getSettingsForSource('userSettings')?.model
|
||||
if (model === 'sonnet[1m]') {
|
||||
updateSettingsForSource('userSettings', {
|
||||
model: 'sonnet-4-5-20250929[1m]',
|
||||
})
|
||||
}
|
||||
|
||||
// Also migrate the in-memory override if already set
|
||||
const override = getMainLoopModelOverride()
|
||||
if (override === 'sonnet[1m]') {
|
||||
setMainLoopModelOverride('sonnet-4-5-20250929[1m]')
|
||||
}
|
||||
|
||||
saveGlobalConfig(current => ({
|
||||
...current,
|
||||
sonnet1m45MigrationComplete: true,
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
logEvent,
|
||||
} from '../services/analytics/index.js'
|
||||
import {
|
||||
isMaxSubscriber,
|
||||
isProSubscriber,
|
||||
isTeamPremiumSubscriber,
|
||||
} from '../utils/auth.js'
|
||||
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
|
||||
import { getAPIProvider } from '../utils/model/providers.js'
|
||||
import {
|
||||
getSettingsForSource,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
|
||||
/**
|
||||
* Migrate Pro/Max/Team Premium first-party users off explicit Sonnet 4.5
|
||||
* model strings to the 'sonnet' alias (which now resolves to Sonnet 4.6).
|
||||
*
|
||||
* Users may have been pinned to explicit Sonnet 4.5 strings by:
|
||||
* - The earlier migrateSonnet1mToSonnet45 migration (sonnet[1m] → explicit 4.5[1m])
|
||||
* - Manually selecting it via /model
|
||||
*
|
||||
* Reads userSettings specifically (not merged) so we only migrate what /model
|
||||
* wrote — project/local pins are left alone.
|
||||
* Idempotent: only writes if userSettings.model matches a Sonnet 4.5 string.
|
||||
*/
|
||||
export function migrateSonnet45ToSonnet46(): void {
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isProSubscriber() && !isMaxSubscriber() && !isTeamPremiumSubscriber()) {
|
||||
return
|
||||
}
|
||||
|
||||
const model = getSettingsForSource('userSettings')?.model
|
||||
if (
|
||||
model !== 'claude-sonnet-4-5-20250929' &&
|
||||
model !== 'claude-sonnet-4-5-20250929[1m]' &&
|
||||
model !== 'sonnet-4-5-20250929' &&
|
||||
model !== 'sonnet-4-5-20250929[1m]'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const has1m = model.endsWith('[1m]')
|
||||
updateSettingsForSource('userSettings', {
|
||||
model: has1m ? 'sonnet[1m]' : 'sonnet',
|
||||
})
|
||||
|
||||
// Skip notification for brand-new users — they never experienced the old default
|
||||
const config = getGlobalConfig()
|
||||
if (config.numStartups > 1) {
|
||||
saveGlobalConfig(current => ({
|
||||
...current,
|
||||
sonnet45To46MigrationTimestamp: Date.now(),
|
||||
}))
|
||||
}
|
||||
|
||||
logEvent('tengu_sonnet45_to_46_migration', {
|
||||
from_model:
|
||||
model as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
has_1m: has1m,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { feature } from 'bun:bundle'
|
||||
import { logEvent } from 'src/services/analytics/index.js'
|
||||
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
|
||||
import { logError } from '../utils/log.js'
|
||||
import { getAutoModeEnabledState } from '../utils/permissions/permissionSetup.js'
|
||||
import {
|
||||
getSettingsForSource,
|
||||
updateSettingsForSource,
|
||||
} from '../utils/settings/settings.js'
|
||||
|
||||
/**
|
||||
* One-shot migration: clear skipAutoPermissionPrompt for users who accepted
|
||||
* the old 2-option AutoModeOptInDialog but don't have auto as their default.
|
||||
* Re-surfaces the dialog so they see the new "make it my default mode" option.
|
||||
* Guard lives in GlobalConfig (~/.claude.json), not settings.json, so it
|
||||
* survives settings resets and doesn't re-arm itself.
|
||||
*
|
||||
* Only runs when tengu_auto_mode_config.enabled === 'enabled'. For 'opt-in'
|
||||
* users, clearing skipAutoPermissionPrompt would remove auto from the carousel
|
||||
* (permissionSetup.ts:988) — the dialog would become unreachable and the
|
||||
* migration would defeat itself. In practice the ~40 target ants are all
|
||||
* 'enabled' (they reached the old dialog via bare Shift+Tab, which requires
|
||||
* 'enabled'), but the guard makes it safe regardless.
|
||||
*/
|
||||
export function resetAutoModeOptInForDefaultOffer(): void {
|
||||
if (feature('TRANSCRIPT_CLASSIFIER')) {
|
||||
const config = getGlobalConfig()
|
||||
if (config.hasResetAutoModeOptInForDefaultOffer) return
|
||||
if (getAutoModeEnabledState() !== 'enabled') return
|
||||
|
||||
try {
|
||||
const user = getSettingsForSource('userSettings')
|
||||
if (
|
||||
user?.skipAutoPermissionPrompt &&
|
||||
user?.permissions?.defaultMode !== 'auto'
|
||||
) {
|
||||
updateSettingsForSource('userSettings', {
|
||||
skipAutoPermissionPrompt: undefined,
|
||||
})
|
||||
logEvent('tengu_migrate_reset_auto_opt_in_for_default_offer', {})
|
||||
}
|
||||
|
||||
saveGlobalConfig(c => {
|
||||
if (c.hasResetAutoModeOptInForDefaultOffer) return c
|
||||
return { ...c, hasResetAutoModeOptInForDefaultOffer: true }
|
||||
})
|
||||
} catch (error) {
|
||||
logError(new Error(`Failed to reset auto mode opt-in: ${error}`))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { logEvent } from 'src/services/analytics/index.js'
|
||||
import { isProSubscriber } from '../utils/auth.js'
|
||||
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
|
||||
import { getAPIProvider } from '../utils/model/providers.js'
|
||||
import { getSettings_DEPRECATED } from '../utils/settings/settings.js'
|
||||
|
||||
export function resetProToOpusDefault(): void {
|
||||
const config = getGlobalConfig()
|
||||
|
||||
if (config.opusProMigrationComplete) {
|
||||
return
|
||||
}
|
||||
|
||||
const apiProvider = getAPIProvider()
|
||||
|
||||
// Pro users on firstParty get auto-migrated to Opus 4.5 default
|
||||
if (apiProvider !== 'firstParty' || !isProSubscriber()) {
|
||||
saveGlobalConfig(current => ({
|
||||
...current,
|
||||
opusProMigrationComplete: true,
|
||||
}))
|
||||
logEvent('tengu_reset_pro_to_opus_default', { skipped: true })
|
||||
return
|
||||
}
|
||||
|
||||
const settings = getSettings_DEPRECATED()
|
||||
|
||||
// Only show notification if user was on default (no custom model setting)
|
||||
if (settings?.model === undefined) {
|
||||
const opusProMigrationTimestamp = Date.now()
|
||||
saveGlobalConfig(current => ({
|
||||
...current,
|
||||
opusProMigrationComplete: true,
|
||||
opusProMigrationTimestamp,
|
||||
}))
|
||||
logEvent('tengu_reset_pro_to_opus_default', {
|
||||
skipped: false,
|
||||
had_custom_model: false,
|
||||
})
|
||||
} else {
|
||||
// User has a custom model setting, just mark migration complete
|
||||
saveGlobalConfig(current => ({
|
||||
...current,
|
||||
opusProMigrationComplete: true,
|
||||
}))
|
||||
logEvent('tengu_reset_pro_to_opus_default', {
|
||||
skipped: false,
|
||||
had_custom_model: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user