/** * Pack discovery substrate (ADR-097 § 5 Q5 + § 10, mmnto-ai/totem#1768). * * Reads `.totem/installed-packs.json` synchronously at engine boot, * resolves each registered pack's registration callback module, and * invokes the callback with a `PackRegistrationAPI` so the pack can * register its ChunkStrategy + ast-grep Lang + WASM grammar entries * before the engine seals. * * Sealing happens at the end of `loadInstalledPacks()` after every pack * callback has returned. Once sealed, subsequent `register()` calls on * either registry throw — see `chunker-registry.ts:seal()` and * `ast-classifier.ts:sealLangRegistry()`. * * The seal is the only synchronization boundary between the registration * phase and the runtime phase. CLI commands invoke `loadInstalledPacks()` * immediately after config load and before any other engine surface, so * pack registration is always complete before any chunker / language * lookup happens. * * Failure-mode discipline (Tenet 4): * - Missing manifest: silent (treated as no packs); user runs `totem sync` * to generate. * - Malformed manifest: hard error. * - Pack require throws: hard error. * - engines['@mmnto/totem'] version mismatch: structured error per ADR-097 * Q6 (amended 2026-05-03 — moved from peerDependencies to engines field * per mmnto-ai/totem#1803 to avoid changesets `fixed` group sibling * peer-dep collision; see #1776 / #1777). * - Pack callback throws: hard error. */ import { z } from 'zod'; import { type SupportedLanguage } from './ast-classifier.js'; import type { Chunker } from './chunkers/chunker.js'; /** * `.totem/installed-packs.json` substrate. Written by `totem sync`, * consumed by `loadInstalledPacks()` at boot. * * `version: 1` is the load-bearing sentinel for forward compatibility: * future schema changes bump the version, callers fail loud on unknown * versions rather than silently mis-parsing. */ export declare const InstalledPacksManifestSchema: z.ZodEffects; /** * `@mmnto/totem` package version that wrote the manifest. Optional * for forward-compat with pre-1.27.0 manifests. Stamped at write * time by `writeInstalledPacksManifest()` from `resolveEngineVersion()`. * * Read on the lint-time stale-manifest UX-nudge fast-path * (`rule-engine.ts` parser-error intercept). Schema does not * enforce semver-validity here so a malformed cohort doesn't make * the entire manifest unreadable; the consumer treats malformed * or missing values as "stale" and surfaces the same nudge * (mmnto-ai/totem#1811, ADR-101). */ cohort: z.ZodOptional; packs: z.ZodArray; /** * The pack's `engines['@mmnto/totem']` semver range, verbatim. * (Pre-1.26.0 packs used `peerDependencies['@mmnto/totem']`; * mmnto-ai/totem#1803 moved the constraint to the `engines` * field to free `peerDependencies` for actual peer packages * and avoid changesets fixed-group sibling collisions.) */ declaredEngineRange: z.ZodString; }, "strict", z.ZodTypeAny, { name: string; resolvedPath: string; declaredEngineRange: string; }, { name: string; resolvedPath: string; declaredEngineRange: string; }>, "many">; }, "strict", z.ZodTypeAny, { version: 1; packs: { name: string; resolvedPath: string; declaredEngineRange: string; }[]; cohort?: string | undefined; }, { version: 1; packs: { name: string; resolvedPath: string; declaredEngineRange: string; }[]; cohort?: string | undefined; }>, { version: 1; packs: { name: string; resolvedPath: string; declaredEngineRange: string; }[]; cohort?: string | undefined; }, { version: 1; packs: { name: string; resolvedPath: string; declaredEngineRange: string; }[]; cohort?: string | undefined; }>; export type InstalledPacksManifest = z.infer; /** * Surface a pack's registration callback uses to extend the engine's * built-in chunker + language tables. Callbacks are synchronous (per * ADR-097 § 5 Q5 — boot must remain synchronous); WASM grammar bytes * load lazily on first ast-grep dispatch via the `wasmLoader` thunk. */ export interface PackRegistrationAPI { /** * Register a pack-contributed `ChunkStrategy` name + chunker class. * The strategy name appears in `targets[].strategy` validation and * `totem describe` output. Built-in names are immutable; pack-vs-pack * collisions on the same name throw. */ registerChunkStrategy(name: string, chunkerCtor: new () => Chunker): void; /** * Register a pack-contributed (extension, language, wasmLoader) triple. * The extension flows through `extensionToLanguage()` for ast-grep * dispatch; the language drives `loadGrammar()`; the wasmLoader thunk * resolves the grammar bytes lazily on first use. * * Built-in extensions/languages are immutable; pack-vs-pack collisions * on the same extension throw. */ registerLanguage(extension: string, lang: SupportedLanguage, wasmLoader: () => string | Uint8Array | Promise): void; } /** * The shape a pack's registration callback module must export. Packs * default-export a function matching this signature; `loadInstalledPacks` * requires the module and invokes the function once with the API surface. */ export type PackRegisterCallback = (api: PackRegistrationAPI) => void; /** * Runtime descriptor for a discovered + loaded pack. Returned from * `loadInstalledPacks` for diagnostics + `totem doctor` consumption. */ export interface LoadedPack { readonly name: string; readonly resolvedPath: string; readonly declaredEngineRange: string; } /** Options for `loadInstalledPacks` — primarily test-driven overrides. */ export interface LoadInstalledPacksOptions { /** * Project root for manifest resolution. The manifest is expected at * `//installed-packs.json`. Defaults to * `process.cwd()` when omitted. */ projectRoot?: string; /** * `config.totemDir` from the resolved totem config. Defaults to * `'.totem'` so callers without a loaded config (e.g., simple CLIs, * tests) work out of the box. */ totemDir?: string; /** * Engine semver to compare against each pack's declared * `engines['@mmnto/totem']` range. Defaults to the engine's * own `package.json#version`. */ engineVersion?: string; /** * Test-only escape hatch: list of `{ pack, callback }` tuples that * bypass the manifest read + `require()` resolution and feed callbacks * directly into the registration phase. Useful for unit tests that * register fixture chunkers/languages without writing fixture packages * to disk. * * When provided, the manifest read is skipped entirely; only these * inMemoryPacks run. */ inMemoryPacks?: ReadonlyArray<{ pack: LoadedPack; callback: PackRegisterCallback; }>; } /** * Read `.totem/installed-packs.json` and run every registered pack's * registration callback synchronously. After all callbacks return, seal * both the chunker registry and the language registry. * * Idempotent: a second call after the first throws because the engine is * already sealed (callers must not "re-load" packs at runtime). For * tests, see `__resetForTests()`. */ export declare function loadInstalledPacks(options?: LoadInstalledPacksOptions): readonly LoadedPack[]; /** * Snapshot of currently-loaded packs. Empty until `loadInstalledPacks()` * runs; populated thereafter and stable for the engine lifetime. */ export declare function loadedPacks(): readonly LoadedPack[]; /** True iff the engine has sealed (registration phase complete). */ export declare function isEngineSealed(): boolean; /** * Resolve the running `@mmnto/totem` package version from disk. * * Exported (mmnto-ai/totem#1811) so `pack-manifest-writer.ts` can * stamp the manifest's `cohort` field at write time and the * `rule-engine.ts` parser-error intercept can compare the running * engine against the manifest's recorded cohort. */ export declare function resolveEngineVersion(): string; /** * Test-only: reset pack-discovery local state (`PACK_REGISTRY` map and * `engineSealed` flag). NEVER call from production. * * **This does NOT reset downstream registries.** Tests that need a * fresh chunker or language registry must additionally invoke * `__resetForTests` from `chunker-registry.js` and `ast-classifier.js` * — those modules own their own lifecycle. Forgetting either reset * leaks built-in registrations across cases. The standard `afterEach` * pattern in `pack-discovery.test.ts` calls all three. */ export declare function __resetForTests(): void; /** Test-only: inspect chunker registry seal state. */ export declare function __isChunkerRegistrySealedForTests(): boolean; //# sourceMappingURL=pack-discovery.d.ts.map