diff --git a/.github/scripts/check-lint-gate-freshness.mjs b/.github/scripts/check-lint-gate-freshness.mjs index 57a08045002..ea308422770 100644 --- a/.github/scripts/check-lint-gate-freshness.mjs +++ b/.github/scripts/check-lint-gate-freshness.mjs @@ -48,6 +48,7 @@ export const GATE_FILES = [ 'scripts/lint.js', 'eslint.config.js', 'eslint.legacy-filenames.mjs', + 'eslint.legacy-core-barrel-imports.mjs', '.prettierrc.json', '.prettierignore', '.github/workflows/ci.yml', diff --git a/.github/scripts/check-lint-gate-freshness.test.mjs b/.github/scripts/check-lint-gate-freshness.test.mjs index 86d06981a75..7303ff88908 100644 --- a/.github/scripts/check-lint-gate-freshness.test.mjs +++ b/.github/scripts/check-lint-gate-freshness.test.mjs @@ -50,6 +50,7 @@ test('pins the gate file list', () => { 'scripts/lint.js', 'eslint.config.js', 'eslint.legacy-filenames.mjs', + 'eslint.legacy-core-barrel-imports.mjs', '.prettierrc.json', '.prettierignore', '.github/workflows/ci.yml', diff --git a/.github/scripts/run-autofix-review-verification.sh b/.github/scripts/run-autofix-review-verification.sh index ea5c7804a37..e035b94e205 100755 --- a/.github/scripts/run-autofix-review-verification.sh +++ b/.github/scripts/run-autofix-review-verification.sh @@ -734,12 +734,12 @@ sensitive_class_of() { package-lock.json | npm-shrinkwrap.json | */package-lock.json | */npm-shrinkwrap.json | patches/*) echo 'supply-chain' ;; .gitattributes | */.gitattributes) echo 'measurement-config' ;; *) case "${f##*/}" in - eslint.config.* | eslint.legacy-filenames.mjs | vitest.config.* | tsconfig.json | tsconfig.*.json) + eslint.config.* | eslint.legacy-filenames.mjs | eslint.legacy-core-barrel-imports.mjs | vitest.config.* | tsconfig.json | tsconfig.*.json) # Workspace-root configs are machinery; a scaffold template deep in # a src tree is test/fixture data (same exemption manifests get). if at_workspace_root "${f}"; then case "${f##*/}" in - eslint.config.* | eslint.legacy-filenames.mjs) echo 'lint-config' ;; + eslint.config.* | eslint.legacy-filenames.mjs | eslint.legacy-core-barrel-imports.mjs) echo 'lint-config' ;; vitest.config.*) echo 'test-config' ;; *) echo 'ts-config' ;; esac diff --git a/.github/workflows/repo-hygiene.yml b/.github/workflows/repo-hygiene.yml index 1f4d97ca11d..143ad293420 100644 --- a/.github/workflows/repo-hygiene.yml +++ b/.github/workflows/repo-hygiene.yml @@ -431,6 +431,7 @@ jobs: "write_file(**/tsconfig.*.json)", "write_file(**/eslint.config.*)", "write_file(**/eslint.legacy-filenames.*)", + "write_file(**/eslint.legacy-core-barrel-imports.*)", "write_file(**/vitest.config.*)", "write_file(**/vite.config.*)", "write_file(**/node_modules/**)" diff --git a/AGENTS.md b/AGENTS.md index 342ab369e0f..6f88c6cec84 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -166,6 +166,7 @@ npm run preflight # Full check: clean → install → format → lint → build 2-space indent, 80-char width - **Linting**: No `any` types, consistent type imports, no relative imports between packages +- **Core imports in cli**: production code in `packages/cli/src` imports core values from the module that defines them (`@qwen-code/qwen-code-core/utils/debugLogger.js`), not the package root, which evaluates all of core in every test that reaches the file. Type-only imports are exempt. Files that predate the rule are allowlisted in `eslint.legacy-core-barrel-imports.mjs`; drop an entry when you move its file off the root, never add one. - **Tests**: Collocated with source (`file.test.ts` next to `file.ts`), vitest framework - **File naming**: `PascalCase.tsx` for React components, `kebab-case.ts` for diff --git a/eslint-rules/no-core-root-barrel-import.js b/eslint-rules/no-core-root-barrel-import.js index 54795e401fc..c58c3e6c4c8 100644 --- a/eslint-rules/no-core-root-barrel-import.js +++ b/eslint-rules/no-core-root-barrel-import.js @@ -30,7 +30,7 @@ function isCoreProductionFile(filename) { const CORE_PACKAGE_SPECIFIER = '@qwen-code/qwen-code-core'; // The package exports map ("./*", "./src/*", "./dist/*") also exposes the root // barrel through these self-reference subpaths. -const CORE_BARREL_SPECIFIERS = new Set([ +export const CORE_BARREL_SPECIFIERS = new Set([ CORE_PACKAGE_SPECIFIER, `${CORE_PACKAGE_SPECIFIER}/index.js`, `${CORE_PACKAGE_SPECIFIER}/src/index.js`, diff --git a/eslint.config.js b/eslint.config.js index 4f7edd2bcb2..faf422dfc20 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -13,10 +13,13 @@ import importPlugin from 'eslint-plugin-import'; import vitest from '@vitest/eslint-plugin'; import globals from 'globals'; import checkFile from 'eslint-plugin-check-file'; -import noCoreRootBarrelImport from './eslint-rules/no-core-root-barrel-import.js'; +import noCoreRootBarrelImport, { + CORE_BARREL_SPECIFIERS, +} from './eslint-rules/no-core-root-barrel-import.js'; import noUtilsUpwardImport from './eslint-rules/no-utils-upward-import.js'; import noCoreUtilsUpwardImport from './eslint-rules/no-core-utils-upward-import.js'; import { legacyFilenames } from './eslint.legacy-filenames.mjs'; +import { legacyCoreBarrelImports } from './eslint.legacy-core-barrel-imports.mjs'; import noConfigObjectCreate from './eslint-rules/no-config-object-create.js'; // General syntax restrictions applied to every TS/TSX source file. Hoisted so @@ -291,6 +294,33 @@ export default tseslint.config( 'architecture/no-core-utils-upward-import': 'error', }, }, + { + // Importing a value from core's package root evaluates all of core in + // every test whose import graph reaches the importing file, which is + // where most cli test time goes (#10908). Type-only imports are erased + // and stay allowed. Files that predate this rule are listed in + // eslint.legacy-core-barrel-imports.mjs; drop an entry when migrating it. + files: ['packages/cli/src/**/*.{ts,tsx}'], + ignores: [ + '**/*.{test,spec}.{ts,tsx}', + '**/__tests__/**', + '**/fixtures/**', + ...legacyCoreBarrelImports, + ], + rules: { + '@typescript-eslint/no-restricted-imports': [ + 'error', + { + paths: [...CORE_BARREL_SPECIFIERS].map((name) => ({ + name, + allowTypeImports: true, + message: + "Import from the core module that defines the symbol, e.g. '@qwen-code/qwen-code-core/utils/debugLogger.js'. The package root evaluates all of core in every test that reaches this file (#10908).", + })), + }, + ], + }, + }, { // no-restricted-imports only sees static import/export declarations, so a // dynamic `await import('../serve/...')` would slip past the #8084 guard diff --git a/eslint.legacy-core-barrel-imports.mjs b/eslint.legacy-core-barrel-imports.mjs new file mode 100644 index 00000000000..091d6cdd111 --- /dev/null +++ b/eslint.legacy-core-barrel-imports.mjs @@ -0,0 +1,383 @@ +/** + * cli production files that still import values from the core package root. + * + * Used by eslint.config.js to exempt these files from the rule that sends cli + * imports to the core module defining each symbol. The list only shrinks: + * remove an entry when its file moves off the package root, and never add one. + * + * See: https://github.com/QwenLM/qwen-code/issues/10908 + */ +export const legacyCoreBarrelImports = [ + 'packages/cli/src/acp-integration/acpAgent.ts', + 'packages/cli/src/acp-integration/active-work-reporter.ts', + 'packages/cli/src/acp-integration/authMethods.ts', + 'packages/cli/src/acp-integration/extension-skills.ts', + 'packages/cli/src/acp-integration/generation.ts', + 'packages/cli/src/acp-integration/live/capture-screen-context.ts', + 'packages/cli/src/acp-integration/live/live-speak-to-user.ts', + 'packages/cli/src/acp-integration/live/live-task-tools.ts', + 'packages/cli/src/acp-integration/model-configuration.ts', + 'packages/cli/src/acp-integration/runtimeOutputDirContext.ts', + 'packages/cli/src/acp-integration/service/filesystem.ts', + 'packages/cli/src/acp-integration/session-model-persistence.ts', + 'packages/cli/src/acp-integration/session/Session.ts', + 'packages/cli/src/acp-integration/session/SubAgentTracker.ts', + 'packages/cli/src/acp-integration/session/emitters/MessageEmitter.ts', + 'packages/cli/src/acp-integration/session/emitters/tool-call-emitter.ts', + 'packages/cli/src/acp-integration/session/history-replay-page.ts', + 'packages/cli/src/acp-integration/session/history-replayer.ts', + 'packages/cli/src/acp-integration/session/permissionUtils.ts', + 'packages/cli/src/acp-integration/session/recovered-goal-update.ts', + 'packages/cli/src/acp-integration/session/repeated-tool-failure-guard.ts', + 'packages/cli/src/acp-integration/session/rewrite/LlmRewriter.ts', + 'packages/cli/src/acp-integration/session/rewrite/MessageRewriteMiddleware.ts', + 'packages/cli/src/acp-integration/session/tasksSnapshot.ts', + 'packages/cli/src/acp-integration/session/tool-call-preparation-tracker.ts', + 'packages/cli/src/acp-integration/skill-management.ts', + 'packages/cli/src/acp-integration/skill-source-download.ts', + 'packages/cli/src/commands/channel/config-utils.ts', + 'packages/cli/src/commands/channel/daemon-worker.ts', + 'packages/cli/src/commands/channel/loop-runtime.ts', + 'packages/cli/src/commands/channel/observed-contact-store.ts', + 'packages/cli/src/commands/channel/pidfile.ts', + 'packages/cli/src/commands/channel/proxy.ts', + 'packages/cli/src/commands/channel/runtime.ts', + 'packages/cli/src/commands/channel/start.ts', + 'packages/cli/src/commands/channel/status.ts', + 'packages/cli/src/commands/channel/stop.ts', + 'packages/cli/src/commands/extensions/enable.ts', + 'packages/cli/src/commands/extensions/install.ts', + 'packages/cli/src/commands/extensions/link.ts', + 'packages/cli/src/commands/extensions/new.ts', + 'packages/cli/src/commands/extensions/settings.ts', + 'packages/cli/src/commands/extensions/sources.ts', + 'packages/cli/src/commands/extensions/uninstall.ts', + 'packages/cli/src/commands/extensions/update.ts', + 'packages/cli/src/commands/extensions/utils.ts', + 'packages/cli/src/commands/hooks.tsx', + 'packages/cli/src/commands/mcp/approve.ts', + 'packages/cli/src/commands/mcp/list.ts', + 'packages/cli/src/commands/mcp/reconnect.ts', + 'packages/cli/src/commands/mcp/remove.ts', + 'packages/cli/src/commands/review/agent-prompt.ts', + 'packages/cli/src/commands/review/comment-status.ts', + 'packages/cli/src/commands/review/cost-ledger.ts', + 'packages/cli/src/commands/review/findings.ts', + 'packages/cli/src/commands/review/lib/deadline.ts', + 'packages/cli/src/commands/review/lib/diff-plan.ts', + 'packages/cli/src/commands/review/lib/inline-counts.ts', + 'packages/cli/src/commands/review/lib/paths.ts', + 'packages/cli/src/commands/review/lib/run-ledger.ts', + 'packages/cli/src/commands/review/lib/transcripts.ts', + 'packages/cli/src/commands/review/lib/worktree.ts', + 'packages/cli/src/commands/review/parse-args.ts', + 'packages/cli/src/commands/review/pr-context.ts', + 'packages/cli/src/commands/review/recover-findings.ts', + 'packages/cli/src/commands/review/repo-context.ts', + 'packages/cli/src/commands/review/run.ts', + 'packages/cli/src/commands/review/save-artifact.ts', + 'packages/cli/src/commands/review/submit.ts', + 'packages/cli/src/commands/review/test-plan.ts', + 'packages/cli/src/commands/review/workflow-script.ts', + 'packages/cli/src/commands/serve.ts', + 'packages/cli/src/commands/sessions/common.ts', + 'packages/cli/src/commands/sessions/controllers.ts', + 'packages/cli/src/commands/sessions/ps.ts', + 'packages/cli/src/config/auth.ts', + 'packages/cli/src/config/claudeMcpImport.ts', + 'packages/cli/src/config/config.ts', + 'packages/cli/src/config/daemon-trust-policy-monitor.ts', + 'packages/cli/src/config/daemon-trust-policy.ts', + 'packages/cli/src/config/environment.ts', + 'packages/cli/src/config/extension-runtime-reload.ts', + 'packages/cli/src/config/hot-reload.ts', + 'packages/cli/src/config/lsp-config-watcher.ts', + 'packages/cli/src/config/mcpApprovals.ts', + 'packages/cli/src/config/mcpJson.ts', + 'packages/cli/src/config/migration/scheduler.ts', + 'packages/cli/src/config/permission-settings.ts', + 'packages/cli/src/config/sandboxConfig.ts', + 'packages/cli/src/config/settings-cache.ts', + 'packages/cli/src/config/settings.ts', + 'packages/cli/src/config/settingsSchema.ts', + 'packages/cli/src/config/settingsWatcher.ts', + 'packages/cli/src/config/skill-settings.ts', + 'packages/cli/src/config/trustedFolders.ts', + 'packages/cli/src/core/auth.ts', + 'packages/cli/src/core/initializer.ts', + 'packages/cli/src/dualOutput/DualOutputBridge.ts', + 'packages/cli/src/external-agents/acp-subagent-executor.ts', + 'packages/cli/src/external-agents/codex-subagent-executor.ts', + 'packages/cli/src/i18n/index.ts', + 'packages/cli/src/i18n/languageUtils.ts', + 'packages/cli/src/llm.tsx', + 'packages/cli/src/nonInteractive/chat-recording-failure.ts', + 'packages/cli/src/nonInteractive/control/controllers/baseController.ts', + 'packages/cli/src/nonInteractive/control/controllers/systemController.ts', + 'packages/cli/src/nonInteractive/io/BaseJsonOutputAdapter.ts', + 'packages/cli/src/nonInteractive/io/StreamJsonOutputAdapter.ts', + 'packages/cli/src/nonInteractive/nonInteractiveHelpers.ts', + 'packages/cli/src/nonInteractive/tool-result-boundary-diagnostics.ts', + 'packages/cli/src/nonInteractiveCli.ts', + 'packages/cli/src/nonInteractiveCliCommands.ts', + 'packages/cli/src/peerMessaging/peer-messaging.ts', + 'packages/cli/src/runtime/channel-delivery.ts', + 'packages/cli/src/runtime/scheduled-task-run.ts', + 'packages/cli/src/serve/acp-http/client-mcp-ws.ts', + 'packages/cli/src/serve/acp-http/dispatch.ts', + 'packages/cli/src/serve/acp-http/index.ts', + 'packages/cli/src/serve/auth/qwen-device-flow-provider.ts', + 'packages/cli/src/serve/conversations/standalone-session-service.ts', + 'packages/cli/src/serve/core-runtime.ts', + 'packages/cli/src/serve/create-sub-session.ts', + 'packages/cli/src/serve/daemon-git-worktree-guard.ts', + 'packages/cli/src/serve/daemon-status-provider.ts', + 'packages/cli/src/serve/env-snapshot.ts', + 'packages/cli/src/serve/fs/paths.ts', + 'packages/cli/src/serve/fs/policy.ts', + 'packages/cli/src/serve/fs/workspace-file-system.ts', + 'packages/cli/src/serve/live/live-session-coordinator.ts', + 'packages/cli/src/serve/live/live-task-service.ts', + 'packages/cli/src/serve/live/realtime-startup-context.ts', + 'packages/cli/src/serve/local-control/service.ts', + 'packages/cli/src/serve/model-configuration.ts', + 'packages/cli/src/serve/model-providers-edit.ts', + 'packages/cli/src/serve/prompt-terminal-ledger.ts', + 'packages/cli/src/serve/routes/scheduled-tasks.ts', + 'packages/cli/src/serve/routes/session-pr-backfill.ts', + 'packages/cli/src/serve/routes/session.ts', + 'packages/cli/src/serve/routes/sse-events.ts', + 'packages/cli/src/serve/routes/standalone-sessions.ts', + 'packages/cli/src/serve/routes/usage-stats.ts', + 'packages/cli/src/serve/routes/workspace-auth.ts', + 'packages/cli/src/serve/routes/workspace-extensions-controller.ts', + 'packages/cli/src/serve/routes/workspace-extensions.ts', + 'packages/cli/src/serve/routes/workspace-git-branches.ts', + 'packages/cli/src/serve/routes/workspace-git-diff.ts', + 'packages/cli/src/serve/routes/workspace-git-log.ts', + 'packages/cli/src/serve/routes/workspace-git.ts', + 'packages/cli/src/serve/routes/workspace-github-prs.ts', + 'packages/cli/src/serve/routes/workspace-management.ts', + 'packages/cli/src/serve/routes/workspace-mcp-config.ts', + 'packages/cli/src/serve/routes/workspace-models.ts', + 'packages/cli/src/serve/routes/workspace-trust.ts', + 'packages/cli/src/serve/scheduled-task-keepalive.ts', + 'packages/cli/src/serve/scheduled-task-session-lifecycle.ts', + 'packages/cli/src/serve/server.ts', + 'packages/cli/src/serve/server/aone-mrs.ts', + 'packages/cli/src/serve/server/auth-provider-helpers.ts', + 'packages/cli/src/serve/server/error-response.ts', + 'packages/cli/src/serve/server/git-branch-ops.ts', + 'packages/cli/src/serve/server/session-archive.ts', + 'packages/cli/src/serve/server/session-export.ts', + 'packages/cli/src/serve/server/session-list.ts', + 'packages/cli/src/serve/server/session-pr-refresh.ts', + 'packages/cli/src/serve/server/telemetry.ts', + 'packages/cli/src/serve/server/worktree-orphan-cleanup.ts', + 'packages/cli/src/serve/session-attachments-root.ts', + 'packages/cli/src/serve/session-id-admission.ts', + 'packages/cli/src/serve/session-organization-helpers.ts', + 'packages/cli/src/serve/virtual-subagent-sessions.ts', + 'packages/cli/src/serve/voice/resolve-voice-config.ts', + 'packages/cli/src/serve/voice/voice-ws.ts', + 'packages/cli/src/serve/workspace-agents.ts', + 'packages/cli/src/serve/workspace-git-state.ts', + 'packages/cli/src/serve/workspace-memory.ts', + 'packages/cli/src/serve/workspace-providers-status.ts', + 'packages/cli/src/serve/workspace-remember.ts', + 'packages/cli/src/serve/workspace-runtime-storage.ts', + 'packages/cli/src/serve/workspace-skill-management.ts', + 'packages/cli/src/serve/workspace-skills-status.ts', + 'packages/cli/src/services/BuiltinCommandLoader.ts', + 'packages/cli/src/services/BundledSkillLoader.ts', + 'packages/cli/src/services/CommandService.ts', + 'packages/cli/src/services/FileCommandLoader.ts', + 'packages/cli/src/services/McpPromptLoader.ts', + 'packages/cli/src/services/SkillCommandLoader.ts', + 'packages/cli/src/services/command-factory.ts', + 'packages/cli/src/services/commandUtils.ts', + 'packages/cli/src/services/housekeeping/scheduler.ts', + 'packages/cli/src/services/insight/generators/DataProcessor.ts', + 'packages/cli/src/services/insight/generators/StaticInsightGenerator.ts', + 'packages/cli/src/services/insight/generators/TemplateRenderer.ts', + 'packages/cli/src/services/markdown-command-parser.ts', + 'packages/cli/src/services/prompt-processors/argumentProcessor.ts', + 'packages/cli/src/services/prompt-processors/atFileProcessor.ts', + 'packages/cli/src/services/prompt-processors/shellProcessor.ts', + 'packages/cli/src/services/review-worktree-lease.ts', + 'packages/cli/src/services/saved-workflow-loader.ts', + 'packages/cli/src/services/setup-github.ts', + 'packages/cli/src/services/skill-args-file.ts', + 'packages/cli/src/services/voice-keyterms.ts', + 'packages/cli/src/services/voice-model.ts', + 'packages/cli/src/services/voice-service.ts', + 'packages/cli/src/services/voice-transcriber.ts', + 'packages/cli/src/services/web-shell-brand.ts', + 'packages/cli/src/startup/startup-prefetch.ts', + 'packages/cli/src/ui/AppContainer.tsx', + 'packages/cli/src/ui/auth/ProviderSetupSteps.tsx', + 'packages/cli/src/ui/auth/useAuth.ts', + 'packages/cli/src/ui/auth/useProviderSetupFlow.ts', + 'packages/cli/src/ui/commands/advisor-command.ts', + 'packages/cli/src/ui/commands/approvalModeCommand.ts', + 'packages/cli/src/ui/commands/arenaCommand.ts', + 'packages/cli/src/ui/commands/btwCommand.ts', + 'packages/cli/src/ui/commands/bugCommand.ts', + 'packages/cli/src/ui/commands/cdCommand.ts', + 'packages/cli/src/ui/commands/clearCommand.ts', + 'packages/cli/src/ui/commands/compressCommand.ts', + 'packages/cli/src/ui/commands/compressFastCommand.ts', + 'packages/cli/src/ui/commands/contextCommand.ts', + 'packages/cli/src/ui/commands/curator-command.ts', + 'packages/cli/src/ui/commands/diffCommand.ts', + 'packages/cli/src/ui/commands/directoryCommand.tsx', + 'packages/cli/src/ui/commands/docsCommand.ts', + 'packages/cli/src/ui/commands/doctorChecks.ts', + 'packages/cli/src/ui/commands/doctorCommand.ts', + 'packages/cli/src/ui/commands/dreamCommand.ts', + 'packages/cli/src/ui/commands/effort-command.ts', + 'packages/cli/src/ui/commands/exportCommand.ts', + 'packages/cli/src/ui/commands/extensionsCommand.ts', + 'packages/cli/src/ui/commands/forkCommand.ts', + 'packages/cli/src/ui/commands/goalCommand.ts', + 'packages/cli/src/ui/commands/ideCommand.ts', + 'packages/cli/src/ui/commands/initCommand.ts', + 'packages/cli/src/ui/commands/insightCommand.ts', + 'packages/cli/src/ui/commands/languageCommand.ts', + 'packages/cli/src/ui/commands/learn-command.ts', + 'packages/cli/src/ui/commands/modelCommand.ts', + 'packages/cli/src/ui/commands/output-style-command.ts', + 'packages/cli/src/ui/commands/output-style-utils.ts', + 'packages/cli/src/ui/commands/peers-command.ts', + 'packages/cli/src/ui/commands/planCommand.ts', + 'packages/cli/src/ui/commands/recapCommand.ts', + 'packages/cli/src/ui/commands/rememberCommand.ts', + 'packages/cli/src/ui/commands/renameCommand.ts', + 'packages/cli/src/ui/commands/skillsCommand.ts', + 'packages/cli/src/ui/commands/statsCommand.ts', + 'packages/cli/src/ui/commands/summaryCommand.ts', + 'packages/cli/src/ui/commands/tasksCommand.ts', + 'packages/cli/src/ui/commands/workflowsCommand.ts', + 'packages/cli/src/ui/components/AppHeader.tsx', + 'packages/cli/src/ui/components/DebugModeNotification.tsx', + 'packages/cli/src/ui/components/DialogManager.tsx', + 'packages/cli/src/ui/components/ModelDialog.tsx', + 'packages/cli/src/ui/components/WorktreeExitDialog.tsx', + 'packages/cli/src/ui/components/arena/ArenaStartDialog.tsx', + 'packages/cli/src/ui/components/background-view/workflow-save-overlay.tsx', + 'packages/cli/src/ui/components/extensions/steps/UninstallConfirmStep.tsx', + 'packages/cli/src/ui/components/extensions/tabs/DiscoverTab.tsx', + 'packages/cli/src/ui/components/extensions/tabs/InstalledTab.tsx', + 'packages/cli/src/ui/components/extensions/tabs/SourcesTab.tsx', + 'packages/cli/src/ui/components/extensions/views/ExtensionActionsView.tsx', + 'packages/cli/src/ui/components/extensions/views/McpServerActionsView.tsx', + 'packages/cli/src/ui/components/extensions/views/PluginDetailView.tsx', + 'packages/cli/src/ui/components/hooks/HooksManagementDialog.tsx', + 'packages/cli/src/ui/components/hooks/constants.ts', + 'packages/cli/src/ui/components/mcp/steps/AuthenticateStep.tsx', + 'packages/cli/src/ui/components/mcp/steps/ServerDetailStep.tsx', + 'packages/cli/src/ui/components/messages/CompactToolGroupDisplay.tsx', + 'packages/cli/src/ui/components/messages/GoalStatusMessage.tsx', + 'packages/cli/src/ui/components/shared/MaxSizedBox.tsx', + 'packages/cli/src/ui/components/shared/text-buffer.ts', + 'packages/cli/src/ui/components/subagents/create/DescriptionInput.tsx', + 'packages/cli/src/ui/context-menu/ContentMouseController.tsx', + 'packages/cli/src/ui/contexts/AgentViewContext.tsx', + 'packages/cli/src/ui/contexts/KeypressContext.tsx', + 'packages/cli/src/ui/contexts/SessionContext.tsx', + 'packages/cli/src/ui/handleAutoUpdate.ts', + 'packages/cli/src/ui/hooks/atCommandProcessor.ts', + 'packages/cli/src/ui/hooks/session-completion.ts', + 'packages/cli/src/ui/hooks/session-mention-ref.ts', + 'packages/cli/src/ui/hooks/shellCommandProcessor.ts', + 'packages/cli/src/ui/hooks/slashCommandProcessor.ts', + 'packages/cli/src/ui/hooks/use-llm-stream.ts', + 'packages/cli/src/ui/hooks/use-voice-input.ts', + 'packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts', + 'packages/cli/src/ui/hooks/useAwaySummary.ts', + 'packages/cli/src/ui/hooks/useBranchCommand.ts', + 'packages/cli/src/ui/hooks/useEditorSettings.ts', + 'packages/cli/src/ui/hooks/useFollowupSuggestions.tsx', + 'packages/cli/src/ui/hooks/useHistoryManager.ts', + 'packages/cli/src/ui/hooks/useIdeTrustListener.ts', + 'packages/cli/src/ui/hooks/useMcpApproval.ts', + 'packages/cli/src/ui/hooks/usePreferredEditor.ts', + 'packages/cli/src/ui/hooks/useProviderUpdates.ts', + 'packages/cli/src/ui/hooks/useQwenAuth.ts', + 'packages/cli/src/ui/hooks/useReactToolScheduler.ts', + 'packages/cli/src/ui/hooks/useResumeCommand.ts', + 'packages/cli/src/ui/hooks/useSelectionList.ts', + 'packages/cli/src/ui/hooks/useShellHistory.ts', + 'packages/cli/src/ui/hooks/useShowMemoryCommand.ts', + 'packages/cli/src/ui/hooks/useSlashCompletion.ts', + 'packages/cli/src/ui/hooks/useStatusLine.ts', + 'packages/cli/src/ui/hooks/useTurnDiffs.ts', + 'packages/cli/src/ui/hooks/useWelcomeBack.ts', + 'packages/cli/src/ui/models/availableModels.ts', + 'packages/cli/src/ui/opentui/client-tool-run.ts', + 'packages/cli/src/ui/opentui/commands-dispatch.ts', + 'packages/cli/src/ui/opentui/dialog-data.ts', + 'packages/cli/src/ui/opentui/dialogs-arena.tsx', + 'packages/cli/src/ui/opentui/dialogs-auth.tsx', + 'packages/cli/src/ui/opentui/followup-generation.ts', + 'packages/cli/src/ui/opentui/input-prompt.tsx', + 'packages/cli/src/ui/opentui/item-projection.ts', + 'packages/cli/src/ui/opentui/live-session.ts', + 'packages/cli/src/ui/opentui/opentui-app-shell.tsx', + 'packages/cli/src/ui/opentui/opentui-footer.tsx', + 'packages/cli/src/ui/opentui/opentui-header.tsx', + 'packages/cli/src/ui/opentui/opentui-runtime.ts', + 'packages/cli/src/ui/opentui/shell-mode.ts', + 'packages/cli/src/ui/opentui/start-opentui-ui.tsx', + 'packages/cli/src/ui/opentui/transcript-view.tsx', + 'packages/cli/src/ui/selection/use-text-selection.tsx', + 'packages/cli/src/ui/standalone-update.ts', + 'packages/cli/src/ui/startInteractiveUI.tsx', + 'packages/cli/src/ui/systemInfo.ts', + 'packages/cli/src/ui/systemInfoFields.ts', + 'packages/cli/src/ui/themes/color-utils.ts', + 'packages/cli/src/ui/themes/detect-terminal-theme.ts', + 'packages/cli/src/ui/themes/theme-manager.ts', + 'packages/cli/src/ui/utils/CodeColorizer.tsx', + 'packages/cli/src/ui/utils/InlineMarkdownRenderer.tsx', + 'packages/cli/src/ui/utils/approvalModeDisplay.ts', + 'packages/cli/src/ui/utils/backgroundWorkUtils.ts', + 'packages/cli/src/ui/utils/clipboardUtils.ts', + 'packages/cli/src/ui/utils/commandUtils.ts', + 'packages/cli/src/ui/utils/compression-text.ts', + 'packages/cli/src/ui/utils/export/export-transcript-document.ts', + 'packages/cli/src/ui/utils/export/normalize.ts', + 'packages/cli/src/ui/utils/formatters.ts', + 'packages/cli/src/ui/utils/goal-runtime.ts', + 'packages/cli/src/ui/utils/historyMapping.ts', + 'packages/cli/src/ui/utils/inline-image-parts.ts', + 'packages/cli/src/ui/utils/osc8.ts', + 'packages/cli/src/ui/utils/resumeHistoryUtils.ts', + 'packages/cli/src/ui/utils/statsDataService.ts', + 'packages/cli/src/ui/utils/terminal-image-renderer.ts', + 'packages/cli/src/ui/utils/terminalSetup.ts', + 'packages/cli/src/ui/utils/updateCheck.ts', + 'packages/cli/src/ui/utils/workflow-keyword.ts', + 'packages/cli/src/ui/voice/native-audio-recorder.ts', + 'packages/cli/src/ui/voice/qwen-asr-realtime-session.ts', + 'packages/cli/src/ui/voice/voice-availability.ts', + 'packages/cli/src/ui/voice/voice-recorder.ts', + 'packages/cli/src/ui/voice/voice-refine.ts', + 'packages/cli/src/ui/voice/voice-stream-retry.ts', + 'packages/cli/src/ui/voice/voice-stream-session.ts', + 'packages/cli/src/utils/acpModelUtils.ts', + 'packages/cli/src/utils/apiPreconnect.ts', + 'packages/cli/src/utils/deferred-core-runtime.ts', + 'packages/cli/src/utils/errors.ts', + 'packages/cli/src/utils/extension-mention.ts', + 'packages/cli/src/utils/gitUtils.ts', + 'packages/cli/src/utils/housekeeping/cleanup.ts', + 'packages/cli/src/utils/housekeeping/throttledOnce.ts', + 'packages/cli/src/utils/installationInfo.ts', + 'packages/cli/src/utils/modelConfigUtils.ts', + 'packages/cli/src/utils/osc.ts', + 'packages/cli/src/utils/resolvePath.ts', + 'packages/cli/src/utils/runBudget.ts', + 'packages/cli/src/utils/sessionPaths.ts', + 'packages/cli/src/utils/startupWarnings.ts', +]; diff --git a/scripts/tests/no-core-root-barrel-config.test.js b/scripts/tests/no-core-root-barrel-config.test.js index 1947acff16b..d299f76aaef 100644 --- a/scripts/tests/no-core-root-barrel-config.test.js +++ b/scripts/tests/no-core-root-barrel-config.test.js @@ -1,5 +1,7 @@ +import { existsSync } from 'node:fs'; import { describe, expect, it } from 'vitest'; import { ESLint } from 'eslint'; +import { legacyCoreBarrelImports } from '../../eslint.legacy-core-barrel-imports.mjs'; describe('core root barrel flat-config integration', () => { it('reports production self-imports (static, type-only, inline-type, and dynamic), ignores tests', async () => { @@ -51,4 +53,72 @@ describe('core root barrel flat-config integration', () => { // test files stay exempt via the rule's own test/fixture exemption expect(hasViolation(testStatic)).toBe(false); }); + + it('reports cli production value imports from the core root, except type-only, tests, and legacy entries', async () => { + const eslint = new ESLint({ + cwd: process.cwd(), + overrideConfigFile: 'eslint.config.js', + }); + const cliFile = 'packages/cli/src/ui/fixture-boundary.ts'; + const [ + valueImport, + reExport, + indexSubpath, + typeOnly, + inlineTypeOnly, + ownerModule, + testFile, + legacyFile, + ] = await Promise.all([ + eslint.lintText("import { Storage } from '@qwen-code/qwen-code-core';", { + filePath: cliFile, + }), + eslint.lintText("export { Storage } from '@qwen-code/qwen-code-core';", { + filePath: cliFile, + }), + eslint.lintText( + "import { Storage } from '@qwen-code/qwen-code-core/index.js';", + { filePath: cliFile }, + ), + eslint.lintText( + "import type { Config } from '@qwen-code/qwen-code-core';", + { filePath: cliFile }, + ), + eslint.lintText( + "import { type Config } from '@qwen-code/qwen-code-core';", + { filePath: cliFile }, + ), + eslint.lintText( + "import { Storage } from '@qwen-code/qwen-code-core/config/storage.js';", + { filePath: cliFile }, + ), + eslint.lintText("import { Storage } from '@qwen-code/qwen-code-core';", { + filePath: 'packages/cli/src/ui/fixture-boundary.test.ts', + }), + eslint.lintText("import { Storage } from '@qwen-code/qwen-code-core';", { + filePath: legacyCoreBarrelImports[0], + }), + ]); + + const hasViolation = (results) => + results.some((r) => + r.messages.some( + (m) => m.ruleId === '@typescript-eslint/no-restricted-imports', + ), + ); + + expect(hasViolation(valueImport)).toBe(true); + expect(hasViolation(reExport)).toBe(true); + expect(hasViolation(indexSubpath)).toBe(true); + expect(hasViolation(typeOnly)).toBe(false); + expect(hasViolation(inlineTypeOnly)).toBe(false); + expect(hasViolation(ownerModule)).toBe(false); + expect(hasViolation(testFile)).toBe(false); + expect(hasViolation(legacyFile)).toBe(false); + }); + + it('lists only cli files that still exist', () => { + const missing = legacyCoreBarrelImports.filter((file) => !existsSync(file)); + expect(missing).toEqual([]); + }); }); diff --git a/scripts/tests/qwen-autofix-workflow.test.js b/scripts/tests/qwen-autofix-workflow.test.js index a37805abce1..12797435c2f 100644 --- a/scripts/tests/qwen-autofix-workflow.test.js +++ b/scripts/tests/qwen-autofix-workflow.test.js @@ -13966,6 +13966,7 @@ exit 1 'packages/core/.gitattributes', 'packages/desktop-shell/.npmrc', 'eslint.legacy-filenames.mjs', + 'eslint.legacy-core-barrel-imports.mjs', '.github/workflows/qwen-pr-safety-precheck.yml', ]); expect(classes).toContain('.github/actions/a/action.yml=ci-workflows'); @@ -13991,6 +13992,9 @@ exit 1 ); expect(classes).toContain('packages/desktop-shell/.npmrc=toolchain-config'); expect(classes).toContain('eslint.legacy-filenames.mjs=lint-config'); + expect(classes).toContain( + 'eslint.legacy-core-barrel-imports.mjs=lint-config', + ); expect(classes).toContain( '.github/workflows/qwen-pr-safety-precheck.yml=autofix-loop', );