import { type WakeOrigin } from './bearings.js'; import { type NodeMeta, type Mode, type Lifecycle } from '../canvas/index.js'; export interface SpawnChildOpts { kind: string; mode?: Mode; cwd: string; name?: string; prompt: string; /** Override the parent (defaults to the calling node from env). */ parent?: string; /** Spawn an INDEPENDENT root instead of a managed child: parent=null, no * subscription back to the spawner, spawned_by=spawner. Resident and brought * forefront by default — see `rootLifecycle` for the unattended variant. */ root?: boolean; /** Only meaningful with `root`. The independent node's lifecycle. * * `'resident'` (default) is the ATTENDED root: a standing conversation a * human picks up, so it owes no final, never reaps on its own, and is * brought forefront in tmux on spawn. * * `'terminal'` is the UNATTENDED root: still parentless (nobody subscribes, * so nothing receives its push) but it still owes a final, so it reaps when * its work is done — and it is NEVER brought forefront. This is what * machinery firing with no human present must birth: the cron executor * spawns one when its cron's creating node is gone. A resident root there * would accrete one permanently-live node per fire (the count-based prune * never deletes live nodes) and steal the human's tmux focus every time. */ rootLifecycle?: Lifecycle; /** Direct root creation waits until the broker accepts viewers before it * returns. Cron-launched births use `launch`: the daemon must never wait in * its supervision loop. */ readiness?: 'await' | 'launch'; /** Fork the new node from an existing pi conversation instead of starting it * fresh: a node id (resolved to that node's session file), an absolute * `.jsonl` path, or a partial pi session uuid. pi COPIES that history into a * new session for the child — the source is untouched — then `prompt` is the * next message. A one-shot at birth; the child resumes its own session after. */ forkFrom?: string; /** Set ONLY by the daemon when a `spawn`/spawn-cron wake births this node: the * provenance of the timer that fired (see WakeOrigin). In-memory only — it is * NOT part of the stored recipe (the daemon spreads it in at fire time via * `spawnChild({ ...recipe, wakeOrigin })`); `node new` never sets it. When set, * a block is prepended to the kickoff so the newborn knows a clock * birthed it. */ wakeOrigin?: WakeOrigin; /** Pin the node to a model spec — exact `provider/id`, `provider/tier` * (e.g. `openai/ultra`), bare tier (ultra/strong/medium/light), or family * alias (opus/sonnet/haiku) — overriding the persona's declared default. * The RAW spec is persisted to `meta.model_override` (buildLaunchSpec * re-normalizes through the current ladders on every revive/polymorph, so * ladder config edits keep propagating). Omit to use the persona default. */ model?: string; /** Select the profile this node runs under — an exact profile id or a unique * manifest name, validated through `loadProfileManifest`. Omit to INHERIT the * spawner's current `profile_id` (managed child or --root alike — --root only * means top-level, it does not reset to a different profile; a shell root * falls back to the stable root profile in the startup selector). Passed * through unchanged into a scheduled birth command so a cron-launched birth * re-resolves the SAME choice at run time (an explicit value re-validates; * inheritance re-reads the creator's THEN-current profile). */ profile?: string | null; /** Create a managed worktree for this node and pin its cwd to it. */ worktree?: boolean; /** Local branch the managed worktree is cut from and later landed onto. */ worktreeBase?: string; /** Preallocated node id, used when a managed worktree must be named before birth. */ nodeId?: string; /** Hidden ambient "current situation" text — NOT the visible prompt/body. * Persisted via `appendSituationalContext` BEFORE launch so canvas-context- * intro's session_start bearings carry it as a `` * sibling from the node's very first turn. Passed through unchanged into a * scheduled node-birth command. Omit for no ambient context. */ situationalContext?: string; } /** Resolve a `--fork-from` value to an ABSOLUTE `.jsonl` source path for the * broker fork (`SessionManager.forkFrom`, which loads a file — never a bare id). * A live node id resolves to its captured session FILE (absolute, cwd-immune); a * relative path is made absolute; a bare/partial uuid is resolved against pi's * sessions store. Throws when a known node has no captured session file, or when * a uuid resolves to zero or multiple sessions. */ export declare function resolveForkSource(value: string): string; /** Resolve the profile a spawned child runs under: an explicit `--profile` * operand (id or name) validated through `loadProfileManifest`, else INHERIT * the spawner's current `profile_id` (null when the spawner has none). `--root` * never resets this to null on its own; only an explicit override does. When * there is NO spawner at all — `crtr node new --root` run directly from a * shell, not from inside a node — there is no profile to inherit, so this runs * the same startup selector the front door uses (MRU covering `cwd`, else the * root-profile prompt/default). */ export declare function resolveProfileId(explicit: string | null | undefined, spawner: string | null, cwd: string): Promise; export interface SpawnChildResult { node: NodeMeta; /** The viewer window opened for a --root in tmux; null otherwise (a managed * child opens no viewer, and a --root spawned outside tmux opens none). */ window: string | null; /** The session the --root's viewer opened into (the caller's current session); * null when no viewer was opened. */ session: string | null; } /** Resolve who a spawn is attributed to. A managed child needs a spine parent * (explicit `--parent` or the calling node's CRTR_NODE_ID). A --root spawn * does not: it is top-level by definition and the spawner identity is * provenance only — a human shell with no CRTR_NODE_ID is a legitimate root * spawner (regression: `crtr node new --root` from outside a node used to * throw here). */ export declare function resolveSpawner(parent: string | undefined, ctxNodeId: string | null, root: boolean): string | null; /** Spawn a node from a live node. By default a managed terminal worker in a * background window, with the spawner auto-subscribed (active) via spawnNode. * With `root`: an independent resident root — parent=null, NO subscription back * to the spawner (it carries spawned_by=spawner for provenance only), brought * forefront so a human can pick up the conversation directly. */ type BeforeBrokerLaunch = (nodeId: string) => void; export declare function spawnChildPrepared(opts: SpawnChildOpts, beforeBrokerLaunch?: BeforeBrokerLaunch): Promise; export declare function spawnChild(opts: SpawnChildOpts): Promise; /** Create an independent, idle root from a node's conversation and durable * context. Runtime/graph state is intentionally not inherited. */ export declare function forkNode(sourceId: string): Promise; export {};