Files
msd-core/tests/adapter-imperative.test.cjs
Jakub Zych a9a7a328e6 refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
2026-10-06 01:47:40 +02:00

113 lines
5.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/**
* Tests for the imperative embedding adapter (ADR-1239 Phase C-1, AC2 / #1680).
*
* Pins:
* 1. KIND — `kind: 'imperative'`, satisfies the same HostIntegrationInterface
* as the declarative adapter (both bind one engine).
* 2. REGISTRY COMPOSITION — the adapter composes loadRegistry({includeInstalled:
* true}) and exposes the result as `.registry` (first-party ∪ installed, so
* an in-process host gets identical trust semantics to the CLI).
* 3. DELEGATION — install/uninstall delegate in-process to install-engine
* (byte-identity link, same as the declarative adapter).
* 4. FAIL-CLOSED CONSTRUCTION — missing/invalid runtime throws.
*
* Behavioral tests only; delegation + loadRegistry verified via module-ref
* monkeypatch (Node module cache shares the one module object).
*/
const { test } = require('node:test');
const assert = require('node:assert/strict');
const { createImperativeAdapter } = require('../msd-core/bin/lib/adapter-imperative.cjs');
const installEngine = require('../msd-core/bin/lib/install-engine.cjs');
const capabilityLoader = require('../msd-core/bin/lib/capability-loader.cjs');
const registry = require('../msd-core/bin/lib/capability-registry.cjs');
const RUNTIMES = Object.keys(registry.runtimes);
test('imperative adapter: kind === "imperative" + runtime echoed + registry present, for every registry runtime', () => {
for (const r of RUNTIMES) {
const adapter = createImperativeAdapter({ runtime: r });
assert.strictEqual(adapter.kind, 'imperative', `${r}: kind must be 'imperative'`);
assert.strictEqual(adapter.runtime, r, `${r}: adapter must echo the runtime id`);
assert.ok(adapter.registry && typeof adapter.registry === 'object', `${r}: registry must be present (composed loadRegistry result)`);
assert.strictEqual(typeof adapter.install, 'function', `${r}: install must be a function`);
assert.strictEqual(typeof adapter.uninstall, 'function', `${r}: uninstall must be a function`);
}
});
test('imperative adapter: loadRegistry composed with includeInstalled:true (host gets CLI-equivalent trust semantics)', () => {
// Restore-able spy on capabilityLoader.loadRegistry (module-ref, shared via Node cache).
const original = capabilityLoader.loadRegistry;
const calls = [];
capabilityLoader.loadRegistry = function (opts) {
calls.push(opts);
// Return a minimal stand-in registry so the factory does not crash.
return { _spy: true, runtimes: registry.runtimes };
};
try {
const adapter = createImperativeAdapter({ runtime: 'opencode' });
assert.ok(calls.length >= 1, 'loadRegistry must be invoked once during construction');
assert.strictEqual(calls[0].includeInstalled, true, 'loadRegistry must be called with includeInstalled:true (compose first-party ∪ installed)');
assert.strictEqual(adapter.registry._spy, true, 'adapter.registry must expose the composed loadRegistry result');
} finally {
capabilityLoader.loadRegistry = original;
}
});
test('imperative adapter: loadOptions forwarded to loadRegistry (cwd/msdHome/hostVersion pass-through)', () => {
const original = capabilityLoader.loadRegistry;
let captured = null;
capabilityLoader.loadRegistry = function (opts) { captured = opts; return { runtimes: registry.runtimes }; };
try {
createImperativeAdapter({ runtime: 'codex' }, { loadOptions: { cwd: '/tmp/proj', hostVersion: '1.7.0' } });
assert.strictEqual(captured.includeInstalled, true, 'includeInstalled default preserved');
assert.strictEqual(captured.cwd, '/tmp/proj', 'loadOptions.cwd forwarded');
assert.strictEqual(captured.hostVersion, '1.7.0', 'loadOptions.hostVersion forwarded');
} finally {
capabilityLoader.loadRegistry = original;
}
});
test('imperative adapter.install/uninstall delegate in-process to install-engine with exact args', () => {
const origInstall = installEngine.installRuntimeArtifacts;
const origUninstall = installEngine.uninstallRuntimeArtifacts;
try {
for (const r of RUNTIMES) {
const adapter = createImperativeAdapter({ runtime: r });
let installArgs = null;
let uninstallArgs = null;
installEngine.installRuntimeArtifacts = function (...a) { installArgs = a; return undefined; };
installEngine.uninstallRuntimeArtifacts = function (...a) { uninstallArgs = a; return undefined; };
adapter.install({ configDir: '/tmp/imp/' + r, scope: 'global', resolvedProfile: { p: 1 } });
adapter.uninstall({ configDir: '/tmp/imp/' + r, scope: 'local' });
// The trailing arg is the composed capability registry (#2322): the adapter
// must forward one, or third-party capability skills never materialize on
// the default `full` install path. Its contents are the loader's business —
// pin only that a registry-shaped value is threaded through, not its bulk.
const [, , , , manifest, registry] = installArgs;
assert.deepStrictEqual(
installArgs.slice(0, 5),
[r, '/tmp/imp/' + r, 'global', { p: 1 }, undefined],
`${r}: install delegation args`,
);
assert.strictEqual(manifest, undefined, `${r}: manifest arg unchanged`);
assert.ok(
registry && typeof registry === 'object' && 'capabilityClusters' in registry,
`${r}: install must forward a composed capability registry (#2322), got: ${typeof registry}`,
);
assert.deepStrictEqual(uninstallArgs, [r, '/tmp/imp/' + r, 'local'], `${r}: uninstall delegation args`);
}
} finally {
installEngine.installRuntimeArtifacts = origInstall;
installEngine.uninstallRuntimeArtifacts = origUninstall;
}
});
test('createImperativeAdapter: throws on missing/invalid runtime (fail-closed construction)', () => {
for (const bad of ['', undefined, null]) {
assert.throws(() => createImperativeAdapter({ runtime: bad }), TypeError, `runtime=${JSON.stringify(bad)} must throw`);
}
assert.throws(() => createImperativeAdapter({}), TypeError, 'missing runtime must throw');
});