feat(#2092): migrate Qwen Code onto EoS imperative adapter + native subagents + SubagentStart (ADR-1239)

Fold all runtime==='qwen'/isQwen logic branches (skill-priority frontmatter,
branding/path rewrites, legacy commands/gsd cleanup, hyphen-namespace
normalization, RUNTIME_CONTENT_DISPATCH, hooks-surface label) into
descriptor-driven runtime.hostBehaviors on capabilities/qwen/capability.json,
read via _hostBehaviors(). Shared claude/qwen/hermes legacy-migration branches
in install-engine.cts folded to descriptor flags (claude+hermes descriptors
updated; FALLBACK_HOST_BEHAVIORS.claude floored). Byte-identical golden parity
for qwen/hermes/claude(global+local).

UPGRADE 1: native .qwen/agents/*.md subagent projection — new agents
artifact-layout kind + convertClaudeAgentToQwenAgent converter (name +
description + tools YAML block list; color/model dropped). qwen routed onto
the descriptor-driven agents path (_DESCRIPTOR_AGENTS_RUNTIMES).
UPGRADE 2: SubagentStart hook wired into extendedHookEvents + the
descriptor-gated hook-writer loop (activates only for qwen).

Tests: qwen-imperative-reference (adapter/axes/fail-closed/hostBehaviors +
no runtime==='qwen' source-grep across 4 files) + qwen-upgrades (agents file
validity + SubagentStart mirrors SubagentStop, descriptor-gated). Docs matrix
+ how-to updated; changeset added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-07-10 14:46:59 -04:00
parent 91a68ae8e6
commit c6ce110efa
24 changed files with 819 additions and 172 deletions

View File

@@ -470,7 +470,7 @@ function _runLegacyInstallMigrations(runtime: string, configDir: string, scope:
// that for Hermes the flat skills/gsd-*/ removal (below) does not delete the freshly
// created skills/gsd-dev-preferences/ skill dir.
let savedLegacyArtifacts: Map<string, string> | null = null;
if (runtime === 'claude' || runtime === 'qwen' || runtime === 'hermes') {
if (_hostBehaviors(runtime).legacyCommandsGsdInstallMigration) {
if (fs.existsSync(legacyCommandsGsd)) {
savedLegacyArtifacts = preserveUserArtifacts(legacyCommandsGsd, ['dev-preferences.md']);
fs.rmSync(legacyCommandsGsd, { recursive: true });
@@ -531,7 +531,8 @@ function _runLegacyUninstallCleanup(runtime: string, configDir: string, scope: s
// commands/gsd/ for claude local, preserving dev-preferences.md by restoring it
// to the same location (#1423). Using migrateLegacyDevPreferencesToSkill here
// (which would redirect to skills/) conflicts with the test contract for local installs.
const isLegacyCommandsGsd = runtime === 'qwen' || runtime === 'hermes' || (runtime === 'claude' && scope === 'global');
const _lu = _hostBehaviors(runtime).legacyCommandsGsdUninstall;
const isLegacyCommandsGsd = _lu === true || (_lu === 'global' && scope === 'global');
if (isLegacyCommandsGsd) {
const legacyCommandsGsd = path.join(configDir, 'commands', 'gsd');
if (fs.existsSync(legacyCommandsGsd)) {