mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10: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 <[email protected]>
60 lines
1.6 KiB
JavaScript
60 lines
1.6 KiB
JavaScript
function importsConfig(node) {
|
|
return (
|
|
typeof node.source.value === 'string' &&
|
|
node.source.value.endsWith('/config/config.js') &&
|
|
node.specifiers.some(
|
|
(specifier) =>
|
|
specifier.type === 'ImportSpecifier' &&
|
|
specifier.imported.type === 'Identifier' &&
|
|
specifier.imported.name === 'Config',
|
|
)
|
|
);
|
|
}
|
|
|
|
function isObjectCreate(node) {
|
|
return (
|
|
node.callee.type === 'MemberExpression' &&
|
|
!node.callee.computed &&
|
|
node.callee.object.type === 'Identifier' &&
|
|
node.callee.object.name === 'Object' &&
|
|
node.callee.property.type === 'Identifier' &&
|
|
node.callee.property.name === 'create' &&
|
|
!(node.arguments[0]?.type === 'Literal' && node.arguments[0].value === null)
|
|
);
|
|
}
|
|
|
|
export default {
|
|
meta: {
|
|
type: 'problem',
|
|
docs: {
|
|
description:
|
|
'Require Config prototype derivation to go through deriveConfig.',
|
|
},
|
|
schema: [],
|
|
messages: {
|
|
useDeriveConfig:
|
|
'Do not derive Config with Object.create(). Use deriveConfig() or a specialized Config factory.',
|
|
},
|
|
},
|
|
|
|
create(context) {
|
|
let hasConfigImport = false;
|
|
const objectCreateCalls = [];
|
|
|
|
return {
|
|
ImportDeclaration(node) {
|
|
if (importsConfig(node)) hasConfigImport = true;
|
|
},
|
|
CallExpression(node) {
|
|
if (isObjectCreate(node)) objectCreateCalls.push(node);
|
|
},
|
|
'Program:exit'() {
|
|
if (!hasConfigImport) return;
|
|
for (const node of objectCreateCalls) {
|
|
context.report({ node, messageId: 'useDeriveConfig' });
|
|
}
|
|
},
|
|
};
|
|
},
|
|
};
|