import { type GjcLifecycleError, type GjcPluginRegistry, type GjcPluginRegistryEntry, type GjcPluginRegistrySource, type GjcPluginScope, type NormalizedGjcPluginBundle } from "./types"; export interface GjcBundleTransactionOptions { scope: GjcPluginScope; cwd: string; /** * Policy hook evaluated while both scope locks are held. It decides whether * to commit the candidate, report an already-satisfied no-op, or abort with * a typed lifecycle error. Only the lifecycle service supplies this. */ decide: (input: GjcBundleTransactionContext) => Promise; } export interface GjcBundleTransactionContext { targetRegistry: GjcPluginRegistry; /** Both scopes, deterministically sorted, for cross-scope decisions. */ effective: GjcPluginRegistryEntry[]; existing: GjcPluginRegistryEntry | undefined; bundle: NormalizedGjcPluginBundle; /** Entry the candidate would produce if committed as-is. */ candidate: GjcPluginRegistryEntry; } export type GjcBundleTransactionDecision = { kind: "commit"; entry: GjcPluginRegistryEntry; } | { kind: "noop"; entry: GjcPluginRegistryEntry; } | { kind: "abort"; error: GjcLifecycleError; }; export type GjcBundleTransactionResult = { status: "committed"; entry: GjcPluginRegistryEntry; remnants: string[]; } | { status: "noop"; entry: GjcPluginRegistryEntry; remnants: string[]; } | { status: "aborted"; error: GjcLifecycleError; remnants: string[]; }; export declare class GjcPluginSourceUnavailableError extends Error { readonly code: "source_unavailable"; constructor(); } /** * Serialized bundle transaction: prepare outside the locks, then hold the * user->project locks in a fixed order so the decision sees a consistent * cross-scope view. Only the target scope is ever committed. */ export declare function runGjcBundleTransaction(source: string, options: GjcBundleTransactionOptions): Promise; /** Compile a source into a validated candidate bundle without touching disk state. */ export declare function resolveGjcBundleCandidate(source: string, fn: (input: { bundle: NormalizedGjcPluginBundle; source: GjcPluginRegistrySource; }) => Promise): Promise; /** Build the registry entry a candidate bundle would produce at a target path. */ export declare function candidateRegistryEntry(bundle: NormalizedGjcPluginBundle, scope: GjcPluginScope, cwd: string, source: GjcPluginRegistrySource, now: string): GjcPluginRegistryEntry; /** * True when a spec has the SHAPE of a GJC bundle source: a filesystem path, a * git locator, or a tarball. This is a pure string test that never touches the * filesystem or the network, so a deleted or unreachable source is still * recognised as GJC-intent and can reach the lifecycle's typed refusal instead * of falling through to npm. * * npm and marketplace specs are never path/git/tarball shaped, so this cleanly * separates the two install worlds. */ export declare function isGjcPluginSourceShape(source: string): boolean; /** True only when the source actually resolves to a GJC plugin bundle (root gajae-plugin.json). */ export declare function isGjcPluginBundleSource(source: string): Promise;