export type SkillUpdateKind = "none" | "patch" | "minor" | "major" | "unknown"; /** * Per-skill source override. Lets an operator/QA point one skill at a * different repo/branch/path than the manifest declares — e.g. testing a skill * on a feature branch without editing the checked-in manifest. * * A per-skill `branch` override **beats** the global `SENPI_SKILLS_BRANCH` * env knob (per-skill intent wins over the force-all knob); only the * `SENPI_SKILLS_BRANCH_` per-skill env var outranks it. See * `resolveSkillSource` for the full precedence. */ export interface SkillSourceOverride { repo?: string; branch?: string; /** Pin to a commit SHA, or `"latest"` to track the branch tip. */ commit?: string; path?: string; /** * Auto-update major-version ceiling for this skill (overrides the manifest). * See {@link import("./manifest.js").SkillManifestEntry.maxMajor}. */ maxMajor?: number; } /** Minimal logger interface accepted throughout the skills-manager package. */ export interface LoggerLike { info(...args: unknown[]): void; warn(...args: unknown[]): void; error(...args: unknown[]): void; } export type SkillsManagerHealth = "healthy" | "degraded" | "unhealthy" | "disabled"; /** * Raw user-supplied config block before defaults are applied. * All fields are optional — resolveSkillsManagerConfig() fills in the rest. */ export interface RawSkillsManagerConfig { enabled?: boolean; /** * Skills install/search directory. * * Accepts either a single string (legacy form) or an array of strings * (search path, first is the primary write target). `resolveSkillsManagerConfig` * normalises both shapes to a non-empty `string[]` and falls back to * `DEFAULT_SKILLS_DIRS` when omitted, null, an empty array, or wrong-typed. */ skillsDir?: string | string[]; /** * @deprecated Ignored. The managed skill set is defined solely by the * manifest (`skills-manifest.json`). This field is tolerated for backward * compatibility with existing configs but no longer affects which skills are * managed. Use `overrides` to retarget a skill's source, or `enabled: false` * to disable the manager. */ skills?: string[]; /** * Per-skill source overrides keyed by skill name. Optional. Each entry may * override `repo`, `branch`, and/or `path` for that skill (e.g. * `{ "senpi-strategy-ops": { "branch": "strategy-v2" } }`). The global * `SENPI_SKILLS_BRANCH` env var still takes precedence over these. */ overrides?: Record; } /** Resolved config — all fields have safe defaults filled in. */ export interface SkillsManagerConfig { enabled: boolean; /** * Skills directory search path. Always a non-empty array after * resolution; `[0]` is the **primary** (writes go here), the rest are * read-only mirrors scanned during version checks and discovery. * * For backward compat with code that wants a single string (logs, snapshot * fields, single-dir helpers), use `skillsDir[0]`. */ skillsDir: string[]; /** * @deprecated Ignored by the coordinator. The managed skill set is the * manifest set (`getManifestSkillNames`), full stop. Still resolved here * (defaults to the manifest names) for backward-compatible config shape, but * nothing reads it to define the set. To disable the manager use * `enabled: false`; to retarget a skill's source use `overrides`. */ skills: string[]; /** * Per-skill source overrides (repo/branch/path), keyed by skill name. * Always present after resolution (defaults to `{}`). See * {@link SkillSourceOverride}. */ overrides: Record; } /** Per-skill state persisted across gateway restarts. */ export interface SkillState { name: string; installedVersion: string | null; /** * Most recent remote version observed during a successful version check. * Persisted (alongside `installedVersion`) so `getSnapshot()` — and * therefore `senpi.skills.status` / dashboards — return useful data * immediately after a gateway restart, instead of `null` until the first * post-restart tick fires (which can be up to * `autoUpdate.startupDelaySeconds` + one poll interval away). * * Written by every code path that calls `checkSkillVersion` (tick, * `updateSkill`, `updateAll`); read by `buildSnapshot`. */ latestVersion: string | null; lastCheckedAt: string | null; consecutiveFailures: number; lastFailureAt: string | null; lastFailureReason: string | null; } /** Top-level persisted state for the skills manager. */ export interface SkillsManagerState { skills: Record; } /** Read-only snapshot for gateway RPCs and health views. */ export interface SkillsManagerSnapshot { enabled: boolean; /** * Skills directory search path. Mirrors `SkillsManagerConfig.skillsDir` — a * non-empty array where `[0]` is the primary write target. Callers * rendering this for humans should join with commas (e.g. `dirs.join(", ")`). */ skillsDir: string[]; health: SkillsManagerHealth; lastAction: string; lastError: string | null; skills: SkillSnapshot[]; } /** Per-skill entry in a snapshot. */ export interface SkillSnapshot { name: string; installedVersion: string | null; latestVersion: string | null; lastCheckedAt: string | null; consecutiveFailures: number; lastFailureReason: string | null; /** * True when the latest observed remote major exceeds the installed major — * i.e. a major upgrade is available but not yet installed (gated unless the * skill's `maxMajor` ceiling authorizes it). Surfaced by `senpi skills status` * so pending majors are visible without notifications. */ majorPending: boolean; } /** Result of a version check for a single skill. */ export interface SkillVersionInfo { localVersion: string | null; remoteVersion: string | null; updateKind: SkillUpdateKind; } /** Injectable overrides used in unit tests to avoid network and git calls. */ export interface SkillsUpdateCoordinatorDeps { /** * Override version check — called as (skillsDirs, skillName, rawBaseUrl, logger). * Defaults to the real checkSkillVersion with fetchImpl omitted (uses global fetch). * * `skillsDirs` is the search-path array from the resolved config; the real * `checkSkillVersion` tries each in order when reading SKILL.md. */ checkSkillVersion?: (skillsDirs: readonly string[], skillName: string, rawBaseUrl: string, logger?: LoggerLike, remotePath?: string) => Promise; /** * Override clone + install — receives the list of skill names that need * updating and the config. Defaults to real cloneSkillsRepo + installSkill. */ cloneAndInstall?: (skills: string[], config: SkillsManagerConfig) => Promise>; /** Override bootstrap — avoids real git clone in unit tests. */ bootstrapSkillsIfNeeded?: (config: SkillsManagerConfig, logger: LoggerLike) => Promise; /** * Override the managed skill set. **Test-only seam** — production always * uses the manifest (`getManifestSkillNames`). Lets unit tests drive the set * without a fixture manifest on disk. */ listManagedSkills?: () => string[]; } /** Constructor options for {@link SkillsUpdateCoordinator}. */ export interface SkillsUpdateCoordinatorOptions { config: SkillsManagerConfig; stateDir: string; logger: LoggerLike; deps?: SkillsUpdateCoordinatorDeps; } /** * Per-skill outcome from a clone+install batch. * * Populated by {@link SkillsUpdateCoordinator.cloneAndInstallMany}: one entry * per skill name passed in. `error` is set when that specific skill's install * failed (clone succeeded, install failed); absent on success. `version` is * the installed version when known, `null` otherwise (e.g. missing on the * failure path or when the injected test dep didn't supply one). */ export type InstallOutcome = { version: string | null; error?: string; }; /** * Discriminated-union wrapper returned by * {@link SkillsUpdateCoordinator.processInstallOutcome}. Collapses the raw * {@link InstallOutcome} shape (where `error` is optional) into an explicit * success/failure tag so callers can branch without re-checking `error` — * mirrors the Result/Either pattern. */ export type ProcessedInstallOutcome = { success: true; version: string | null; } | { success: false; error: string; }; //# sourceMappingURL=types.d.ts.map