cleanup: remove dead USER_TYPE fast mode and setup branches (#315)
This commit is contained in:
40
src/setup.ts
40
src/setup.ts
@@ -6,7 +6,6 @@ import {
|
|||||||
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||||
logEvent,
|
logEvent,
|
||||||
} from 'src/services/analytics/index.js'
|
} from 'src/services/analytics/index.js'
|
||||||
import { isAntEmployee } from 'src/utils/buildConfig.js'
|
|
||||||
import { getCwd } from 'src/utils/cwd.js'
|
import { getCwd } from 'src/utils/cwd.js'
|
||||||
import { checkForReleaseNotes } from 'src/utils/releaseNotes.js'
|
import { checkForReleaseNotes } from 'src/utils/releaseNotes.js'
|
||||||
import { setCwd } from 'src/utils/Shell.js'
|
import { setCwd } from 'src/utils/Shell.js'
|
||||||
@@ -335,19 +334,6 @@ export async function setup(
|
|||||||
// overhead. NOT an early-return: the --dangerously-skip-permissions safety
|
// overhead. NOT an early-return: the --dangerously-skip-permissions safety
|
||||||
// gate, tengu_started beacon, and apiKeyHelper prefetch below must still run.
|
// gate, tengu_started beacon, and apiKeyHelper prefetch below must still run.
|
||||||
if (!isBareMode()) {
|
if (!isBareMode()) {
|
||||||
if (isAntEmployee()) {
|
|
||||||
// Prime repo classification cache for auto-undercover mode. Default is
|
|
||||||
// undercover ON until proven internal; if this resolves to internal, clear
|
|
||||||
// the prompt cache so the next turn picks up the OFF state.
|
|
||||||
void import('./utils/commitAttribution.js').then(async m => {
|
|
||||||
if (await m.isInternalModelRepo()) {
|
|
||||||
const { clearSystemPromptSections } = await import(
|
|
||||||
'./constants/systemPromptSections.js'
|
|
||||||
)
|
|
||||||
clearSystemPromptSections()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (feature('COMMIT_ATTRIBUTION')) {
|
if (feature('COMMIT_ATTRIBUTION')) {
|
||||||
// Dynamic import to enable dead code elimination (module contains excluded strings).
|
// Dynamic import to enable dead code elimination (module contains excluded strings).
|
||||||
// Defer to next tick so the git subprocess spawn runs after first render
|
// Defer to next tick so the git subprocess spawn runs after first render
|
||||||
@@ -414,32 +400,6 @@ export async function setup(
|
|||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
isAntEmployee() &&
|
|
||||||
// Skip for Desktop's local agent mode — same trust model as CCR/BYOC
|
|
||||||
// (trusted Anthropic-managed launcher intentionally pre-approving everything).
|
|
||||||
// Precedent: permissionSetup.ts:861, applySettingsChange.ts:55 (PR #19116)
|
|
||||||
process.env.CLAUDE_CODE_ENTRYPOINT !== 'local-agent' &&
|
|
||||||
// Same for CCD (Claude Code in Desktop) — apps#29127 passes the flag
|
|
||||||
// unconditionally to unlock mid-session bypass switching
|
|
||||||
process.env.CLAUDE_CODE_ENTRYPOINT !== 'claude-desktop'
|
|
||||||
) {
|
|
||||||
// Only await if permission mode is set to bypass
|
|
||||||
const [isDocker, hasInternet] = await Promise.all([
|
|
||||||
envDynamic.getIsDocker(),
|
|
||||||
env.hasInternetAccess(),
|
|
||||||
])
|
|
||||||
const isBubblewrap = envDynamic.getIsBubblewrapSandbox()
|
|
||||||
const isSandbox = process.env.IS_SANDBOX === '1'
|
|
||||||
const isSandboxed = isDocker || isBubblewrap || isSandbox
|
|
||||||
if (!isSandboxed || hasInternet) {
|
|
||||||
// biome-ignore lint/suspicious/noConsole:: intentional console output
|
|
||||||
console.error(
|
|
||||||
`--dangerously-skip-permissions can only be used in Docker/sandbox containers with no internet access but got Docker: ${isDocker}, Bubblewrap: ${isBubblewrap}, IS_SANDBOX: ${isSandbox}, hasInternet: ${hasInternet}`,
|
|
||||||
)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'test') {
|
if (process.env.NODE_ENV === 'test') {
|
||||||
|
|||||||
162
src/utils/fastMode.test.ts
Normal file
162
src/utils/fastMode.test.ts
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
import { afterEach, describe, expect, mock, test } from 'bun:test'
|
||||||
|
|
||||||
|
const originalEnv = { ...process.env }
|
||||||
|
|
||||||
|
async function importFreshFastModeModule() {
|
||||||
|
return import(`./fastMode.ts?ts=${Date.now()}-${Math.random()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function installCommonMocks(options?: {
|
||||||
|
cachedEnabled?: boolean
|
||||||
|
apiKey?: string | null
|
||||||
|
oauthToken?: string | null
|
||||||
|
hasProfileScope?: boolean
|
||||||
|
axiosReject?: boolean
|
||||||
|
}) {
|
||||||
|
mock.module('axios', () => ({
|
||||||
|
default: {
|
||||||
|
get: options?.axiosReject
|
||||||
|
? async () => {
|
||||||
|
throw new Error('network fail')
|
||||||
|
}
|
||||||
|
: async () => ({ data: { enabled: false, disabled_reason: 'preference' } }),
|
||||||
|
isAxiosError: () => false,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('src/constants/oauth.js', () => ({
|
||||||
|
getOauthConfig: () => ({ BASE_API_URL: 'https://api.anthropic.com' }),
|
||||||
|
OAUTH_BETA_HEADER: 'test-beta',
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('src/services/analytics/growthbook.js', () => ({
|
||||||
|
getFeatureValue_CACHED_MAY_BE_STALE: (_name: string, defaultValue: unknown) =>
|
||||||
|
defaultValue,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('../bootstrap/state.js', () => ({
|
||||||
|
getIsNonInteractiveSession: () => false,
|
||||||
|
getKairosActive: () => false,
|
||||||
|
preferThirdPartyAuthentication: () => false,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('../services/analytics/index.js', () => ({
|
||||||
|
logEvent: () => {},
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./auth.js', () => ({
|
||||||
|
getAnthropicApiKey: () => options?.apiKey ?? null,
|
||||||
|
getClaudeAIOAuthTokens: () =>
|
||||||
|
options?.oauthToken ? { accessToken: options.oauthToken } : null,
|
||||||
|
handleOAuth401Error: async () => {},
|
||||||
|
hasProfileScope: () => options?.hasProfileScope ?? false,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./bundledMode.js', () => ({
|
||||||
|
isInBundledMode: () => true,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./config.js', () => ({
|
||||||
|
getGlobalConfig: () => ({
|
||||||
|
penguinModeOrgEnabled: options?.cachedEnabled === true,
|
||||||
|
}),
|
||||||
|
saveGlobalConfig: (updater: (current: Record<string, unknown>) => Record<string, unknown>) =>
|
||||||
|
updater({ penguinModeOrgEnabled: options?.cachedEnabled === true }),
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./debug.js', () => ({
|
||||||
|
logForDebugging: () => {},
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./envUtils.js', () => ({
|
||||||
|
isEnvTruthy: (value: string | undefined) =>
|
||||||
|
!!value && value !== '0' && value.toLowerCase() !== 'false',
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./model/model.js', () => ({
|
||||||
|
getDefaultMainLoopModelSetting: () => 'claude-sonnet-4-6',
|
||||||
|
isOpus1mMergeEnabled: () => false,
|
||||||
|
parseUserSpecifiedModel: (model: string) => model,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./model/providers.js', () => ({
|
||||||
|
getAPIProvider: () => 'firstParty',
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./privacyLevel.js', () => ({
|
||||||
|
isEssentialTrafficOnly: () => false,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./settings/settings.js', () => ({
|
||||||
|
getInitialSettings: () => ({ fastMode: true }),
|
||||||
|
getSettingsForSource: () => ({}),
|
||||||
|
updateSettingsForSource: () => {},
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module('./signal.js', () => ({
|
||||||
|
createSignal: () => {
|
||||||
|
const subscribe = () => () => {}
|
||||||
|
const emit = () => {}
|
||||||
|
return { subscribe, emit }
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
mock.restore()
|
||||||
|
process.env = { ...originalEnv }
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('fastMode ant-only fallback cleanup', () => {
|
||||||
|
test('resolveFastModeStatusFromCache does not force-enable from USER_TYPE=ant', async () => {
|
||||||
|
process.env.USER_TYPE = 'ant'
|
||||||
|
installCommonMocks({ cachedEnabled: false })
|
||||||
|
|
||||||
|
const {
|
||||||
|
resolveFastModeStatusFromCache,
|
||||||
|
getFastModeUnavailableReason,
|
||||||
|
} = await importFreshFastModeModule()
|
||||||
|
|
||||||
|
resolveFastModeStatusFromCache()
|
||||||
|
|
||||||
|
expect(getFastModeUnavailableReason()).toBe(
|
||||||
|
'Fast mode is currently unavailable',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('prefetchFastModeStatus without auth does not force-enable from USER_TYPE=ant', async () => {
|
||||||
|
process.env.USER_TYPE = 'ant'
|
||||||
|
installCommonMocks({ cachedEnabled: false, apiKey: null, oauthToken: null })
|
||||||
|
|
||||||
|
const {
|
||||||
|
prefetchFastModeStatus,
|
||||||
|
getFastModeUnavailableReason,
|
||||||
|
} = await importFreshFastModeModule()
|
||||||
|
|
||||||
|
await prefetchFastModeStatus()
|
||||||
|
|
||||||
|
expect(getFastModeUnavailableReason()).toBe(
|
||||||
|
'Fast mode has been disabled by your organization',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('prefetchFastModeStatus network failure does not force-enable from USER_TYPE=ant', async () => {
|
||||||
|
process.env.USER_TYPE = 'ant'
|
||||||
|
installCommonMocks({
|
||||||
|
cachedEnabled: false,
|
||||||
|
apiKey: 'test-key',
|
||||||
|
axiosReject: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
prefetchFastModeStatus,
|
||||||
|
getFastModeUnavailableReason,
|
||||||
|
} = await importFreshFastModeModule()
|
||||||
|
|
||||||
|
await prefetchFastModeStatus()
|
||||||
|
|
||||||
|
expect(getFastModeUnavailableReason()).toBe(
|
||||||
|
'Fast mode unavailable due to network connectivity issues',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -396,10 +396,9 @@ export function resolveFastModeStatusFromCache(): void {
|
|||||||
if (orgStatus.status !== 'pending') {
|
if (orgStatus.status !== 'pending') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const isAnt = process.env.USER_TYPE === 'ant'
|
|
||||||
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
||||||
orgStatus =
|
orgStatus =
|
||||||
isAnt || cachedEnabled
|
cachedEnabled
|
||||||
? { status: 'enabled' }
|
? { status: 'enabled' }
|
||||||
: { status: 'disabled', reason: 'unknown' }
|
: { status: 'disabled', reason: 'unknown' }
|
||||||
}
|
}
|
||||||
@@ -428,10 +427,9 @@ export async function prefetchFastModeStatus(): Promise<void> {
|
|||||||
const hasUsableOAuth =
|
const hasUsableOAuth =
|
||||||
getClaudeAIOAuthTokens()?.accessToken && hasProfileScope()
|
getClaudeAIOAuthTokens()?.accessToken && hasProfileScope()
|
||||||
if (!hasUsableOAuth && !apiKey) {
|
if (!hasUsableOAuth && !apiKey) {
|
||||||
const isAnt = process.env.USER_TYPE === 'ant'
|
|
||||||
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
||||||
orgStatus =
|
orgStatus =
|
||||||
isAnt || cachedEnabled
|
cachedEnabled
|
||||||
? { status: 'enabled' }
|
? { status: 'enabled' }
|
||||||
: { status: 'disabled', reason: 'preference' }
|
: { status: 'disabled', reason: 'preference' }
|
||||||
return
|
return
|
||||||
@@ -511,10 +509,9 @@ export async function prefetchFastModeStatus(): Promise<void> {
|
|||||||
// On failure: ants default to enabled (don't block internal users).
|
// On failure: ants default to enabled (don't block internal users).
|
||||||
// External users: fall back to the cached penguinModeOrgEnabled value;
|
// External users: fall back to the cached penguinModeOrgEnabled value;
|
||||||
// if no positive cache, disable with network_error reason.
|
// if no positive cache, disable with network_error reason.
|
||||||
const isAnt = process.env.USER_TYPE === 'ant'
|
|
||||||
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
||||||
orgStatus =
|
orgStatus =
|
||||||
isAnt || cachedEnabled
|
cachedEnabled
|
||||||
? { status: 'enabled' }
|
? { status: 'enabled' }
|
||||||
: { status: 'disabled', reason: 'network_error' }
|
: { status: 'disabled', reason: 'network_error' }
|
||||||
logForDebugging(
|
logForDebugging(
|
||||||
|
|||||||
Reference in New Issue
Block a user