/** * Orchestration-path resolver (mmnto-ai/totem-strategy#341, ADR-106 — Proposal 282). * * Per Proposal 282 (Local-Only Orchestration), inter-agent coordination * (handoffs + journals) lives in per-repo * `.totem/orchestration//{outbox,processed,journal}/` directories, * gitignored. Each agent writes only to its own subdirectory in its home * repo; cross-repo handoffs work via sender-side outbox writes that * recipients discover by polling. * * This is an ADDITIVE sibling to `resolveSubstratePaths`. The substrate * remains live as a frozen-archive read path through and after the * cohort cutover — new writes flow through this resolver; legacy reads * (forensic / historical) continue through `resolveSubstratePaths`. Per * Proposal 282 § Scope and the totem-Claude impl-lane review (substrate * `.handoff/strategy-claude/inbox/2026-05-17T0220Z-totem-claude.md` Q3), * the two resolvers stay parallel rather than rename + deprecate so * downstream consumers can migrate independently. * * Pure utility. No caching, no side effects, no logging — same stance * as `resolveStrategyRoot` / `resolveSubstratePaths`. */ /** * Resolved orchestration path triple for a single agent's tree within * a single repo. Non-null path values are absolute and normalized. * * - `source: 'orchestration'` ⟹ at least one subdir exists for the agent. * - `source: 'none'` ⟹ no agent tree found at the repo root. * * Partial-presence is valid: an agent may have a populated `journal/` * but no `outbox/` (because it has not yet sent any handoffs in this * repo). Consumers MUST tolerate any combination of null fields. */ export interface OrchestrationPaths { outbox: string | null; processed: string | null; journal: string | null; source: 'orchestration' | 'none'; } export declare function resolveOrchestrationPaths(repoRoot: string, agentId: string): OrchestrationPaths; /** * Enumerate the seat directories registered in a repo's orchestration tree: * immediate child DIRECTORIES of `/.totem/orchestration/` whose * names pass the full path-segment guard, excluding `.`/`_`-prefixed entries * (`config.json` is a file; `_broadcast`-class dirs are routing surfaces, not * seats). The dirs ARE the registration (Tenet 20; mmnto-ai/totem#2141 * roster ruling: repo+1 touches zero surfaces — a seat's first write creates * its dir, and from that moment it is sensed). One-level, dirent-only, no * symlink following (`Dirent.isDirectory()` is false for symlinks). * * Any readdir failure (missing tree on a fresh clone — orchestration is * gitignored — EACCES, raced rename) degrades to an empty contribution so * callers fall back to the basename map, preserving pre-dirs behavior. * * Export widened from module-private for mmnto-ai/totem#2511's * `seat-lifecycle.ts` (module-internal consumer; `deriveSeatStatuses` is the * public read surface). Deliberately NOT barrel-exported — see index.ts. */ export declare function readSeatDirs(repoRoot: string): string[]; /** * Known cohort agent-ids, sorted. Zero-arg: the `COHORT_AGENT_MAP` flatten * (one source of truth for the pre-known roster — sorted so both call shapes * share one ordering contract, CR on mmnto-ai/totem#2160). With * `workspace`: the map UNION every seat directory registered in any immediate * workspace repo (`//.totem/orchestration//`), so a * dir-registered seat (e.g. totem-codex) is a known recipient with zero * registration surfaces (mmnto-ai/totem#2141). One-level traversal only, * dirent-only directories, no symlink following, the same dot/`_`/ * node_modules exclusions as the mail scan. * * Consumed by the outbound mail validator (`mail send`) to flag an unknown * recipient — a *content* warning, never a block (ADR-106 inv6 fail-open). * `broadcast` is a valid recipient too, but it is a routing literal, not an * agent, so callers handle it separately. */ /** * The repositories `COHORT_AGENT_MAP` carries an entry for, sorted — every * key, a zero-seat entry (`totem-playground`) included. `knownCohortAgents()` * flattens the map to its seat values, so an entry with no seats is invisible * through it; the signoff table-to-map lock reads this to hold the map's ROWS * to the table's rows as well as its seats (bot round 1 on * mmnto-ai/totem#2882, Greptile P2). */ export declare function cohortAgentMapRepositories(): string[]; export declare function knownCohortAgents(workspace?: string): string[]; /** * True iff `id` is safe to use as a `.totem/orchestration//…` path segment * (or any filename token): a non-empty string with no path separators, null * byte, or `..` traversal, and no control/whitespace/win32-reserved characters * (which would otherwise propagate into dispatch markdown, filenames, and CLI * logs — terminal-injection class). The single source of truth for the guard — * consumers (e.g. `totem mail send`'s `--from`/`--to` validation) reuse this * rather than re-deriving the pattern (Greptile P2 + CR R2 on * mmnto-ai/totem#2134). */ export declare function isPathSafeAgentId(id: string): boolean; /** * Resolution result for `resolveSelfAgents`. `source` discriminates which * precedence layer answered (tri-state honesty for the union layer — * mmnto-ai/totem#2141): * * - `'env'` — `TOTEM_SELF_AGENT` env var (highest precedence; for hooks/tests) * - `'config'` — `.totem/orchestration/config.json` `host_agents` override * - `'dirs'` — orchestration seat dirs (the map contributed nothing novel) * - `'map'` — hardcoded basename → agent-ids cohort map (no usable dirs) * - `'dirs+map'` — both layers contributed unique seats (partial-dir state) * - `'none'` — no resolution; `agents: []` */ export interface SelfAgentResolution { agents: string[]; source: 'env' | 'config' | 'dirs' | 'map' | 'dirs+map' | 'none'; /** * Loud diagnostics that must reach the user (Tenet 4): today the single * producer is the config warn-shape — `host_agents` answered while omitting * a PRESENT safe seat dir, the silent-unbind class from mmnto-ai/totem#2141 * (config keeps its shipped replace semantics; the suppression stops being * silent). Absent = nothing to report. Consumers (mail) append these to * their warning stream. */ warnings?: string[]; } /** * Resolve the set of agent-ids "self" for the calling repo. Used by * `totem mail` and any consumer that needs to filter cross-repo handoffs * by recipient. * * Precedence (highest → lowest): * * 1. `TOTEM_SELF_AGENT` env var (comma-separated; hook + test contexts) * 2. `/.totem/orchestration/config.json` `host_agents: string[]` * — replace semantics preserved (shipped contract), but omitting a * PRESENT safe seat dir attaches a loud warning naming the omitted * seat(s) (mmnto-ai/totem#2141 warn-shape; the in-repo mirror of the * strategy-side `ecl-self-agent-binding` superset-of-dirs probe) * 3. Seat dirs UNION the cohort map for this REPOSITORY * ({@link cohortSeatsForRepo}: the `origin` remote's repo name, else the * repo-root basename) — union, not replace: orchestration is gitignored, * so on a partial-dir fresh clone a dirs-only answer would vanish roster * siblings; the map keeps them visible while present dirs admit unmapped * seats with zero registration surfaces (Tenet 20; the totem-codex * exhibit) * 4. `{ agents: [], source: 'none' }` * * Entries failing `isPathSafeAgentId` (path traversal, null byte, control/ * whitespace/win32-reserved characters) are dropped at every layer — the * same contract the mail actuator enforces on recipients. An empty list from * a higher-precedence layer falls through to the next (so a malformed env * var doesn't shadow a valid config or map entry). * * No caching, no logging, no mutation. Reads: a single `fs.readFileSync` of * config.json when present, the seat-dir listing, and — on layer 3 ONLY, so * never when the env or config answered — one synchronous `git config --get * remote.origin.url` spawn to key the cohort map on the repository rather than * on the directory name (mmnto-ai/totem#2801). That read never throws; a * failure degrades to the basename key. * * @param repoRoot — Absolute path to the consuming repo's root. * @param env — Optional env override (default: `process.env`). Injection * surface for tests so the env-precedence branch can be exercised * without mutating real env state. */ export declare function resolveSelfAgents(repoRoot: string, env?: Record): SelfAgentResolution; //# sourceMappingURL=orchestration-resolver.d.ts.map