/** * Per-step build timeouts (milliseconds) used by the git-based auto-update * path. Slow hosts (notably ARM64 nodes compiling Solidity contracts via the * WASM solc fallback) can exceed the defaults; operators set overrides via * `~/.dkg/config.json` -> `autoUpdate.buildTimeoutMs`. All keys are optional; * unset keys fall back through network/.json -> built-in defaults. */ export interface AutoUpdateBuildTimeouts { /** `pnpm install --frozen-lockfile` (default 180_000). */ install?: number; /** `pnpm build:runtime` / `pnpm build` (default 180_000). */ build?: number; /** * @deprecated Ignored since the auto-updater stopped invoking `hardhat * compile` on node hosts. Committed `packages/evm-module/abi/*.json` are * now the runtime contract surface, and CI enforces freshness (see * `abi-freshness` job in `.github/workflows/ci.yml`). The field is * retained on the type so existing user configs don't fail to parse. */ contracts?: number; /** MarkItDown bundling step (default 900_000). */ markitdown?: number; } export interface AutoUpdateConfig { enabled: boolean; /** Optional in ~/.dkg/config.json: omit to inherit from network/project config. */ repo?: string; /** Optional in ~/.dkg/config.json: omit to inherit from network/project config. */ branch?: string; /** Allow auto-updating to pre-release versions (e.g. 9.0.5-rc.1). */ allowPrerelease?: boolean; /** Optional SSH private key path for git-based update fetches/clones. */ sshKeyPath?: string; /** Optional raw GIT_SSH_COMMAND override for git-based update fetches/clones. */ sshCommand?: string; /** * Optional in ~/.dkg/config.json: omit to inherit from network/project config. * `resolveAutoUpdateConfig()` falls back to network -> 30 (minutes). */ checkIntervalMinutes?: number; /** Optional per-step build timeout overrides for the git-based update path. */ buildTimeoutMs?: AutoUpdateBuildTimeouts; /** * Override how the daemon resolves "am I an npm-installed node or a * monorepo dev checkout?" under OT-RFC-41 §4.3 / Bundle B1d. * * `'npm'` (recommended; default for fresh installs from rc.12+): * Edge → `npm install -g`; Core → `npm install` into a * blue-green slot. `dkg init` writes this value explicitly * for every new node. * * `'monorepo'`: dev checkout — auto-update polling is suppressed * entirely. Contributors update via `git pull && pnpm install * && pnpm build` from the repo root. * * `'auto'` (legacy; pre-rc.12): probe the filesystem * (`repoDir() === null`). Treated as `'npm'` under rc.12+ via * `resolveStandaloneInstall()`. * * `'git'` (legacy; pre-rc.12): the now-removed git-build update * path. Treated as `'monorepo'` under rc.12+ (the daemon does * not auto-update, no git pull/build). User-facing `dkg * update` from such a config refuses to run — see OT-RFC-41 * §4.2 and `cli.ts dkg update`. * * Implementation: read once at boot via `resolveStandaloneInstall(source)` * in `daemon/state.ts`, which writes the result into the shared * `daemonState.standaloneCache` memo so every later caller (status * route, `dkg update` CLI subcommand, …) sees the same answer. */ source?: 'auto' | 'npm' | 'git' | 'monorepo'; } /** * AutoUpdateConfig with `repo` and `branch` guaranteed present — the shape * returned by `resolveAutoUpdateConfig()` after falling back through * ~/.dkg/config.json -> network/.json -> project.json. Consumers of the * auto-update subsystem should accept this type, not the raw `AutoUpdateConfig`, * since the raw form allows `repo`/`branch` to be omitted. */ export type ResolvedAutoUpdateConfig = AutoUpdateConfig & { repo: string; branch: string; checkIntervalMinutes: number; }; export interface NetworkConfig { networkName: string; networkId: string; genesisVersion: number; relays: string[]; /** V10: context graphs */ defaultContextGraphs?: string[]; defaultNodeRole: 'core' | 'edge'; autoUpdate?: { enabled: boolean; repo: string; branch: string; allowPrerelease?: boolean; sshKeyPath?: string; sshCommand?: string; checkIntervalMinutes: number; buildTimeoutMs?: AutoUpdateBuildTimeouts; /** * Network-level default for `AutoUpdateConfig.source` — see the * matching doc comment on that field. Lets `network/.json` set the * recommended source policy (e.g. testnet defaulting to `'npm'` so new * Core operators don't have to know about the override). Local config * still wins per field. */ source?: 'auto' | 'npm' | 'git'; }; chain?: { type: 'evm'; rpcUrl: string; rpcUrls?: string[]; hubAddress: string; tokenAddress?: string; chainId: string; }; faucet?: { url: string; mode: string; }; /** * Maintainer-controlled marker bumped on every chain reset (e.g. testnet * V10 staking consolidation, fresh contract redeploy with state wipe). * The daemon's chain-reset-wipe hook compares this against the last value * persisted in `/.network-state.json`; on mismatch it auto-wipes * `store.nq` + `publish-journal.*` + `random-sampling.wal` so the node * boots clean against the new chain. Operators do nothing. * * Distinct from `networkId` which is a SHA256 of the bundled genesis * TriG and only changes when the genesis itself does — chain redeploys * happen far more often than that, so they need a separate marker. * * Free-form string, suggested format: `-` (e.g. * `v10-rs-staking-consolidation-2026-04-30`). Maintainer bumps in the * same commit that captures the post-deploy state. */ chainResetMarker?: string; } /** * Operator-facing config block for V10 TRAC allowance sizing. Mirrors * `ApprovalPolicy` from `@origintrail-official/dkg-chain` but with * stringly-typed numeric fields (YAML doesn't speak bigint) so YAML/JSON * config can express it. * * Defaults match the legacy behaviour (`mode: per-publish`); operators * preparing for high-volume publishing should consider `replenishing`. * See `packages/cli/skills/dkg-node/SKILL.md` §8 for the operator guide. */ export interface ApprovalPolicyConfig { /** * Allowance sizing strategy. Defaults to `'per-publish'`: * * - `per-publish` — approve exactly each publish's TRAC cost (with the * on-chain `1n` floor). Cheapest blast radius, most approve-gas at * scale. Backward-compatible. * - `replenishing` — approve a configurable ceiling (default 1000 TRAC), * refill when allowance drops below `target × refillBelowFraction` * (default 10%). One approve per ~9 publishes' worth of TRAC. * **Recommended for mainnet.** * - `unlimited` — approve `MaxUint256` once per wallet, never again. * Lowest gas, widest blast radius. Use only if you trust the V10 KA * contract absolutely. */ mode?: 'per-publish' | 'replenishing' | 'unlimited'; /** * `replenishing` only. TRAC amount (decimal wei-TRAC string — `1000 * * 10^18 = '1000000000000000000000'` for 1000 TRAC) to approve up to. * Defaults to `'1000000000000000000000'` (1000 TRAC). */ targetAllowance?: string; /** * `replenishing` only. Refill when current allowance drops below * `targetAllowance × refillBelowFraction`. Float between 0 and 1. * Defaults to `0.1` (refill at 10% remaining). */ refillBelowFraction?: number; } export interface ChainConfig { /** 'evm' for real blockchain, omit or 'mock' for in-memory (testing only) */ type: 'evm' | 'mock'; /** JSON-RPC endpoint URL */ rpcUrl: string; /** Ordered JSON-RPC backup endpoints. `rpcUrl` remains the primary endpoint. */ rpcUrls?: string[]; /** Hub contract address */ hubAddress: string; /** Optional token contract address override. When omitted, resolve from Hub.Token. */ tokenAddress?: string; /** Chain identifier (e.g., 'base:84532') */ chainId?: string; /** * Test-only: when using `type: "mock"`, force the daemon's signer address to map * to this identity ID so private participant flows can be exercised from black-box CLI tests. */ mockIdentityId?: string; /** * V10 TRAC auto-approve policy. Controls how the adapter sizes the * allowance it requests from each operational signer before a publish or * update. See {@link ApprovalPolicyConfig} for the modes and * `packages/cli/skills/dkg-node/SKILL.md` §8 for the operator guide. */ approvalPolicy?: ApprovalPolicyConfig; } export interface LargeLiteralStorageConfig { enabled?: boolean; thresholdBytes?: number; directory?: string; } export interface SharedMemoryPublicSnapshotStorageConfig { enabled?: boolean; directory?: string; } /** Optional LLM config for the Node UI chatbot (OpenAI-compatible API). */ export interface LlmConfig { /** API key (e.g. OpenAI, Anthropic, or compatible provider). */ apiKey: string; /** Model name (default: gpt-4o-mini). */ model?: string; /** Base URL for the API (default: https://api.openai.com/v1). */ baseURL?: string; } export type LocalAgentIntegrationStatus = 'disconnected' | 'configured' | 'connecting' | 'ready' | 'degraded' | 'error'; export interface LocalAgentIntegrationCapabilities { localChat?: boolean; chatAttachments?: boolean; connectFromUi?: boolean; installNode?: boolean; dkgPrimaryMemory?: boolean; wmImportPipeline?: boolean; nodeServedSkill?: boolean; } export interface LocalAgentIntegrationTransport { kind?: string; bridgeUrl?: string; gatewayUrl?: string; healthUrl?: string; } export interface LocalAgentIntegrationManifest { packageName?: string; version?: string; setupEntry?: string; } export interface LocalAgentIntegrationRuntime { status?: LocalAgentIntegrationStatus; ready?: boolean; lastError?: string | null; updatedAt?: string; } /** * Inbound chat authorisation policy. Layered on top of the existing * Ed25519 signature check on every libp2p chat message — this controls * *which* authenticated peers we're willing to talk to, not *whether* * they're authenticated. * * Modes: * - `any` — accept all authenticated peers (legacy behaviour). Only * appropriate on a closed dev network where every peer is trusted. * - `peer-allowlist` — only accept peerIds listed in `peerAllowlist`. * Strongest, also most manual. * - `scoped` (recommended Phase 1 default) — only accept peers whose * node-principal is an `active` member of `contextGraphId`. Requires * `contextGraphId` to be set; if it isn't, all inbound chats are * rejected (fail-closed). * - `shared-context-graph` — accept any peer that's an active * node-member of at least one CG this node is also subscribed to. * More flexible than `scoped`; less strict. * * Loopback (a node chatting itself) is always accepted, regardless of * mode — useful for local CLI testing and for the daemon's own * outbound→inbound debugging shortcuts. */ export type ChatAclMode = 'any' | 'peer-allowlist' | 'scoped' | 'shared-context-graph'; export interface ChatAclConfig { mode?: ChatAclMode; /** Required when `mode: 'scoped'`. */ contextGraphId?: string; /** Required when `mode: 'peer-allowlist'`. */ peerAllowlist?: string[]; } export interface ChatConfig { /** Inbound chat authorisation policy. See {@link ChatAclConfig}. */ acl?: ChatAclConfig; } export interface LocalAgentIntegrationConfig { id?: string; name?: string; description?: string; enabled?: boolean; transport?: LocalAgentIntegrationTransport; capabilities?: LocalAgentIntegrationCapabilities; manifest?: LocalAgentIntegrationManifest; setupEntry?: string; metadata?: Record; runtime?: LocalAgentIntegrationRuntime; connectedAt?: string; updatedAt?: string; } export interface QueryAccessConfig { defaultPolicy: 'deny' | 'public'; contextGraphs?: Record; sparqlEnabled?: boolean; sparqlTimeout?: number; sparqlMaxResults?: number; }>; rateLimitPerMinute?: number; } export interface DkgConfig { name: string; relay?: string; apiPort: number; /** Host to bind the API server (default '127.0.0.1', use '0.0.0.0' for external access). */ apiHost?: string; listenPort: number; nodeRole: 'core' | 'edge'; /** * Core-Node-specific operator tuning. Today only `allowDegradedRelay`; * future Core-only knobs (e.g. relay-target prioritisation) belong here * rather than at the top level so they stay grouped. */ core?: { /** * Gate for the boot-time core-relay sanity check (`core-prereq-check.ts`). * * - `true` (default): the daemon logs `[CORE-PREREQ] looks degraded` * with a structured reason if its bound multiaddrs can't serve * inbound traffic, but boots normally. Backwards-compatible — no * behaviour change for any existing operator on this PR. * - `false`: the daemon refuses to boot if the sanity check says * degraded. Opt-in for operators who want fail-loud semantics * instead of warn-and-continue. * * Edge nodes ignore this field — the prereq check skips the degraded * verdict for `nodeRole: 'edge'`. */ allowDegradedRelay?: boolean; }; /** * Core Node relay-server capacity tuning. Forwarded into the libp2p * relay configuration via `DKGNodeConfig.relayServerCapacity`. Sets * the maximum number of simultaneous circuit-relay v2 reservations * this node will hold; HOP/STOP stream caps and * `connectionManager.maxConnections` are derived at a 1:2 ratio * (capacity=1024 → 2048 streams + 2048 max conns). * * Default: 1024 when omitted on a Core Node. Ignored on edge nodes * (with a startup warning if set there). Invalid values (0, * negative, fractional, NaN) fall back to the default with a * warning. See packages/core/src/types.ts and packages/cli/README.md * for the full rationale + ulimit -n requirements. */ relayServerCapacity?: number; /** * Number of relay reservations to hold in parallel when behind NAT. * Forwarded into `DKGNodeConfig.relayReservationCount`. Defaults to 3 * when relayPeers are configured (N-2 tolerance to relay blackouts). * Capped at 16. Ignored (with a warning when set explicitly) in two * cases: no relayPeers configured, or the node itself runs a relay * server (core / `enableRelayServer: true` — relay servers don't * multi-reserve through other relays). Invalid values * (0/neg/NaN/fractional/non-numeric/over-cap) fall back to the * default with a warning. See packages/core/src/types.ts for the * full rationale. */ relayReservationCount?: number; /** * Operator-preferred relay multiaddrs that take priority over the * network/.json public relay set (rc.9 PR-7). * * When set, these multiaddrs are prepended to the active relayPeers * list at daemon startup so libp2p attempts reservations on them * first. The public testnet relays remain configured as fallback — * if an operator-relay disappears, the node continues to function * via the public set. Repeatable; populate from CLI via * `dkg start --relay-preferred ` (sets env var * `DKG_RELAY_PREFERRED` for the spawned daemon, comma-separated) * or write into `~/.dkg/config.json` for persistence. * * See `docs/messenger-operator.md` for the relay-setup playbook * (standing up a relay VM, sharing multiaddrs, monitoring). */ preferredRelays?: string[]; /** Public multiaddrs to announce (for VPS/cloud nodes where the public IP is not on the interface). */ announceAddresses?: string[]; /** Bootstrap peer multiaddrs to connect to on startup (for direct peer discovery without relay). */ bootstrapPeers?: string[]; /** V10: context graphs to subscribe. */ contextGraphs?: string[]; /** Cross-agent query access policy for inbound query-remote requests. */ queryAccess?: QueryAccessConfig; autoUpdate?: AutoUpdateConfig; /** * Chain config. Field-merged on top of `network/.json#chain` via * `resolveChainConfig()`, so an operator can override individual fields * (e.g. just `rpcUrl` to point at a private RPC) without having to * restate `hubAddress` and `chainId`. Fields omitted here inherit the * network defaults — including future hub rotations propagated by the * auto-updater pulling a fresh network/.json. */ chain?: Partial; /** Optional LLM for the Node UI chatbot (natural language → SPARQL, answers). */ llm?: LlmConfig; /** Block explorer URL for TX links (default: derived from chainId). */ blockExplorerUrl?: string; /** Triple store backend override (default: oxigraph-worker with file persistence). */ store?: { backend: string; options?: Record; }; /** * Cap on how many persisted context-graph subscriptions a node ACTIVATES on * boot (gossip + sync). A large stale backlog otherwise fans out store work * and starves authenticated routes (#997). coreHosted graphs are always * restored regardless of this cap. Non-negative integer; 0 = no cap. Raise it * on nodes that legitimately subscribe to more than the default (64). */ maxRehydratedContextGraphSubscriptions?: number; /** Out-of-line storage for large public SWM RDF literal object terms. */ largeLiteralStorage?: LargeLiteralStorageConfig; /** Out-of-line storage for immutable public SWM operation snapshots. */ sharedMemoryPublicSnapshotStorage?: SharedMemoryPublicSnapshotStorageConfig; /** Disable expensive peer-connect SWM catch-up for bulk benchmark/devnet runs. */ syncSharedMemoryOnConnect?: boolean; /** * Generic local agent integration registry used by node-owned connect/install * flows. Framework-specific bridges (OpenClaw now, Hermes next) should store * status/capabilities here instead of relying on one-off config flags. */ localAgentIntegrations?: Record; /** * API authentication. When enabled, all non-public endpoints require * a Bearer token in the Authorization header. A token is auto-generated * on first start and stored in `/auth.token`. */ auth?: { enabled?: boolean; tokens?: string[]; }; /** Opt-in telemetry streaming to central network dashboard. */ telemetry?: { enabled?: boolean; }; /** Shared memory (workspace) data TTL in milliseconds. Default: 30 days (2592000000). Set to 0 to disable cleanup. */ sharedMemoryTtlMs?: number; /** @deprecated Legacy alias for sharedMemoryTtlMs */ workspaceTtlMs?: number; /** EPCIS plugin config. When set, POST /api/epcis/capture is enabled. */ epcis?: { contextGraphId?: string; }; /** Async publisher runtime options. */ publisher?: { enabled?: boolean; pollIntervalMs?: number; errorBackoffMs?: number; maxRetries?: number; }; /** * Async promote queue worker (WM → SWM). Unlike `publisher` which is * opt-in, the promote worker is **on by default** — without it, jobs * enqueued via `POST /api/knowledge-assets/{name}/swm/share-async` sit in * `queued` forever. Set `enabled: false` to disable when running a * read-only / forensic node where you don't want the worker mutating * SWM. See `docs/specs/SPEC_ASYNC_PROMOTE_QUEUE.md` and the * `dkg-node` skill (§8 "Async promote queue") for the full contract. */ promoteQueue?: { /** Default `true`. Set `false` to disable the in-daemon worker. */ enabled?: boolean; /** Default 4. Number of concurrent worker slots polling the queue. */ workerConcurrency?: number; /** Default 100ms. Polling interval per slot. */ pollIntervalMs?: number; /** Default 60_000ms (1 min). Must be >0 and shorter than the queue's 5-min lease when enabled. */ heartbeatIntervalMs?: number; /** Default 30_000ms. Max time `stop()` waits for in-flight promotes to drain on shutdown. */ shutdownTimeoutMs?: number; }; /** Allowed CORS origins. Defaults to '*' when apiHost is '127.0.0.1', otherwise restrictive. */ corsOrigins?: string | string[]; /** HTTP rate limiting settings. */ rateLimit?: { requestsPerMinute?: number; exempt?: string[]; }; /** * V10 Random Sampling prover (core-only). When the node is `core` * AND has an on-chain identity, the agent automatically schedules * `RandomSamplingProver.tick()` on `tickIntervalMs`. Edge nodes * ignore this block. See `dkg-random-sampling` for the prover * itself; the bind layer is in `dkg-agent/random-sampling-bind.ts`. */ randomSampling?: { /** * Persistent WAL path. When set, prover state transitions are * appended to this file (JSONL, fsync per write) for crash * recovery + `dkg rs wal-tail`. When unset, the prover uses an * in-memory WAL (test/dev only — production SHOULD set this). */ walPath?: string; /** * Tick cadence in ms. Default 30_000. Set lower (e.g. 5_000) for * devnet smoke tests where you want the prover to react quickly * after a publish lands. The orchestrator is idempotent under * fast double-ticks (already-solved short-circuit). */ tickIntervalMs?: number; /** * Default true on core. When false, the V10 Merkle build runs on * the agent's main thread. Useful in tests where spawning a * worker is undesirable. */ useWorkerThread?: boolean; }; /** * RFC 04 v0.3 / Issue #461 — opt this node into the Network State * Registry as a circuit-relay provider. When true, the daemon flips * the on-chain `relayCapable` flag on the node's profile so other * peers can resolve it as a candidate relay during the chain-driven * NetworkStateRegistry rollout (Phase 2+ via attestation KCs). * * Multiaddrs themselves are NOT published to chain via Profile * (RFC 04 §5.2 — they live in per-RS-round attestation KCs). This * flag is the operator's "I intend to run as a relay" hint that * gates whether they bother running the attestation cosig + submit * pipeline at all. * * Tri-state semantics on startup (Codex PR #506 fix): * - true → daemon ensures on-chain flag is true * - false → daemon ensures on-chain flag is false (actively * clears any stale prior opt-in) * - undefined → daemon does not touch the on-chain flag, preserving * any manual `dkg admin set-relay-capable` flips * * Default: undefined (i.e. no chain interaction unless the operator * has set this explicitly in config). For a fresh node this is * equivalent to relay-incapable. */ relayCapable?: boolean; /** * Agent-to-agent chat settings. Phase 1 (RFC: agent debug chat) only * uses the `acl` block, which controls who is allowed to send us * inbound chats over `/dkg/message/1.0.0`. Authentication is always * enforced by the protocol; this is the authorisation layer on top. * See {@link ChatConfig} / {@link ChatAclConfig}. */ chat?: ChatConfig; /** Route-plugin specs (absolute paths / package names) loaded at daemon startup. ADR 0001. */ routePlugins?: string[]; /** * libp2p / discovery network tunables for small / sparse meshes. * Forwarded through `DKGAgentConfig` and applied at `createLibp2p` / * `kadDHT` construction (libp2p tunables) and to the agent-profile * heartbeat timer (phonebook side). All fields optional; omitting * any field preserves the built-in default. See companion knobs in * `packages/core/src/types.ts` (libp2p side) + * `packages/agent/src/dkg-agent-constants.ts` (agent side). * * Targeted at testnet / small-mesh operators where DHT lookups are * flaky (sparse routing tables) and direct addresses age out before * being re-discovered. Mainnet / large-mesh deployments should leave * all fields unset to keep upstream defaults. * * Note: a per-step PeerResolver timeout knob was intentionally NOT * exposed here. Production callers (`connectToPeerId`, chat / * routed sends) always pass an explicit `perStepTimeoutMs` derived * from their own deadline budget, so an operator default would be a * silent no-op for those paths. To influence dial latency on small * networks, bump the caller-side `timeoutMs` (e.g. `connectToPeerId`'s * `timeoutMs` option) instead. Codex review of PR #698 caught this. */ network?: { /** libp2p `peerStore.maxAddressAge` (default 3_600_000 = 1h upstream). */ peerStoreMaxAddressAgeMs?: number; /** libp2p `peerStore.maxPeerAge` (default 21_600_000 = 6h upstream). */ peerStoreMaxPeerAgeMs?: number; /** libp2p `kadDHT.querySelfInterval` (default kad-DHT upstream). */ dhtQuerySelfIntervalMs?: number; /** * Cadence at which the daemon re-publishes its own profile to the * `agents` Context Graph (default 5min — see * `AGENT_PROFILE_HEARTBEAT_MS`). Set to `0` to disable; the * one-shot startup publish still fires. * * Each heartbeat refreshes `dkg:multiaddr` + `dkg:lastSeen` so * other peers' dial fallback can find fresh phonebook entries * even when direct connections have aged out of the peerStore. */ agentProfileHeartbeatMs?: number; }; } /** * Hardcoded per-network telemetry endpoints. * Nodes resolve the correct endpoints from the network they're on. * Operators only see a single toggle — no endpoint configuration. */ export declare const TELEMETRY_ENDPOINTS: Record; /** Resolve context graphs from config. */ export declare function resolveContextGraphs(config: DkgConfig): string[]; /** Resolve context graphs from network config. */ export declare function resolveNetworkDefaultContextGraphs(network: NetworkConfig | null | undefined): string[]; /** Resolve shared memory TTL from config, accepting both V10 and legacy keys. */ export declare function resolveSharedMemoryTtlMs(config: DkgConfig): number | undefined; /** * Translates the operator-facing {@link ApprovalPolicyConfig} (YAML/JSON, * string-typed numerics) into the runtime `ApprovalPolicy` shape the * chain adapter expects (`bigint` for `targetAllowance`). * * - Returns `undefined` if the operator didn't configure a policy — lets * the chain adapter fall back to its built-in default * (`DEFAULT_APPROVAL_POLICY`, currently `per-publish`). * - Throws a descriptive `Error` if the operator supplied an unparseable * `targetAllowance` (e.g. `'one thousand TRAC'`). Fails fast at startup * rather than silently falling back — config bugs are easier to find * when they don't lurk for hours. */ export declare function resolveApprovalPolicy(policy: ApprovalPolicyConfig | undefined): { mode: 'per-publish' | 'replenishing' | 'unlimited'; targetAllowance?: bigint; refillBelowFraction?: number; } | undefined; export declare function _resetNetworkConfigCache(): void; export interface ProjectConfig { repo: string; defaultBranch: string; githubUrl: string; projectName: string; syslogAppName: string; defaultNetwork: string; } /** * Load project.json — the single source of truth for repo name, * branch, GitHub URL, and default network. Values here drive the * startup banner, auto-update fallbacks, and network selection. * * To rename the repo or change the default branch/network, edit * project.json at the repo root — all runtime code follows. */ export declare function loadProjectConfig(): ProjectConfig; export declare function _resetProjectConfigCache(): void; /** * Field-level merge of the effective auto-update configuration. * * Precedence per field: `~/.dkg/config.json` → `network/.json` → * `project.json` (or static fallback). Returns null when auto-update is * explicitly disabled in the local config. * * Rationale: `dkg init` intentionally omits `repo`/`branch` from the * persisted config when the user accepts the defaults, so that future * changes to the shipped network/project defaults propagate without a * config rewrite. Callers must therefore resolve the effective values * instead of reading `config.autoUpdate.repo` directly. */ export declare function resolveAutoUpdateConfig(config: Pick | null | undefined, network: Pick | null | undefined): ResolvedAutoUpdateConfig | null; export declare function resolveAutoUpdateSource(config: Pick | null | undefined, network: Pick | null | undefined): AutoUpdateConfig['source']; /** * Field-level merge of the effective chain configuration. * * Precedence per field: `~/.dkg/config.json#chain` → `network/.json#chain`. * Returns `undefined` when neither source provides a chain block. * * Rationale: the daemon previously read chain via `config.chain ?? network.chain` * (whole-object fallback), which meant an operator who set just `rpcUrl` in their * local config would lose `hubAddress` / `chainId` from the network file and * crash deeper inside ethers. With per-field merge, operators can override * individual fields (e.g. swap public RPC for a private one) and still inherit * the rest — including future hub rotations the auto-updater pulls down. * * The return type is `Partial` because either source may be * partial; consumers that need both `rpcUrl` and `hubAddress` (lifecycle, * publisher-runner) MUST guard for those fields before passing to the agent. */ export declare function resolveChainConfig(config: Pick | null | undefined, network: Pick | null | undefined): Partial | undefined; /** * Load a network config from network/.json. * * @param network - Network name (e.g. 'testnet', 'mainnet'). Defaults to * the `defaultNetwork` value from project.json. * * Candidate paths (tried in order): * 1. Monorepo root when running from packages/cli/dist/ * 2. Monorepo root when running from packages/cli/src/ during dev * 3. Bundled alongside dist/ in the published NPM package (dist/../network/) * * Monorepo paths are checked first so that edits to the repo-root * network/ files are picked up immediately during development * without requiring a rebuild of the CLI package. */ export declare function loadNetworkConfig(network?: string): Promise; export declare function dkgDir(): string; export declare function isDkgMonorepo(): boolean; export type MonorepoInitTarget = 'not-monorepo' | 'explicit-home' | 'dev-home' | 'shared-npm-home'; /** * Classify what `dkg init`'s config-home resolution means for a given run, so * the command can notify the operator without hard-blocking (issue #960). Pure * + fully injectable so the three meaningful branches are unit-testable. * * - `not-monorepo` — an npm install; init behaves normally, no notice. * - `explicit-home` — the user set `DKG_HOME`; their explicit choice, no notice. * - `dev-home` — monorepo checkout, no `DKG_HOME`, resolves to the * separate dev home (`~/.dkg-dev`); safe — informational * notice only. * - `shared-npm-home` — monorepo checkout, no `DKG_HOME`, but a config already * exists at `~/.dkg` so `resolveDkgConfigHome` falls back * to it; init would read and may OVERWRITE the shared * `~/.dkg` home (which *might* be an npm-installed node). * The command must NOT silently proceed (that can mutate * an installed node's config if the operator misses the * warning) and must NOT hard-block (config presence isn't * proof of npm ownership, and a dev may intentionally use * `~/.dkg`). The caller gates this case behind an explicit * opt-in via {@link sharedHomeInitGate}. * * `resolvedHome === npmHome` is the signal for the fallback: `dkgDir()` returns * `~/.dkg` (rather than `~/.dkg-dev`) only when the resolver's own * config-existence check (`config.json` OR `config.yaml`) matched, so the YAML * case is handled here for free. */ export declare function classifyMonorepoInit(params: { isMonorepo: boolean; dkgHomeEnv: string | undefined; resolvedHome: string; npmHome: string; }): MonorepoInitTarget; export type SharedHomeInitGate = 'proceed' | 'prompt' | 'refuse'; /** * Decide how `dkg init` should gate the {@link classifyMonorepoInit} * `shared-npm-home` case — running from a monorepo checkout into a pre-existing * `~/.dkg` that may belong to an npm-installed node (issue #960, round-3 * review). A plain warn-and-proceed is a regression: a contributor who misses * the warning silently mutates the installed node's config. A hard refusal is * also wrong (a dev may intentionally target `~/.dkg`). So we require an * **explicit opt-in**: * * - `proceed` — the operator passed `--yes`; honor the explicit opt-in. * - `prompt` — interactive TTY; ask for confirmation before touching `~/.dkg`. * - `refuse` — non-interactive and no `--yes`; we can't ask and must not * silently overwrite, so abort with guidance (re-run with * `--yes`, or set `DKG_HOME`). * * Pure + injectable so all three branches are unit-testable without a TTY. */ export declare function sharedHomeInitGate(params: { yes: boolean; isTty: boolean; }): SharedHomeInitGate; /** * Resolve the repo root from the compiled code location. * Works from packages/cli/dist/ (compiled) or packages/cli/src/ (dev). */ export declare function findRepoDir(startDir: string): string | null; export declare function repoDir(): string | null; export declare function gitCommandEnv(autoUpdate?: Pick | null): NodeJS.ProcessEnv; export declare function gitCommandArgs(repoUrl?: string, autoUpdate?: Pick | null): string[]; export declare function releasesDir(): string; /** Read the active slot from the `releases/current` symlink. Falls back to the `active` file. */ export declare function activeSlot(): Promise<'a' | 'b' | null>; export declare function inactiveSlot(): Promise<'a' | 'b'>; /** * Atomically swap the `releases/current` symlink to point to `target` slot. * Uses tmp-symlink + rename to avoid any window where the symlink is broken. */ export declare function swapSlot(target: 'a' | 'b'): Promise; export declare function configPath(): string; export declare function configYamlPath(): string; export declare function pidPath(): string; export declare function logPath(): string; export declare function apiPortPath(): string; export declare function ensureDkgDir(): Promise; export declare function readNodeRoleFromConfigSync(): 'edge' | 'core'; export declare function loadConfig(): Promise; export interface StoreConfigValidationError { /** Field path within the config that failed validation. */ field: string; /** Human-readable error message including remediation hint. */ message: string; } export declare function validateStoreConfig(config: DkgConfig): StoreConfigValidationError[]; /** * Convenience helper: validate, log every error, exit if any. Daemon * boot uses this; the future wizard path will iterate `errors` to * re-prompt instead of exiting. */ export declare function exitOnStoreConfigErrors(config: DkgConfig, log: (msg: string) => void): void; export declare function saveConfig(config: DkgConfig): Promise; export declare function configExists(): boolean; export declare function readPid(): Promise; export declare function writePid(pid: number): Promise; export declare function removePid(): Promise; export declare function readApiPort(): Promise; export declare function writeApiPort(port: number): Promise; export declare function removeApiPort(): Promise; export declare function isProcessRunning(pid: number): boolean; export declare const CLI_NPM_PACKAGE = "@origintrail-official/dkg"; /** * True when running from an `npm install`-ed package rather than a * monorepo checkout. In standalone mode the auto-updater uses NPM * instead of git to fetch new versions. */ export declare function isStandaloneInstall(): boolean; /** * Resolve the CLI entry point within a blue-green slot. * Supports both git layout (packages/cli/dist/cli.js) and * NPM layout (node_modules/@origintrail-official/dkg/dist/cli.js). */ export declare function slotEntryPoint(slotDir: string): string | null; /** Return true when a blue-green slot has an entry point and install metadata. */ export declare function slotReady(slotDir: string): boolean; //# sourceMappingURL=config.d.ts.map