chore: clear dead test and allowlist leftovers of dropped runtimes
Some checks failed
Tests / PR mergeability (push) Successful in 18s
Tests / Base branch health (push) Successful in 9s
Tests / Detect test scope (push) Successful in 16s
Tests / lint-tests (push) Failing after 1m43s
Tests / plugin-validate (push) Successful in 58s
Tests / test (ubuntu-latest, 24, shard 1/3) (push) Failing after 19s
Tests / test (ubuntu-latest, 24, shard 2/3) (push) Failing after 20s
Tests / test (ubuntu-latest, 24, shard 3/3) (push) Failing after 20s
Tests / test (ubuntu-latest, 24) (push) Failing after 18s
Tests / test (inert CI) (push) Has been skipped
Tests / QA loop walk (smell ratchet) (push) Failing after 19s
Tests / Coverage gate (merged shards) (push) Has been skipped
Tests / Publish emitted-baseline artifact (push) Has been skipped
Duplicate auto-close sweep / sweep (push) Successful in 19s
CI timeout budget report / report (push) Failing after 14s
Close Draft PRs (sweep) / Sweep open draft PRs (push) Successful in 9s
Dismiss Unauthorized PR Approvals / dismiss-unauthorized-approval (push) Successful in 9s
Tests / conformance test (macos-latest, 24) (push) Has been cancelled
Tests / conformance test (windows-latest, 24, shard 1/3) (push) Has been cancelled
Tests / conformance test (windows-latest, 24, shard 2/3) (push) Has been cancelled
Tests / conformance test (windows-latest, 24, shard 3/3) (push) Has been cancelled
Tests / Required tests (push) Has been cancelled

This commit is contained in:
Jakub Zych
2026-10-06 20:30:09 +02:00
parent 792139b5ed
commit fe3ed06691
83 changed files with 308 additions and 1997 deletions

View File

@@ -1,4 +1,4 @@
// docs-guard-exempt: docs/... substrings are external URL citations (qwenlm/code.claude.com) in comments, not repo paths.
// docs-guard-exempt: docs/... substrings are external URL citations (code.claude.com) in comments, not repo paths.
/**
* Installer Module — Sections 9–11 + 13.
*
@@ -651,18 +651,12 @@ describe('#1755: .sh hooks are copied and executable after install', () => {
// ─── #1821/#2305: hooks staged iff a surface consumes them ─────────────────────
//
// #1821 reported dead hook scripts staged for runtimes with hooksSurface:'none'.
// OpenCode, pi — and, corrected by #2305, Kilo — ALSO declare
// hooksSurface:'none', but each has a native plugin adapter that spawns the
// staged hooks/*.js scripts as subprocesses (OpenCode's #1914
// plugins/msd-core.js via OpenCode's event bus; pi's #2102 Stage 2 pi/msd.cjs
// → extensions/msd.js via pi.on(...) bridges; Kilo's plugins/msd-core.js,
// byte-identical to OpenCode's) — so for all three, the hooks are LIVE and
// OpenCode ALSO declares hooksSurface:'none', but has a native plugin adapter
// that spawns the staged hooks/*.js scripts as subprocesses (OpenCode's #1914
// plugins/msd-core.js via OpenCode's event bus) — so its hooks are LIVE and
// must keep being copied. ZCode has no plugin surface at all, so its staged
// hooks are genuinely dead: that is the case #1821's fix removes. (#1821
// originally excluded Kilo too, on the false premise that it had no plugin
// surface — #2305 reversed that: the skip flag silently no-opped every guard
// hook Kilo's plugin spawns.) These tests assert the split: ZCode gets no
// hooks; Kilo/OpenCode/pi (and Claude) do.
// hooks are genuinely dead: that is the case #1821's fix removes. These tests
// assert the split: ZCode gets no hooks; OpenCode (and Claude) do.
describe('#1821/#2305: ZCode receives no dead hook files; OpenCode/Claude keep their hooks', () => {
function msdHookFilesUnder(configDir, hooksDirName) {
@@ -686,7 +680,7 @@ describe('#1821/#2305: ZCode receives no dead hook files; OpenCode/Claude keep t
// Collect results while targetDir still exists — cleanup() below removes it.
const pluginRelPath = opts.pluginRelPath || path.join('plugins', 'msd-core.js');
// #3023: the shared hooks bundle's staged directory name is per-runtime
// (hostBehaviors.sharedHooksDirName; pi renames it to `msd-hooks/`) —
// (hostBehaviors.sharedHooksDirName) —
// resolve it the same way the installer does rather than hardcoding
// 'hooks', or every non-default runtime would look hookless.
const hooksDirName = resolveSharedHooksDirName(runtime);
@@ -1183,7 +1177,7 @@ process.env.MSD_TEST_MODE = '1';
* extendedHookEvents descriptor field, not hardcoded runtime-name checks.
*
* Before this change:
* - SubagentStop/Stop/PreCompact were wired only when (isQwen || runtime==='claude')
* - SubagentStop/Stop/PreCompact were wired only when (runtime==='claude')
* - FileChanged was wired only when (runtime === 'claude')
* - BeforeAgent/AfterAgent/BeforeModel were wired only when (isGemini)
*
@@ -1348,9 +1342,9 @@ describe('enh-1076 phase 5f-3: claude extendedHookEvents → SubagentStop/Stop/P
});
});
// ─── Suite 2: qwen shape (SubagentStop+Stop+PreCompact, no FileChanged) ───────
// ─── Suite 2: SubagentStop+Stop+PreCompact shape (no FileChanged) ─────────────
describe('enh-1076 phase 5f-3: qwen extendedHookEvents → SubagentStop/Stop/PreCompact only', () => {
describe('enh-1076 phase 5f-3: extendedHookEvents → SubagentStop/Stop/PreCompact only', () => {
let targetDir;
let settings;
@@ -1358,7 +1352,7 @@ describe('enh-1076 phase 5f-3: qwen extendedHookEvents → SubagentStop/Stop/Pre
targetDir = createStubTargetDir();
settings = { hooks: {} };
const opts = buildOpts(targetDir, {
runtime: 'qwen',
runtime: 'hypothetical-stop-shape',
extendedHookEvents: ['SubagentStop', 'Stop', 'PreCompact'],
});
applySettingsJsonHooks(settings, opts);
@@ -1380,7 +1374,7 @@ describe('enh-1076 phase 5f-3: qwen extendedHookEvents → SubagentStop/Stop/Pre
assert.strictEqual(
hasHooksFor(settings, 'FileChanged'),
false,
`FileChanged must NOT be wired for qwen shape; hooks keys: ${JSON.stringify(Object.keys(settings.hooks || {}))}`
`FileChanged must NOT be wired for the SubagentStop/Stop/PreCompact shape; hooks keys: ${JSON.stringify(Object.keys(settings.hooks || {}))}`
);
});
@@ -1491,7 +1485,7 @@ describe('enh-1076 phase 5f-3: arbitrary runtime with SubagentStop in descriptor
targetDir = createStubTargetDir();
settings = { hooks: {} };
const opts = buildOpts(targetDir, {
runtime: 'hypothetical', // NOT 'claude' or 'qwen' — would have been skipped before
runtime: 'hypothetical', // NOT 'claude' — would have been skipped before
extendedHookEvents: ['SubagentStop'],
});
applySettingsJsonHooks(settings, opts);
@@ -1753,7 +1747,7 @@ describe('enh-1077 phase 5f-2: gemini hookEvents dialect → AfterTool/BeforeToo
// ─── Suite 2: Claude-dialect runtimes use PostToolUse/PreToolUse ──────────────
//
// Registry runtimes with hookEvents='claude': claude, augment
// Registry runtimes with hookEvents='claude': claude
describe('enh-1077 phase 5f-2: claude hookEvents dialect → PostToolUse/PreToolUse', () => {
// ── claude ──
@@ -1837,7 +1831,7 @@ describe('enh-1077 phase 5f-2: registry-parity — hookEvents descriptor drives
}
// Runtimes that have settings.json surfaces and a hookEvents descriptor
const SETTINGS_JSON_RUNTIMES = ['claude', 'antigravity', 'augment', 'qwen', 'hermes', 'codebuddy'];
const SETTINGS_JSON_RUNTIMES = ['claude', 'antigravity'];
const failures = [];
@@ -1908,11 +1902,10 @@ describe('enh-1077 phase 5f-2: registry-parity — hookEvents descriptor drives
process.env.MSD_TEST_MODE = '1';
/**
* Enhancement #788: Expand Qwen Code hook-event coverage.
* Enhancement #788: Expand hook-event coverage.
*
* Qwen Code supports 15 hook events; msd previously registered only
* SessionStart and PostToolUse. This suite asserts that a Qwen install
* registers the 3 new high-value events:
* msd previously registered only SessionStart and PostToolUse. This suite
* asserts that an install registers the 3 new high-value events:
* - SubagentStop — subagent lifecycle finalisation (context tracking)
* - Stop — model stop / final-response hook (context tracking)
* - PreCompact — pre-compaction awareness (context tracking)
@@ -1923,11 +1916,6 @@ process.env.MSD_TEST_MODE = '1';
* Note: UserPromptSubmit is NOT wired — msd-prompt-guard exits unless
* tool_name is Write|Edit (PreToolUse shape), so it would be a no-op for
* the UserPromptSubmit payload. Deferred to a follow-on issue.
*
* Also asserts the inverse: Claude Code installs do NOT gain these events
* (strict isQwen scope guard).
*
* Source: https://qwenlm.github.io/qwen-code-docs/en/users/features/hooks/
*/
const { test, describe, beforeEach, afterEach } = require('node:test');
@@ -1977,8 +1965,7 @@ function stubHooksIntoTarget(targetDir) {
}
// ─── Suite 2: Claude install DOES get the context events (since #770) ───────
// Note: Prior to #770, these were Qwen-only events. #770 extended them to
// Claude Code. This suite is updated to match the new expected behavior.
// Note: #770 extended these events to Claude Code.
describe('enh-788 (updated by #770): Claude install registers context lifecycle events', () => {
let tmpDir;
@@ -2095,10 +2082,10 @@ process.env.MSD_TEST_MODE = '1';
* PreCompact / FileChanged).
*
* Claude Code now supports the same SubagentStop, Stop, and PreCompact events
* that were wired for Qwen Code in #788. This suite asserts:
* that were wired in #788. This suite asserts:
*
* 1. Claude Code installs register SubagentStop, Stop, and PreCompact, each
* wired to msd-context-monitor.js (same as Qwen).
* wired to msd-context-monitor.js.
* 2. Claude Code installs register a FileChanged hook for .planning/config.json
* wired to msd-config-reload.js (new hook; hot-reloads msd config).
* 3. All four registrations are idempotent (reinstall does not duplicate).
@@ -2683,9 +2670,7 @@ describe('#4087 regression: Codex install stages the hook helpers its hooks requ
// statusline hook, which Codex never installs, so every registered Codex
// event was a guaranteed silent no-op. The #4087 bug class this describe
// block guards (a staged hook requiring an unshipped hooks/lib/ helper)
// remains covered live via Windsurf's own guards — see the
// "#4087 review: Windsurf install..." describe block below, unaffected
// by this change.
// remains covered by the grammar-level rows below.
const hooksDir = installCodex(tmpDir);
const libDir = path.join(hooksDir, 'lib');
@@ -2724,8 +2709,8 @@ describe('#4087 regression: Codex install stages the hook helpers its hooks requ
// dependency closure is correctly empty. This row still proves the
// GRAMMAR holds (whatever IS required must be staged) — it is just that
// "whatever is required" is now the empty set for Codex specifically.
// The non-trivial case (closure size > 0) is covered live by the
// "#4087 review: Windsurf install..." describe block below.
// The non-trivial case (closure size > 0) is covered by the grammar-level
// rows below.
assert.strictEqual(required.size, 0,
'no staged Codex hook should require a ./lib/ helper post-#2586 — if this becomes non-zero, '
+ 'extend this row (do not just raise the bar back to ">0") so the new dependency stays proven');
@@ -2756,8 +2741,8 @@ describe('#4087 regression: Codex install stages the hook helpers its hooks requ
// #2586: Codex's closure is now legitimately empty (msd-context-monitor.js,
// the only staged Codex hook that ever required a helper, is no longer
// staged) — the deepStrictEqual below is still the real assertion and
// holds for the empty case too; the non-empty case remains covered live
// by the "#4087 review: Windsurf install..." describe block below.
// holds for the empty case too; the non-empty case remains covered by the
// grammar-level rows below.
assert.strictEqual(stagedLibs.length, 0, 'no helpers should be staged for Codex post-#2586');
// Derive the closure independently of the installer.