/** Ports the website probes to detect the bridge (contract section 5). */ export declare const BRIDGE_CANDIDATE_PORTS: readonly [48231, 48242, 48253, 48264, 48275, 48286, 48297]; export interface AgentConfig { agentId: string; /** @deprecated Legacy plaintext key — migrated to secret store on first load. */ apiKey?: string; /** * Reference to the key in the OS secret store (keyring / encrypted file). * The actual secret lives in the secret store, never in config.json. */ keyRef?: string; /** * Optional per-agent LLM provider key (e.g. an opencode-go API key) that * OVERRIDES the global `opencodeKey`. Agents use this instead of the * user's default opencode credentials so agent usage never bills the * user's personal account. */ opencodeKey?: string; } /** Per-project git pipeline switches (all default ON). */ export interface ProjectGitOptions { /** Give every task its own branch (teamshare/). Default true. */ autoBranch?: boolean; /** PR base branch override (default: try main, then master). */ baseBranch?: string; /** Open a PR after a successful push (needs a stored/env token). Default true. */ openPr?: boolean; /** Remote to push to (default "origin"). */ remote?: string; } /** * Cache-cleanup policy knobs. Every field is optional - the sweeper applies * its own defaults (see src/lib/cache-cleaner.ts DEFAULT_CLEANUP_POLICY). */ export interface CleanupPolicy { /** Master switch. Default true. */ enabled?: boolean; /** Sweep cadence in hours (daemon). Default 6. */ intervalHours?: number; /** Delete session captures/transcripts older than N days. Default 14. */ sessionMaxAgeDays?: number; /** LRU-trim sessions dir when it exceeds N MB. Default 200. */ sessionMaxSizeMb?: number; /** Rotate daemon.log when it exceeds N MB. Default 10. */ logMaxSizeMb?: number; /** Delete OS-temp teamshare-* files/dirs older than N days. Default 7. */ tempMaxAgeDays?: number; /** Delete orchestrator repo clones unused for N days (0 = never). Default 30. */ reposMaxAgeDays?: number; /** LRU-trim repos/ clones beyond N MB total. Default 2048. */ reposMaxSizeMb?: number; } /** * Discovered git sub-repository inside a multi-repo parent folder. * Populated by `scanSubRepos()` when linking a parent that contains * multiple independent git repos (e.g. a monorepo-without-a-monorepo). */ export interface ProjectRepo { /** Folder name (e.g. "teamshare-backend"). */ name: string; /** Absolute path to the sub-repo. */ path: string; /** Git remote origin URL, if configured. */ remote?: string; /** Whether the folder is a git repo. */ isGitRepo: boolean; } /** Project -> local folder mapping (the "project guard", IMP-6xx). */ export interface ProjectLink { /** Canonical absolute path the agent may work inside. */ path: string; /** Strict mode (default true): unlinked projects are hard-blocked. */ guard?: boolean; /** Git pipeline options for agent runs in this folder. */ git?: ProjectGitOptions; /** * Workspace arbitration (IMP-950): when a second live presence shows up * in the linked folder, new task/build wakes spawn into an auto-created * git worktree instead of sharing the folder. Opt-in per project. */ autoWorktree?: boolean; /** * Multi-repo support: discovered git sub-repositories inside the linked * parent folder. Populated automatically when linking a folder that * contains multiple git repos (but is not itself a git repo). */ repos?: ProjectRepo[]; /** * True when the linked folder is a parent directory containing multiple * independent git sub-repos (each entry in `repos` is one). When true, * the orchestrator resolves per-task which sub-repo to work in. */ multiRepo?: boolean; } export interface BridgeConfig { agents: AgentConfig[]; port: number; harness: 'auto' | 'opencode' | 'claude' | 'codex' | 'gemini' | 'antigravity' | 'copilot' | 'goose' | 'openhands' | 'aider' | 'openrouter' | 'none'; quietHours: { start: string; end: string; } | null; wakeRules: { priorities: string[]; } | null; projects: Record; /** * Default LLM provider key for agents (e.g. an opencode-go API key). * Agents run the harness with this key via OPENCODE_API_KEY so their * usage never touches the user's default opencode credentials. A * per-agent `opencodeKey` overrides it. NEVER logged. */ opencodeKey?: string; /** * DeepSeek API key for chat replies (the lightweight chat model). * Chat replies always use this key with deepseek:deepseek-chat at low * settings, regardless of the agent's task model. Falls back to * LLM_API_KEY / CHAT_LLM_API_KEY env vars. */ chatKey?: string; /** Run sessions as detached background processes (no visible terminal). */ backgroundSessions?: boolean; /** Cache-cleanup policy (optional - defaults apply when absent). */ cleanup?: CleanupPolicy; /** * WS URL for orchestrator namespace (e.g. ws://localhost:4000). * When set, the bridge connects to this URL for orchestrator commands * instead of deriving from TEAMSHARE_API_URL or using the live default. */ wsUrl?: string; /** * Stable random id for THIS machine (generated once, persisted). Every * folder link is attributed to one machine, so the server never leaks one * PC's path onto another. Sent with links + bridge-state pushes. */ machineId?: string; /** Human-readable label for this machine (hostname); shown to its owner only. */ machineLabel?: string; } export declare function configPath(): string; export declare function defaultConfig(): BridgeConfig; export declare function loadConfig(): BridgeConfig; export declare function saveConfig(config: BridgeConfig): void; /** * Stable id for THIS machine. Generated once and persisted to config.json. * Every folder link is attributed to one machine so the server never shows * one PC's path as another user's/agent's link. */ export declare function machineId(): string; /** Human-readable label for this machine (hostname), persisted with machineId. */ export declare function machineLabel(): string; /** * Retrieve an agent's API key from the secret store. Resolves via keyRef * (stored in config.json) against the OS keyring / encrypted file. * Falls back to legacy plaintext apiKey for backward compat during migration. */ export declare function getAgentKey(agent: AgentConfig): string | null; /** * Resolve the FIRST configured agent's API key, or null when no agent is * configured. Fresh installs boot the daemon with an empty `agents` array - * callers must never index `agents[0]` directly (that produced * "Cannot read properties of undefined (reading 'keyRef')"). */ export declare function firstAgentKey(config: BridgeConfig): string | null; /** Adds/updates an agent key entry (used by `connect` and `add-agent`). */ export declare function upsertAgent(agentId: string, apiKey: string): BridgeConfig; /** * Removes an agent entry from config.json. Does NOT touch the secret store - * callers (the `disconnect` command) delete the stored key separately. */ export declare function removeAgent(agentId: string): BridgeConfig; export type PreflightResult = { ok: true; canonical: string; } | { ok: false; reason: string; }; /** * Preflight a folder before linking it (the permission gate, IMP-6xx): * must exist, be a directory, be readable AND writable by this user, and * must not be a network location (UNC or mapped drive), OneDrive, or * outside the user profile. The link command IS the permission grant - the * agent never runs anywhere but linked folders. */ export declare function preflightFolder(rawPath: string): PreflightResult; /** Links a project to a local folder (guard on by default). Returns the result. */ export declare function linkProject(projectId: string, path: string, guard?: boolean, opts?: { autoWorktree?: boolean; repos?: ProjectRepo[]; multiRepo?: boolean; }): PreflightResult & { config?: BridgeConfig; }; /** * Update arbitration options for an existing link without touching the path * (used by `teamshare-agent link --project --auto-worktree `). */ export declare function setProjectAutoWorktree(projectId: string, enabled: boolean): BridgeConfig | null; /** * Updates the discovered repos list on an existing project link. * Called after re-scanning a parent folder for sub-repos. */ export declare function updateProjectRepos(projectId: string, repos: ProjectRepo[], multiRepo: boolean): BridgeConfig | null; /** Removes a project link. */ export declare function unlinkProject(projectId: string): BridgeConfig; /** * Working folder for a project, or null when it is not linked (hard block - * the caller must refuse the session and explain how to link it). */ export declare function projectCwd(projectId: string): string | null; /** * Scan a parent folder for git sub-repositories (subdirectories * that contain `.git`). Recurses up to `maxDepth` levels deep (default 3) * to find repos like `packages/backend/` inside a monorepo. * Returns a list of discovered repos with their names, paths, and remote * origin URLs. */ export declare function scanSubRepos(parentPath: string, maxDepth?: number): ProjectRepo[]; /** * Resolve the working directory for a project, optionally targeting a * specific sub-repo by name. For multi-repo projects, pass `repoName` * to get that sub-repo's path; omit to get the parent path. * For single-repo projects, always returns the linked folder. */ export declare function resolveRepoPath(projectId: string, repoName?: string): string | null; /** Per-project git pipeline options (empty object = all defaults ON). */ export declare function projectGitOptions(projectId: string | null | undefined): ProjectGitOptions; /** The exact command shown when a project is not linked (guard message). */ export declare function linkHint(projectId: string): string; /** * Validates a DB-stored folder path at spawn time with the same rules as * `link` (exists, readable+writable). Network/OneDrive/outside-profile * paths were already rejected at write time; this re-checks existence so a * deleted/renamed folder falls through instead of crashing the session. */ export declare function dbFolderPath(rawPath: string | null | undefined): string | null; /** * Working folder resolved from the server-side overrides: * project.folderPath (project override) > agent.folderPath (agent default). * Returns null when neither applies - callers fall back to the local * bridge-config link, then hard-block. */ export declare function serverFolderCwd(projectFolder?: string | null, agentFolder?: string | null): string | null; /** * Sets the agent LLM provider key. Without `agentId` it is the GLOBAL * default for every agent; with `agentId` it overrides that agent only. * `null` clears it (global null falls back to the user's own credentials). */ export declare function setOpenCodeKey(key: string | null, agentId?: string): BridgeConfig; /** * Resolves the LLM provider key for an agent: per-agent override > * global default > an already-set OPENCODE_API_KEY env (leave untouched) > * none (opencode falls back to the user's auth.json). The key itself is * NEVER logged - callers only ever log which source won. */ export declare function agentOpenCodeKey(agentId: string): string | null; /** * Sets the chat model API key (DeepSeek key for chat replies). Stored in * config.json as `chatKey`. `null` clears it. Chat always uses this key * with deepseek:deepseek-chat at low settings, regardless of agent model. */ export declare function setChatKey(key: string | null): BridgeConfig; /** * Resolves the chat model API key: config chatKey > CHAT_LLM_API_KEY env > * LLM_API_KEY env > none. */ export declare function chatKey(): string | null; export declare function msg(err: unknown): string; /** * Wires the TeamShare MCP server into opencode's config. Idempotent — * skips if already wired. The entry is: * mcp.teamshare = { type: "remote", url: "https://api.teamshare.name.ng/mcp", * headers: { "X-Api-Key": "" } } * * Returns true if wired, false if already present. */ export declare function wireOpencodeMcp(apiKey: string): boolean; /** * Removes the TeamShare MCP entry from opencode's config. * Returns true if removed, false if not present. */ export declare function unwireOpencodeMcp(): boolean; /** * Returns the current MCP wiring status for opencode. */ export declare function mcpStatus(): { wired: boolean; configPath: string | null; entry?: unknown; };