/** * Filesystem helpers shared by the init write-* modules: atomic and * timestamp-stable writes, the conversion-target guard, and tree walkers. */ import type { InitResult } from './types.js'; export declare function atomicWriteFile(target: string, content: string | Buffer, encoding?: BufferEncoding): void; /** * Write a generated file that embeds a `Generated: ` line, * skipping the write entirely when that stamp is the only thing that would * change. Otherwise every `init --force` rewrote these files with a fresh * timestamp and left the repository dirty by exactly two files, for * information nobody can act on. Skipping the write (rather than reusing the * old stamp) keeps the mtime stable too, and the stamp keeps its meaning: * when this content was generated. */ export declare function writeGeneratedFile(target: string, content: string): void; /** * Guard for the write-opencode.ts / write-kimicode.ts converters, which read * `.claude/{agents,commands,skills}` and write the converted result into what * is expected to be a separate platform directory (`.opencode/...`, * `.kimi-code/...`). If that destination has been symlinked back into * `.claude/` (observed live: a committed `.opencode/command -> ../.claude/commands` * symlink), the atomic write-then-rename in `atomicWriteFile` resolves through * the symlink and lands the converted, flattened, field-injected output * straight back in the Claude source tree it was just read from — silently * corrupting hand-authored agent/skill/command files and resurrecting * "deleted" flattened command duplicates on every `--force` run. * * Checked once per destination directory (not per file) before its copy loop. * Returns false and records one `result.errors` entry when `destDir` resolves * inside `claudeDir`; the caller should skip the whole loop rather than write * file-by-file into the wrong place. A `destDir` that is itself a symlink to * `claudeDir/` is a deliberate mirror (this repo links * `.opencode/agent -> ../.claude/agents`), so it is skipped without the error. */ export declare function isSafeConversionTarget(destDir: string, claudeDir: string, result: InitResult, label: string, mirrorOf?: string): boolean; /** Relative file paths under `dir` (files only). Used by every o-38 mirror * sweep (copySkills's `.gemini`/`.agents`, writeOpencodeFiles's * `.opencode/skills`) to tell "content the source regenerated" from "a file * someone added directly inside the mirror" (o-38 §2·0b). */ export declare function listFilesRecursive(dir: string): Set; /** * Copy directory recursively, leaving out any source path `skip` returns true for */ export declare function copyDirRecursive(src: string, dest: string, skip?: (srcPath: string) => boolean): void; /** * Count files with extension in directory */ export declare function countFiles(dir: string, ext: string): number; /** Recursively collect .md files under dir, returned relative to dir. */ export declare function walkMdFiles(dir: string): string[]; /** Skip READMEs and other non-definition markdown. */ export declare function isLikelyUserFile(rel: string): boolean; /** Pull the `name:` scalar from a frontmatter block (best-effort). */ export declare function extractFmName(md: string): string | null; //# sourceMappingURL=fs-helpers.d.ts.map