/** * Session-drift watchdog (file-scope drift). * * Detects when files modified in the working tree fall *outside* the * scope declared by the active task's `Task.files[]` declaration. * * This is the file-modification analogue of `session-drift.ts`'s * task-completion drift signal. The two cooperate but address different * symptoms of the same underlying problem (silent sidetrack work): * - `session-drift.ts` measures drift across the *task graph*. * - `drift-watchdog.ts` measures drift across the *file tree*. * * Project-agnostic: relies on `git status --porcelain`, which exists in * every git project regardless of language, framework, or build system. * * @task T1594 * @epic T1586 */ /** * Result of one drift-watchdog evaluation. * * @public */ export interface DriftReport { /** Active session ID, or null if no session is active. */ sessionId: string | null; /** Active task ID (`taskWork.taskId`), or null if no task is in focus. */ activeTaskId: string | null; /** Files declared on the active task's `files[]` (normalized to repo-relative). */ declaredFiles: string[]; /** Files git reports as modified (porcelain --short). */ modifiedFiles: string[]; /** Modified files NOT covered by the declared scope. */ outsideScope: string[]; /** Modified files covered by the declared scope. */ insideScope: string[]; /** * Suggested `cleo pivot` command if drift exceeds the threshold (50%). * Omitted when no pivot recommendation applies. */ suggestedPivot?: string; } /** * Options controlling drift detection. * * @public */ export interface DetectSessionDriftOptions { /** Absolute path to the project root (the git repo). */ projectRoot: string; /** * Audit-log scope. * - `"global"` (default): writes to `~/.local/share/cleo/audit/session-drift.jsonl` * - `"local"`: writes to `/.cleo/audit/session-drift.jsonl` */ auditScope?: 'global' | 'local'; /** * Drift ratio (`outsideScope.length / modifiedFiles.length`) above which a * pivot recommendation is emitted. Default: `0.5`. */ pivotThreshold?: number; /** * Test seam — override the modified-files reader. Defaults to * `git status --porcelain` against `projectRoot`. * @internal */ listChangedFiles?: (projectRoot: string) => Promise; /** * Test seam — override the audit append path. When set, the watchdog * writes the JSONL line to this absolute file instead of the resolved * default. Used by tests to avoid polluting the real audit log. * @internal */ auditPathOverride?: string; } /** * Persisted shape of a single drift-watchdog audit line. One JSON object per * line in `session-drift.jsonl`. Append-only, never read by CLEO at runtime. * * @public */ export interface DriftAuditEntry { timestamp: string; sessionId: string | null; activeTaskId: string | null; declaredFiles: string[]; modifiedFiles: string[]; outsideScope: string[]; ratio: number; pivotSuggested: boolean; } /** Default ratio above which we emit a pivot suggestion. */ export declare const DEFAULT_PIVOT_THRESHOLD = 0.5; /** Default env-var name controlling watchdog cadence (seconds). */ export declare const DRIFT_WATCHDOG_INTERVAL_ENV = "CLEO_DRIFT_WATCHDOG_INTERVAL_SEC"; /** Default cadence in seconds (used by future periodic firing — not this task). */ export declare const DRIFT_WATCHDOG_INTERVAL_DEFAULT_SEC = 300; /** Relative path used when writing to the local-scope audit log. */ export declare const LOCAL_AUDIT_RELPATH = ".cleo/audit/session-drift.jsonl"; /** Relative path under `~/.local/share/cleo` for the global-scope audit log. */ export declare const GLOBAL_AUDIT_RELPATH = "audit/session-drift.jsonl"; /** * Return the audit-log path for the requested scope. * - `local` → `/.cleo/audit/session-drift.jsonl` * - `global` → `/audit/session-drift.jsonl` * * Resolves the global path through the `@cleocode/paths` SSoT so the * watchdog stays consistent with the rest of the CLEO ecosystem * (XDG on Linux, Library/Application Support on macOS, %LOCALAPPDATA% * on Windows — and `CLEO_HOME` overrides on every platform). */ export declare function resolveDriftAuditPath(projectRoot: string, scope: 'global' | 'local'): string; /** * Detect file-scope session drift for the active session. * * Compares files modified in the git working tree against the active * task's declared `files[]` scope. Files modified but not declared * surface as `outsideScope`; if their fraction exceeds the pivot * threshold, a `cleo pivot` suggestion is attached and the event is * recorded to the audit log. * * Returns an empty (no-drift) report when there is no active session * or no active task — sessions and unfocused work cannot drift. * * @example * ```ts * const report = await detectSessionDrift({ projectRoot: process.cwd() }); * if (report.outsideScope.length > 0) { * console.warn(`Drift: ${report.outsideScope.length} files outside scope`); * if (report.suggestedPivot) console.warn(report.suggestedPivot); * } * ``` * * @public * @task T1594 */ export declare function detectSessionDrift(opts: DetectSessionDriftOptions): Promise; /** * Read the configured watchdog cadence (seconds) from * `CLEO_DRIFT_WATCHDOG_INTERVAL_SEC`, falling back to the default. * * Periodic firing is a future task — for now the value is plumbed so * callers (e.g. a daemon, a hook) can read it without re-implementing * the env-var contract. * * @public * @task T1594 */ export declare function getDriftWatchdogIntervalSec(env?: NodeJS.ProcessEnv): number; //# sourceMappingURL=drift-watchdog.d.ts.map