mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-09-10 19:01:58 +00:00
* refactor(core): centralize worktree config derivation * refactor(core): centralize agent config derivation (#9918) * refactor(core): centralize agent config derivation * refactor(core): centralize scoped config profiles (#9920) * fix(core): keep approval-mode transitions working on derived teammate and dispatch configs Give every per-agent config child-local approval state, not just the ones spawned with an explicit mode: tools bind to the config and teammate mode switches (Shift+Tab) plus 'Proceed always' confirmations call setApprovalMode on it, which the derived-Config guard rejects without an approval profile. Snapshot the base mode when none is requested so no AUTO strip is acquired and cleanup stays a no-op. Layer an approval profile over the workflow-orchestrator's derived dispatch contexts (worktree isolation / workingDir) as agent.ts does, with cleanup in the outer finally. * fix(core): anchor plans-directory assertions at the plans-owning base Config Derived agent profiles rebind targetDir to their own workspace, but the plan file stays in the owning base's configured plans directory. The containment assertions in savePlan/loadPlan compared against the derived workspace and threw FatalConfigError for teammates whose cwd differs from the parent project root, which savePlanBestEffort swallowed into a debug warning — silently dropping the plan. Resolve the anchor to the Config that owns the plans-directory state instead. * test(core): cover deriveAgentConfig workspace rebinds Mirror the deriveWorktreeConfig pairing test: assert the public getter overrides (getCwd/getProjectRoot/getWorkingDir/getTargetDir, plan-file path) and the paired private targetDir/cwd field writes plus own workspaceContext/fileDiscoveryService, so a refactor that drops any rebind fails loudly instead of leaking parent-tree reads into spawned agents. * test(scripts): add flat-config integration test for no-config-object-create Mirror no-core-root-barrel-config.test.js: load the real eslint.config.js via new ESLint({overrideConfigFile}) and lintText virtual packages/core/src/** paths, so a future edit to the flat-config wiring (plugin key, rule name, ignores) that silently stops the gate applying to packages/core/src/** turns this test red instead of degrading the invariant with no signal. --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
46 lines
1.5 KiB
JavaScript
46 lines
1.5 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2026 Qwen Team
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
import { ESLint } from 'eslint';
|
|
|
|
describe('no-config-object-create flat-config integration', () => {
|
|
it('reports Object.create Config derivation in production paths, ignores tests and config.ts', async () => {
|
|
const eslint = new ESLint({
|
|
cwd: process.cwd(),
|
|
overrideConfigFile: 'eslint.config.js',
|
|
});
|
|
const snippet =
|
|
"import { Config } from '../config/config.js';\n" +
|
|
'const child = Object.create(base);\n';
|
|
const [prodObjectCreate, testObjectCreate, configTsObjectCreate] =
|
|
await Promise.all([
|
|
eslint.lintText(snippet, {
|
|
filePath: 'packages/core/src/foo/bar.ts',
|
|
}),
|
|
eslint.lintText(snippet, {
|
|
filePath: 'packages/core/src/foo/bar.test.ts',
|
|
}),
|
|
eslint.lintText(snippet, {
|
|
filePath: 'packages/core/src/config/config.ts',
|
|
}),
|
|
]);
|
|
|
|
const hasViolation = (results) =>
|
|
results.some((r) =>
|
|
r.messages.some(
|
|
(m) => m.ruleId === 'qwen-code/no-config-object-create',
|
|
),
|
|
);
|
|
|
|
// production file: prototype derivation of Config is caught
|
|
expect(hasViolation(prodObjectCreate)).toBe(true);
|
|
// test files and the canonical factory module stay exempt via the
|
|
// flat-config `ignores` list
|
|
expect(hasViolation(testObjectCreate)).toBe(false);
|
|
expect(hasViolation(configTsObjectCreate)).toBe(false);
|
|
});
|
|
});
|