import type { CommandResult } from '../types.js'; /** Org names are used to build filesystem paths under .monomind/orgs — reject * anything that isn't a plain identifier to prevent path traversal (e.g. * `monomind org stop '../../../../tmp/x'`). */ export declare const ORG_NAME_RE: RegExp; export declare function validateOrgName(name: string | undefined): { ok: true; name: string; } | { ok: false; result: CommandResult; }; /** Suffixes of org-internal artifact files (state/goals/threads/etc) that * share the `.json`/`.jsonl` naming pattern with the org's own config * file. Single source of truth for both listOrgConfigFiles() (which must * exclude them when discovering real org configs) and deleteAction (which * must remove all of them when deleting an org). */ export declare const ORG_ARTIFACT_SUFFIXES: string[]; export declare function listOrgConfigFiles(orgsDir: string): string[]; /** Remove a lingering stopfile so a fresh `org run` doesn't self-terminate. */ export declare const clearStopfile: (cwd: string, name: string) => void; /** Remove a lingering reload request so a fresh `org run` doesn't apply it on * its first tick. One is left behind when a previous run's stop and reload * landed in the same tick: the stop ends the wait before the reload poll runs. */ export declare const clearReloadfile: (cwd: string, name: string) => void; /** Drop stop/reload requests left behind by a previous run, for every org * `org serve` serves. #264: runAction clears these before its wait loop, but * serveAction started polling with whatever was on disk — so an `org stop` * that landed after the last daemon exited stopped the next daemon's org * seconds into its run, and a leftover `org reload` was applied to a * definition nobody had touched. * * Scope is the org config files, not `daemon.listRunning()` (what * pollStopfiles/pollReloadfiles walk): nothing is running yet at startup, so * sweeping by that would sweep nothing. Called before the first org can * start, so a request that arrives once serve is up is never discarded. * * Runfiles are deliberately left in place. `.../run` is not the same kind of * leftover: runAction writes one only against a live daemon and retracts it * itself when nothing consumes it within 15s, and it reads the file's * disappearance as "the daemon took the run". Deleting one here would report * success to a waiting `org run` and start nothing — the silent loss that ack * loop exists to prevent. A stale runfile at worst starts an org the operator * did ask for; pollRunfiles already no-ops on one that is running. * * Returns the orgs it cleared something for. */ export declare const clearStaleControlFiles: (cwd: string) => string[]; /** True when a pause sentinel exists for an org. */ export declare const isOrgPaused: (cwd: string, name: string) => boolean; export declare const clearPausefile: (cwd: string, name: string) => void; /** PID of a live `org serve` daemon for this project, or null. * * The heartbeat file is written every 30s and removed on clean exit, but a * SIGKILLed daemon leaves it behind — so liveness is confirmed against the pid * itself, not the file's presence. A stale heartbeat must not make `org run` * post a runfile nobody will ever read. */ export declare function liveServeDaemonPid(cwd: string): number | null; /** Verdict of {@link classifyRun} — what `org status` should say about a * runtime.json record that claims to be running. * - `running` — alive and producing events. * - `idle` — alive, but its event log has been silent for a while. * - `crashed` — nothing says it is alive any more. */ export type RunState = 'running' | 'idle' | 'crashed'; /** Why a run was judged alive — `pid` is the recorded one still answering; * the others mean the recorded pid is stale but the run demonstrably isn't. */ export type RunLiveEvidence = 'pid' | 'daemon-heartbeat' | 'run-activity'; /** Liveness verdict for one org's runtime.json record. * * #274: a single `process.kill(pid, 0)` probe used to be the whole verdict, so * a run whose recorded pid had gone stale — the orchestrating process was * restarted or re-attached without runtime.json being rewritten — was reported * as "crashed" while its roles were actively exchanging messages, with a * `mark-complete` suggestion that would have closed out live work. The pid is * still the first and best signal; when it is gone, two independent signs of * life are cross-checked before declaring a crash: a fresh `org serve` * heartbeat that still lists this org, and the run's own event log still * growing. * * Unchanged from before: a record that already says 'crashed' (including one * written by the process-level crash handler) stays crashed — that is a * recorded fact, not an inference. */ export declare function classifyRun(cwd: string, org: string, state: { status?: string; run?: string; pid?: number; pidStart?: string; closedBy?: string; }, now?: number): { state: RunState; evidence?: RunLiveEvidence; }; /** Result of {@link checkServeLock}. */ export type ServeLockCheck = { ok: true; staleHeartbeatRemoved: boolean; } | { ok: false; pid: number; }; /** Mutual-exclusion check for `org serve` startup. * * Two `org serve` processes started against the same project root have zero * visibility into each other — each builds its own in-memory `OrgDaemon` and * independently decides which orgs are "due now", so both can call * `daemon.startOrg(name)` for the same org and have both processes write to * the same on-disk state (runtime.json, decisions.jsonl, history.jsonl, * .mail/) at once. `liveServeDaemonPid` already knows how to read this * project's serve-heartbeat.json and tell a live daemon's heartbeat from a * stale one (dead pid, or aged past a few missed 30s beats) — reused here * as the actual pidfile lock, rather than inventing a second file, since it * already IS a pidfile (pid + timestamp, written at startup and every * heartbeat, removed on clean shutdown by `daemon.clearHeartbeat()`). * * Call this before the daemon/server/scheduler are constructed, so a * refusal never opens a port, binds a broker lease, or touches any org's * state. */ export declare function checkServeLock(cwd: string): ServeLockCheck; //# sourceMappingURL=org-control.d.ts.map