/** * A pack install (DES-artifact-editor-plugins §3.2, §5.2, §9.2, §12.1; EP-C1 + the install-time * conformance run of EP-C8, operator ruling X3). * * Install is human-only (§6.4) and fail closed at every step, in this order: * 1. garden's `pack check --json` on the pack root (schema, every editor's entry inside the pack, its * hash, its size, nothing loaded from outside); * 2. the pack ships editors only: one that also ships skills or blocks is refused with the approval * list (501 `pack_ships_skills_or_blocks`), since their own "Add these" step (§3.2) is not built; * 3. the **conformance run**, done by crew itself: garden's `scripts/editor/conformance.py --pack * --host-url ` drives studio's conformance host page (served by this daemon) * in headless Chromium against each editor. A host with no browser runtime gets crew's own * (`conformance-runtime.ts`: a private venv with Playwright, made once, B8). A failed case, a * browser that cannot be provisioned or no runner is a 422 with the report — an unverified * editor is never installed. Only crew's run counts (§12.1, review S13); * an author's own run is not consulted; * 4. the registry reads every editor back from disk at its pinned hash and records it. * Nothing is written into the pack. The registry file is `daemon-editors.json`. */ import type { EditorConformanceSummary, InstallEditorResponse, PackCheckResult } from '../core/types.js'; import { execCapped } from '../core/exec.js'; import { EditorRegistry } from './registry.js'; import { type ConformanceProvisioner } from './conformance-runtime.js'; export type PackCheckRunner = (packRoot: string) => Promise; /** * Garden's gate, run as a child: `python3 /scripts/pack/check.py --json --garden-root ` * (`python` when `python3` is not on PATH). A missing garden or an unparseable verdict is a FAILED * check with the reason — never a pass. */ export declare function gardenPackCheck(gardenRoot: string | null): PackCheckRunner; export declare class PackInstallError extends Error { readonly status: 400 | 404 | 409 | 422 | 501; readonly check?: PackCheckResult | undefined; readonly body?: Record | undefined; constructor(status: 400 | 404 | 409 | 422 | 501, message: string, check?: PackCheckResult | undefined, body?: Record | undefined); } /** The install-time conformance run: the pack root in, garden's report out; `editors` (the manifest's * entries) sizes the run's overall cap. */ export type ConformanceRunner = (packRoot: string, editors?: readonly Record[]) => Promise; /** garden's bound on each load of the conformance host page (scripts/editor/conformance.py `--timeout`): * this env var, read by garden's runner itself in the daemon's environment, else 120 s. */ export declare const CONFORMANCE_TIMEOUT_ENV = "WG_EDITOR_CONFORMANCE_TIMEOUT"; export declare const DEFAULT_CONFORMANCE_LOAD_S = 120; /** * The per-load bound the runner will use, read the way garden's `load_timeout` reads it: Python's * `float()` of the env value (surrounding spaces and digit-group underscores allowed, `1_000` = 1000), * valid only within 5-1800 s. A value garden refuses fails its run at once, so the default stands. */ export declare function conformanceLoadSeconds(env?: NodeJS.ProcessEnv): number; /** * The overall cap on one conformance run, derived from garden's per-load bound so the two never * disagree. Per editor (garden scripts/editor/conformance.py): * - host-page loads, each allowed the whole bound: 2 (the cases, then the hash-pinned reload); for an * editor that speaks protocol 2, 1 more for the card (full screen reuses it) and 1 per plugin-rendered * options tab (at least 1 when it declares options); * - the cases' fixed waits (~30 s) plus each sequential answer the host allows up to 2 s: every card * action, every options tab, and the two full-screen mode changes; * plus 60 s for the browser start. One protocol-2 editor with no surfaces, at the default 120 s: * 60 + (30 + 2 x 2) + 3 x 120 = 454 s. A fixed 240 s cap killed a correct install at 249 s. */ export declare function conformanceCapMs(editors: readonly Record[], loadS: number): number; /** The cases a conformance run must report passing for every editor (garden's runner: 0-6 and 8-12). */ export declare const CONFORMANCE_CASES: readonly ["0-manifest", "1-handshake", "2-sizes", "3-no-network", "4-permissions", "5-typing", "6-forwarding", "8-strict-input", "9-liveness", "10-keyboard", "11-theme", "12-hash-pinned"]; /** The protocol-2 cases an editor whose `protocol` lists 2 must also pass (DES-EDITOR-PLUGIN-CONTRACT-001 §8.3): * its surfaces, card, options and full screen. A garden runner before them reports none, so such an editor is * refused (fail closed). Case 17 (protocol-1 compatibility) restates cases 1-12, so it is not required. */ export declare const CONFORMANCE_CASES_V2: readonly ["13-surfaces", "14-card", "15-options", "16-full"]; /** The cases one editor's install requires, by the protocols its manifest entry lists. */ export declare function requiredCases(entry: Record): string[]; /** * Garden's conformance runner as a child: `python3 /scripts/editor/conformance.py --pack * --host-url --json`. A missing garden or runner, no daemon URL, no browser, or an * unreadable report is a FAILED run with the reason — never a pass. */ export declare function gardenConformance(gardenRoot: string | null, hostUrl: () => string | null, deps?: { env?: NodeJS.ProcessEnv; exec?: typeof execCapped; provision?: ConformanceProvisioner; }): ConformanceRunner; /** `POST /editors {packRoot, enabled?}`: the gate, the conformance run, then the registry. */ export declare function installPack(packRootRaw: string, enabled: boolean | undefined, deps: { check: PackCheckRunner; conformance: ConformanceRunner; registry: EditorRegistry; }): Promise; //# sourceMappingURL=pack-install.d.ts.map