/** * store.ts — The files the extension itself reads and writes, and the probe * that decides who owns them. * * The *meaning* of those files lives elsewhere: `state.ts` parses the state * mirror and decides whether it may be adopted, `config.ts` overlays the * config file. This module is only the disk: where the bytes go, how they * get there without a crash leaving half a file behind, how a pid is * tested for life, and which of the possible worker binaries a given * deployment actually has on it. * * That split is what keeps both halves testable. Everything here takes its * paths as arguments (so a test can point it at a temp directory, the way * `log.ts` and `media.ts` already do), and nothing here imports another * module of this extension at runtime, which node's type stripper requires. * * Errors are thrown rather than logged: the caller owns the logger, and the * one place that must never fail loudly — sweeping credentials, where a * single unremovable file must not abort the rest — collects them instead. */ /** * Write a file so that a reader never sees a partial one. * * A crash midway through a plain overwrite leaves truncated JSON, and a * state file that fails to parse takes the whole queue and the undelivered * reply with it. Write-then-rename makes the swap atomic. */ export declare function writeFileAtomic(file: string, contents: string): void; /** * Read whichever of `files` exists first, reporting which one it was. * * Used for the state mirror and its pre-0.2 predecessor: the caller has to * know which layout it got, and — for the legacy file — must not delete it * until the contents are safely stored in the new one. */ export declare function readFirstExisting(files: readonly string[]): { file: string; text: string; } | null; /** The bound owner, or '' when nothing is bound yet. Throws if unreadable. */ export declare function readOwnerFile(file: string): string; export declare function writeOwnerFile(file: string, userId: string, boundAt: string): void; export declare function removeOwnerFile(file: string): void; export interface CredentialSweep { removed: number; /** One message per file that could not be removed; the caller logs them. */ failures: string[]; } /** * Delete the SDK's credential store, so the next login needs a scan. * * The SDK's FileStorage writes one JSON file per key into its storage dir, * which is WECHAT_HOME. These four are its STORAGE_KEYS * (`dist/storage/interface.js`), not a guess; the list is named explicitly * rather than wiping the directory because owner.json, the state mirror and * the channel log all live there too. A key the SDK adds later is simply * not removed — logging out and finding a stale cursor is recoverable, * deleting the owner binding is not. */ export declare function clearCredentialFiles(dir: string): CredentialSweep; export interface WorkerCommand { /** Executable to spawn. */ command: string; args: string[]; /** A note the caller should log. Non-fatal: the spawn goes ahead. */ warning?: string; } /** * Decide how to start the worker in *this* deployment. * * Three shapes exist and all three are real. The npm package ships * `dist/` only, and pi loads `dist/index.js` — so `packageDir` is the * `dist/` directory itself and the worker sits beside it. In a source * checkout pi loads `index.ts` and `packageDir` is the repo root, with the * build one level down. A directory hand-copied into * `~/.pi/agent/extensions/` with no build at all is the third, and it has * to keep working: that is what `tsx` is for. * * `nodeExecPath` is the interpreter to run the compiled worker with — * `process.execPath`, the binary already running pi. Spawning a bare * `node` instead searches PATH, which is not the same thing: pi may have * been launched by a version manager, a desktop app or a launch agent * whose PATH has no `node` on it, or an older one. * * The tsx fallback prefers the local install for the same class of reason. * `npx tsx` resolves against the *child's* cwd, inherited from wherever the * user started pi — some unrelated project — so it misses this extension's * own install and fetches tsx from the registry, making the first worker * start need network. * * Filesystem probes, not guesses, and the reason this is here rather than * in the closure: a wrong answer means the channel silently never starts, * and until it was a function of its arguments nothing could assert it. */ export declare function resolveWorkerCommand(packageDir: string, nodeExecPath: string): WorkerCommand; /** * Does this pid belong to a running process? * * Signal 0 tests for existence without touching the process. This is half * of the ownership decision in `state.ts`: the other half is the lease, * because a pid alone cannot survive a SIGKILL — the number gets recycled, * and an unrelated process then looks exactly like a live pi. */ export declare function isProcessAlive(pid: number): boolean; //# sourceMappingURL=store.d.ts.map