nexus-agents 2.134.0 → 2.136.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{child-mcp-config-TWHH63UK.js → child-mcp-config-TM6OCARU.js} +4 -3
- package/dist/{child-mcp-config-TWHH63UK.js.map → child-mcp-config-TM6OCARU.js.map} +1 -1
- package/dist/{chunk-E64SZTEP.js → chunk-257QMFTM.js} +3 -3
- package/dist/{chunk-PQHVC4BD.js → chunk-2XRPKJKX.js} +23 -12
- package/dist/chunk-2XRPKJKX.js.map +1 -0
- package/dist/{chunk-FUJ3XR7T.js → chunk-3AAJWZCR.js} +4 -4
- package/dist/{chunk-Z6DXZ6AS.js → chunk-3JSDOBOA.js} +2 -2
- package/dist/{chunk-FPMQ2JAK.js → chunk-3QH2KWLH.js} +2 -2
- package/dist/{chunk-7TQZR5VU.js → chunk-3WBEEYCS.js} +116 -22
- package/dist/chunk-3WBEEYCS.js.map +1 -0
- package/dist/{chunk-UDB5NHJI.js → chunk-4GVPON4W.js} +3 -3
- package/dist/{chunk-QZUT22LP.js → chunk-5546JU53.js} +8 -8
- package/dist/chunk-5SXGPX34.js +44 -0
- package/dist/chunk-5SXGPX34.js.map +1 -0
- package/dist/{chunk-7GSYICTL.js → chunk-66TXNH4S.js} +14 -12
- package/dist/{chunk-7GSYICTL.js.map → chunk-66TXNH4S.js.map} +1 -1
- package/dist/{chunk-76R5ES6Z.js → chunk-6JOXXQK2.js} +191 -132
- package/dist/chunk-6JOXXQK2.js.map +1 -0
- package/dist/{chunk-ZMDOGN33.js → chunk-7E5UXA4U.js} +2 -2
- package/dist/{chunk-F74ZGHAP.js → chunk-7G63H7ZT.js} +2 -2
- package/dist/{chunk-FVSZLVMR.js → chunk-CQDGPGTL.js} +3 -3
- package/dist/{chunk-33MFMXBQ.js → chunk-ESP6U3LW.js} +13 -81
- package/dist/chunk-ESP6U3LW.js.map +1 -0
- package/dist/{chunk-MY52DFXC.js → chunk-FHFEC2XM.js} +2 -2
- package/dist/{chunk-ORQAFTAZ.js → chunk-FIQSOSQU.js} +2 -2
- package/dist/{chunk-EHLJLIHS.js → chunk-FSUZIIOJ.js} +2 -2
- package/dist/{chunk-3EYXPV5F.js → chunk-GWOXPCIF.js} +13 -13
- package/dist/{chunk-WYJJUF6N.js → chunk-HMZT2SJK.js} +4 -4
- package/dist/{chunk-OCKZ6F5O.js → chunk-JK4L2TQ6.js} +3 -3
- package/dist/{chunk-6UCWR3DS.js → chunk-JVZ7FGWR.js} +3 -3
- package/dist/{chunk-PFBV5FCT.js → chunk-KOVTOPEQ.js} +2 -2
- package/dist/{chunk-GZ4NF4ZW.js → chunk-L4QFWOOQ.js} +63 -92
- package/dist/chunk-L4QFWOOQ.js.map +1 -0
- package/dist/{chunk-6LMZ7HFU.js → chunk-LCSGGLZZ.js} +2 -2
- package/dist/{chunk-IWQH6TP7.js → chunk-MTE7THMR.js} +6 -6
- package/dist/{chunk-DLUFDKPA.js → chunk-N67LHY47.js} +89 -32
- package/dist/chunk-N67LHY47.js.map +1 -0
- package/dist/{chunk-DBDWMHUL.js → chunk-OCJEYHUQ.js} +18 -10
- package/dist/chunk-OCJEYHUQ.js.map +1 -0
- package/dist/chunk-UGAKYSDO.js +92 -0
- package/dist/chunk-UGAKYSDO.js.map +1 -0
- package/dist/{chunk-VI7LELES.js → chunk-UH3F4RZB.js} +7 -7
- package/dist/{chunk-COJOUIO2.js → chunk-VN3CKPEF.js} +3 -3
- package/dist/{chunk-FSFF7EFR.js → chunk-VVBKPRLI.js} +2 -2
- package/dist/{chunk-OU2NQVKD.js → chunk-VY4FZNZA.js} +2 -2
- package/dist/{chunk-BTYYZ6VU.js → chunk-WOE5J5M6.js} +4 -4
- package/dist/{chunk-B26FGLIJ.js → chunk-ZHCEOIEQ.js} +2 -2
- package/dist/{chunk-WFKVUZ3O.js → chunk-ZII5MDUO.js} +2 -2
- package/dist/{chunk-CLRSNWRQ.js → chunk-ZLENFXL5.js} +4 -4
- package/dist/cli-circuit-breaker-HFFMCA43.js +14 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +68 -66
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-E6FXXMMR.js → composite-router-PS42433A.js} +4 -3
- package/dist/consensus-vote-K2SHY4TC.js +39 -0
- package/dist/{consensus-vote-types-CYBHW8vY.d.ts → consensus-vote-types-Dx4pf3YW.d.ts} +16 -0
- package/dist/{context-retriever-I4NEOUEV.js → context-retriever-NIFXFYPQ.js} +12 -10
- package/dist/{dist-C4457XNQ.js → dist-KGTVHDVC.js} +4 -2
- package/dist/doctor-deep-VQQNT7VN.js +13 -0
- package/dist/{expert-bridge-GMB5IHHF.js → expert-bridge-NY6FAFQH.js} +6 -5
- package/dist/factory-6A26HIWS.js +15 -0
- package/dist/factory-GGSACEWN.js +22 -0
- package/dist/{improvement-review-77BKIQGN.js → improvement-review-JDSRWFHM.js} +8 -5
- package/dist/index.d.ts +27 -20
- package/dist/index.js +64 -62
- package/dist/index.js.map +1 -1
- package/dist/{init-opencode-4H2VPN23.js → init-opencode-C7U6ZQK3.js} +8 -7
- package/dist/{init-opencode-4H2VPN23.js.map → init-opencode-C7U6ZQK3.js.map} +1 -1
- package/dist/issue-triage-7RN74LBU.js +17 -0
- package/dist/{learning-persistence-2KO4CXNL.js → learning-persistence-EHTHKWR5.js} +3 -2
- package/dist/{pr-reviewer-helpers-F3SHCHNV.js → pr-reviewer-helpers-D47TVXFX.js} +6 -5
- package/dist/{registry-command-VFCSMHME.js → registry-command-PVC47NSQ.js} +4 -3
- package/dist/{registry-command-VFCSMHME.js.map → registry-command-PVC47NSQ.js.map} +1 -1
- package/dist/{repo-security-plan-U2ZIFW53.js → repo-security-plan-76IXMJNC.js} +5 -4
- package/dist/research-helpers-synthesize-WH4IC36H.js +15 -0
- package/dist/{routing-memory-VVLJL3MG.js → routing-memory-RAYIYIUP.js} +4 -3
- package/dist/{session-memory-GMQYZLJE.js → session-memory-WZCS7WDH.js} +5 -4
- package/dist/{setup-command-IMAX6EAO.js → setup-command-O62DVQ2U.js} +13 -12
- package/dist/setup-config-KEBEUMC3.js +11 -0
- package/dist/{setup-custom-api-NJGCRIRO.js → setup-custom-api-2PQP6UOT.js} +5 -4
- package/dist/{setup-custom-api-NJGCRIRO.js.map → setup-custom-api-2PQP6UOT.js.map} +1 -1
- package/dist/tool-memory-RAQWOUXV.js +22 -0
- package/dist/tool-memory-registry-adapters-Y4EGADHN.js +12 -0
- package/dist/unified-registry-L5PGLSEI.js +25 -0
- package/dist/{weather-report-OU65NJS3.js → weather-report-TEBEALS7.js} +4 -3
- package/dist/weather-report-TEBEALS7.js.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-33MFMXBQ.js.map +0 -1
- package/dist/chunk-76R5ES6Z.js.map +0 -1
- package/dist/chunk-7TQZR5VU.js.map +0 -1
- package/dist/chunk-DBDWMHUL.js.map +0 -1
- package/dist/chunk-DLUFDKPA.js.map +0 -1
- package/dist/chunk-GZ4NF4ZW.js.map +0 -1
- package/dist/chunk-PQHVC4BD.js.map +0 -1
- package/dist/cli-circuit-breaker-VXBDCAD7.js +0 -13
- package/dist/consensus-vote-R6X5IL57.js +0 -37
- package/dist/doctor-deep-CZXN4YD6.js +0 -12
- package/dist/factory-WR62MEIJ.js +0 -14
- package/dist/factory-ZBQGA373.js +0 -21
- package/dist/issue-triage-NJB6SL4S.js +0 -16
- package/dist/research-helpers-synthesize-5TLNHT3I.js +0 -14
- package/dist/setup-config-2ZSJ3HNE.js +0 -10
- package/dist/tool-memory-TSYJXGOV.js +0 -20
- package/dist/unified-registry-IMAL3SY6.js +0 -24
- /package/dist/{chunk-E64SZTEP.js.map → chunk-257QMFTM.js.map} +0 -0
- /package/dist/{chunk-FUJ3XR7T.js.map → chunk-3AAJWZCR.js.map} +0 -0
- /package/dist/{chunk-Z6DXZ6AS.js.map → chunk-3JSDOBOA.js.map} +0 -0
- /package/dist/{chunk-FPMQ2JAK.js.map → chunk-3QH2KWLH.js.map} +0 -0
- /package/dist/{chunk-UDB5NHJI.js.map → chunk-4GVPON4W.js.map} +0 -0
- /package/dist/{chunk-QZUT22LP.js.map → chunk-5546JU53.js.map} +0 -0
- /package/dist/{chunk-ZMDOGN33.js.map → chunk-7E5UXA4U.js.map} +0 -0
- /package/dist/{chunk-F74ZGHAP.js.map → chunk-7G63H7ZT.js.map} +0 -0
- /package/dist/{chunk-FVSZLVMR.js.map → chunk-CQDGPGTL.js.map} +0 -0
- /package/dist/{chunk-MY52DFXC.js.map → chunk-FHFEC2XM.js.map} +0 -0
- /package/dist/{chunk-ORQAFTAZ.js.map → chunk-FIQSOSQU.js.map} +0 -0
- /package/dist/{chunk-EHLJLIHS.js.map → chunk-FSUZIIOJ.js.map} +0 -0
- /package/dist/{chunk-3EYXPV5F.js.map → chunk-GWOXPCIF.js.map} +0 -0
- /package/dist/{chunk-WYJJUF6N.js.map → chunk-HMZT2SJK.js.map} +0 -0
- /package/dist/{chunk-OCKZ6F5O.js.map → chunk-JK4L2TQ6.js.map} +0 -0
- /package/dist/{chunk-6UCWR3DS.js.map → chunk-JVZ7FGWR.js.map} +0 -0
- /package/dist/{chunk-PFBV5FCT.js.map → chunk-KOVTOPEQ.js.map} +0 -0
- /package/dist/{chunk-6LMZ7HFU.js.map → chunk-LCSGGLZZ.js.map} +0 -0
- /package/dist/{chunk-IWQH6TP7.js.map → chunk-MTE7THMR.js.map} +0 -0
- /package/dist/{chunk-VI7LELES.js.map → chunk-UH3F4RZB.js.map} +0 -0
- /package/dist/{chunk-COJOUIO2.js.map → chunk-VN3CKPEF.js.map} +0 -0
- /package/dist/{chunk-FSFF7EFR.js.map → chunk-VVBKPRLI.js.map} +0 -0
- /package/dist/{chunk-OU2NQVKD.js.map → chunk-VY4FZNZA.js.map} +0 -0
- /package/dist/{chunk-BTYYZ6VU.js.map → chunk-WOE5J5M6.js.map} +0 -0
- /package/dist/{chunk-B26FGLIJ.js.map → chunk-ZHCEOIEQ.js.map} +0 -0
- /package/dist/{chunk-WFKVUZ3O.js.map → chunk-ZII5MDUO.js.map} +0 -0
- /package/dist/{chunk-CLRSNWRQ.js.map → chunk-ZLENFXL5.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-VXBDCAD7.js.map → cli-circuit-breaker-HFFMCA43.js.map} +0 -0
- /package/dist/{composite-router-E6FXXMMR.js.map → composite-router-PS42433A.js.map} +0 -0
- /package/dist/{consensus-vote-R6X5IL57.js.map → consensus-vote-K2SHY4TC.js.map} +0 -0
- /package/dist/{context-retriever-I4NEOUEV.js.map → context-retriever-NIFXFYPQ.js.map} +0 -0
- /package/dist/{dist-C4457XNQ.js.map → dist-KGTVHDVC.js.map} +0 -0
- /package/dist/{doctor-deep-CZXN4YD6.js.map → doctor-deep-VQQNT7VN.js.map} +0 -0
- /package/dist/{expert-bridge-GMB5IHHF.js.map → expert-bridge-NY6FAFQH.js.map} +0 -0
- /package/dist/{factory-WR62MEIJ.js.map → factory-6A26HIWS.js.map} +0 -0
- /package/dist/{factory-ZBQGA373.js.map → factory-GGSACEWN.js.map} +0 -0
- /package/dist/{improvement-review-77BKIQGN.js.map → improvement-review-JDSRWFHM.js.map} +0 -0
- /package/dist/{issue-triage-NJB6SL4S.js.map → issue-triage-7RN74LBU.js.map} +0 -0
- /package/dist/{learning-persistence-2KO4CXNL.js.map → learning-persistence-EHTHKWR5.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-F3SHCHNV.js.map → pr-reviewer-helpers-D47TVXFX.js.map} +0 -0
- /package/dist/{repo-security-plan-U2ZIFW53.js.map → repo-security-plan-76IXMJNC.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-5TLNHT3I.js.map → research-helpers-synthesize-WH4IC36H.js.map} +0 -0
- /package/dist/{routing-memory-VVLJL3MG.js.map → routing-memory-RAYIYIUP.js.map} +0 -0
- /package/dist/{session-memory-GMQYZLJE.js.map → session-memory-WZCS7WDH.js.map} +0 -0
- /package/dist/{setup-command-IMAX6EAO.js.map → setup-command-O62DVQ2U.js.map} +0 -0
- /package/dist/{setup-config-2ZSJ3HNE.js.map → setup-config-KEBEUMC3.js.map} +0 -0
- /package/dist/{tool-memory-TSYJXGOV.js.map → tool-memory-RAQWOUXV.js.map} +0 -0
- /package/dist/{unified-registry-IMAL3SY6.js.map → tool-memory-registry-adapters-Y4EGADHN.js.map} +0 -0
- /package/dist/{weather-report-OU65NJS3.js.map → unified-registry-L5PGLSEI.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/learning-persistence.ts","../src/config/nexus-data-dir.ts","../src/config/sandbox-detection.ts","../src/config/repo-root-detection.ts","../src/config/portable-mode.ts"],"sourcesContent":["/**\n * Shared configuration for cross-session learning persistence.\n *\n * Controls where learning data (outcomes, distilled rules) is stored\n * on disk and whether persistence is enabled via feature flag.\n *\n * @module config/learning-persistence\n * (Source: Issue #1009 — Cross-session persistence)\n */\n\nimport { mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getNexusDataDir } from './nexus-data-dir.js';\n\n// ============================================================================\n// Path resolution (#2316: must read NEXUS_DATA_DIR at call time, not import)\n// ============================================================================\n\n/**\n * Base directory for learning persistence data. Resolved at call time so\n * `NEXUS_DATA_DIR` overrides take effect — the const-at-import-time\n * pattern this replaces was the bug discovered while dogfooding v2.63.0\n * (#2316). Outcome counts on a fresh portable workspace were leaking\n * the host home directory's outcome history.\n */\nexport function getLearningDir(): string {\n return join(getNexusDataDir(), 'learning');\n}\n\n/** JSONL file for persisted task outcomes. */\nexport function getOutcomesFile(): string {\n return join(getLearningDir(), 'outcomes.jsonl');\n}\n\n/** JSON file for persisted distilled rules. */\nexport function getRulesFile(): string {\n return join(getLearningDir(), 'rules.json');\n}\n\n/**\n * JSONL file for per-voter pr_review eval verdicts (#3848).\n *\n * Stores ONLY rubric-scored per-voter TP/FP/FN tallies vs ground truth — never\n * raw diffs, prompts, or model outputs. Lets per-voter precision/recall accrue\n * across runs so a chronically-noisy-voter demotion (Epic D / ADR-0017) has\n * citable evidence.\n */\nexport function getPrReviewEvalFile(): string {\n return join(getLearningDir(), 'pr-review-eval.jsonl');\n}\n\n/**\n * JSONL file for per-decision cost rollups (#3855).\n *\n * Stores ONLY the per-decision cost summary (per-voter / per-model token + USD\n * totals) for a governed `consensus_vote` / `pr_review` run — never raw\n * proposals, diffs, prompts, or model outputs. Lets \"what did this governed\n * decision cost?\" be answered from recorded data (epic #3854; feeds Epic G's\n * weather_report + manifest cost profiles in #3856).\n */\nexport function getDecisionCostFile(): string {\n return join(getLearningDir(), 'decision-costs.jsonl');\n}\n\n/**\n * JSONL file for the MetaOrchestrator shadow selector's training outcomes\n * (#3593). Stores ONLY numeric/categorical bandit-feature values + a boolean\n * success flag — never raw task text. Lets the shadow selector learn across\n * processes by replaying past outcomes on construction.\n */\nexport function getMetaOutcomesFile(): string {\n return join(getLearningDir(), 'meta-outcomes.jsonl');\n}\n\n// Note: previous LEARNING_DIR / OUTCOMES_FILE / RULES_FILE exports were\n// removed in #2316 — they were evaluated at module import time and ignored\n// `NEXUS_DATA_DIR`. All callers must use the getter functions above.\n\n/** Directory mode: owner-only (rwx------). */\nconst DIR_MODE = 0o700;\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Check whether learning persistence is enabled via feature flag.\n *\n * Defaults to true — cross-session LinUCB routing data persists to\n * `~/.nexus-agents/learning/` unless explicitly disabled.\n * Only routing metadata is stored (model, success, duration, category).\n * No user prompts, API keys, or model outputs are persisted.\n *\n * Set NEXUS_PERSIST_LEARNING=false to disable.\n */\nexport function isPersistenceEnabled(): boolean {\n return process.env['NEXUS_PERSIST_LEARNING'] !== 'false';\n}\n\n/** Ensure the learning data directory exists. */\nexport function ensureLearningDir(dir?: string): void {\n mkdirSync(dir ?? getLearningDir(), { recursive: true, mode: DIR_MODE });\n}\n","/**\n * Nexus runtime data directory resolver (#2302, child of #2301).\n *\n * Returns the absolute path under which nexus-agents stores runtime state.\n * Two categories of state exist (epic #2872, vote #2876):\n *\n * - **Per-repo** state (sessions, checkpoints, traces, runs, audit,\n * pipeline, tasks) — tied to the work happening in a specific codebase.\n * When `NEXUS_REPO_PREFERRED=1` is set and the caller is inside a git\n * repo, these resolve to `<repo-root>/.nexus-agents/<subdir>/`.\n * - **Cross-repo** state (learning, voting, memory, weather, research,\n * auth, usage, models manifest) — accumulates across the operator's\n * whole workflow. Always resolves to `~/.nexus-agents/<subdir>/` so the\n * learning/routing feedback loop from #1389 / #1407 keeps working.\n *\n * Resolution order (first match wins):\n * 1. `NEXUS_DATA_DIR` env var if set + non-empty. Wins for both categories\n * — the operator's explicit choice overrides the split.\n * 2. Sandbox-mode default (#2501): when `NEXUS_SANDBOX` is set, use\n * `${NEXUS_SANDBOX_ROOT ?? '/'}/.nexus-agents`. Sandboxed deployments\n * typically mount a multi-repo root; state goes there, shared across\n * repo subfolders rather than buried inside one.\n * 3. Per-repo subdirs (when `findRepoRoot(cwd)` succeeds AND\n * `NEXUS_REPO_PREFERRED` is not explicitly `'0'`):\n * `<repo-root>/.nexus-agents/<subdir>/`. Auto-adds `.nexus-agents/`\n * to the repo's `.gitignore` on first resolution (fail-closed).\n * 4. Cross-repo subdirs when `~/.nexus-agents/` is unwritable AND we're\n * in a repo: per-repo fallback at `<repo-root>/.nexus-agents/<subdir>/`\n * with one-time stderr announce. Issue #2888 — gives sandbox users\n * a working `research/`, `memory/`, etc. without env-var wrangling\n * while preserving the vote #2876 default for normal-machine users.\n * 5. `<homedir>/.nexus-agents` (cross-repo state on normal machines,\n * plus everything when not in a git repo or when\n * `NEXUS_REPO_PREFERRED=0`).\n *\n * `NEXUS_REPO_PREFERRED` defaults **ON** as of this release per vote\n * #2876. Escape hatches preserved:\n * - `NEXUS_REPO_PREFERRED=0` — fully opt out (homedir for everything).\n * - `NEXUS_DATA_DIR=~/.nexus-agents` — explicit override wins over\n * the tier and the categorization both.\n * - `nexus-agents migrate` (#2879) — relocate existing homedir state\n * into `<repo>/.nexus-agents/` before flipping in production.\n *\n * @module config/nexus-data-dir\n */\n\nimport {\n accessSync,\n constants as fsConstants,\n copyFileSync,\n existsSync,\n mkdirSync,\n renameSync,\n unlinkSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nimport { detectSandbox } from './sandbox-detection.js';\nimport { findRepoRoot } from './repo-root-detection.js';\nimport { ensureGitignored } from './portable-mode.js';\n\n/**\n * Subdirs scoped to a single repo's work (per the epic #2872 vote).\n * When `NEXUS_REPO_PREFERRED=1` and the caller is inside a git repo, these\n * route to `<repo-root>/.nexus-agents/`; otherwise homedir. The complement\n * (everything not in this set) always goes to homedir so cross-project\n * learning state stays intact.\n *\n * Source-of-truth for the categorization: vote #2876 conditions + audit\n * thread on epic #2872. Adding a new entry here is the appropriate way to\n * mark new state as per-repo — do that as a deliberate decision, not by\n * default.\n */\nconst PER_REPO_SUBDIRS: ReadonlySet<string> = new Set([\n 'sessions',\n 'checkpoints',\n 'traces',\n 'runs',\n 'audit',\n 'pipeline',\n 'tasks',\n // Async-mode job results (#3042 / epic #2631). Tied to work happening\n // in a specific codebase — a job dispatched on repo A shouldn't be\n // polled-against on repo B, which would happen if jobs/ were homedir-scoped.\n 'jobs',\n // CI health-check events (#3076 / #3084). Per-repo because outages\n // reported via `ci_health_check({ repo })` are repo-correlated; a wedge\n // on repo A's queue does not predict repo B's health.\n 'ci-health',\n]);\n\n/** Returns the absolute path to the nexus-agents data directory. */\nexport function getNexusDataDir(): string {\n const fromEnv = process.env['NEXUS_DATA_DIR']?.trim();\n if (fromEnv !== undefined && fromEnv !== '') {\n return resolve(fromEnv);\n }\n const sandbox = detectSandbox();\n if (sandbox.active) {\n return resolve(sandbox.root ?? '/', '.nexus-agents');\n }\n return join(homedir(), '.nexus-agents');\n}\n\n/**\n * No-op kept for source-compatibility with consumers that called this\n * earlier in development. The resolver is no longer cached, so resetting\n * is unnecessary. Kept exported (rather than removed) to avoid breaking\n * imports in tests that may have already adopted it.\n */\nexport function resetNexusDataDirCache(): void {\n // intentionally empty — see module docstring\n}\n\n/**\n * Tracks per-process state for the auto-gitignore wiring: we only need\n * to (a) probe + append to `.gitignore` once per repo, and (b) bail\n * cleanly if the operator has explicitly silenced the auto-add via\n * `NEXUS_GITIGNORE_AUTO=0`. Reset in tests via the helper below.\n */\nconst gitignoredRoots = new Set<string>();\n\n/** Test helper — clears the auto-gitignore \"already did this\" memo. */\nexport function _resetGitignoreMemoForTests(): void {\n gitignoredRoots.clear();\n}\n\n/**\n * Returns the repo-scoped `.nexus-agents/` directory if all of the\n * following hold: `NEXUS_REPO_PREFERRED` is NOT explicitly `'0'` (it\n * defaults ON as of vote #2876), `NEXUS_DATA_DIR` is not explicitly set\n * (explicit override always wins), no sandbox is active, and\n * `findRepoRoot(cwd)` finds an ancestor `.git`.\n *\n * Side effect: on the first successful resolution per process per repo,\n * appends `.nexus-agents/` to the repo's `.gitignore` if not already\n * present. The operator can silence this with `NEXUS_GITIGNORE_AUTO=0`\n * (e.g. on CI runners with a frozen working tree).\n *\n * Returns `null` when any precondition fails; callers fall back to\n * `getNexusDataDir()` (homedir).\n */\nexport function getNexusRepoDir(): string | null {\n if (process.env['NEXUS_REPO_PREFERRED'] === '0') return null;\n const fromEnv = process.env['NEXUS_DATA_DIR']?.trim();\n if (fromEnv !== undefined && fromEnv !== '') return null;\n if (detectSandbox().active) return null;\n const root = findRepoRoot(process.cwd());\n if (root === null) return null;\n maybeAutoGitignore(root);\n return join(root, '.nexus-agents');\n}\n\n/**\n * Best-effort fail-closed wiring: once per process per repo, ensure\n * `.nexus-agents/` is in `<repo>/.gitignore`. Silenced via\n * `NEXUS_GITIGNORE_AUTO=0`. Failures are non-fatal — the helper logs\n * to stderr and continues.\n */\nfunction maybeAutoGitignore(repoRoot: string): void {\n if (process.env['NEXUS_GITIGNORE_AUTO'] === '0') return;\n if (gitignoredRoots.has(repoRoot)) return;\n gitignoredRoots.add(repoRoot);\n // Only attempt when the repo root looks real — avoid spamming stderr\n // from temp-dir test fixtures that race the lifecycle.\n if (!existsSync(repoRoot)) return;\n ensureGitignored(repoRoot, '.nexus-agents/');\n}\n\n/**\n * Per-process memo: was the homedir base directory found writable on first\n * probe? Used to short-circuit the sandbox-fallback decision in\n * `nexusDataPath()` without spending a syscall on every call.\n */\nlet homedirWritable: boolean | undefined;\n\n/** Per-process memo: have we already announced a fallback for this subdir? */\nconst announcedFallbacks = new Set<string>();\n\n/** Test helper — clears the homedir-writability + announcement memos. */\nexport function _resetWritabilityMemoForTests(): void {\n homedirWritable = undefined;\n announcedFallbacks.clear();\n}\n\n/**\n * Returns true if `getNexusDataDir()` resolves to a writable location. Probed\n * once per process and memo'd — flips the sandbox-fallback on/off for\n * cross-repo subdirs. `mkdirSync(recursive: true)` is the safest probe\n * because it both creates the dir if missing and surfaces ENOENT/EACCES\n * issues at the same point. Failures here are non-fatal — they just route\n * cross-repo state to the per-repo fallback (issue #2888).\n */\nfunction isHomedirBaseWritable(): boolean {\n if (homedirWritable !== undefined) return homedirWritable;\n const base = getNexusDataDir();\n try {\n mkdirSync(base, { recursive: true });\n accessSync(base, fsConstants.W_OK);\n homedirWritable = true;\n } catch {\n homedirWritable = false;\n }\n return homedirWritable;\n}\n\n/**\n * Emit a one-time stderr warning when a cross-repo subdir falls back to\n * the per-repo location. Operators in sandboxes get a clear signal about\n * what happened without per-call noise.\n */\nfunction announceCrossRepoFallback(subdir: string, repoPath: string): void {\n if (announcedFallbacks.has(subdir)) return;\n announcedFallbacks.add(subdir);\n process.stderr.write(\n `[nexus] ${subdir}: homedir ~/.nexus-agents is not writable; ` +\n `using per-repo fallback at ${repoPath}. See docs/guides/SANDBOXED-USAGE.md.\\n`\n );\n}\n\n/**\n * Returns a path joined under the appropriate data directory for the\n * given subdir.\n *\n * Routing decision (first match wins):\n * 1. **Per-repo subdir + in a repo + `NEXUS_REPO_PREFERRED` not '0'** →\n * `<repo>/.nexus-agents/<subdir>/...`. Standard behavior since #2884.\n * 2. **Cross-repo subdir + homedir unwritable + in a repo** →\n * `<repo>/.nexus-agents/<subdir>/...` as a sandbox-friendly fallback\n * (issue #2888). Emits a one-time stderr warning per subdir.\n * 3. **Otherwise** → `<homedir>/.nexus-agents/<subdir>/...`. If homedir\n * is also unwritable, the actual write will surface the error.\n *\n * Existing callers don't need to change — the routing decision is driven\n * by the first segment, not by caller-declared intent.\n */\nexport function nexusDataPath(...segments: string[]): string {\n const first = segments[0];\n\n // Tier 1: per-repo subdir + repo-preferred default.\n if (first !== undefined && PER_REPO_SUBDIRS.has(first)) {\n const repoDir = getNexusRepoDir();\n if (repoDir !== null) {\n return join(repoDir, ...segments);\n }\n }\n\n // Tier 2: cross-repo subdir but homedir isn't reachable. Fall back to\n // the per-repo location if we're in a repo, so sandbox users get a\n // working `research/`, `memory/`, etc. without manual env-var setup.\n // Vote #2876 preserved: this only fires when homedir is physically\n // unreachable; normal-machine users see no change.\n if (first !== undefined && !isHomedirBaseWritable()) {\n const repoDir = getNexusRepoDir();\n if (repoDir !== null) {\n const fallbackPath = join(repoDir, ...segments);\n announceCrossRepoFallback(first, fallbackPath);\n return fallbackPath;\n }\n // No repo to fall back to AND homedir unreachable — return the\n // homedir path anyway. The caller's eventual write will surface\n // the underlying EACCES/ENOENT, which is the right error to show\n // because the environment is genuinely broken at that point.\n }\n\n return join(getNexusDataDir(), ...segments);\n}\n\n/**\n * Like `nexusDataPath()` but eagerly creates the parent directory so\n * callers don't have to remember `mkdirSync(dirname(p), { recursive: true })`\n * before every write. Issue #2890. Use when the returned path will be\n * written to immediately; for read-only resolution prefer `nexusDataPath()`.\n *\n * If the call resolves to a directory (single segment or no segments),\n * the target IS the resolved path. If it resolves to a file (multiple\n * segments), the target is its parent.\n */\nexport function nexusDataPathEnsure(...segments: string[]): string {\n const resolved = nexusDataPath(...segments);\n const target = segments.length > 1 ? dirname(resolved) : resolved;\n mkdirSync(target, { recursive: true });\n return resolved;\n}\n\n/**\n * Explicitly homedir-scoped path. Use this in code that handles\n * cross-project state (routing memory, model registry cache, auth,\n * research catalog) where you want a hard guarantee that the resolver\n * never routes per-repo, even if a new subdir gets accidentally added\n * to the `PER_REPO_SUBDIRS` allowlist later.\n */\nexport function nexusSharedPath(...segments: string[]): string {\n return join(getNexusDataDir(), ...segments);\n}\n\n/**\n * Returns the read-only categorization used by `nexusDataPath()`.\n * Exposed for tests and for tooling that wants to introspect which\n * subdirs are per-repo (e.g. the `nexus-agents migrate` command).\n */\nexport function getPerRepoSubdirs(): ReadonlySet<string> {\n return PER_REPO_SUBDIRS;\n}\n\n/** Per-process memo — the legacy session-DB relocation runs at most once. */\nlet legacySessionsDbMigrated = false;\n\n/** Test helper — clears the session-DB migration \"already did this\" memo. */\nexport function _resetSessionsDbMigrationMemoForTests(): void {\n legacySessionsDbMigrated = false;\n}\n\n/** SQLite sidecar suffixes that must travel with the main DB file. */\nconst SQLITE_SIDECAR_SUFFIXES = ['', '-wal', '-shm', '-journal'] as const;\n\n/**\n * Resolves the session-database path, performing a one-time relocation\n * of any pre-#2902 database on the first call per process.\n *\n * The session DB is per-repo episodic state and belongs in the\n * `sessions/` bucket alongside the session journals — vote #2876\n * categorized `sessions/` as per-repo, and issue #2902 (consensus\n * 3/3) extended that to the DB. Before #2902 the DB resolved via\n * `nexusDataPath('sessions.db')`; because `sessions.db` is not a\n * per-repo first segment, that landed cross-repo at\n * `~/.nexus-agents/sessions.db`, so a DB started in one repo leaked\n * into every other repo.\n *\n * If a legacy DB exists at the old location and none exists at the\n * new one, the legacy file (and any SQLite sidecars) is moved so\n * existing session history is preserved rather than silently\n * orphaned. The move is best-effort: a failure leaves the legacy DB\n * untouched for manual recovery and the caller gets a fresh DB at the\n * new path. `NEXUS_DATA_DIR` / `NEXUS_REPO_PREFERRED` / the\n * `NEXUS_SESSIONS_DB` override all sit upstream of this resolver.\n */\nexport function sessionsDbPath(): string {\n const target = nexusDataPath('sessions', 'sessions.db');\n if (!legacySessionsDbMigrated) {\n legacySessionsDbMigrated = true;\n migrateLegacySessionsDb(target);\n }\n return target;\n}\n\n/** One-time relocation of a pre-#2902 session DB. Best-effort — see `sessionsDbPath`. */\nfunction migrateLegacySessionsDb(target: string): void {\n const legacy = nexusDataPath('sessions.db'); // pre-#2902 resolution\n if (legacy === target || !existsSync(legacy) || existsSync(target)) return;\n try {\n mkdirSync(dirname(target), { recursive: true });\n for (const suffix of SQLITE_SIDECAR_SUFFIXES) {\n const from = `${legacy}${suffix}`;\n if (existsSync(from)) moveFile(from, `${target}${suffix}`);\n }\n } catch {\n // Best-effort — a migration failure must never break session storage.\n }\n}\n\n/** Moves a file, falling back to copy+unlink across a filesystem boundary. */\nfunction moveFile(from: string, to: string): void {\n try {\n renameSync(from, to);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EXDEV') throw err;\n copyFileSync(from, to);\n unlinkSync(from);\n }\n}\n","/**\n * Sandbox detection (#2501, child 1 of epic #2500).\n *\n * nexus-agents needs to know whether it's running inside a host-provided\n * sandbox (Docker Desktop Sandbox + OpenCode, Codex sandbox, locked-down\n * CI runner) so it can adjust behaviour:\n *\n * - default `NEXUS_DATA_DIR` to the multi-repo root rather than `~/...`\n * - skip CLI subprocess detection (binaries aren't there)\n * - fail-fast when the gateway is unreachable instead of degrading\n * - suppress diagnostics that don't apply\n *\n * The signal is **explicit**: the image author (Dockerfile, devcontainer,\n * harness wrapper) sets `NEXUS_SANDBOX=<flavor>`. The flavor string is\n * for diagnostics + per-flavor branching (`docker-opencode`, `codex`,\n * `claude-code`, `ci-restricted`, …); presence is the on/off signal.\n *\n * A heuristic check runs alongside for verification — if `NEXUS_SANDBOX`\n * claims `docker-opencode` but `/.dockerenv` is missing, that's a\n * misconfiguration worth surfacing to the operator.\n *\n * @module config/sandbox-detection\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\n\n/**\n * Heuristic detection result. Independent from the explicit\n * `NEXUS_SANDBOX` env var; produced by inspecting filesystem markers.\n */\nexport type SandboxHeuristic = 'docker' | 'podman' | 'unknown' | null;\n\nexport interface SandboxInfo {\n /**\n * True iff `NEXUS_SANDBOX` is set + non-empty. The explicit signal\n * the rest of the codebase keys off — never `true` by heuristic alone.\n */\n readonly active: boolean;\n /**\n * Operator-supplied flavor string, e.g. `docker-opencode`. Undefined\n * when `active === false` or the env var is empty.\n */\n readonly flavor: string | undefined;\n /**\n * Multi-repo root the user mounted. From `NEXUS_SANDBOX_ROOT`. Undefined\n * when unset; consumers that need a default substitute `/`.\n */\n readonly root: string | undefined;\n /**\n * Independent heuristic match — `null` when we couldn't run the check,\n * `'unknown'` when ran but no marker matched. Used by `doctor` to flag\n * mismatches between the explicit signal and the runtime environment.\n */\n readonly heuristicMatch: SandboxHeuristic;\n}\n\n/**\n * Detect whether nexus-agents is running inside a host-provided sandbox.\n * Pure read of env + filesystem; no caching (cheap enough to recompute,\n * and tests routinely mutate process.env).\n */\nexport function detectSandbox(): SandboxInfo {\n const flavorRaw = process.env['NEXUS_SANDBOX']?.trim();\n const flavor = flavorRaw !== undefined && flavorRaw !== '' ? flavorRaw : undefined;\n const active = flavor !== undefined;\n\n const rootRaw = process.env['NEXUS_SANDBOX_ROOT']?.trim();\n const root = rootRaw !== undefined && rootRaw !== '' ? rootRaw : undefined;\n\n return {\n active,\n flavor,\n root,\n heuristicMatch: detectContainerHeuristic(),\n };\n}\n\n/**\n * Look for filesystem markers indicating a container runtime. Used as a\n * cross-check against the explicit `NEXUS_SANDBOX` signal.\n *\n * Order of checks:\n * 1. `/.dockerenv` (Docker)\n * 2. `/run/.containerenv` (Podman)\n * 3. `/proc/1/cgroup` containing `docker` or `containerd` strings\n *\n * Returns `null` when none of the checks could run (non-Linux host with\n * no `/proc`, sandbox blocks `existsSync`, etc.) — distinct from\n * `'unknown'` (checks ran, no marker matched) so the doctor message can\n * differentiate \"we couldn't tell\" from \"we checked, no container\".\n */\nfunction detectContainerHeuristic(): SandboxHeuristic {\n try {\n if (existsSync('/.dockerenv')) return 'docker';\n if (existsSync('/run/.containerenv')) return 'podman';\n if (existsSync('/proc/1/cgroup')) {\n const cgroup = readFileSync('/proc/1/cgroup', 'utf8');\n if (/\\bdocker\\b/.test(cgroup)) return 'docker';\n if (/\\bcontainerd\\b/.test(cgroup)) return 'docker';\n }\n return 'unknown';\n } catch {\n return null;\n }\n}\n","/**\n * Repo-root detection — walks upward from a starting directory looking for\n * `.git` so callers can scope state to the current git repo. Built for\n * epic #2872 (issue #2882) to support the per-repo `.nexus-agents/` data\n * directory ratified by vote #2876.\n *\n * Defenses adopted:\n * - Walks upward but stops at filesystem root (no infinite loop on\n * symlinks-to-self).\n * - Stops at filesystem boundary (different `stat.dev`) — refuses to\n * escape across mount points. Prevents a sandboxed workdir from\n * resolving a `.git` on the host filesystem.\n * - Detects git worktrees: `.git` may be a *file* containing\n * `gitdir: <path>` rather than a directory.\n * - Realpath's the final root and rejects results that escape the\n * starting cwd by symlink.\n *\n * Deferred (tracked separately; not blocking #2882):\n * - CVE-2022-24765-style ownership check (refuse `.git` owned by a\n * different uid than the running process). The git CLI added\n * `safe.directory` for this; we don't have a comparable allowlist\n * surface yet. In CI the heuristic is too noisy to be useful\n * (runners often clone as a different uid than the workload).\n * File-system isolation (the `stat.dev` check above) covers the\n * bulk of the attack class.\n *\n * @module config/repo-root-detection\n */\n\nimport { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, resolve } from 'node:path';\n\n/**\n * Walks upward from `start` looking for `.git` (file or directory).\n * Returns the absolute path to the directory containing it, or `null`.\n *\n * Worktrees: a `.git` file (not dir) with contents `gitdir: <path>` is\n * still recognised as marking the repo root. The pointed-to gitdir is\n * NOT followed — we just need the worktree's own root.\n *\n * Filesystem boundary: stops walking if the next ancestor lives on a\n * different filesystem (different `stat.dev`). This prevents a workdir\n * mounted inside a sandbox from finding a host-side `.git`.\n */\nexport function findRepoRoot(start: string): string | null {\n if (!isAbsolute(start)) {\n start = resolve(start);\n }\n\n let current: string;\n try {\n current = realpathSync(start);\n } catch {\n return null;\n }\n\n let startDev: number | undefined;\n try {\n startDev = statSync(current).dev;\n } catch {\n return null;\n }\n\n // Walk up. Depth cap is paranoid but bounds the loop on pathological\n // symlinks even though realpathSync above should already prevent cycles.\n for (let i = 0; i < 64; i++) {\n if (isRepoRoot(current)) {\n return current;\n }\n const parent = dirname(current);\n if (parent === current) {\n // Hit filesystem root.\n return null;\n }\n try {\n if (statSync(parent).dev !== startDev) {\n // Crossed a mount point; refuse to escape.\n return null;\n }\n } catch {\n return null;\n }\n current = parent;\n }\n return null;\n}\n\n/** True iff `dir/.git` exists as a directory or a git-worktree marker file. */\nexport function isRepoRoot(dir: string): boolean {\n const gitPath = `${dir}/.git`;\n if (!existsSync(gitPath)) return false;\n try {\n const st = statSync(gitPath);\n if (st.isDirectory()) return true;\n if (st.isFile()) {\n // Worktree: first line should be `gitdir: <path>`.\n const head = readFileSync(gitPath, 'utf-8').slice(0, 256);\n return head.startsWith('gitdir:');\n }\n } catch {\n return false;\n }\n return false;\n}\n","/**\n * portable-mode — auto-detect sandboxed execution environments and\n * redirect nexus-agents data to a workspace-local directory.\n *\n * The existing `getNexusDataDir()` already respects `NEXUS_DATA_DIR` and\n * `NEXUS_PORTABLE_MODE`. This module wires up the *auto-detection* path\n * so operators running inside a Docker / restricted-FS / sandboxed\n * environment don't have to set the env vars manually — nexus-agents\n * notices and announces the flip.\n *\n * Source: Issue #2471 (epic #2467 child).\n *\n * Detection rules (first match wins):\n * 1. `NEXUS_DATA_DIR` already set → respect, no auto-detect\n * 2. `NEXUS_PORTABLE_MODE=0` → operator opted out, no auto-detect\n * 3. `NEXUS_PORTABLE_MODE=1` → portable mode, no detection needed\n * 4. Heuristic: home directory not writable\n * 5. Heuristic: container env vars set (KUBERNETES_SERVICE_HOST,\n * DOCKER_CONTAINER, ECS_CONTAINER_METADATA_URI, SANDBOX, etc.)\n *\n * When portable mode fires:\n * - Sets `process.env.NEXUS_DATA_DIR` to `<cwd>/.nexus-agents`\n * - Announces once on stderr (subsequent calls are silent)\n * - If cwd is a git repo, appends `.nexus-agents/` to .gitignore\n *\n * To force off: `NEXUS_PORTABLE_MODE=0`. To force on without heuristics:\n * `NEXUS_PORTABLE_MODE=1`. To override target dir: `NEXUS_DATA_DIR=...`.\n */\n\nimport { accessSync, constants, existsSync, readFileSync, appendFileSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\n\n/** Container / sandbox environment variables that strongly imply portable mode. */\nconst SANDBOX_ENV_VARS: readonly string[] = [\n 'KUBERNETES_SERVICE_HOST',\n 'DOCKER_CONTAINER',\n 'ECS_CONTAINER_METADATA_URI',\n 'ECS_CONTAINER_METADATA_URI_V4',\n 'SANDBOX',\n 'NEXUS_SANDBOX',\n];\n\nlet DETECTED = false;\n\ninterface DetectionResult {\n readonly portable: boolean;\n readonly dataDir: string;\n readonly reason:\n | 'env-data-dir'\n | 'env-opt-out'\n | 'env-opt-in'\n | 'home-unwritable'\n | 'container-env'\n | 'default';\n}\n\nfunction isHomeWritable(): boolean {\n try {\n const home = homedir();\n if (!existsSync(home)) return false;\n accessSync(home, constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction inSandboxEnv(): boolean {\n for (const v of SANDBOX_ENV_VARS) {\n const val = process.env[v];\n if (val !== undefined && val !== '') return true;\n }\n return false;\n}\n\nfunction checkExplicitEnv(cwd: string): DetectionResult | null {\n const fromEnv = process.env['NEXUS_DATA_DIR']?.trim();\n if (fromEnv !== undefined && fromEnv !== '') {\n return { portable: false, dataDir: resolve(fromEnv), reason: 'env-data-dir' };\n }\n const portableEnv = process.env['NEXUS_PORTABLE_MODE'];\n if (portableEnv === '0' || portableEnv === 'false') {\n return { portable: false, dataDir: join(homedir(), '.nexus-agents'), reason: 'env-opt-out' };\n }\n if (portableEnv === '1' || portableEnv === 'true') {\n return { portable: true, dataDir: join(cwd, '.nexus-agents'), reason: 'env-opt-in' };\n }\n return null;\n}\n\nfunction checkHeuristics(cwd: string): DetectionResult | null {\n if (!isHomeWritable()) {\n return { portable: true, dataDir: join(cwd, '.nexus-agents'), reason: 'home-unwritable' };\n }\n if (inSandboxEnv()) {\n return { portable: true, dataDir: join(cwd, '.nexus-agents'), reason: 'container-env' };\n }\n return null;\n}\n\n/**\n * Decide whether to flip nexus-agents to portable mode and what data dir\n * to use. Pure function; no side effects beyond reading env + filesystem.\n */\nexport function detectPortableMode(cwd: string = process.cwd()): DetectionResult {\n return (\n checkExplicitEnv(cwd) ??\n checkHeuristics(cwd) ?? {\n portable: false,\n dataDir: join(homedir(), '.nexus-agents'),\n reason: 'default',\n }\n );\n}\n\n/**\n * Apply detected portable mode at process startup. Idempotent (subsequent\n * calls are no-ops). Announces on stderr once when the auto-detection\n * heuristic triggers — env-opt-in/out doesn't announce because the\n * operator already knows.\n */\nexport function applyPortableMode(cwd: string = process.cwd()): void {\n if (DETECTED) return;\n DETECTED = true;\n\n const result = detectPortableMode(cwd);\n\n // No env, no heuristic match — nothing to do.\n if (!result.portable) return;\n\n // The heuristic-driven cases announce; explicit opt-in is silent.\n if (result.reason === 'home-unwritable' || result.reason === 'container-env') {\n process.stderr.write(\n `[portable-mode] Sandbox detected (${result.reason}). Using ${result.dataDir} for all nexus-agents data.\\n` +\n ` Set NEXUS_PORTABLE_MODE=0 to override; see docs/guides/SANDBOXED-USAGE.md\\n`\n );\n }\n\n process.env['NEXUS_DATA_DIR'] = result.dataDir;\n\n if (isInsideGitRepo(cwd)) {\n ensureGitignored(cwd, '.nexus-agents/');\n }\n}\n\nfunction isInsideGitRepo(cwd: string): boolean {\n try {\n const gitDir = join(cwd, '.git');\n return existsSync(gitDir) && statSync(gitDir).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Append `entry` to `<cwd>/.gitignore` if not already present. Stderr\n * announce on the first append. Exported because the repo-preferred\n * resolver in `nexus-data-dir.ts` reuses the same auto-gitignore behavior\n * when `<repo>/.nexus-agents/` becomes the active data dir (epic #2872).\n */\nexport function ensureGitignored(cwd: string, entry: string): void {\n const path = join(cwd, '.gitignore');\n try {\n const existing = existsSync(path) ? readFileSync(path, 'utf-8') : '';\n const lines = existing.split('\\n').map((l) => l.trim());\n if (lines.includes(entry) || lines.includes(entry.replace(/\\/$/, ''))) return;\n const sep = existing.length > 0 && !existing.endsWith('\\n') ? '\\n' : '';\n appendFileSync(path, `${sep}${entry}\\n`, 'utf-8');\n process.stderr.write(\n `[portable-mode] Added '${entry}' to ${path} so nexus-agents data is gitignored.\\n`\n );\n } catch (e: unknown) {\n // Non-fatal — operator can add the line themselves.\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(\n `[portable-mode] Could not auto-update ${path} (${msg}). Add '${entry}' manually if you don't want nexus-agents data tracked by git.\\n`\n );\n }\n}\n\n/** Test-only reset of the once-only state. */\nexport function _resetDetectedForTests(): void {\n DETECTED = false;\n}\n"],"mappings":";AAUA,SAAS,aAAAA,kBAAiB;AAC1B,SAAS,QAAAC,aAAY;;;ACmCrB;AAAA,EACE,cAAAC;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAAC,gBAAe;AACxB,SAAS,WAAAC,UAAS,QAAAC,OAAM,WAAAC,gBAAe;;;AChCvC,SAAS,YAAY,oBAAoB;AAqClC,SAAS,gBAA6B;AAC3C,QAAM,YAAY,QAAQ,IAAI,eAAe,GAAG,KAAK;AACrD,QAAM,SAAS,cAAc,UAAa,cAAc,KAAK,YAAY;AACzE,QAAM,SAAS,WAAW;AAE1B,QAAM,UAAU,QAAQ,IAAI,oBAAoB,GAAG,KAAK;AACxD,QAAM,OAAO,YAAY,UAAa,YAAY,KAAK,UAAU;AAEjE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,yBAAyB;AAAA,EAC3C;AACF;AAgBA,SAAS,2BAA6C;AACpD,MAAI;AACF,QAAI,WAAW,aAAa,EAAG,QAAO;AACtC,QAAI,WAAW,oBAAoB,EAAG,QAAO;AAC7C,QAAI,WAAW,gBAAgB,GAAG;AAChC,YAAM,SAAS,aAAa,kBAAkB,MAAM;AACpD,UAAI,aAAa,KAAK,MAAM,EAAG,QAAO;AACtC,UAAI,iBAAiB,KAAK,MAAM,EAAG,QAAO;AAAA,IAC5C;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC3EA,SAAS,cAAAC,aAAY,gBAAAC,eAAc,cAAc,gBAAgB;AACjE,SAAS,SAAS,YAAY,eAAe;AActC,SAAS,aAAa,OAA8B;AACzD,MAAI,CAAC,WAAW,KAAK,GAAG;AACtB,YAAQ,QAAQ,KAAK;AAAA,EACvB;AAEA,MAAI;AACJ,MAAI;AACF,cAAU,aAAa,KAAK;AAAA,EAC9B,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,eAAW,SAAS,OAAO,EAAE;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AAIA,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,QAAI,WAAW,OAAO,GAAG;AACvB,aAAO;AAAA,IACT;AACA,UAAM,SAAS,QAAQ,OAAO;AAC9B,QAAI,WAAW,SAAS;AAEtB,aAAO;AAAA,IACT;AACA,QAAI;AACF,UAAI,SAAS,MAAM,EAAE,QAAQ,UAAU;AAErC,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,IACT;AACA,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAGO,SAAS,WAAW,KAAsB;AAC/C,QAAM,UAAU,GAAG,GAAG;AACtB,MAAI,CAACD,YAAW,OAAO,EAAG,QAAO;AACjC,MAAI;AACF,UAAM,KAAK,SAAS,OAAO;AAC3B,QAAI,GAAG,YAAY,EAAG,QAAO;AAC7B,QAAI,GAAG,OAAO,GAAG;AAEf,YAAM,OAAOC,cAAa,SAAS,OAAO,EAAE,MAAM,GAAG,GAAG;AACxD,aAAO,KAAK,WAAW,SAAS;AAAA,IAClC;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;AC1EA,SAAS,YAAY,WAAW,cAAAC,aAAY,gBAAAC,eAAc,gBAAgB,YAAAC,iBAAgB;AAC1F,SAAS,eAAe;AACxB,SAAS,MAAM,WAAAC,gBAAe;AAG9B,IAAM,mBAAsC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAI,WAAW;AAcf,SAAS,iBAA0B;AACjC,MAAI;AACF,UAAM,OAAO,QAAQ;AACrB,QAAI,CAACH,YAAW,IAAI,EAAG,QAAO;AAC9B,eAAW,MAAM,UAAU,IAAI;AAC/B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAwB;AAC/B,aAAW,KAAK,kBAAkB;AAChC,UAAM,MAAM,QAAQ,IAAI,CAAC;AACzB,QAAI,QAAQ,UAAa,QAAQ,GAAI,QAAO;AAAA,EAC9C;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,KAAqC;AAC7D,QAAM,UAAU,QAAQ,IAAI,gBAAgB,GAAG,KAAK;AACpD,MAAI,YAAY,UAAa,YAAY,IAAI;AAC3C,WAAO,EAAE,UAAU,OAAO,SAASG,SAAQ,OAAO,GAAG,QAAQ,eAAe;AAAA,EAC9E;AACA,QAAM,cAAc,QAAQ,IAAI,qBAAqB;AACrD,MAAI,gBAAgB,OAAO,gBAAgB,SAAS;AAClD,WAAO,EAAE,UAAU,OAAO,SAAS,KAAK,QAAQ,GAAG,eAAe,GAAG,QAAQ,cAAc;AAAA,EAC7F;AACA,MAAI,gBAAgB,OAAO,gBAAgB,QAAQ;AACjD,WAAO,EAAE,UAAU,MAAM,SAAS,KAAK,KAAK,eAAe,GAAG,QAAQ,aAAa;AAAA,EACrF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,KAAqC;AAC5D,MAAI,CAAC,eAAe,GAAG;AACrB,WAAO,EAAE,UAAU,MAAM,SAAS,KAAK,KAAK,eAAe,GAAG,QAAQ,kBAAkB;AAAA,EAC1F;AACA,MAAI,aAAa,GAAG;AAClB,WAAO,EAAE,UAAU,MAAM,SAAS,KAAK,KAAK,eAAe,GAAG,QAAQ,gBAAgB;AAAA,EACxF;AACA,SAAO;AACT;AAMO,SAAS,mBAAmB,MAAc,QAAQ,IAAI,GAAoB;AAC/E,SACE,iBAAiB,GAAG,KACpB,gBAAgB,GAAG,KAAK;AAAA,IACtB,UAAU;AAAA,IACV,SAAS,KAAK,QAAQ,GAAG,eAAe;AAAA,IACxC,QAAQ;AAAA,EACV;AAEJ;AAQO,SAAS,kBAAkB,MAAc,QAAQ,IAAI,GAAS;AACnE,MAAI,SAAU;AACd,aAAW;AAEX,QAAM,SAAS,mBAAmB,GAAG;AAGrC,MAAI,CAAC,OAAO,SAAU;AAGtB,MAAI,OAAO,WAAW,qBAAqB,OAAO,WAAW,iBAAiB;AAC5E,YAAQ,OAAO;AAAA,MACb,qCAAqC,OAAO,MAAM,YAAY,OAAO,OAAO;AAAA;AAAA;AAAA,IAE9E;AAAA,EACF;AAEA,UAAQ,IAAI,gBAAgB,IAAI,OAAO;AAEvC,MAAI,gBAAgB,GAAG,GAAG;AACxB,qBAAiB,KAAK,gBAAgB;AAAA,EACxC;AACF;AAEA,SAAS,gBAAgB,KAAsB;AAC7C,MAAI;AACF,UAAM,SAAS,KAAK,KAAK,MAAM;AAC/B,WAAOH,YAAW,MAAM,KAAKE,UAAS,MAAM,EAAE,YAAY;AAAA,EAC5D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQO,SAAS,iBAAiB,KAAa,OAAqB;AACjE,QAAM,OAAO,KAAK,KAAK,YAAY;AACnC,MAAI;AACF,UAAM,WAAWF,YAAW,IAAI,IAAIC,cAAa,MAAM,OAAO,IAAI;AAClE,UAAM,QAAQ,SAAS,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACtD,QAAI,MAAM,SAAS,KAAK,KAAK,MAAM,SAAS,MAAM,QAAQ,OAAO,EAAE,CAAC,EAAG;AACvE,UAAM,MAAM,SAAS,SAAS,KAAK,CAAC,SAAS,SAAS,IAAI,IAAI,OAAO;AACrE,mBAAe,MAAM,GAAG,GAAG,GAAG,KAAK;AAAA,GAAM,OAAO;AAChD,YAAQ,OAAO;AAAA,MACb,0BAA0B,KAAK,QAAQ,IAAI;AAAA;AAAA,IAC7C;AAAA,EACF,SAAS,GAAY;AAEnB,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,YAAQ,OAAO;AAAA,MACb,yCAAyC,IAAI,KAAK,GAAG,WAAW,KAAK;AAAA;AAAA,IACvE;AAAA,EACF;AACF;;;AHzGA,IAAM,mBAAwC,oBAAI,IAAI;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AACF,CAAC;AAGM,SAAS,kBAA0B;AACxC,QAAM,UAAU,QAAQ,IAAI,gBAAgB,GAAG,KAAK;AACpD,MAAI,YAAY,UAAa,YAAY,IAAI;AAC3C,WAAOG,SAAQ,OAAO;AAAA,EACxB;AACA,QAAM,UAAU,cAAc;AAC9B,MAAI,QAAQ,QAAQ;AAClB,WAAOA,SAAQ,QAAQ,QAAQ,KAAK,eAAe;AAAA,EACrD;AACA,SAAOC,MAAKC,SAAQ,GAAG,eAAe;AACxC;AAkBA,IAAM,kBAAkB,oBAAI,IAAY;AAsBjC,SAAS,kBAAiC;AAC/C,MAAI,QAAQ,IAAI,sBAAsB,MAAM,IAAK,QAAO;AACxD,QAAM,UAAU,QAAQ,IAAI,gBAAgB,GAAG,KAAK;AACpD,MAAI,YAAY,UAAa,YAAY,GAAI,QAAO;AACpD,MAAI,cAAc,EAAE,OAAQ,QAAO;AACnC,QAAM,OAAO,aAAa,QAAQ,IAAI,CAAC;AACvC,MAAI,SAAS,KAAM,QAAO;AAC1B,qBAAmB,IAAI;AACvB,SAAOC,MAAK,MAAM,eAAe;AACnC;AAQA,SAAS,mBAAmB,UAAwB;AAClD,MAAI,QAAQ,IAAI,sBAAsB,MAAM,IAAK;AACjD,MAAI,gBAAgB,IAAI,QAAQ,EAAG;AACnC,kBAAgB,IAAI,QAAQ;AAG5B,MAAI,CAACC,YAAW,QAAQ,EAAG;AAC3B,mBAAiB,UAAU,gBAAgB;AAC7C;AAOA,IAAI;AAGJ,IAAM,qBAAqB,oBAAI,IAAY;AAgB3C,SAAS,wBAAiC;AACxC,MAAI,oBAAoB,OAAW,QAAO;AAC1C,QAAM,OAAO,gBAAgB;AAC7B,MAAI;AACF,cAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACnC,IAAAC,YAAW,MAAM,YAAY,IAAI;AACjC,sBAAkB;AAAA,EACpB,QAAQ;AACN,sBAAkB;AAAA,EACpB;AACA,SAAO;AACT;AAOA,SAAS,0BAA0B,QAAgB,UAAwB;AACzE,MAAI,mBAAmB,IAAI,MAAM,EAAG;AACpC,qBAAmB,IAAI,MAAM;AAC7B,UAAQ,OAAO;AAAA,IACb,WAAW,MAAM,yEACe,QAAQ;AAAA;AAAA,EAC1C;AACF;AAkBO,SAAS,iBAAiB,UAA4B;AAC3D,QAAM,QAAQ,SAAS,CAAC;AAGxB,MAAI,UAAU,UAAa,iBAAiB,IAAI,KAAK,GAAG;AACtD,UAAM,UAAU,gBAAgB;AAChC,QAAI,YAAY,MAAM;AACpB,aAAOC,MAAK,SAAS,GAAG,QAAQ;AAAA,IAClC;AAAA,EACF;AAOA,MAAI,UAAU,UAAa,CAAC,sBAAsB,GAAG;AACnD,UAAM,UAAU,gBAAgB;AAChC,QAAI,YAAY,MAAM;AACpB,YAAM,eAAeA,MAAK,SAAS,GAAG,QAAQ;AAC9C,gCAA0B,OAAO,YAAY;AAC7C,aAAO;AAAA,IACT;AAAA,EAKF;AAEA,SAAOA,MAAK,gBAAgB,GAAG,GAAG,QAAQ;AAC5C;AAYO,SAAS,uBAAuB,UAA4B;AACjE,QAAM,WAAW,cAAc,GAAG,QAAQ;AAC1C,QAAM,SAAS,SAAS,SAAS,IAAIC,SAAQ,QAAQ,IAAI;AACzD,YAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACrC,SAAO;AACT;AASO,SAAS,mBAAmB,UAA4B;AAC7D,SAAOD,MAAK,gBAAgB,GAAG,GAAG,QAAQ;AAC5C;AAOO,SAAS,oBAAyC;AACvD,SAAO;AACT;AAGA,IAAI,2BAA2B;AAQ/B,IAAM,0BAA0B,CAAC,IAAI,QAAQ,QAAQ,UAAU;AAuBxD,SAAS,iBAAyB;AACvC,QAAM,SAAS,cAAc,YAAY,aAAa;AACtD,MAAI,CAAC,0BAA0B;AAC7B,+BAA2B;AAC3B,4BAAwB,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAGA,SAAS,wBAAwB,QAAsB;AACrD,QAAM,SAAS,cAAc,aAAa;AAC1C,MAAI,WAAW,UAAU,CAACE,YAAW,MAAM,KAAKA,YAAW,MAAM,EAAG;AACpE,MAAI;AACF,cAAUC,SAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,eAAW,UAAU,yBAAyB;AAC5C,YAAM,OAAO,GAAG,MAAM,GAAG,MAAM;AAC/B,UAAID,YAAW,IAAI,EAAG,UAAS,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE;AAAA,IAC3D;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAGA,SAAS,SAAS,MAAc,IAAkB;AAChD,MAAI;AACF,eAAW,MAAM,EAAE;AAAA,EACrB,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,QAAS,OAAM;AAC3D,iBAAa,MAAM,EAAE;AACrB,eAAW,IAAI;AAAA,EACjB;AACF;;;AD1VO,SAAS,iBAAyB;AACvC,SAAOE,MAAK,gBAAgB,GAAG,UAAU;AAC3C;AAGO,SAAS,kBAA0B;AACxC,SAAOA,MAAK,eAAe,GAAG,gBAAgB;AAChD;AAGO,SAAS,eAAuB;AACrC,SAAOA,MAAK,eAAe,GAAG,YAAY;AAC5C;AAUO,SAAS,sBAA8B;AAC5C,SAAOA,MAAK,eAAe,GAAG,sBAAsB;AACtD;AAWO,SAAS,sBAA8B;AAC5C,SAAOA,MAAK,eAAe,GAAG,sBAAsB;AACtD;AAQO,SAAS,sBAA8B;AAC5C,SAAOA,MAAK,eAAe,GAAG,qBAAqB;AACrD;AAOA,IAAM,WAAW;AAgBV,SAAS,uBAAgC;AAC9C,SAAO,QAAQ,IAAI,wBAAwB,MAAM;AACnD;AAGO,SAAS,kBAAkB,KAAoB;AACpD,EAAAC,WAAU,OAAO,eAAe,GAAG,EAAE,WAAW,MAAM,MAAM,SAAS,CAAC;AACxE;","names":["mkdirSync","join","accessSync","existsSync","homedir","dirname","join","resolve","existsSync","readFileSync","existsSync","readFileSync","statSync","resolve","resolve","join","homedir","join","existsSync","accessSync","join","dirname","existsSync","dirname","join","mkdirSync"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../nexus-memory/src/telemetry.ts","../../nexus-memory/src/backends/memory.ts","../../nexus-memory/src/backends/sqlite.ts","../../nexus-memory/src/registry.ts","../../nexus-memory/src/factory.ts","../../nexus-memory/src/importer.ts"],"sourcesContent":["/**\n * Memory telemetry — aggregated counters (default) + opt-in full-audit mode.\n *\n * Phase 2 vote (#2768) settled on **C**: per-`{domain, op}` counters in\n * steady state, full per-event payloads when `NEXUS_MEMORY_AUDIT_MODE=audit`.\n *\n * The catfish-mitigation requirement is honored: audit mode emits\n * `{ op, keySummary, payloadSummary, resultSummary, cli, durationMs, hit }`\n * — not just counters — so an incident replay can reconstruct individual\n * ops. Summaries are truncated to keep emission cheap.\n *\n * @module nexus-memory/telemetry\n */\n\nimport type { MemoryEvent, MemoryEventCounters, MemoryEventListener } from './types.js';\n\nconst KEY_SUMMARY_LIMIT = 120;\nconst PAYLOAD_SUMMARY_LIMIT = 240;\n\n/** Per-`{domain, op}` rolling counters. */\nconst counters = new Map<string, MemoryEventCounters>();\nconst listeners = new Set<MemoryEventListener>();\n\n/** Audit mode is opt-in via env. Checked once per emission so the env\n * can be toggled at runtime by tests via `process.env`. */\nfunction isAuditMode(): boolean {\n return process.env['NEXUS_MEMORY_AUDIT_MODE'] === 'audit';\n}\n\nfunction counterKey(domain: string, op: MemoryEvent['op']): string {\n return `${domain}::${op}`;\n}\n\nfunction truncate(value: unknown, limit: number): string {\n let s: string;\n if (typeof value === 'string') {\n s = value;\n } else if (value === undefined) {\n s = '<undefined>';\n } else if (value === null) {\n s = '<null>';\n } else {\n try {\n s = JSON.stringify(value);\n } catch {\n s = '<unserializable>';\n }\n }\n return s.length > limit ? `${s.slice(0, limit - 1)}…` : s;\n}\n\ninterface RecordedEvent extends Omit<\n MemoryEvent,\n 'keySummary' | 'payloadSummary' | 'resultSummary'\n> {\n readonly key?: unknown;\n readonly payload?: unknown;\n readonly result?: unknown;\n}\n\nfunction updateCounter(event: RecordedEvent): void {\n const ck = counterKey(event.domain, event.op);\n const existing = counters.get(ck);\n const hitDelta = event.hit === true ? 1 : 0;\n counters.set(ck, {\n domain: event.domain,\n op: event.op,\n count: (existing?.count ?? 0) + 1,\n hitCount: (existing?.hitCount ?? 0) + hitDelta,\n totalDurationMs: (existing?.totalDurationMs ?? 0) + event.durationMs,\n maxDurationMs: Math.max(existing?.maxDurationMs ?? 0, event.durationMs),\n });\n}\n\nfunction buildPublicEvent(event: RecordedEvent, audit: boolean): MemoryEvent {\n return {\n domain: event.domain,\n op: event.op,\n durationMs: event.durationMs,\n ...(event.cli !== undefined && { cli: event.cli }),\n ...(event.hit !== undefined && { hit: event.hit }),\n ...(audit &&\n event.key !== undefined && {\n keySummary: truncate(event.key, KEY_SUMMARY_LIMIT),\n }),\n ...(audit &&\n event.payload !== undefined && {\n payloadSummary: truncate(event.payload, PAYLOAD_SUMMARY_LIMIT),\n }),\n ...(audit &&\n event.result !== undefined && {\n resultSummary: truncate(event.result, PAYLOAD_SUMMARY_LIMIT),\n }),\n };\n}\n\n/**\n * Record a memory operation. Updates counters always; emits the event\n * to subscribers always (subscribers get the full event in audit mode,\n * the aggregate-only event otherwise).\n *\n * Implementation note: the `op` argument is the typed `MemoryEvent['op']`\n * literal — backends never pass an unknown string here.\n */\nexport function recordMemoryEvent(event: RecordedEvent): void {\n updateCounter(event);\n const publicEvent = buildPublicEvent(event, isAuditMode());\n for (const listener of listeners) {\n try {\n listener(publicEvent);\n } catch {\n // Subscriber failures must never affect memory operations.\n }\n }\n}\n\n/** Snapshot of current counters. Returned array is a copy. */\nexport function getMemoryEventCounters(): readonly MemoryEventCounters[] {\n return [...counters.values()];\n}\n\n/** Subscribe to the per-event stream. Returns an unsubscribe function. */\nexport function subscribeToMemoryEvents(listener: MemoryEventListener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\n/**\n * Reset counters + drop all subscribers. Tests should call this in\n * `beforeEach` to keep state from leaking.\n */\nexport function resetMemoryTelemetry(): void {\n counters.clear();\n listeners.clear();\n}\n","/**\n * In-memory backend — primarily for tests, but also used as the cold-archive\n * fallback when no `dbPath` is provided.\n *\n * Implements {@link IMemoryBackend}; passes the same contract test as\n * {@link SqliteBackend}.\n *\n * @module nexus-memory/backends/memory\n */\n\nimport type { z } from 'zod';\nimport { recordMemoryEvent } from '../telemetry.js';\nimport type { BackendStats, IMemoryBackend, QueryFilter, WriteMeta } from '../types.js';\n\ninterface Row<TValue> {\n readonly value: TValue;\n readonly cli?: string;\n readonly source?: string;\n readonly timestamp: number;\n readonly trustTier?: 1 | 2 | 3 | 4;\n}\n\nexport interface InMemoryBackendOptions<TValue> {\n readonly domain: string;\n /**\n * Optional Zod schema. Phase 2 vote mitigation #1 (security dissent):\n * when supplied, every `write()` validates the value first; invalid\n * payloads throw `MemoryValidationError`.\n */\n readonly schema?: z.ZodType<TValue>;\n}\n\nexport class MemoryValidationError extends Error {\n constructor(domain: string, cause: unknown) {\n super(`nexus-memory: write rejected for domain \"${domain}\": ${String(cause)}`);\n this.name = 'MemoryValidationError';\n }\n}\n\nfunction buildInMemoryRow<TValue>(value: TValue, meta: WriteMeta | undefined): Row<TValue> {\n return {\n value,\n ...(meta?.cli !== undefined && { cli: meta.cli }),\n ...(meta?.source !== undefined && { source: meta.source }),\n timestamp: meta?.timestamp ?? Date.now(),\n ...(meta?.trustTier !== undefined && { trustTier: meta.trustTier }),\n };\n}\n\n/** Apply `where`, `orderBy`, `limit` to an in-memory row set. Extracted from\n * `query` to satisfy the eslint complexity gate. */\nfunction applyInMemoryFilter<T>(values: T[], filter?: QueryFilter<T>): T[] {\n let out = values;\n if (filter?.where !== undefined) {\n const where = filter.where;\n out = out.filter((v) => {\n for (const [k, expected] of Object.entries(where)) {\n if ((v as Record<string, unknown>)[k] !== expected) return false;\n }\n return true;\n });\n }\n if (filter?.orderBy !== undefined) {\n const orderBy = filter.orderBy;\n const dir = filter.orderDir === 'desc' ? -1 : 1;\n out = [...out].sort((a, b) => {\n const av = (a as Record<string | symbol | number, unknown>)[orderBy];\n const bv = (b as Record<string | symbol | number, unknown>)[orderBy];\n if (av === bv) return 0;\n if (av === undefined || av === null) return 1;\n if (bv === undefined || bv === null) return -1;\n return (av < bv ? -1 : 1) * dir;\n });\n }\n if (filter?.limit !== undefined) {\n out = out.slice(0, filter.limit);\n }\n return out;\n}\n\nexport class InMemoryBackend<TKey, TValue> implements IMemoryBackend<TKey, TValue> {\n readonly domain: string;\n private readonly rows = new Map<TKey, Row<TValue>>();\n private readonly schema?: z.ZodType<TValue>;\n private closed = false;\n\n constructor(options: InMemoryBackendOptions<TValue>) {\n this.domain = options.domain;\n if (options.schema !== undefined) {\n this.schema = options.schema;\n }\n }\n\n async read(key: TKey): Promise<TValue | undefined> {\n this.assertOpen();\n const start = Date.now();\n const row = this.rows.get(key);\n recordMemoryEvent({\n domain: this.domain,\n op: 'read',\n hit: row !== undefined,\n durationMs: Date.now() - start,\n key,\n result: row?.value,\n });\n return Promise.resolve(row?.value);\n }\n\n private validate(value: TValue): void {\n if (this.schema === undefined) return;\n const result = this.schema.safeParse(value);\n if (!result.success) {\n throw new MemoryValidationError(this.domain, result.error);\n }\n }\n\n async write(key: TKey, value: TValue, meta?: WriteMeta): Promise<void> {\n this.assertOpen();\n const start = Date.now();\n this.validate(value);\n this.rows.set(key, buildInMemoryRow(value, meta));\n recordMemoryEvent({\n domain: this.domain,\n op: 'write',\n ...(meta?.cli !== undefined && { cli: meta.cli }),\n durationMs: Date.now() - start,\n key,\n payload: value,\n });\n return Promise.resolve();\n }\n\n async query(filter?: QueryFilter<TValue>): Promise<readonly TValue[]> {\n this.assertOpen();\n const start = Date.now();\n let rows = [...this.rows.values()];\n if (filter?.cli !== undefined) {\n rows = rows.filter((r) => r.cli === filter.cli);\n }\n const values = applyInMemoryFilter(\n rows.map((r) => r.value),\n filter\n );\n recordMemoryEvent({\n domain: this.domain,\n op: 'query',\n hit: values.length > 0,\n ...(filter?.cli !== undefined && { cli: filter.cli }),\n durationMs: Date.now() - start,\n key: filter,\n result: { count: values.length },\n });\n return Promise.resolve(values);\n }\n\n async delete(key: TKey): Promise<boolean> {\n this.assertOpen();\n const start = Date.now();\n const removed = this.rows.delete(key);\n recordMemoryEvent({\n domain: this.domain,\n op: 'delete',\n hit: removed,\n durationMs: Date.now() - start,\n key,\n });\n return Promise.resolve(removed);\n }\n\n async stats(): Promise<BackendStats> {\n this.assertOpen();\n const start = Date.now();\n const timestamps = [...this.rows.values()].map((r) => r.timestamp);\n const result: BackendStats = {\n domain: this.domain,\n count: this.rows.size,\n oldestTimestamp: timestamps.length > 0 ? Math.min(...timestamps) : null,\n newestTimestamp: timestamps.length > 0 ? Math.max(...timestamps) : null,\n };\n recordMemoryEvent({\n domain: this.domain,\n op: 'stats',\n durationMs: Date.now() - start,\n result,\n });\n return Promise.resolve(result);\n }\n\n async close(): Promise<void> {\n this.closed = true;\n this.rows.clear();\n return Promise.resolve();\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(`nexus-memory: backend \"${this.domain}\" is closed`);\n }\n }\n}\n","/**\n * SQLite backend — async wrapper over `better-sqlite3` (which is sync).\n *\n * One table per domain (Phase 2 vote shape C, hot-table side). The schema\n * is intentionally minimal: `key`, `value` (JSON-serialized), `cli`,\n * `source`, `timestamp`, `trust_tier`. Hot-path backends extending this\n * will add typed columns and indexes for query performance.\n *\n * Async surface: every method returns `Promise<T>` so we can swap in a\n * network-backed implementation later without changing callers. The\n * actual SQLite ops are sync inside.\n *\n * @module nexus-memory/backends/sqlite\n */\n\nimport Database, { type Database as DatabaseType, type Statement } from 'better-sqlite3';\nimport type { z } from 'zod';\nimport { recordMemoryEvent } from '../telemetry.js';\nimport type { BackendStats, IMemoryBackend, QueryFilter, WriteMeta } from '../types.js';\nimport { MemoryValidationError } from './memory.js';\n\nexport interface SqliteBackendOptions<TValue> {\n readonly domain: string;\n /** Absolute path to the SQLite file. Use `':memory:'` for tests. */\n readonly dbPath: string;\n /**\n * Zod schema for cold-archive validation (Phase 2 vote mitigation #1).\n * When supplied, every `write()` validates first.\n */\n readonly schema?: z.ZodType<TValue>;\n /** Pre-existing database handle. Used by `MemoryRegistry` to share a single connection. */\n readonly db?: DatabaseType;\n}\n\ninterface SqliteRow {\n readonly key: string;\n readonly value: string;\n readonly cli: string | null;\n readonly source: string | null;\n readonly timestamp: number;\n readonly trust_tier: number | null;\n}\n\nfunction buildWriteRow(\n key: unknown,\n value: unknown,\n meta: WriteMeta | undefined\n): Record<string, string | number | null> {\n return {\n key: keyToString(key),\n value: JSON.stringify(value),\n cli: meta?.cli ?? null,\n source: meta?.source ?? null,\n timestamp: meta?.timestamp ?? Date.now(),\n trust_tier: meta?.trustTier ?? null,\n };\n}\n\n/** Stringify a key so SQLite primary-key lookups stay simple. */\nfunction keyToString(key: unknown): string {\n if (typeof key === 'string') return key;\n if (typeof key === 'number' || typeof key === 'boolean') return String(key);\n return JSON.stringify(key);\n}\n\n/** Apply `where`, `orderBy`, `limit` to an in-memory row set. Extracted from\n * `query` to satisfy the eslint complexity gate. */\nfunction applyQueryFilter<T>(values: T[], filter?: QueryFilter<T>): T[] {\n let out = values;\n if (filter?.where !== undefined) {\n const where = filter.where;\n out = out.filter((v) => {\n for (const [k, expected] of Object.entries(where)) {\n if ((v as Record<string, unknown>)[k] !== expected) return false;\n }\n return true;\n });\n }\n if (filter?.orderBy !== undefined) {\n const orderBy = filter.orderBy;\n const dir = filter.orderDir === 'desc' ? -1 : 1;\n out = [...out].sort((a, b) => {\n const av = (a as Record<string | symbol | number, unknown>)[orderBy];\n const bv = (b as Record<string | symbol | number, unknown>)[orderBy];\n if (av === bv) return 0;\n if (av === undefined || av === null) return 1;\n if (bv === undefined || bv === null) return -1;\n return (av < bv ? -1 : 1) * dir;\n });\n }\n if (filter?.limit !== undefined) {\n out = out.slice(0, filter.limit);\n }\n return out;\n}\n\nexport class SqliteBackend<TKey, TValue> implements IMemoryBackend<TKey, TValue> {\n readonly domain: string;\n private readonly db: DatabaseType;\n private readonly ownsDb: boolean;\n private readonly schema?: z.ZodType<TValue>;\n private readonly stmts: {\n read: Statement;\n write: Statement;\n delete: Statement;\n count: Statement;\n bounds: Statement;\n queryAll: Statement;\n };\n private closed = false;\n\n constructor(options: SqliteBackendOptions<TValue>) {\n this.domain = options.domain;\n if (options.db !== undefined) {\n this.db = options.db;\n this.ownsDb = false;\n } else {\n const db = new Database(options.dbPath);\n (db as unknown as { pragma(s: string): void }).pragma('journal_mode = WAL');\n this.db = db;\n this.ownsDb = true;\n }\n if (options.schema !== undefined) {\n this.schema = options.schema;\n }\n this.ensureTable();\n this.stmts = this.prepareStatements();\n }\n\n private ensureTable(): void {\n // Table name = domain. Domain comes from in-tree code, never untrusted input,\n // so direct interpolation is safe; still validate the shape defensively.\n if (!/^[a-z][a-z0-9_]{0,63}$/i.test(this.domain)) {\n throw new Error(\n `nexus-memory: invalid domain \"${this.domain}\" — must match [a-zA-Z][a-zA-Z0-9_]{0,63}`\n );\n }\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${this.domain} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n cli TEXT,\n source TEXT,\n timestamp INTEGER NOT NULL,\n trust_tier INTEGER\n );\n CREATE INDEX IF NOT EXISTS ${this.domain}_cli ON ${this.domain}(cli);\n CREATE INDEX IF NOT EXISTS ${this.domain}_timestamp ON ${this.domain}(timestamp);\n `);\n }\n\n private prepareStatements(): SqliteBackend<TKey, TValue>['stmts'] {\n return {\n read: this.db.prepare(\n `SELECT key, value, cli, source, timestamp, trust_tier FROM ${this.domain} WHERE key = ?`\n ),\n write: this.db.prepare(\n `INSERT INTO ${this.domain} (key, value, cli, source, timestamp, trust_tier)\n VALUES (@key, @value, @cli, @source, @timestamp, @trust_tier)\n ON CONFLICT(key) DO UPDATE SET\n value = excluded.value,\n cli = excluded.cli,\n source = excluded.source,\n timestamp = excluded.timestamp,\n trust_tier = excluded.trust_tier`\n ),\n delete: this.db.prepare(`DELETE FROM ${this.domain} WHERE key = ?`),\n count: this.db.prepare(`SELECT COUNT(*) AS count FROM ${this.domain}`),\n bounds: this.db.prepare(\n `SELECT MIN(timestamp) AS oldest, MAX(timestamp) AS newest FROM ${this.domain}`\n ),\n queryAll: this.db.prepare(\n `SELECT key, value, cli, source, timestamp, trust_tier FROM ${this.domain}`\n ),\n };\n }\n\n async read(key: TKey): Promise<TValue | undefined> {\n this.assertOpen();\n const start = Date.now();\n const row = this.stmts.read.get(keyToString(key)) as SqliteRow | undefined;\n const value = row !== undefined ? (JSON.parse(row.value) as TValue) : undefined;\n recordMemoryEvent({\n domain: this.domain,\n op: 'read',\n hit: value !== undefined,\n ...(row?.cli !== null && row?.cli !== undefined && { cli: row.cli as never }),\n durationMs: Date.now() - start,\n key,\n result: value,\n });\n return Promise.resolve(value);\n }\n\n private validate(value: TValue): void {\n if (this.schema === undefined) return;\n const result = this.schema.safeParse(value);\n if (!result.success) {\n throw new MemoryValidationError(this.domain, result.error);\n }\n }\n\n async write(key: TKey, value: TValue, meta?: WriteMeta): Promise<void> {\n this.assertOpen();\n const start = Date.now();\n this.validate(value);\n this.stmts.write.run(buildWriteRow(key, value, meta));\n recordMemoryEvent({\n domain: this.domain,\n op: 'write',\n ...(meta?.cli !== undefined && { cli: meta.cli }),\n durationMs: Date.now() - start,\n key,\n payload: value,\n });\n return Promise.resolve();\n }\n\n async query(filter?: QueryFilter<TValue>): Promise<readonly TValue[]> {\n this.assertOpen();\n const start = Date.now();\n // Phase 3 keeps query simple — full table scan with in-process filter.\n // Hot-path backends will override or extend with indexed columns.\n let rows = this.stmts.queryAll.all() as SqliteRow[];\n if (filter?.cli !== undefined) {\n rows = rows.filter((r) => r.cli === filter.cli);\n }\n let values = rows.map((r) => JSON.parse(r.value) as TValue);\n values = applyQueryFilter(values, filter);\n recordMemoryEvent({\n domain: this.domain,\n op: 'query',\n hit: values.length > 0,\n ...(filter?.cli !== undefined && { cli: filter.cli }),\n durationMs: Date.now() - start,\n key: filter,\n result: { count: values.length },\n });\n return Promise.resolve(values);\n }\n\n async delete(key: TKey): Promise<boolean> {\n this.assertOpen();\n const start = Date.now();\n const result = this.stmts.delete.run(keyToString(key));\n const removed = result.changes > 0;\n recordMemoryEvent({\n domain: this.domain,\n op: 'delete',\n hit: removed,\n durationMs: Date.now() - start,\n key,\n });\n return Promise.resolve(removed);\n }\n\n async stats(): Promise<BackendStats> {\n this.assertOpen();\n const start = Date.now();\n const countRow = this.stmts.count.get() as { count: number };\n const boundsRow = this.stmts.bounds.get() as { oldest: number | null; newest: number | null };\n const result: BackendStats = {\n domain: this.domain,\n count: countRow.count,\n oldestTimestamp: boundsRow.oldest,\n newestTimestamp: boundsRow.newest,\n };\n recordMemoryEvent({\n domain: this.domain,\n op: 'stats',\n durationMs: Date.now() - start,\n result,\n });\n return Promise.resolve(result);\n }\n\n async close(): Promise<void> {\n if (this.closed) return Promise.resolve();\n this.closed = true;\n if (this.ownsDb) this.db.close();\n return Promise.resolve();\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(`nexus-memory: backend \"${this.domain}\" is closed`);\n }\n }\n}\n","/**\n * MemoryRegistry — the single entry point for accessing memory backends.\n *\n * Every concept-space (experience, outcomes, beliefs, …) registers a\n * backend; callers reach it via `registry.get('experience')` or, more\n * commonly, the typed accessors that wrap the registry.\n *\n * Sharing a SQLite connection across backends keeps WAL-mode behavior\n * coherent — one writer thread, many tables.\n *\n * @module nexus-memory/registry\n */\n\nimport Database, { type Database as DatabaseType } from 'better-sqlite3';\nimport type { z } from 'zod';\nimport { InMemoryBackend } from './backends/memory.js';\nimport { SqliteBackend } from './backends/sqlite.js';\nimport type { IMemoryBackend } from './types.js';\n\nexport interface MemoryRegistryOptions {\n /**\n * SQLite file path. Use `':memory:'` for tests. When omitted, the\n * registry creates `InMemoryBackend` instances and never touches disk\n * — the standard test-isolation pattern (Phase 2 acceptance criterion).\n */\n readonly dbPath?: string;\n}\n\nexport interface RegisterBackendOptions<TValue> {\n /** Stable domain identifier. Becomes the SQLite table name. */\n readonly domain: string;\n /** Optional Zod schema for cold-archive validation. */\n readonly schema?: z.ZodType<TValue>;\n}\n\n/**\n * The registry. One per `dbPath` (or one in-memory registry per test).\n * `MemoryRegistry.get(domain)` is `O(1)` after registration.\n */\nexport class MemoryRegistry {\n private readonly backends = new Map<string, IMemoryBackend<unknown, unknown>>();\n private readonly db?: DatabaseType;\n private closed = false;\n\n constructor(options: MemoryRegistryOptions = {}) {\n if (options.dbPath !== undefined) {\n const db = new Database(options.dbPath);\n (db as unknown as { pragma(s: string): void }).pragma('journal_mode = WAL');\n this.db = db;\n }\n }\n\n /**\n * Register a backend for `domain`. Throws on duplicate domain.\n *\n * When the registry has a `dbPath`, the new backend is SQLite-backed\n * and shares the registry's connection. Otherwise, an `InMemoryBackend`\n * is created (used for tests).\n */\n register<TKey, TValue>(options: RegisterBackendOptions<TValue>): IMemoryBackend<TKey, TValue> {\n this.assertOpen();\n if (this.backends.has(options.domain)) {\n throw new Error(`nexus-memory: domain \"${options.domain}\" already registered`);\n }\n const backend: IMemoryBackend<TKey, TValue> =\n this.db !== undefined\n ? new SqliteBackend<TKey, TValue>({\n domain: options.domain,\n dbPath: '<shared>', // unused when db is supplied\n db: this.db,\n ...(options.schema !== undefined && { schema: options.schema }),\n })\n : new InMemoryBackend<TKey, TValue>({\n domain: options.domain,\n ...(options.schema !== undefined && { schema: options.schema }),\n });\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- TypeScript narrows the union type here, but the Map needs the lifted IMemoryBackend<unknown, unknown>; the assertion documents the variance and survives future contract changes.\n this.backends.set(options.domain, backend as IMemoryBackend<unknown, unknown>);\n return backend;\n }\n\n /**\n * Attach an externally-managed {@link IMemoryBackend}. Use this when the\n * backend owns its own storage (e.g., a pre-existing SQLite file under\n * `~/.nexus-agents/memory/agentic.db`) and you want it discoverable\n * through the registry without changing its persistence.\n *\n * Phase 5–7 of the memory-unification epic use this to bring the\n * tool-memory backends (`agentic`, `adaptive`, `typed`, `belief`),\n * OutcomeStore, SICA, skills, etc. under a unified observability\n * contract without rewriting their internals. Each attached backend\n * still owns its own `.db` (or JSONL, etc.) until a follow-up migration\n * folds the storage in fully.\n */\n attach<TKey, TValue>(\n domain: string,\n backend: IMemoryBackend<TKey, TValue>\n ): IMemoryBackend<TKey, TValue> {\n this.assertOpen();\n if (this.backends.has(domain)) {\n throw new Error(`nexus-memory: domain \"${domain}\" already registered`);\n }\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- See `register`.\n this.backends.set(domain, backend as IMemoryBackend<unknown, unknown>);\n return backend;\n }\n\n /**\n * Get a previously-registered backend. Returns `undefined` if the\n * domain isn't registered — callers should treat that as \"not yet\n * migrated to the unified contract.\"\n */\n get<TKey, TValue>(domain: string): IMemoryBackend<TKey, TValue> | undefined {\n this.assertOpen();\n const backend = this.backends.get(domain);\n return backend as IMemoryBackend<TKey, TValue> | undefined;\n }\n\n /** List all registered domains. Useful for `memory_stats`-style readers. */\n domains(): readonly string[] {\n return [...this.backends.keys()];\n }\n\n /**\n * Close every registered backend and the shared SQLite handle. After\n * `close()` the registry rejects all further operations.\n */\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n for (const backend of this.backends.values()) {\n await backend.close();\n }\n this.backends.clear();\n if (this.db !== undefined) this.db.close();\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error('nexus-memory: registry is closed');\n }\n }\n}\n\n// ============================================================================\n// Singleton accessor\n// ============================================================================\n\nlet sharedRegistry: MemoryRegistry | null = null;\n\n/**\n * Get the process-wide shared registry. Initializes on first call with\n * `dbPath` from `NEXUS_DATA_DIR` (defaults to `~/.nexus-agents/memory/memory.db`)\n * unless `setMemoryRegistry` was called first.\n *\n * Test code should call `setMemoryRegistry(createInMemoryMemoryRegistry())`\n * in `beforeEach` — this matches the existing `setOutcomeStore` pattern.\n */\nexport function getMemoryRegistry(): MemoryRegistry {\n if (sharedRegistry === null) {\n // Default path resolution happens here, NOT at module load — so tests\n // that call `setMemoryRegistry` before any `getMemoryRegistry` see\n // their in-memory instance, not a side-effectful production path.\n const dbPath = resolveDefaultDbPath();\n sharedRegistry = new MemoryRegistry({ dbPath });\n }\n return sharedRegistry;\n}\n\n/**\n * Inject a registry. Used by tests to swap in `InMemoryBackend`-backed\n * registries. After test, call again with `null` to reset, or call\n * `closeMemoryRegistry()` to dispose.\n */\nexport function setMemoryRegistry(registry: MemoryRegistry | null): void {\n sharedRegistry = registry;\n}\n\n/** Close + null out the shared registry. Idempotent. */\nexport async function closeMemoryRegistry(): Promise<void> {\n if (sharedRegistry !== null) {\n await sharedRegistry.close();\n sharedRegistry = null;\n }\n}\n\nfunction resolveDefaultDbPath(): string {\n // Match `nexus-agents`'s `nexusDataPath` convention without importing it\n // (keep nexus-memory free of inter-package deps for nexus-eval-* reuse).\n const root = process.env['NEXUS_DATA_DIR'] ?? `${process.env['HOME'] ?? '/tmp'}/.nexus-agents`;\n return `${root}/memory/memory.db`;\n}\n","/**\n * Test factories. Production code uses {@link getMemoryRegistry} from\n * `./registry.js`; tests use these helpers to avoid touching disk.\n *\n * @module nexus-memory/factory\n */\n\nimport { MemoryRegistry } from './registry.js';\n\n/**\n * Create a registry that lives entirely in memory. Every `register()`\n * call returns an {@link InMemoryBackend}; nothing is persisted.\n *\n * Use this in `beforeEach`:\n *\n * ```ts\n * beforeEach(() => {\n * setMemoryRegistry(createInMemoryMemoryRegistry());\n * });\n * afterEach(async () => {\n * await closeMemoryRegistry();\n * });\n * ```\n */\nexport function createInMemoryMemoryRegistry(): MemoryRegistry {\n return new MemoryRegistry({\n /* no dbPath → InMemoryBackend per domain */\n });\n}\n\n/**\n * Create a SQLite-backed registry rooted at `dbPath`. Pass `':memory:'`\n * for tests that need to exercise the SQLite code path (e.g.,\n * migration tests, parity tests).\n */\nexport function createSqliteMemoryRegistry(dbPath: string): MemoryRegistry {\n return new MemoryRegistry({ dbPath });\n}\n","/**\n * One-shot importer scaffold. Each Phase 4+ migration registers its own\n * importer here; the registry runs them on first launch (after a marker\n * file check) and renames source files to `.bak.<timestamp>` once\n * complete.\n *\n * This file ships the skeleton + the marker-file logic; concrete\n * importers (MobiMem JSON, OutcomeStore JSONL, agentic.db, etc.) plug in\n * during their respective migration phases.\n *\n * @module nexus-memory/importer\n */\n\nimport { existsSync, mkdirSync, renameSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { MemoryRegistry } from './registry.js';\n\nexport interface ImporterRun {\n readonly domain: string;\n readonly rowsImported: number;\n readonly sourcePathBackup: string | null;\n}\n\nexport interface Importer {\n /** Stable identifier — used in the marker filename to track completion. */\n readonly id: string;\n /** Logical domain this importer targets in the registry. */\n readonly domain: string;\n /**\n * Run the import. Implementations: (1) check if source data exists,\n * (2) parse + validate it, (3) write rows into the registry's backend,\n * (4) rename source to `.bak.<timestamp>` and return the backup path.\n * Idempotent — if marker file says we already ran, the registry skips it.\n */\n run(registry: MemoryRegistry): Promise<ImporterRun>;\n}\n\nconst importers = new Map<string, Importer>();\n\n/** Register an importer. Phase 4+ migrations call this at module load. */\nexport function registerImporter(importer: Importer): void {\n if (importers.has(importer.id)) {\n throw new Error(`nexus-memory: importer \"${importer.id}\" already registered`);\n }\n importers.set(importer.id, importer);\n}\n\n/** For tests: clear all registered importers. */\nexport function resetImporters(): void {\n importers.clear();\n}\n\n/** Snapshot of registered importer IDs. */\nexport function listImporters(): readonly string[] {\n return [...importers.keys()];\n}\n\nexport interface RunImportersOptions {\n /**\n * Directory holding `.imported-{id}` marker files. Defaults to the\n * registry's data dir; tests should override.\n */\n readonly markerDir: string;\n /** Skip the marker check (forces re-run). Tests only. */\n readonly force?: boolean;\n}\n\n/**\n * Run every registered importer that hasn't yet completed (per marker\n * file). Returns the list of runs that actually executed.\n *\n * Failures are NOT fatal — a single importer's exception is logged via\n * the returned `errors` array; other importers still get a chance to run.\n */\nexport async function runImporters(\n registry: MemoryRegistry,\n options: RunImportersOptions\n): Promise<{ runs: readonly ImporterRun[]; errors: readonly { id: string; error: Error }[] }> {\n mkdirSync(options.markerDir, { recursive: true });\n const runs: ImporterRun[] = [];\n const errors: { id: string; error: Error }[] = [];\n for (const importer of importers.values()) {\n const marker = join(options.markerDir, `.imported-${importer.id}`);\n if (options.force !== true && existsSync(marker)) continue;\n try {\n const run = await importer.run(registry);\n writeMarker(marker, run);\n runs.push(run);\n } catch (err) {\n errors.push({ id: importer.id, error: err instanceof Error ? err : new Error(String(err)) });\n }\n }\n return { runs, errors };\n}\n\nfunction writeMarker(path: string, run: ImporterRun): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(\n path,\n JSON.stringify({ ...run, completedAt: new Date().toISOString() }, null, 2),\n 'utf-8'\n );\n}\n\n/**\n * Rename a source file to `.bak.<unix-timestamp>`. Used by concrete\n * importers after a successful migration. Returns the backup path, or\n * `null` when the source doesn't exist.\n */\nexport function backupSourceFile(sourcePath: string): string | null {\n if (!existsSync(sourcePath)) return null;\n const backup = `${sourcePath}.bak.${String(Date.now())}`;\n renameSync(sourcePath, backup);\n return backup;\n}\n"],"mappings":"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","names":["Database"]}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CliCircuitBreakerIntegration,
|
|
3
|
-
createCliCircuitBreakerIntegration
|
|
4
|
-
} from "./chunk-FVSZLVMR.js";
|
|
5
|
-
import "./chunk-F74ZGHAP.js";
|
|
6
|
-
import "./chunk-DBDWMHUL.js";
|
|
7
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
8
|
-
import "./chunk-ZPWHCABL.js";
|
|
9
|
-
export {
|
|
10
|
-
CliCircuitBreakerIntegration,
|
|
11
|
-
createCliCircuitBreakerIntegration
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=cli-circuit-breaker-VXBDCAD7.js.map
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CONSENSUS_VOTE_OUTPUT_SCHEMA,
|
|
3
|
-
ConsensusVoteInputSchema,
|
|
4
|
-
VotingStrategySchema,
|
|
5
|
-
createPolicyFailedResult,
|
|
6
|
-
executeVoting,
|
|
7
|
-
registerConsensusVoteTool,
|
|
8
|
-
resetCorrelationTracker,
|
|
9
|
-
runConsensusForGoal
|
|
10
|
-
} from "./chunk-DLUFDKPA.js";
|
|
11
|
-
import "./chunk-COJOUIO2.js";
|
|
12
|
-
import "./chunk-6UCWR3DS.js";
|
|
13
|
-
import "./chunk-33MFMXBQ.js";
|
|
14
|
-
import "./chunk-FPMQ2JAK.js";
|
|
15
|
-
import "./chunk-6T3EPABN.js";
|
|
16
|
-
import "./chunk-PQHVC4BD.js";
|
|
17
|
-
import "./chunk-WYJJUF6N.js";
|
|
18
|
-
import "./chunk-3EYXPV5F.js";
|
|
19
|
-
import "./chunk-ZMDOGN33.js";
|
|
20
|
-
import "./chunk-WFKVUZ3O.js";
|
|
21
|
-
import "./chunk-F74ZGHAP.js";
|
|
22
|
-
import "./chunk-PFBV5FCT.js";
|
|
23
|
-
import "./chunk-ORQAFTAZ.js";
|
|
24
|
-
import "./chunk-DBDWMHUL.js";
|
|
25
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
26
|
-
import "./chunk-ZPWHCABL.js";
|
|
27
|
-
export {
|
|
28
|
-
CONSENSUS_VOTE_OUTPUT_SCHEMA,
|
|
29
|
-
ConsensusVoteInputSchema,
|
|
30
|
-
VotingStrategySchema,
|
|
31
|
-
createPolicyFailedResult,
|
|
32
|
-
executeVoting,
|
|
33
|
-
registerConsensusVoteTool,
|
|
34
|
-
resetCorrelationTracker,
|
|
35
|
-
runConsensusForGoal
|
|
36
|
-
};
|
|
37
|
-
//# sourceMappingURL=consensus-vote-R6X5IL57.js.map
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
formatDeepDiagnostics,
|
|
3
|
-
runDeepDiagnostics
|
|
4
|
-
} from "./chunk-6LMZ7HFU.js";
|
|
5
|
-
import "./chunk-DBDWMHUL.js";
|
|
6
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
7
|
-
import "./chunk-ZPWHCABL.js";
|
|
8
|
-
export {
|
|
9
|
-
formatDeepDiagnostics,
|
|
10
|
-
runDeepDiagnostics
|
|
11
|
-
};
|
|
12
|
-
//# sourceMappingURL=doctor-deep-CZXN4YD6.js.map
|
package/dist/factory-WR62MEIJ.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createGitHubProvider,
|
|
3
|
-
createScmProvider
|
|
4
|
-
} from "./chunk-CLRSNWRQ.js";
|
|
5
|
-
import "./chunk-FSFF7EFR.js";
|
|
6
|
-
import "./chunk-MY52DFXC.js";
|
|
7
|
-
import "./chunk-DBDWMHUL.js";
|
|
8
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
9
|
-
import "./chunk-ZPWHCABL.js";
|
|
10
|
-
export {
|
|
11
|
-
createGitHubProvider,
|
|
12
|
-
createScmProvider
|
|
13
|
-
};
|
|
14
|
-
//# sourceMappingURL=factory-WR62MEIJ.js.map
|
package/dist/factory-ZBQGA373.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createAllAdapters,
|
|
3
|
-
createCliAdapter,
|
|
4
|
-
getAvailableClis,
|
|
5
|
-
isCliAvailable
|
|
6
|
-
} from "./chunk-3EYXPV5F.js";
|
|
7
|
-
import "./chunk-ZMDOGN33.js";
|
|
8
|
-
import "./chunk-WFKVUZ3O.js";
|
|
9
|
-
import "./chunk-F74ZGHAP.js";
|
|
10
|
-
import "./chunk-PFBV5FCT.js";
|
|
11
|
-
import "./chunk-ORQAFTAZ.js";
|
|
12
|
-
import "./chunk-DBDWMHUL.js";
|
|
13
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
14
|
-
import "./chunk-ZPWHCABL.js";
|
|
15
|
-
export {
|
|
16
|
-
createAllAdapters,
|
|
17
|
-
createCliAdapter,
|
|
18
|
-
getAvailableClis,
|
|
19
|
-
isCliAvailable
|
|
20
|
-
};
|
|
21
|
-
//# sourceMappingURL=factory-ZBQGA373.js.map
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
IssueTriage,
|
|
3
|
-
createIssueTriage,
|
|
4
|
-
formatTriageComment
|
|
5
|
-
} from "./chunk-FUJ3XR7T.js";
|
|
6
|
-
import "./chunk-FSFF7EFR.js";
|
|
7
|
-
import "./chunk-EHLJLIHS.js";
|
|
8
|
-
import "./chunk-DBDWMHUL.js";
|
|
9
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
10
|
-
import "./chunk-ZPWHCABL.js";
|
|
11
|
-
export {
|
|
12
|
-
IssueTriage,
|
|
13
|
-
createIssueTriage,
|
|
14
|
-
formatTriageComment
|
|
15
|
-
};
|
|
16
|
-
//# sourceMappingURL=issue-triage-NJB6SL4S.js.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AttributedInsightSchema,
|
|
3
|
-
synthesizeResearch
|
|
4
|
-
} from "./chunk-UDB5NHJI.js";
|
|
5
|
-
import "./chunk-B26FGLIJ.js";
|
|
6
|
-
import "./chunk-NUBSJGQZ.js";
|
|
7
|
-
import "./chunk-DBDWMHUL.js";
|
|
8
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
9
|
-
import "./chunk-ZPWHCABL.js";
|
|
10
|
-
export {
|
|
11
|
-
AttributedInsightSchema,
|
|
12
|
-
synthesizeResearch
|
|
13
|
-
};
|
|
14
|
-
//# sourceMappingURL=research-helpers-synthesize-5TLNHT3I.js.map
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ToolMemoryManager,
|
|
3
|
-
getToolMemory,
|
|
4
|
-
reinitializeMemoryBackends,
|
|
5
|
-
shutdownToolMemory
|
|
6
|
-
} from "./chunk-33MFMXBQ.js";
|
|
7
|
-
import "./chunk-FPMQ2JAK.js";
|
|
8
|
-
import "./chunk-6T3EPABN.js";
|
|
9
|
-
import "./chunk-PQHVC4BD.js";
|
|
10
|
-
import "./chunk-ORQAFTAZ.js";
|
|
11
|
-
import "./chunk-DBDWMHUL.js";
|
|
12
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
13
|
-
import "./chunk-ZPWHCABL.js";
|
|
14
|
-
export {
|
|
15
|
-
ToolMemoryManager,
|
|
16
|
-
getToolMemory,
|
|
17
|
-
reinitializeMemoryBackends,
|
|
18
|
-
shutdownToolMemory
|
|
19
|
-
};
|
|
20
|
-
//# sourceMappingURL=tool-memory-TSYJXGOV.js.map
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
UnifiedAdapterRegistry,
|
|
3
|
-
createUnifiedRegistry,
|
|
4
|
-
getGlobalRegistry,
|
|
5
|
-
resetGlobalRegistry,
|
|
6
|
-
withDefaultOnRetirement
|
|
7
|
-
} from "./chunk-WYJJUF6N.js";
|
|
8
|
-
import "./chunk-3EYXPV5F.js";
|
|
9
|
-
import "./chunk-ZMDOGN33.js";
|
|
10
|
-
import "./chunk-WFKVUZ3O.js";
|
|
11
|
-
import "./chunk-F74ZGHAP.js";
|
|
12
|
-
import "./chunk-PFBV5FCT.js";
|
|
13
|
-
import "./chunk-ORQAFTAZ.js";
|
|
14
|
-
import "./chunk-DBDWMHUL.js";
|
|
15
|
-
import "./chunk-GZ4NF4ZW.js";
|
|
16
|
-
import "./chunk-ZPWHCABL.js";
|
|
17
|
-
export {
|
|
18
|
-
UnifiedAdapterRegistry,
|
|
19
|
-
createUnifiedRegistry,
|
|
20
|
-
getGlobalRegistry,
|
|
21
|
-
resetGlobalRegistry,
|
|
22
|
-
withDefaultOnRetirement
|
|
23
|
-
};
|
|
24
|
-
//# sourceMappingURL=unified-registry-IMAL3SY6.js.map
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{unified-registry-IMAL3SY6.js.map → tool-memory-registry-adapters-Y4EGADHN.js.map}
RENAMED
|
File without changes
|
|
File without changes
|