feat(#1680): ADR-1239 Phase C-1 — declarative embedding adapter + minimal HostIntegrationInterface [AC1] (#1802)
* feat(#1680): ADR-1239 Phase C-1 — declarative embedding adapter + minimal HostIntegrationInterface [AC1] Phase 3 slice 1 (AC1). Names + bounds today's projection path behind the common HostIntegrationInterface that both declarative + imperative adapters will satisfy. - src/embedding-adapter.cts: minimal HostIntegrationInterface (kind + runtime + install/uninstall) + ADAPTER_KINDS. The full 6-point binding surface (command/dispatch/model/hooks/state/artifact) is DEFERRED until the imperative adapter (AC2) fixes the shape — ADR-1239 lists the wire-shape as an open question; freezing it now risks rework across Phases 3-6. - src/adapter-declarative.cts: createDeclarativeAdapter({runtime}) factory. Delegates in-process to install-engine installRuntimeArtifacts / uninstallRuntimeArtifacts (the SAME engine functions bin/install.js uses), so output is byte-identical to today's install (gated by golden-install-parity). Module-ref call style = monkeypatch-friendly for tests. Lossy by design: projects files, does not drive the loop (that's the imperative adapter, AC2). - tests/adapter-declarative-equivalence.test.cjs: kind classification (all 16 runtimes), install/uninstall delegation with exact args (the byte-identity link), fail-closed construction (missing/invalid runtime throws). Purely additive — no install.js/install-engine changes. Unblocks AC2 (imperative adapter) + AC3/AC4 (model/hook/state seams) as follow-up slices. * chore(changeset): add Changed fragment for declarative embedding adapter (#1680) * fix(lint): ignore tsc-emitted embedding-adapter/adapter-declarative .cjs (ADR-457) The new src/embedding-adapter.cts + src/adapter-declarative.cts modules' emitted gsd-core/bin/lib/*.cjs artifacts must join the ADR-457 ignores list (lint the src/*.cts source, not the emitted .cjs). Without this, the .cjs is linted under js.recommended where @typescript-eslint/no-require-imports is undefined, so the verbatim-copied eslint-disable directive surfaces as 'Definition for rule not found' — failing the lint-tests CI job. Also restores the clean line-level disable in adapter-declarative.cts (valid in the .cts source context where the rule IS defined). * fix(docs): add adapter-declarative + embedding-adapter to INVENTORY-MANIFEST cli_modules The new ADR-1239 Phase C-1 modules' built .cjs artifacts must be registered in docs/INVENTORY-MANIFEST.json's cli_modules array or the 'docs/INVENTORY-MANIFEST.json matches the filesystem' drift test fails on CI. Mirrors the existing sorted entries.
This commit is contained in:
42
src/adapter-declarative.cts
Normal file
42
src/adapter-declarative.cts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Declarative embedding adapter (ADR-1239 Phase C-1, AC1 / #1680).
|
||||
*
|
||||
* NAMES + BOUNDS today's projection path (file emission via install-engine)
|
||||
* behind `HostIntegrationInterface`. The declarative adapter is lossy by
|
||||
* design: it projects skills/agents/commands and does NOT drive the loop
|
||||
* orchestration (that is the imperative adapter's job, AC2 / a later slice).
|
||||
*
|
||||
* `install`/`uninstall` delegate IN-PROCESS to install-engine's
|
||||
* `installRuntimeArtifacts` / `uninstallRuntimeArtifacts` — the SAME engine
|
||||
* functions `bin/install.js` uses — so the adapter's output is byte-identical to
|
||||
* today's install (the link is gated by `tests/golden-install-parity.test.cjs`).
|
||||
* The module-ref call style (`installEngine.fn`) keeps it monkeypatch-friendly
|
||||
* for tests, mirroring the install-engine.cts:31-38 pattern.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import installEngine = require('./install-engine.cjs');
|
||||
import type { HostIntegrationInterface, AdapterInstallIntent, AdapterUninstallIntent } from './embedding-adapter.cjs';
|
||||
|
||||
export function createDeclarativeAdapter({ runtime }: { runtime: string }): HostIntegrationInterface {
|
||||
if (!runtime || typeof runtime !== 'string') {
|
||||
throw new TypeError('createDeclarativeAdapter: runtime is required (non-empty string)');
|
||||
}
|
||||
return Object.freeze({
|
||||
kind: 'declarative' as const,
|
||||
runtime,
|
||||
install(intent: AdapterInstallIntent): void {
|
||||
installEngine.installRuntimeArtifacts(
|
||||
runtime,
|
||||
intent.configDir,
|
||||
intent.scope,
|
||||
intent.resolvedProfile,
|
||||
intent.resolveAttribution,
|
||||
);
|
||||
},
|
||||
uninstall(intent: AdapterUninstallIntent): void {
|
||||
installEngine.uninstallRuntimeArtifacts(runtime, intent.configDir, intent.scope);
|
||||
},
|
||||
});
|
||||
}
|
||||
74
src/embedding-adapter.cts
Normal file
74
src/embedding-adapter.cts
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Embedding adapter contract — the common `HostIntegrationInterface` both
|
||||
* embedding adapters satisfy (ADR-1239 Phase C-1, #1680).
|
||||
*
|
||||
* INTENTIONALLY MINIMAL (Phase 3 slice 1). The full six-interface-point binding
|
||||
* surface (command / dispatch / model / hooks / state / artifact) is DEFERRED
|
||||
* until the imperative adapter (AC2) provides a real consumer that fixes the
|
||||
* shape — ADR-1239 lists the wire-shape as an open question:
|
||||
* "Exact wire-shape of the initialize handshake … Where precisely to cut the
|
||||
* engine↔host boundary"
|
||||
* (docs/adr/1239-gsd-embeddable-orchestration-engine.md#open-questions-narrowed-by-the-research).
|
||||
* Freezing a 6-point contract before the imperative adapter exists would risk
|
||||
* rework across Phases 3-6. This slice ships only what the declarative adapter
|
||||
* (AC1) needs: the kind discriminator + runtime + install/uninstall entry.
|
||||
*
|
||||
* Both adapters bind the SAME engine (install-engine.cjs / the loop resolver);
|
||||
* they differ in HOW — declarative projects files (lossy: drops loop
|
||||
* orchestration), imperative drives host primitives in-process. See ADR-1239
|
||||
* "How a capability reaches a host (two adapters, one engine)".
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Kinds
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const ADAPTER_KINDS = Object.freeze(['declarative', 'imperative'] as const);
|
||||
export type AdapterKind = (typeof ADAPTER_KINDS)[number];
|
||||
export type Scope = 'global' | 'local';
|
||||
// ---------------------------------------------------------------------------
|
||||
// Intent shapes (minimal — grow when the imperative adapter fixes the shape)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Install intent accepted by a `HostIntegrationInterface.install`.
|
||||
*
|
||||
* `resolvedProfile` + `resolveAttribution` mirror `installRuntimeArtifacts`
|
||||
* (install-engine.cjs) — the declarative adapter passes them straight through to
|
||||
* the engine. The imperative adapter (future) will source them from the host.
|
||||
*/
|
||||
export interface AdapterInstallIntent {
|
||||
configDir: string;
|
||||
scope: Scope;
|
||||
resolvedProfile: unknown;
|
||||
resolveAttribution?: (runtime: string) => unknown;
|
||||
}
|
||||
|
||||
export interface AdapterUninstallIntent {
|
||||
configDir: string;
|
||||
scope: Scope;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// The contract
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The minimal contract both embedding adapters satisfy. `kind` discriminates
|
||||
* declarative (projection) from imperative (in-process engine drive). Both
|
||||
* `install`/`uninstall` delegate to the shared engine surface; neither
|
||||
* reimplements the loop. The byte-identity of the declarative adapter's output
|
||||
* to today's install is gated by `tests/golden-install-parity.test.cjs`
|
||||
* (both route through the same `installRuntimeArtifacts` engine function).
|
||||
*/
|
||||
export interface HostIntegrationInterface {
|
||||
readonly kind: AdapterKind;
|
||||
readonly runtime: string;
|
||||
install(intent: AdapterInstallIntent): void;
|
||||
uninstall(intent: AdapterUninstallIntent): void;
|
||||
}
|
||||
|
||||
// NOTE: `ADAPTER_KINDS` is exported above as a runtime const so this module
|
||||
// compiles to a non-empty .cjs (the interfaces above are erased by tsc) and so
|
||||
// adapter implementors can reference the frozen kind set at runtime.
|
||||
Reference in New Issue
Block a user