import { chmod, copyFile, mkdir, readFile, rename, rm, stat, unlink, writeFile } from 'node:fs/promises'; import type { IncomingMessage } from 'node:http'; import { dkgDir, releasesDir } from '../config.js'; import { resolveDaemonNodeCommand } from '../daemon-entrypoint.js'; import { type BundledMarkItDownMetadata } from '../extraction/markitdown-bundle-metadata.js'; import { type InstallContext } from '@origintrail-official/dkg-mcp/manifest/install'; import { DkgClient } from '@origintrail-official/dkg-mcp/client'; export type MarkItDownTarget = { platform: string; arch: string; assetName: string; runner?: string; }; /** * Resolve the dkg-v9 repo root from the daemon's compiled location. * The daemon ships at packages/cli/dist/daemon/manifest.js, so the * repo root is four levels up. * * Bakes a monorepo-checkout assumption into every generated * `.dkg/config.yaml`, hooks file, and `mcp.json` the daemon's * manifest install flow produces — absolute paths like * `/packages/mcp-dkg/src/index.ts` are written verbatim into * the workspace. If that assumption is wrong (npm-global install, * tarball extract, etc.) those paths don't exist and the workspace * wiring is silently dead: the MCP server fails to start and every * subsequent tool call 500s with cryptic "ENOENT … index.ts". * * Rather than ship a dead config, fail fast here with a clear message. * When npm distribution lands we'll switch this to a bundled-assets * resolver, but until then "require a checkout" is the actual * invariant of the manifest publish flow. */ export declare function manifestRepoRoot(): string; /** * Resolve the absolute paths of `@origintrail-official/dkg-mcp`'s * runtime assets (bundled entry + capture-chat hook) that get baked * into the generated `.cursor/mcp.json` / `.cursor/hooks.json` / * `.claude/settings.json`. * * Tries three sources, in order: * 1. Node module resolution of `@origintrail-official/dkg-mcp/package.json`. * Works for npm-global installs, per-workspace `node_modules`, and * monorepo checkouts (pnpm symlinks the workspace package in). * 2. The daemon's own monorepo layout (`packages/mcp-dkg/...`) as a * fallback for checkouts where the import graph somehow didn't * surface dkg-mcp on the require paths. * 3. Throws with a clear, actionable error — callers should turn * this into a 500 on `/manifest/plan-install` + `/manifest/install`. * * The returned paths MUST exist on disk; the manifest installer * embeds them in free-form JSON/YAML without further validation, and * a missing path would silently break Cursor/Claude wiring on the * operator's machine. * * Fixes Codex tier-4g finding N7: before this, both install routes * called `manifestRepoRoot()` and 500'd when the daemon ran from a * published `@origintrail-official/dkg` package. */ export interface McpDkgAssets { packageDir: string; distEntry: string; captureScript: string; /** * Absolute path to `/hooks/inject-session-context.mjs`. Used * by `buildManifestInstallContext` to populate the * `{{injectSessionContextScriptPath}}` placeholder in the Cursor * + Claude Code hook templates so installs done via the daemon's * `/manifest/plan-install` and `/manifest/install` routes wire the * inject-session-context hook the same way the MCP CLI's * `dkg-mcp join` flow does. See Codex PR #589 finding 3. */ injectSessionContextScript: string; source: 'node-resolution' | 'repo-fallback'; } export declare function resolveMcpDkgAssets(): McpDkgAssets; /** * Read the installed @origintrail-official/dkg-mcp package version from * its package.json. Used by the manifest install/plan-install routes to * enforce `requiresMcpDkgVersion`. Returns null when the package can't * be located (caller should treat this as "unknown" and skip gating * rather than block). */ export declare function readMcpDkgVersion(): string | null; /** * Parse an "X.Y.Z[-pre]" semver into comparable tuple; returns null on * malformed input so callers can bail cleanly. */ export declare function parseSemver(v: string): [number, number, number, string] | null; export declare function cmpSemverForRange(a: string, b: string): number; /** * Minimal `requiresMcpDkgVersion` range check. Understands the range * forms the mcp-dkg ecosystem actually publishes today: exact version, * `>=a.b.c`, `>a.b.c`, `<=a.b.c`, `, _contextGraphId: string, _requestToken: string | null | undefined, requestAgentAddress: string | undefined | null, daemonApiHost: string, daemonApiPort: number): { ok: true; context: Omit & { tools: SupportedTool[]; agentNickname: string; }; } | { ok: false; error: string; }; export declare const _autoUpdateIo: { readFile: typeof readFile; readdir: (...args: any[]) => Promise; writeFile: typeof writeFile; mkdir: typeof mkdir; rm: typeof rm; chmod: typeof chmod; copyFile: typeof copyFile; stat: typeof stat; rename: typeof rename; unlink: typeof unlink; existsSync: (...args: any[]) => boolean; readFileSync: (...args: any[]) => any; openSync: (...args: any[]) => number; closeSync: (...args: any[]) => void; writeFileSync: (...args: any[]) => void; unlinkSync: (...args: any[]) => void; exec: (...args: any[]) => Promise; execFile: (...args: any[]) => Promise; execSync: (...args: any[]) => any; resolveDaemonNodeCommand: typeof resolveDaemonNodeCommand; dkgDir: typeof dkgDir; releasesDir: typeof releasesDir; activeSlot: () => Promise<"a" | "b">; inactiveSlot: () => Promise<"a" | "b">; swapSlot: (slot: "a" | "b") => Promise; fetch: typeof fetch; hasVerifiedBundledMarkItDownBinary: (...args: any[]) => Promise; expectedBundledMarkItDownBuildMetadata: (...args: any[]) => any; readCliPackageVersion: (...args: any[]) => string | null; }; export declare function loadMarkItDownTargets(): MarkItDownTarget[]; export declare function getNodeVersion(): string; export declare function getCurrentCommitShort(): string; /** * RFC-41 §4.9: bundled commit metadata in published npm artifacts. * * CI writes `build-info.json` into the package root before * `npm publish`. It carries the full commit SHA, build timestamp, * dist-tag, and the CI run identifier — exposed via `/api/status` * so pre-release dist-tag testing is auditable (operators see * exactly which commit they are running, not just a semver tag * that may have had multiple sequential builds). * * Monorepo / dev fallback: when `build-info.json` is absent (which * is the steady state for contributors running from `pnpm dkg start`), * we return a sentinel telling the doctor / agent we're in a dev * build. The fallback values are stable strings so consumers can * branch reliably. * * Cached after first read because the file is immutable for the * lifetime of a daemon process. */ export interface BuildInfo { /** Full commit SHA, or "uncommitted" for monorepo / dev fallback. */ commit: string; /** First 8 chars of commit, or "00000000" for the dev fallback. */ commitShort: string; /** ISO 8601 timestamp of the npm publish build, or null in dev fallback. */ buildTime: string | null; /** npm dist-tag the artifact was published under (e.g. "latest", "next"), or "monorepo" for dev. */ distTag: string; /** CI workflow run identifier (e.g. GitHub Actions run id), or null in dev fallback. */ ciRun: string | null; } export declare function loadBuildInfo(): BuildInfo; /** * RFC-41 §4.3 / §4.7.0: detect the running daemon's install mode. * * The detection is local-only — there is no authoritative network * source for this. We classify based on where `import.meta.url` * resolves on disk: * * - inside a monorepo packages/cli/dist/ → `monorepo` * - inside `/usr/local/lib/node_modules/`, `/opt/homebrew/lib/`, * `~/.nvm/`, `~/.volta/`, `~/.fnm/` → `npm-global` * - inside any other `node_modules/` → `npm-local` * - otherwise → `unknown` * * Cached on first read. */ export type InstallMode = "npm-global" | "npm-local" | "monorepo" | "unknown"; export declare function detectInstallMode(): InstallMode; export declare function loadSkillTemplate(): string; export declare function loadImporterSkillTemplate(): string; export declare function buildSkillMd(opts: { version: string; baseUrl: string; peerId: string; nodeRole: string; extractionPipelines: string[]; }): string; export declare function skillEtag(content: string): string; export declare const DAEMON_EXIT_CODE_RESTART = 75; /** * Validate and parse a `requiredSignatures` value from an API request body. * Returns `{ value }` on success or `{ error }` on failure. */ export declare function parseRequiredSignatures(raw: unknown): { value: number; } | { error: string; }; export declare function normalizeDetectedContentType(contentType: string | undefined): string; /** * #1101: filename-extension fallback for import-file content-type detection. * * Plain `curl -F file=@notes.md` sends `application/octet-stream` for any * file type curl doesn't recognise — which includes Markdown. Relying solely * on the multipart part's Content-Type header therefore silently skipped * extraction for the single most common upload type. When the header (and * the explicit `contentType` override) yields only octet-stream, fall back * to the uploaded filename's extension. Returns undefined when the * extension is unknown so callers keep the octet-stream default. */ export declare function inferContentTypeFromFilename(filename: string | undefined): string | undefined; export declare function currentBundledMarkItDownAssetName(): string | null; export declare function bindingValue(v: unknown): string; export declare function carryForwardBundledMarkItDownBinary(opts: { sourceCandidates: string[]; targetBinaryPath: string; log: (msg: string) => void; context: string; expectedMetadata: BundledMarkItDownMetadata | null; }): Promise; //# sourceMappingURL=manifest.d.ts.map