import { type Context } from '@deepseek-ai/cordis'; import type { GateResult, SecretFinding, ValidationResult } from '@mstar-harness/engine'; import type { FsTarget, FsWriteIntent } from '@deepseek-ai/dsh-fs'; import { HarnessResolver } from './_shared.ts'; import type { Config } from './_shared.ts'; /** The four artifact seams (design-md / audit / compound / roles). */ export type SeamId = 'design-md' | 'audit' | 'compound' | 'roles'; /** * Advisory emitted on seam-gate decisions (the `mstar/status-gate` / * `mstar/skill-lint` advisory pattern reused for the design-md / audit / * compound / roles artifact gates — one event with a `seam` discriminator, * consumers filter on it). Emitted when an in-scope artifact write-intent * finds violations in the pre-write on-disk document (warn mode), when hard * mode allows an ALREADY-invalid document as a repair escape, and when the * gate degrades to allow after an unexpected internal error. Clean passes * stay silent. * * The gate NEVER throws on the listener path (status-gate repair-escape * semantics): the intent waterfall carries no incoming content, so the only * lint signal is the pre-write on-disk state; the typed hard veto lives on * the known-document branch (`lintSeamWrite` + friends, `SeamVetoError`). */ export interface SeamLintAdvisory { /** The artifact seam that decided this intent. */ seam: SeamId; /** Which intent slot passed the gate (write-intent only — no linted edit slot). */ operation: 'write'; /** `displayPath` of the guarded file. */ target: string; /** The gate verdict (warn-mode: `hardBlocked` false; hard repair escape: `hardBlocked` true). */ result: GateResult; /** Resolved enforcement flag: false for warn-mode advisories, true for hard-mode repair escapes. */ hard: boolean; /** True when hard mode allowed a write to an ALREADY-invalid document (repair escape). */ repair?: boolean; /** True when the gate errored internally and degraded to allow (error-containment envelope). */ degraded?: boolean; } /** * Validate a DESIGN.md / DESIGN.dark.md document: token frontmatter plus * light/dark parity against the on-disk sibling when it exists (parity is * inherently cross-file — the sibling is read at validation time; a dark * write with no light sibling skips parity). Shared by the content-blind * listener and the known-document branch. */ export declare function validateDesignDoc(doc: string, path: string): GateResult; /** * Validate a review report document: the credential scan (mstar-audit Hard * Rule 4) — a review report carries no plan Status block, so the scan is the * seam's whole contract. The findings summary (line + type only — secret * values are never reproduced) rides along for the validate tool's `secrets` * output field; the gate path reads only `ok`/`violations`. */ export declare function validateAuditDoc(doc: string, path: string): GateResult & { findings: SecretFinding[]; }; /** * Validate a knowledge doc: schema.yaml frontmatter contract + referenced * path/module existence. The repo root for `referenceExists` is derived as * the parent of `{HARNESS_DIR}` — the plan-conventions discovery layout * always places the harness dir directly under the repo root * (`/.mstar`, `/.agents`, `/plans`). * simplify: single-level harness layout — revisit if a nested harness root * becomes an observed deployment. */ export declare function validateCompoundDoc(doc: string, _path: string, harnessDir: string | null): GateResult; /** * Validate the mstar-roles skill-dir state: role mapping / parameter tables * against the on-disk references layout, plus load-order declarations * across every sibling `mstar-*` skill (unreadable sibling SKILL.md files * are skipped — best-effort reads for a lint that must never take the gate * down). The engine-absent archive is linted over its whole text face, so its * `references/*.md` are merged into its SKILL.md text (missing/unreadable * references dirs contribute nothing — no guard needed at the call site). * The `skillsRoot` override exists for the validate tool (its * explicit `skills_root` parameter); the gate path keeps the default * (the parent of the roles dir). * @param rolesDir - the mstar-roles skill directory. * @param skillsRoot - directory scanned for sibling `mstar-*` skills * (default: `dirname(rolesDir)`). */ export declare function validateRolesState(rolesDir: string, skillsRoot?: string): GateResult; /** * `fs/write-intent` listener for one seam gate. Registered with `prepend` * for the same reachability reason as the status gate: the slot is * first-wins by registration order (dsh-fs-policy README), so without * prepend a policy plugin mounted earlier would make this gate unreachable. * Every gate decision (warn advisory, repair escape, degraded allow) calls * `next()` — the seam gates never own the intent decision and must not * terminate the chain (fs-policy's observed-state CAS stays live in * composed deployments). */ export declare function seamWriteIntentListener(ctx: Context, resolver: HarnessResolver, config: Config, seam: SeamId, target: FsTarget, actor: object | undefined, next: () => FsWriteIntent | undefined | Promise): Promise; /** * Typed hard-mode veto for the seam gates (the dsh fs-policy veto channel: * "veto = throw"; the write tool turns the throw into an isError tool * result carrying `{ name, code }`). Thrown ONLY by {@link lintSeamWrite} — * the entry that lints a KNOWN incoming document (the brief's "hard veto * via throw where the slot semantics allow" branch). The content-blind * `fs/write-intent` listeners never throw: they cannot distinguish a repair * from a re-violation, so hard mode degrades to the repair escape there * (see {@link gateSeamIntent}). */ export declare class SeamVetoError extends Error { /** Stable code for tool-result serialization (the `{ name, code }` convention). */ readonly code: 'seam.veto'; /** The seam whose gate vetoed the write. */ readonly seam: SeamId; /** The violations that caused the veto. */ readonly violations: readonly ValidationResult[]; constructor(seam: SeamId, target: string, violations: readonly ValidationResult[]); } /** * Enforce one seam's lints over a KNOWN document (the brief's "incoming * doc when available" branch): `Enforcement: hard` + violations → throw the * typed {@link SeamVetoError} (fs-policy veto channel); warn mode → return * the gate for advisory logging. A repairing write carries a VALID incoming * document and passes by construction — no repair escape is needed on this * branch. The content-blind listener paths (where the incoming doc is never * visible) route through {@link gateSeamIntent} instead, which applies the * repair-escape decision. * @param seam - the artifact seam whose validator runs. * @param doc - the document about to be written (roles: ignored — the * validator checks the whole mstar-roles dir state). * @param options - target display path (veto message) + resolved hard flag * + the plugin harness dir (compound reference checks; null-tolerant). */ export declare function lintSeamWrite(seam: SeamId, doc: string, options: { target: string; hard: boolean; harnessDir?: string | null; }): GateResult; /** {@link lintSeamWrite} bound to the design-md seam. */ export declare function lintDesignMdWrite(doc: string, options: { target: string; hard: boolean; harnessDir?: string | null; }): GateResult; /** {@link lintSeamWrite} bound to the audit seam. */ export declare function lintAuditWrite(doc: string, options: { target: string; hard: boolean; harnessDir?: string | null; }): GateResult; /** {@link lintSeamWrite} bound to the compound seam. */ export declare function lintCompoundWrite(doc: string, options: { target: string; hard: boolean; harnessDir?: string | null; }): GateResult; /** {@link lintSeamWrite} bound to the roles seam. */ export declare function lintRolesWrite(doc: string, options: { target: string; hard: boolean; harnessDir?: string | null; }): GateResult;