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,14 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
discoverModels,
|
|
3
3
|
readOpencodeGateway
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-WOE5J5M6.js";
|
|
5
|
+
import "./chunk-257QMFTM.js";
|
|
6
|
+
import "./chunk-VN3CKPEF.js";
|
|
7
|
+
import "./chunk-ZII5MDUO.js";
|
|
8
8
|
import {
|
|
9
9
|
createLogger
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-OCJEYHUQ.js";
|
|
11
|
+
import "./chunk-5SXGPX34.js";
|
|
12
|
+
import "./chunk-L4QFWOOQ.js";
|
|
12
13
|
import "./chunk-ZPWHCABL.js";
|
|
13
14
|
|
|
14
15
|
// src/cli/init-opencode.ts
|
|
@@ -175,4 +176,4 @@ export {
|
|
|
175
176
|
runInitOpencode,
|
|
176
177
|
runOpencodeValidate
|
|
177
178
|
};
|
|
178
|
-
//# sourceMappingURL=init-opencode-
|
|
179
|
+
//# sourceMappingURL=init-opencode-C7U6ZQK3.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/init-opencode.ts"],"sourcesContent":["/**\n * `nexus-agents init --opencode <path>` setup helper (#2504, child 4 of #2500).\n *\n * Injects the nexus-agents MCP block + recommended environment into an\n * existing `opencode.json` without overwriting other operator-set keys.\n * Pairs with the existing `init --portable --mcp-config` (which targets\n * Claude Code's `.mcp.json`). Different harness, same merge-not-overwrite\n * pattern.\n *\n * Behaviour:\n * - File exists → merge `mcp.nexus-agents` into the existing JSON.\n * Preserve every other key the operator has set (provider config,\n * model lists, theme, …). Idempotent: re-running produces the same\n * final file.\n * - File missing → write a minimal template with the nexus-agents MCP\n * block + a stubbed `providers.openai-compat` shell the operator\n * fills in (placeholder baseURL + `{env:WORKSPACE_PROXY_KEY}`).\n * - `--dry-run` → print the diff (proposed vs existing) without writing.\n * - `--validate` → after merge (or alongside dry-run), probe\n * `providers.openai-compat.options.baseURL/v1/models` with the\n * resolved apiKey, exit non-zero if unreachable.\n *\n * @module cli/init-opencode\n */\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { createLogger } from '../core/index.js';\nimport { readOpencodeGateway } from '../config/opencode-bridge.js';\nimport { discoverModels } from '../adapters/openai-compat-adapter.js';\n\nconst logger = createLogger({ component: 'init-opencode' });\n\nexport interface InitOpencodeOptions {\n /** Absolute or relative path to opencode.json. */\n readonly path: string;\n /** Path to the nexus-agents CLI binary that the MCP block will spawn. */\n readonly cliPath: string;\n /** Sandbox flavor written to NEXUS_SANDBOX in the MCP environment. */\n readonly sandboxFlavor?: string;\n /** Print the diff without writing. */\n readonly dryRun?: boolean;\n}\n\nexport interface InitOpencodeResult {\n readonly path: string;\n readonly action: 'created' | 'updated' | 'unchanged' | 'dry-run';\n readonly diff: string;\n}\n\ninterface OpencodeMcpBlock {\n type: 'local';\n command: string[];\n enabled: boolean;\n environment: Record<string, string>;\n}\n\ninterface OpencodeFile {\n $schema?: string;\n providers?: Record<string, unknown>;\n mcp?: Record<string, unknown>;\n permission?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Conservative default OpenCode `permission` block (#2658). OpenCode\n * evaluates a glob map with **last-matching-rule-winning**, so the broad\n * `\"*\"` rule is listed first and the hard `deny` patterns last.\n *\n * - `edit` — everything `ask`s; secrets, keys, and `.git/` are hard-denied\n * regardless of operator confirmation. The deny patterns come after\n * `\"*\"` so last-match-wins makes them stick.\n * - `bash` — `ask` unconditionally. Shell is the highest-risk surface.\n * - `skill` — `allow`. Skills are trusted, in-repo, CI-validated content.\n *\n * Emitted only when the operator has not already set their own\n * `permission` block — never overwrites operator config.\n */\nexport function buildDefaultPermissionBlock(): Record<string, unknown> {\n return {\n edit: {\n '*': 'ask',\n '**/.env': 'deny',\n '**/.env.*': 'deny',\n '**/*.pem': 'deny',\n '**/*.key': 'deny',\n '**/id_rsa*': 'deny',\n '**/secrets/**': 'deny',\n '**/.git/**': 'deny',\n },\n bash: 'ask',\n skill: 'allow',\n };\n}\n\n/**\n * Build the canonical nexus-agents MCP block. Mirrors what\n * `Dockerfile.sandbox` writes today plus the env vars from #2501 + #2503.\n */\nexport function buildNexusMcpBlock(opts: {\n readonly cliPath: string;\n readonly sandboxFlavor?: string;\n readonly opencodeConfigPath: string;\n}): OpencodeMcpBlock {\n const env: Record<string, string> = {\n NEXUS_DATA_DIR: '{env:NEXUS_DATA_DIR}',\n NEXUS_OPENCODE_CONFIG: opts.opencodeConfigPath,\n };\n if (opts.sandboxFlavor !== undefined && opts.sandboxFlavor !== '') {\n env['NEXUS_SANDBOX'] = opts.sandboxFlavor;\n }\n return {\n type: 'local',\n command: ['node', opts.cliPath, '--mode=server'],\n enabled: true,\n environment: env,\n };\n}\n\n/**\n * Execute the merge. Pure with respect to `opts.dryRun: true` — no fs\n * writes. Returns the final-or-proposed JSON + a diff string suitable\n * for printing.\n */\nexport function runInitOpencode(opts: InitOpencodeOptions): InitOpencodeResult {\n const existing = readExisting(opts.path);\n const merged = mergeNexusBlock(existing, opts);\n const before = existing === null ? '' : `${JSON.stringify(existing, null, 2)}\\n`;\n const after = `${JSON.stringify(merged, null, 2)}\\n`;\n const diff = simpleDiff(before, after);\n\n if (opts.dryRun === true) {\n return { path: opts.path, action: 'dry-run', diff };\n }\n\n if (existing !== null && before === after) {\n return { path: opts.path, action: 'unchanged', diff };\n }\n\n writeFileSync(opts.path, after, 'utf8');\n return { path: opts.path, action: existing === null ? 'created' : 'updated', diff };\n}\n\nfunction readExisting(path: string): OpencodeFile | null {\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, 'utf8');\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('opencode.json root must be an object');\n }\n return parsed as OpencodeFile;\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to parse opencode.json at ${path}: ${msg}`);\n }\n}\n\nfunction mergeNexusBlock(existing: OpencodeFile | null, opts: InitOpencodeOptions): OpencodeFile {\n const block = buildNexusMcpBlock({\n cliPath: opts.cliPath,\n ...(opts.sandboxFlavor !== undefined && { sandboxFlavor: opts.sandboxFlavor }),\n opencodeConfigPath: opts.path,\n });\n\n if (existing === null) {\n return {\n $schema: 'https://opencode.ai/config.json',\n providers: { 'openai-compat': stubOpenaiCompatProvider() },\n permission: buildDefaultPermissionBlock(),\n mcp: { 'nexus-agents': block },\n };\n }\n\n // Idempotent merge: preserve user-customised fields if they exist on the\n // current MCP block (e.g. `enabled: false`). Update anything else.\n const existingMcp: Record<string, unknown> = existing.mcp ?? {};\n const rawNexus = existingMcp['nexus-agents'];\n const existingNexus: Partial<OpencodeMcpBlock> =\n typeof rawNexus === 'object' && rawNexus !== null ? rawNexus : {};\n const mergedBlock: OpencodeMcpBlock = {\n type: 'local',\n command: block.command,\n enabled: existingNexus.enabled ?? block.enabled,\n environment: { ...block.environment, ...(existingNexus.environment ?? {}) },\n };\n\n // Add the default permission block only when the operator has not set\n // their own — never overwrite an existing `permission` key.\n const permission = existing.permission ?? buildDefaultPermissionBlock();\n\n return {\n ...existing,\n permission,\n mcp: { ...existingMcp, 'nexus-agents': mergedBlock },\n };\n}\n\n/**\n * Stub for `providers.openai-compat`. Operators replace the placeholder\n * baseURL + key with their workspace-proxy values. Empty by design — we\n * never overwrite an existing provider block (see `mergeNexusBlock`).\n */\nfunction stubOpenaiCompatProvider(): Record<string, unknown> {\n return {\n npm: '@ai-sdk/openai-compatible',\n options: {\n baseURL: '<replace with workspace proxy URL>',\n apiKey: '{env:WORKSPACE_PROXY_KEY}',\n },\n };\n}\n\n/**\n * Cheap line-based diff. Three-line context, +/- prefixes. Good enough\n * for an operator preview; not a unified-diff replacement.\n */\nfunction simpleDiff(before: string, after: string): string {\n if (before === after) return '(no changes)';\n const beforeLines = before.split('\\n');\n const afterLines = after.split('\\n');\n const out: string[] = [];\n const max = Math.max(beforeLines.length, afterLines.length);\n for (let i = 0; i < max; i += 1) {\n const b = beforeLines[i];\n const a = afterLines[i];\n if (b === a) {\n out.push(` ${b ?? ''}`);\n } else {\n if (b !== undefined) out.push(`- ${b}`);\n if (a !== undefined) out.push(`+ ${a}`);\n }\n }\n return out.join('\\n');\n}\n\nexport function ensureOpencodeDirExists(path: string): void {\n const dir = dirname(path);\n if (!existsSync(dir)) {\n throw new Error(\n `Parent directory does not exist: ${dir}. Create it first or pass a path under an existing dir.`\n );\n }\n logger.debug('opencode.json target directory exists', { dir });\n}\n\n/**\n * --validate flow for `init --opencode` (follow-up to #2504).\n *\n * After the merge step writes the file, optionally probe the gateway it\n * points at. Reuses the same opencode-bridge loader (#2503) that the\n * runtime uses, so what we validate is exactly what the server will see\n * at boot.\n *\n * Returns:\n * - `{ ok: true, models }` when the gateway is reachable and returns ≥1 model\n * - `{ ok: false, reason }` for every failure path (config missing,\n * probe failed, zero models)\n *\n * Caller (cli-commands-handlers) maps to exit codes + stderr / stdout.\n * The API key never reaches the returned object — only model IDs +\n * baseURL appear in the success payload.\n */\nexport interface OpencodeValidateResult {\n readonly ok: boolean;\n readonly baseURL?: string;\n readonly models?: readonly string[];\n readonly reason?: string;\n}\n\nexport async function runOpencodeValidate(opencodePath: string): Promise<OpencodeValidateResult> {\n const config = readOpencodeGateway(opencodePath);\n if (config === null) {\n return {\n ok: false,\n reason:\n 'opencode.json does not resolve a usable gateway. Check that providers.openai-compat.options.{baseURL, apiKey} are set and that any {env:VAR} interpolation references are exported.',\n };\n }\n const result = await discoverModels({ baseUrl: config.baseURL, apiKey: config.apiKey });\n if (!result.ok) {\n return { ok: false, baseURL: config.baseURL, reason: result.error.message };\n }\n if (result.value.length === 0) {\n return {\n ok: false,\n baseURL: config.baseURL,\n reason: 'gateway returned 0 models. Check upstream provider quotas / list filters.',\n };\n }\n return {\n ok: true,\n baseURL: config.baseURL,\n models: result.value.map((m) => m.id),\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/init-opencode.ts"],"sourcesContent":["/**\n * `nexus-agents init --opencode <path>` setup helper (#2504, child 4 of #2500).\n *\n * Injects the nexus-agents MCP block + recommended environment into an\n * existing `opencode.json` without overwriting other operator-set keys.\n * Pairs with the existing `init --portable --mcp-config` (which targets\n * Claude Code's `.mcp.json`). Different harness, same merge-not-overwrite\n * pattern.\n *\n * Behaviour:\n * - File exists → merge `mcp.nexus-agents` into the existing JSON.\n * Preserve every other key the operator has set (provider config,\n * model lists, theme, …). Idempotent: re-running produces the same\n * final file.\n * - File missing → write a minimal template with the nexus-agents MCP\n * block + a stubbed `providers.openai-compat` shell the operator\n * fills in (placeholder baseURL + `{env:WORKSPACE_PROXY_KEY}`).\n * - `--dry-run` → print the diff (proposed vs existing) without writing.\n * - `--validate` → after merge (or alongside dry-run), probe\n * `providers.openai-compat.options.baseURL/v1/models` with the\n * resolved apiKey, exit non-zero if unreachable.\n *\n * @module cli/init-opencode\n */\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { createLogger } from '../core/index.js';\nimport { readOpencodeGateway } from '../config/opencode-bridge.js';\nimport { discoverModels } from '../adapters/openai-compat-adapter.js';\n\nconst logger = createLogger({ component: 'init-opencode' });\n\nexport interface InitOpencodeOptions {\n /** Absolute or relative path to opencode.json. */\n readonly path: string;\n /** Path to the nexus-agents CLI binary that the MCP block will spawn. */\n readonly cliPath: string;\n /** Sandbox flavor written to NEXUS_SANDBOX in the MCP environment. */\n readonly sandboxFlavor?: string;\n /** Print the diff without writing. */\n readonly dryRun?: boolean;\n}\n\nexport interface InitOpencodeResult {\n readonly path: string;\n readonly action: 'created' | 'updated' | 'unchanged' | 'dry-run';\n readonly diff: string;\n}\n\ninterface OpencodeMcpBlock {\n type: 'local';\n command: string[];\n enabled: boolean;\n environment: Record<string, string>;\n}\n\ninterface OpencodeFile {\n $schema?: string;\n providers?: Record<string, unknown>;\n mcp?: Record<string, unknown>;\n permission?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Conservative default OpenCode `permission` block (#2658). OpenCode\n * evaluates a glob map with **last-matching-rule-winning**, so the broad\n * `\"*\"` rule is listed first and the hard `deny` patterns last.\n *\n * - `edit` — everything `ask`s; secrets, keys, and `.git/` are hard-denied\n * regardless of operator confirmation. The deny patterns come after\n * `\"*\"` so last-match-wins makes them stick.\n * - `bash` — `ask` unconditionally. Shell is the highest-risk surface.\n * - `skill` — `allow`. Skills are trusted, in-repo, CI-validated content.\n *\n * Emitted only when the operator has not already set their own\n * `permission` block — never overwrites operator config.\n */\nexport function buildDefaultPermissionBlock(): Record<string, unknown> {\n return {\n edit: {\n '*': 'ask',\n '**/.env': 'deny',\n '**/.env.*': 'deny',\n '**/*.pem': 'deny',\n '**/*.key': 'deny',\n '**/id_rsa*': 'deny',\n '**/secrets/**': 'deny',\n '**/.git/**': 'deny',\n },\n bash: 'ask',\n skill: 'allow',\n };\n}\n\n/**\n * Build the canonical nexus-agents MCP block. Mirrors what\n * `Dockerfile.sandbox` writes today plus the env vars from #2501 + #2503.\n */\nexport function buildNexusMcpBlock(opts: {\n readonly cliPath: string;\n readonly sandboxFlavor?: string;\n readonly opencodeConfigPath: string;\n}): OpencodeMcpBlock {\n const env: Record<string, string> = {\n NEXUS_DATA_DIR: '{env:NEXUS_DATA_DIR}',\n NEXUS_OPENCODE_CONFIG: opts.opencodeConfigPath,\n };\n if (opts.sandboxFlavor !== undefined && opts.sandboxFlavor !== '') {\n env['NEXUS_SANDBOX'] = opts.sandboxFlavor;\n }\n return {\n type: 'local',\n command: ['node', opts.cliPath, '--mode=server'],\n enabled: true,\n environment: env,\n };\n}\n\n/**\n * Execute the merge. Pure with respect to `opts.dryRun: true` — no fs\n * writes. Returns the final-or-proposed JSON + a diff string suitable\n * for printing.\n */\nexport function runInitOpencode(opts: InitOpencodeOptions): InitOpencodeResult {\n const existing = readExisting(opts.path);\n const merged = mergeNexusBlock(existing, opts);\n const before = existing === null ? '' : `${JSON.stringify(existing, null, 2)}\\n`;\n const after = `${JSON.stringify(merged, null, 2)}\\n`;\n const diff = simpleDiff(before, after);\n\n if (opts.dryRun === true) {\n return { path: opts.path, action: 'dry-run', diff };\n }\n\n if (existing !== null && before === after) {\n return { path: opts.path, action: 'unchanged', diff };\n }\n\n writeFileSync(opts.path, after, 'utf8');\n return { path: opts.path, action: existing === null ? 'created' : 'updated', diff };\n}\n\nfunction readExisting(path: string): OpencodeFile | null {\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, 'utf8');\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('opencode.json root must be an object');\n }\n return parsed as OpencodeFile;\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to parse opencode.json at ${path}: ${msg}`);\n }\n}\n\nfunction mergeNexusBlock(existing: OpencodeFile | null, opts: InitOpencodeOptions): OpencodeFile {\n const block = buildNexusMcpBlock({\n cliPath: opts.cliPath,\n ...(opts.sandboxFlavor !== undefined && { sandboxFlavor: opts.sandboxFlavor }),\n opencodeConfigPath: opts.path,\n });\n\n if (existing === null) {\n return {\n $schema: 'https://opencode.ai/config.json',\n providers: { 'openai-compat': stubOpenaiCompatProvider() },\n permission: buildDefaultPermissionBlock(),\n mcp: { 'nexus-agents': block },\n };\n }\n\n // Idempotent merge: preserve user-customised fields if they exist on the\n // current MCP block (e.g. `enabled: false`). Update anything else.\n const existingMcp: Record<string, unknown> = existing.mcp ?? {};\n const rawNexus = existingMcp['nexus-agents'];\n const existingNexus: Partial<OpencodeMcpBlock> =\n typeof rawNexus === 'object' && rawNexus !== null ? rawNexus : {};\n const mergedBlock: OpencodeMcpBlock = {\n type: 'local',\n command: block.command,\n enabled: existingNexus.enabled ?? block.enabled,\n environment: { ...block.environment, ...(existingNexus.environment ?? {}) },\n };\n\n // Add the default permission block only when the operator has not set\n // their own — never overwrite an existing `permission` key.\n const permission = existing.permission ?? buildDefaultPermissionBlock();\n\n return {\n ...existing,\n permission,\n mcp: { ...existingMcp, 'nexus-agents': mergedBlock },\n };\n}\n\n/**\n * Stub for `providers.openai-compat`. Operators replace the placeholder\n * baseURL + key with their workspace-proxy values. Empty by design — we\n * never overwrite an existing provider block (see `mergeNexusBlock`).\n */\nfunction stubOpenaiCompatProvider(): Record<string, unknown> {\n return {\n npm: '@ai-sdk/openai-compatible',\n options: {\n baseURL: '<replace with workspace proxy URL>',\n apiKey: '{env:WORKSPACE_PROXY_KEY}',\n },\n };\n}\n\n/**\n * Cheap line-based diff. Three-line context, +/- prefixes. Good enough\n * for an operator preview; not a unified-diff replacement.\n */\nfunction simpleDiff(before: string, after: string): string {\n if (before === after) return '(no changes)';\n const beforeLines = before.split('\\n');\n const afterLines = after.split('\\n');\n const out: string[] = [];\n const max = Math.max(beforeLines.length, afterLines.length);\n for (let i = 0; i < max; i += 1) {\n const b = beforeLines[i];\n const a = afterLines[i];\n if (b === a) {\n out.push(` ${b ?? ''}`);\n } else {\n if (b !== undefined) out.push(`- ${b}`);\n if (a !== undefined) out.push(`+ ${a}`);\n }\n }\n return out.join('\\n');\n}\n\nexport function ensureOpencodeDirExists(path: string): void {\n const dir = dirname(path);\n if (!existsSync(dir)) {\n throw new Error(\n `Parent directory does not exist: ${dir}. Create it first or pass a path under an existing dir.`\n );\n }\n logger.debug('opencode.json target directory exists', { dir });\n}\n\n/**\n * --validate flow for `init --opencode` (follow-up to #2504).\n *\n * After the merge step writes the file, optionally probe the gateway it\n * points at. Reuses the same opencode-bridge loader (#2503) that the\n * runtime uses, so what we validate is exactly what the server will see\n * at boot.\n *\n * Returns:\n * - `{ ok: true, models }` when the gateway is reachable and returns ≥1 model\n * - `{ ok: false, reason }` for every failure path (config missing,\n * probe failed, zero models)\n *\n * Caller (cli-commands-handlers) maps to exit codes + stderr / stdout.\n * The API key never reaches the returned object — only model IDs +\n * baseURL appear in the success payload.\n */\nexport interface OpencodeValidateResult {\n readonly ok: boolean;\n readonly baseURL?: string;\n readonly models?: readonly string[];\n readonly reason?: string;\n}\n\nexport async function runOpencodeValidate(opencodePath: string): Promise<OpencodeValidateResult> {\n const config = readOpencodeGateway(opencodePath);\n if (config === null) {\n return {\n ok: false,\n reason:\n 'opencode.json does not resolve a usable gateway. Check that providers.openai-compat.options.{baseURL, apiKey} are set and that any {env:VAR} interpolation references are exported.',\n };\n }\n const result = await discoverModels({ baseUrl: config.baseURL, apiKey: config.apiKey });\n if (!result.ok) {\n return { ok: false, baseURL: config.baseURL, reason: result.error.message };\n }\n if (result.value.length === 0) {\n return {\n ok: false,\n baseURL: config.baseURL,\n reason: 'gateway returned 0 models. Check upstream provider quotas / list filters.',\n };\n }\n return {\n ok: true,\n baseURL: config.baseURL,\n models: result.value.map((m) => m.id),\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IssueTriage,
|
|
3
|
+
createIssueTriage,
|
|
4
|
+
formatTriageComment
|
|
5
|
+
} from "./chunk-3AAJWZCR.js";
|
|
6
|
+
import "./chunk-VVBKPRLI.js";
|
|
7
|
+
import "./chunk-FSUZIIOJ.js";
|
|
8
|
+
import "./chunk-OCJEYHUQ.js";
|
|
9
|
+
import "./chunk-5SXGPX34.js";
|
|
10
|
+
import "./chunk-L4QFWOOQ.js";
|
|
11
|
+
import "./chunk-ZPWHCABL.js";
|
|
12
|
+
export {
|
|
13
|
+
IssueTriage,
|
|
14
|
+
createIssueTriage,
|
|
15
|
+
formatTriageComment
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=issue-triage-7RN74LBU.js.map
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
getPrReviewEvalFile,
|
|
8
8
|
getRulesFile,
|
|
9
9
|
isPersistenceEnabled
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5SXGPX34.js";
|
|
11
|
+
import "./chunk-L4QFWOOQ.js";
|
|
11
12
|
import "./chunk-ZPWHCABL.js";
|
|
12
13
|
export {
|
|
13
14
|
ensureLearningDir,
|
|
@@ -19,4 +20,4 @@ export {
|
|
|
19
20
|
getRulesFile,
|
|
20
21
|
isPersistenceEnabled
|
|
21
22
|
};
|
|
22
|
-
//# sourceMappingURL=learning-persistence-
|
|
23
|
+
//# sourceMappingURL=learning-persistence-EHTHKWR5.js.map
|
|
@@ -17,11 +17,12 @@ import {
|
|
|
17
17
|
parseFindings,
|
|
18
18
|
parseSeverity,
|
|
19
19
|
sumFindings
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-JK4L2TQ6.js";
|
|
21
21
|
import "./chunk-WAYGXUSM.js";
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-FSUZIIOJ.js";
|
|
23
|
+
import "./chunk-OCJEYHUQ.js";
|
|
24
|
+
import "./chunk-5SXGPX34.js";
|
|
25
|
+
import "./chunk-L4QFWOOQ.js";
|
|
25
26
|
import "./chunk-ZPWHCABL.js";
|
|
26
27
|
export {
|
|
27
28
|
assessPRReputation,
|
|
@@ -43,4 +44,4 @@ export {
|
|
|
43
44
|
parseSeverity,
|
|
44
45
|
sumFindings
|
|
45
46
|
};
|
|
46
|
-
//# sourceMappingURL=pr-reviewer-helpers-
|
|
47
|
+
//# sourceMappingURL=pr-reviewer-helpers-D47TVXFX.js.map
|
|
@@ -7,10 +7,11 @@ import {
|
|
|
7
7
|
loadGeneratedRegistryEntries,
|
|
8
8
|
loadUserManifestOverlay,
|
|
9
9
|
reloadDefaultRegistry
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-OCJEYHUQ.js";
|
|
11
|
+
import "./chunk-5SXGPX34.js";
|
|
11
12
|
import {
|
|
12
13
|
nexusDataPath
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-L4QFWOOQ.js";
|
|
14
15
|
import "./chunk-ZPWHCABL.js";
|
|
15
16
|
|
|
16
17
|
// src/cli/registry-command.ts
|
|
@@ -248,4 +249,4 @@ export {
|
|
|
248
249
|
isValidRegistrySubcommand,
|
|
249
250
|
registryCommand
|
|
250
251
|
};
|
|
251
|
-
//# sourceMappingURL=registry-command-
|
|
252
|
+
//# sourceMappingURL=registry-command-PVC47NSQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/registry-command.ts"],"sourcesContent":["/**\n * `nexus-agents registry` CLI subcommands (epic #2174 / issue #2179).\n *\n * Two subcommands:\n *\n * - `doctor` — inspect the ModelRegistry: effective per-source entry counts,\n * the bundled generated registry path/status, the user overlay (reported for\n * inspection), and the unknown-id fallback contextWindow. Surfaces whatever\n * overlay parse rejections occurred at load. Read-only. (#3293 migrated this\n * off the deleted CapabilityDiscovery four-tier chain.)\n *\n * - `refresh` — download a signed `model-registry.generated.json` from a\n * URL, SHA256-verify against a `.sha256` sidecar, write to the user's\n * overlay location. Requires `--source=<url>` today; the GitHub-latest-\n * release automation is #2180's concern.\n *\n * No runtime hot path touches the network — refresh is a one-shot,\n * user-initiated operation.\n *\n * @module cli/registry-command\n */\n\nimport { createHash } from 'node:crypto';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { nexusDataPath } from '../config/nexus-data-dir.js';\nimport { NETWORK_FETCH_TIMEOUT_MS } from '../config/timeouts.js';\n\nimport {\n getDefaultRegistry,\n reloadDefaultRegistry,\n type EntrySource,\n} from '../config/model-registry.js';\nimport { loadGeneratedRegistryEntries } from '../config/models-generated-loader.js';\nimport {\n USER_MANIFEST_ENV_VAR,\n MANIFEST_MAX_BYTES,\n defaultUserManifestPath,\n loadUserManifestOverlay,\n} from '../config/manifest-overlay.js';\n\n// ---------------------------------------------------------------------------\n// Dispatch\n// ---------------------------------------------------------------------------\n\nexport type RegistrySubcommand = 'doctor' | 'refresh';\n\nconst VALID_SUBCOMMANDS: readonly RegistrySubcommand[] = ['doctor', 'refresh'];\n\nexport function isValidRegistrySubcommand(v: string | undefined): v is RegistrySubcommand {\n return v !== undefined && (VALID_SUBCOMMANDS as readonly string[]).includes(v);\n}\n\nexport interface RegistryCommandOptions {\n readonly json?: boolean;\n readonly source?: string;\n readonly dryRun?: boolean;\n readonly overlayPath?: string;\n /** For tests: a fetch function. Defaults to `globalThis.fetch`. */\n readonly fetchImpl?: typeof fetch;\n /** For tests: override the default destination path. */\n readonly destPath?: string;\n}\n\nexport interface RegistryCommandResult {\n readonly text: string;\n readonly exitCode: number;\n}\n\nexport async function registryCommand(\n subcommand: RegistrySubcommand,\n options: RegistryCommandOptions = {}\n): Promise<RegistryCommandResult> {\n if (subcommand === 'doctor') return doctorCommand(options);\n return refreshCommand(options);\n}\n\n// ---------------------------------------------------------------------------\n// doctor\n// ---------------------------------------------------------------------------\n\n/**\n * ContextWindow returned for an id no registry source resolves. This is the\n * old `FAIL_CLOSED_DEFAULT.contextWindow` value (#2177), preserved here after\n * the CapabilityDiscovery four-tier chain was deleted in #3293.\n */\nconst UNKNOWN_MODEL_CONTEXT_WINDOW = 8192;\n\n/** Every registry source, in report order. */\nconst ENTRY_SOURCES: readonly EntrySource[] = [\n 'in-tree',\n 'models-dev',\n 'manifest',\n 'derived',\n 'generated',\n];\n\ninterface DoctorReport {\n /** Effective per-source counts over `getDefaultRegistry().allEntries()`. */\n readonly sourceCounts: Record<EntrySource, number>;\n readonly totalEntries: number;\n readonly bundled: {\n readonly path: string;\n readonly status: 'loaded' | 'missing' | 'malformed';\n readonly entryCount: number;\n };\n readonly overlay: {\n readonly path: string;\n readonly status: 'missing' | 'empty' | 'malformed' | 'too-large' | 'loaded';\n readonly entryCount: number;\n readonly rejections: readonly { index: number; id?: string; reason: string }[];\n readonly envOverride: string | undefined;\n };\n readonly unknownIdFallback: {\n readonly contextWindow: number;\n };\n}\n\nfunction doctorCommand(options: RegistryCommandOptions): RegistryCommandResult {\n const report = buildDoctorReport(options);\n if (options.json === true) {\n return { text: JSON.stringify(report, null, 2), exitCode: 0 };\n }\n return { text: formatDoctorReport(report), exitCode: 0 };\n}\n\nfunction buildDoctorReport(options: RegistryCommandOptions): DoctorReport {\n // Effective per-source counts over the fully-merged registry: dedup/override\n // across tiers has already happened, so `allEntries()` reflects what actually\n // wins, grouped by the surviving entry's `source`.\n const entries = getDefaultRegistry().allEntries();\n const sourceCounts: Record<EntrySource, number> = {\n 'in-tree': 0,\n 'models-dev': 0,\n manifest: 0,\n derived: 0,\n generated: 0,\n };\n for (const entry of entries) {\n sourceCounts[entry.source] += 1;\n }\n\n // The bundled generated catalog (long-tail breadth tier) — reported from the\n // same loader the registry ingests, so the path/status here matches reality.\n const generated = loadGeneratedRegistryEntries();\n\n // User overlay (`~/.nexus-agents/models.yaml`) status, reported for\n // inspection. As of #3351 this IS wired into the registry's manifest tier\n // (below the operator manifest), loaded via the same manifest-overlay loader.\n const overlay =\n options.overlayPath !== undefined\n ? loadUserManifestOverlay({ path: options.overlayPath })\n : loadUserManifestOverlay();\n\n return {\n sourceCounts,\n totalEntries: entries.length,\n bundled: {\n path: generated.path,\n status: generated.status,\n entryCount: generated.entries.length,\n },\n overlay: {\n path: overlay.path,\n status: overlay.status,\n entryCount: overlay.entries.length,\n rejections: overlay.rejections.map((r) => ({\n index: r.index,\n ...(r.id !== undefined ? { id: r.id } : {}),\n reason: r.reason,\n })),\n envOverride: process.env[USER_MANIFEST_ENV_VAR],\n },\n unknownIdFallback: {\n contextWindow: UNKNOWN_MODEL_CONTEXT_WINDOW,\n },\n };\n}\n\nfunction formatDoctorReport(r: DoctorReport): string {\n const lines: string[] = [];\n lines.push('nexus-agents registry doctor');\n lines.push('============================');\n lines.push('');\n lines.push(`Registry entries by source (total ${String(r.totalEntries)}):`);\n for (const source of ENTRY_SOURCES) {\n lines.push(` ${source.padEnd(11)}: ${String(r.sourceCounts[source])}`);\n }\n lines.push('');\n lines.push('Bundled generated registry (long-tail breadth tier):');\n lines.push(` path : ${r.bundled.path}`);\n lines.push(` status : ${r.bundled.status}`);\n lines.push(` entryCount : ${String(r.bundled.entryCount)}`);\n lines.push('');\n // User overlay reported for inspection; not consumed by the merged registry.\n lines.push('T3 user overlay (reported for inspection):');\n lines.push(` path : ${r.overlay.path}`);\n lines.push(` status : ${r.overlay.status}`);\n lines.push(` entryCount : ${String(r.overlay.entryCount)}`);\n lines.push(` env override: ${r.overlay.envOverride ?? '(not set)'}`);\n if (r.overlay.rejections.length > 0) {\n lines.push(' rejections :');\n for (const rej of r.overlay.rejections) {\n const idPart = rej.id !== undefined ? ` id=${rej.id}` : '';\n lines.push(` - [${String(rej.index)}]${idPart} ${rej.reason}`);\n }\n }\n lines.push('');\n lines.push('Unknown-id fallback (id resolves in no source):');\n lines.push(` contextWindow : ${String(r.unknownIdFallback.contextWindow)}`);\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// refresh\n// ---------------------------------------------------------------------------\n\nconst MAX_REFRESH_BYTES = 5 * 1024 * 1024;\n\nfunction missingSourceResult(): RegistryCommandResult {\n return {\n text: [\n 'registry refresh requires --source=<url>.',\n '',\n 'The url should point at a model-registry.generated.json file with a',\n 'matching <url>.sha256 sidecar (single line containing the SHA256 hash).',\n '',\n 'A signed GitHub release artifact is a planned default but not wired yet;',\n `that is tracked in #2180. Use --source=<your-mirror-url> in the meantime.`,\n ].join('\\n'),\n exitCode: 2,\n };\n}\n\ninterface VerifiedArtifact {\n readonly body: string;\n readonly sha256: string;\n}\n\nasync function fetchAndVerify(\n source: string,\n fetchImpl: typeof fetch\n): Promise<VerifiedArtifact | RegistryCommandResult> {\n const body = await fetchWithCap(source, fetchImpl);\n if (!body.ok || body.body === undefined) {\n return { text: `Failed to fetch ${source}: ${body.error ?? 'unknown'}`, exitCode: 1 };\n }\n const sha = await fetchWithCap(`${source}.sha256`, fetchImpl);\n if (!sha.ok || sha.body === undefined) {\n return {\n text: `Failed to fetch ${source}.sha256 for integrity check: ${sha.error ?? 'unknown'}`,\n exitCode: 1,\n };\n }\n const expected = sha.body.trim().split(/\\s+/)[0] ?? '';\n if (expected === '') {\n return { text: `SHA256 sidecar at ${source}.sha256 is empty`, exitCode: 1 };\n }\n const actual = createHash('sha256').update(body.body, 'utf-8').digest('hex');\n if (actual.toLowerCase() !== expected.toLowerCase()) {\n return {\n text: `SHA256 mismatch: expected ${expected}, got ${actual}. Aborting write.`,\n exitCode: 1,\n };\n }\n return { body: body.body, sha256: actual };\n}\n\nfunction formatRefreshReport(\n verb: 'would write to' | 'wrote to',\n source: string,\n artifact: VerifiedArtifact,\n dest: string,\n extraTail: readonly string[] = []\n): string {\n return [\n `registry refresh${verb.startsWith('would') ? ' --dry-run' : ''}`,\n `source : ${source}`,\n `sha256 : ${artifact.sha256} (verified)`,\n `bytes : ${String(artifact.body.length)}`,\n `${verb}: ${dest}`,\n ...extraTail,\n ].join('\\n');\n}\n\nasync function refreshCommand(options: RegistryCommandOptions): Promise<RegistryCommandResult> {\n const source = options.source;\n if (source === undefined || source === '') return missingSourceResult();\n\n const artifact = await fetchAndVerify(source, options.fetchImpl ?? fetch);\n if ('text' in artifact) return artifact;\n\n const dest = options.destPath ?? nexusDataPath('model-registry.generated.json');\n if (options.dryRun === true) {\n return { text: formatRefreshReport('would write to', source, artifact, dest), exitCode: 0 };\n }\n\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, artifact.body, 'utf-8');\n // Hot-reload the in-process model registry + adapter routing so the refresh\n // takes effect immediately, without a restart (#3185). Re-reads the overlay\n // (fail-closed) and atomically resets both singletons.\n await reloadDefaultRegistry();\n return {\n text: formatRefreshReport('wrote to', source, artifact, dest, [\n '',\n 'The in-process model registry and adapter routing were hot-reloaded — the',\n 'refresh is live now in THIS process (#3185). Other already-running CLI / MCP',\n 'server processes still need a restart (or their own refresh) to pick it up.',\n ]),\n exitCode: 0,\n };\n}\n\ninterface FetchResult {\n readonly ok: boolean;\n readonly body?: string;\n readonly error?: string;\n}\n\nconst overCapError = (bytes: number | null): FetchResult => ({\n ok: false,\n error:\n bytes === null\n ? `payload exceeds cap ${String(MAX_REFRESH_BYTES)} bytes (stream aborted)`\n : `payload ${String(bytes)} bytes exceeds cap ${String(MAX_REFRESH_BYTES)}`,\n});\n\nasync function fetchWithCap(url: string, fetchImpl: typeof fetch): Promise<FetchResult> {\n try {\n const response = await fetchImpl(url, {\n signal: AbortSignal.timeout(NETWORK_FETCH_TIMEOUT_MS),\n });\n if (!response.ok) {\n return { ok: false, error: `HTTP ${String(response.status)}` };\n }\n\n // Reject on the declared size before reading a single byte (#3354). A\n // compromised/typo'd mirror could otherwise stream gigabytes; the old\n // `response.text()` buffered the whole body before checking the cap and\n // could exhaust memory first.\n const declared = Number(response.headers.get('content-length'));\n if (Number.isFinite(declared) && declared > MAX_REFRESH_BYTES) {\n return overCapError(declared);\n }\n\n // No declared length we can trust: stream with a running cap and abort\n // the moment the accumulated bytes exceed it, so an undeclared or lying\n // Content-Length can't OOM the process.\n if (response.body === null) {\n const body = await response.text();\n return body.length > MAX_REFRESH_BYTES ? overCapError(body.length) : { ok: true, body };\n }\n return await readStreamWithCap(response.body);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return { ok: false, error: message };\n }\n}\n\n/**\n * Read a response body stream, aborting the moment the accumulated bytes\n * exceed {@link MAX_REFRESH_BYTES} (#3354). Keeps a hostile mirror with an\n * undeclared/lying Content-Length from buffering unbounded data into memory.\n */\nasync function readStreamWithCap(stream: ReadableStream<Uint8Array>): Promise<FetchResult> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let total = 0;\n let body = '';\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > MAX_REFRESH_BYTES) {\n await reader.cancel();\n return overCapError(null);\n }\n body += decoder.decode(value, { stream: true });\n }\n body += decoder.decode();\n return { ok: true, body };\n}\n\n// ---------------------------------------------------------------------------\n// Usage\n// ---------------------------------------------------------------------------\n\nexport function formatRegistryUsage(): string {\n return [\n 'Usage:',\n ' nexus-agents registry doctor [--json]',\n ' Inspect the merged ModelRegistry: per-source entry counts, the',\n ' bundled generated registry, the user overlay, and the unknown-id',\n ' fallback contextWindow.',\n '',\n ' nexus-agents registry refresh --source=<url> [--dry-run]',\n ' Download a signed model-registry.generated.json from <url>,',\n ' SHA256-verify against <url>.sha256, and write to:',\n ` ${nexusDataPath('model-registry.generated.json')}`,\n '',\n `User overlay path is ${defaultUserManifestPath()} by default,`,\n `or whatever ${USER_MANIFEST_ENV_VAR} points to. Overlay max size is ${String(MANIFEST_MAX_BYTES)} bytes.`,\n ].join('\\n');\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/registry-command.ts"],"sourcesContent":["/**\n * `nexus-agents registry` CLI subcommands (epic #2174 / issue #2179).\n *\n * Two subcommands:\n *\n * - `doctor` — inspect the ModelRegistry: effective per-source entry counts,\n * the bundled generated registry path/status, the user overlay (reported for\n * inspection), and the unknown-id fallback contextWindow. Surfaces whatever\n * overlay parse rejections occurred at load. Read-only. (#3293 migrated this\n * off the deleted CapabilityDiscovery four-tier chain.)\n *\n * - `refresh` — download a signed `model-registry.generated.json` from a\n * URL, SHA256-verify against a `.sha256` sidecar, write to the user's\n * overlay location. Requires `--source=<url>` today; the GitHub-latest-\n * release automation is #2180's concern.\n *\n * No runtime hot path touches the network — refresh is a one-shot,\n * user-initiated operation.\n *\n * @module cli/registry-command\n */\n\nimport { createHash } from 'node:crypto';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { nexusDataPath } from '../config/nexus-data-dir.js';\nimport { NETWORK_FETCH_TIMEOUT_MS } from '../config/timeouts.js';\n\nimport {\n getDefaultRegistry,\n reloadDefaultRegistry,\n type EntrySource,\n} from '../config/model-registry.js';\nimport { loadGeneratedRegistryEntries } from '../config/models-generated-loader.js';\nimport {\n USER_MANIFEST_ENV_VAR,\n MANIFEST_MAX_BYTES,\n defaultUserManifestPath,\n loadUserManifestOverlay,\n} from '../config/manifest-overlay.js';\n\n// ---------------------------------------------------------------------------\n// Dispatch\n// ---------------------------------------------------------------------------\n\nexport type RegistrySubcommand = 'doctor' | 'refresh';\n\nconst VALID_SUBCOMMANDS: readonly RegistrySubcommand[] = ['doctor', 'refresh'];\n\nexport function isValidRegistrySubcommand(v: string | undefined): v is RegistrySubcommand {\n return v !== undefined && (VALID_SUBCOMMANDS as readonly string[]).includes(v);\n}\n\nexport interface RegistryCommandOptions {\n readonly json?: boolean;\n readonly source?: string;\n readonly dryRun?: boolean;\n readonly overlayPath?: string;\n /** For tests: a fetch function. Defaults to `globalThis.fetch`. */\n readonly fetchImpl?: typeof fetch;\n /** For tests: override the default destination path. */\n readonly destPath?: string;\n}\n\nexport interface RegistryCommandResult {\n readonly text: string;\n readonly exitCode: number;\n}\n\nexport async function registryCommand(\n subcommand: RegistrySubcommand,\n options: RegistryCommandOptions = {}\n): Promise<RegistryCommandResult> {\n if (subcommand === 'doctor') return doctorCommand(options);\n return refreshCommand(options);\n}\n\n// ---------------------------------------------------------------------------\n// doctor\n// ---------------------------------------------------------------------------\n\n/**\n * ContextWindow returned for an id no registry source resolves. This is the\n * old `FAIL_CLOSED_DEFAULT.contextWindow` value (#2177), preserved here after\n * the CapabilityDiscovery four-tier chain was deleted in #3293.\n */\nconst UNKNOWN_MODEL_CONTEXT_WINDOW = 8192;\n\n/** Every registry source, in report order. */\nconst ENTRY_SOURCES: readonly EntrySource[] = [\n 'in-tree',\n 'models-dev',\n 'manifest',\n 'derived',\n 'generated',\n];\n\ninterface DoctorReport {\n /** Effective per-source counts over `getDefaultRegistry().allEntries()`. */\n readonly sourceCounts: Record<EntrySource, number>;\n readonly totalEntries: number;\n readonly bundled: {\n readonly path: string;\n readonly status: 'loaded' | 'missing' | 'malformed';\n readonly entryCount: number;\n };\n readonly overlay: {\n readonly path: string;\n readonly status: 'missing' | 'empty' | 'malformed' | 'too-large' | 'loaded';\n readonly entryCount: number;\n readonly rejections: readonly { index: number; id?: string; reason: string }[];\n readonly envOverride: string | undefined;\n };\n readonly unknownIdFallback: {\n readonly contextWindow: number;\n };\n}\n\nfunction doctorCommand(options: RegistryCommandOptions): RegistryCommandResult {\n const report = buildDoctorReport(options);\n if (options.json === true) {\n return { text: JSON.stringify(report, null, 2), exitCode: 0 };\n }\n return { text: formatDoctorReport(report), exitCode: 0 };\n}\n\nfunction buildDoctorReport(options: RegistryCommandOptions): DoctorReport {\n // Effective per-source counts over the fully-merged registry: dedup/override\n // across tiers has already happened, so `allEntries()` reflects what actually\n // wins, grouped by the surviving entry's `source`.\n const entries = getDefaultRegistry().allEntries();\n const sourceCounts: Record<EntrySource, number> = {\n 'in-tree': 0,\n 'models-dev': 0,\n manifest: 0,\n derived: 0,\n generated: 0,\n };\n for (const entry of entries) {\n sourceCounts[entry.source] += 1;\n }\n\n // The bundled generated catalog (long-tail breadth tier) — reported from the\n // same loader the registry ingests, so the path/status here matches reality.\n const generated = loadGeneratedRegistryEntries();\n\n // User overlay (`~/.nexus-agents/models.yaml`) status, reported for\n // inspection. As of #3351 this IS wired into the registry's manifest tier\n // (below the operator manifest), loaded via the same manifest-overlay loader.\n const overlay =\n options.overlayPath !== undefined\n ? loadUserManifestOverlay({ path: options.overlayPath })\n : loadUserManifestOverlay();\n\n return {\n sourceCounts,\n totalEntries: entries.length,\n bundled: {\n path: generated.path,\n status: generated.status,\n entryCount: generated.entries.length,\n },\n overlay: {\n path: overlay.path,\n status: overlay.status,\n entryCount: overlay.entries.length,\n rejections: overlay.rejections.map((r) => ({\n index: r.index,\n ...(r.id !== undefined ? { id: r.id } : {}),\n reason: r.reason,\n })),\n envOverride: process.env[USER_MANIFEST_ENV_VAR],\n },\n unknownIdFallback: {\n contextWindow: UNKNOWN_MODEL_CONTEXT_WINDOW,\n },\n };\n}\n\nfunction formatDoctorReport(r: DoctorReport): string {\n const lines: string[] = [];\n lines.push('nexus-agents registry doctor');\n lines.push('============================');\n lines.push('');\n lines.push(`Registry entries by source (total ${String(r.totalEntries)}):`);\n for (const source of ENTRY_SOURCES) {\n lines.push(` ${source.padEnd(11)}: ${String(r.sourceCounts[source])}`);\n }\n lines.push('');\n lines.push('Bundled generated registry (long-tail breadth tier):');\n lines.push(` path : ${r.bundled.path}`);\n lines.push(` status : ${r.bundled.status}`);\n lines.push(` entryCount : ${String(r.bundled.entryCount)}`);\n lines.push('');\n // User overlay reported for inspection; not consumed by the merged registry.\n lines.push('T3 user overlay (reported for inspection):');\n lines.push(` path : ${r.overlay.path}`);\n lines.push(` status : ${r.overlay.status}`);\n lines.push(` entryCount : ${String(r.overlay.entryCount)}`);\n lines.push(` env override: ${r.overlay.envOverride ?? '(not set)'}`);\n if (r.overlay.rejections.length > 0) {\n lines.push(' rejections :');\n for (const rej of r.overlay.rejections) {\n const idPart = rej.id !== undefined ? ` id=${rej.id}` : '';\n lines.push(` - [${String(rej.index)}]${idPart} ${rej.reason}`);\n }\n }\n lines.push('');\n lines.push('Unknown-id fallback (id resolves in no source):');\n lines.push(` contextWindow : ${String(r.unknownIdFallback.contextWindow)}`);\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// refresh\n// ---------------------------------------------------------------------------\n\nconst MAX_REFRESH_BYTES = 5 * 1024 * 1024;\n\nfunction missingSourceResult(): RegistryCommandResult {\n return {\n text: [\n 'registry refresh requires --source=<url>.',\n '',\n 'The url should point at a model-registry.generated.json file with a',\n 'matching <url>.sha256 sidecar (single line containing the SHA256 hash).',\n '',\n 'A signed GitHub release artifact is a planned default but not wired yet;',\n `that is tracked in #2180. Use --source=<your-mirror-url> in the meantime.`,\n ].join('\\n'),\n exitCode: 2,\n };\n}\n\ninterface VerifiedArtifact {\n readonly body: string;\n readonly sha256: string;\n}\n\nasync function fetchAndVerify(\n source: string,\n fetchImpl: typeof fetch\n): Promise<VerifiedArtifact | RegistryCommandResult> {\n const body = await fetchWithCap(source, fetchImpl);\n if (!body.ok || body.body === undefined) {\n return { text: `Failed to fetch ${source}: ${body.error ?? 'unknown'}`, exitCode: 1 };\n }\n const sha = await fetchWithCap(`${source}.sha256`, fetchImpl);\n if (!sha.ok || sha.body === undefined) {\n return {\n text: `Failed to fetch ${source}.sha256 for integrity check: ${sha.error ?? 'unknown'}`,\n exitCode: 1,\n };\n }\n const expected = sha.body.trim().split(/\\s+/)[0] ?? '';\n if (expected === '') {\n return { text: `SHA256 sidecar at ${source}.sha256 is empty`, exitCode: 1 };\n }\n const actual = createHash('sha256').update(body.body, 'utf-8').digest('hex');\n if (actual.toLowerCase() !== expected.toLowerCase()) {\n return {\n text: `SHA256 mismatch: expected ${expected}, got ${actual}. Aborting write.`,\n exitCode: 1,\n };\n }\n return { body: body.body, sha256: actual };\n}\n\nfunction formatRefreshReport(\n verb: 'would write to' | 'wrote to',\n source: string,\n artifact: VerifiedArtifact,\n dest: string,\n extraTail: readonly string[] = []\n): string {\n return [\n `registry refresh${verb.startsWith('would') ? ' --dry-run' : ''}`,\n `source : ${source}`,\n `sha256 : ${artifact.sha256} (verified)`,\n `bytes : ${String(artifact.body.length)}`,\n `${verb}: ${dest}`,\n ...extraTail,\n ].join('\\n');\n}\n\nasync function refreshCommand(options: RegistryCommandOptions): Promise<RegistryCommandResult> {\n const source = options.source;\n if (source === undefined || source === '') return missingSourceResult();\n\n const artifact = await fetchAndVerify(source, options.fetchImpl ?? fetch);\n if ('text' in artifact) return artifact;\n\n const dest = options.destPath ?? nexusDataPath('model-registry.generated.json');\n if (options.dryRun === true) {\n return { text: formatRefreshReport('would write to', source, artifact, dest), exitCode: 0 };\n }\n\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, artifact.body, 'utf-8');\n // Hot-reload the in-process model registry + adapter routing so the refresh\n // takes effect immediately, without a restart (#3185). Re-reads the overlay\n // (fail-closed) and atomically resets both singletons.\n await reloadDefaultRegistry();\n return {\n text: formatRefreshReport('wrote to', source, artifact, dest, [\n '',\n 'The in-process model registry and adapter routing were hot-reloaded — the',\n 'refresh is live now in THIS process (#3185). Other already-running CLI / MCP',\n 'server processes still need a restart (or their own refresh) to pick it up.',\n ]),\n exitCode: 0,\n };\n}\n\ninterface FetchResult {\n readonly ok: boolean;\n readonly body?: string;\n readonly error?: string;\n}\n\nconst overCapError = (bytes: number | null): FetchResult => ({\n ok: false,\n error:\n bytes === null\n ? `payload exceeds cap ${String(MAX_REFRESH_BYTES)} bytes (stream aborted)`\n : `payload ${String(bytes)} bytes exceeds cap ${String(MAX_REFRESH_BYTES)}`,\n});\n\nasync function fetchWithCap(url: string, fetchImpl: typeof fetch): Promise<FetchResult> {\n try {\n const response = await fetchImpl(url, {\n signal: AbortSignal.timeout(NETWORK_FETCH_TIMEOUT_MS),\n });\n if (!response.ok) {\n return { ok: false, error: `HTTP ${String(response.status)}` };\n }\n\n // Reject on the declared size before reading a single byte (#3354). A\n // compromised/typo'd mirror could otherwise stream gigabytes; the old\n // `response.text()` buffered the whole body before checking the cap and\n // could exhaust memory first.\n const declared = Number(response.headers.get('content-length'));\n if (Number.isFinite(declared) && declared > MAX_REFRESH_BYTES) {\n return overCapError(declared);\n }\n\n // No declared length we can trust: stream with a running cap and abort\n // the moment the accumulated bytes exceed it, so an undeclared or lying\n // Content-Length can't OOM the process.\n if (response.body === null) {\n const body = await response.text();\n return body.length > MAX_REFRESH_BYTES ? overCapError(body.length) : { ok: true, body };\n }\n return await readStreamWithCap(response.body);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return { ok: false, error: message };\n }\n}\n\n/**\n * Read a response body stream, aborting the moment the accumulated bytes\n * exceed {@link MAX_REFRESH_BYTES} (#3354). Keeps a hostile mirror with an\n * undeclared/lying Content-Length from buffering unbounded data into memory.\n */\nasync function readStreamWithCap(stream: ReadableStream<Uint8Array>): Promise<FetchResult> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let total = 0;\n let body = '';\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > MAX_REFRESH_BYTES) {\n await reader.cancel();\n return overCapError(null);\n }\n body += decoder.decode(value, { stream: true });\n }\n body += decoder.decode();\n return { ok: true, body };\n}\n\n// ---------------------------------------------------------------------------\n// Usage\n// ---------------------------------------------------------------------------\n\nexport function formatRegistryUsage(): string {\n return [\n 'Usage:',\n ' nexus-agents registry doctor [--json]',\n ' Inspect the merged ModelRegistry: per-source entry counts, the',\n ' bundled generated registry, the user overlay, and the unknown-id',\n ' fallback contextWindow.',\n '',\n ' nexus-agents registry refresh --source=<url> [--dry-run]',\n ' Download a signed model-registry.generated.json from <url>,',\n ' SHA256-verify against <url>.sha256, and write to:',\n ` ${nexusDataPath('model-registry.generated.json')}`,\n '',\n `User overlay path is ${defaultUserManifestPath()} by default,`,\n `or whatever ${USER_MANIFEST_ENV_VAR} points to. Overlay max size is ${String(MANIFEST_MAX_BYTES)} bytes.`,\n ].join('\\n');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAsBA,SAAS,kBAAkB;AAC3B,SAAS,WAAW,qBAAqB;AACzC,SAAS,eAAe;AAuBxB,IAAM,oBAAmD,CAAC,UAAU,SAAS;AAEtE,SAAS,0BAA0B,GAAgD;AACxF,SAAO,MAAM,UAAc,kBAAwC,SAAS,CAAC;AAC/E;AAkBA,eAAsB,gBACpB,YACA,UAAkC,CAAC,GACH;AAChC,MAAI,eAAe,SAAU,QAAO,cAAc,OAAO;AACzD,SAAO,eAAe,OAAO;AAC/B;AAWA,IAAM,+BAA+B;AAGrC,IAAM,gBAAwC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAuBA,SAAS,cAAc,SAAwD;AAC7E,QAAM,SAAS,kBAAkB,OAAO;AACxC,MAAI,QAAQ,SAAS,MAAM;AACzB,WAAO,EAAE,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,UAAU,EAAE;AAAA,EAC9D;AACA,SAAO,EAAE,MAAM,mBAAmB,MAAM,GAAG,UAAU,EAAE;AACzD;AAEA,SAAS,kBAAkB,SAA+C;AAIxE,QAAM,UAAU,mBAAmB,EAAE,WAAW;AAChD,QAAM,eAA4C;AAAA,IAChD,WAAW;AAAA,IACX,cAAc;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AACA,aAAW,SAAS,SAAS;AAC3B,iBAAa,MAAM,MAAM,KAAK;AAAA,EAChC;AAIA,QAAM,YAAY,6BAA6B;AAK/C,QAAM,UACJ,QAAQ,gBAAgB,SACpB,wBAAwB,EAAE,MAAM,QAAQ,YAAY,CAAC,IACrD,wBAAwB;AAE9B,SAAO;AAAA,IACL;AAAA,IACA,cAAc,QAAQ;AAAA,IACtB,SAAS;AAAA,MACP,MAAM,UAAU;AAAA,MAChB,QAAQ,UAAU;AAAA,MAClB,YAAY,UAAU,QAAQ;AAAA,IAChC;AAAA,IACA,SAAS;AAAA,MACP,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ;AAAA,MAChB,YAAY,QAAQ,QAAQ;AAAA,MAC5B,YAAY,QAAQ,WAAW,IAAI,CAAC,OAAO;AAAA,QACzC,OAAO,EAAE;AAAA,QACT,GAAI,EAAE,OAAO,SAAY,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;AAAA,QACzC,QAAQ,EAAE;AAAA,MACZ,EAAE;AAAA,MACF,aAAa,QAAQ,IAAI,qBAAqB;AAAA,IAChD;AAAA,IACA,mBAAmB;AAAA,MACjB,eAAe;AAAA,IACjB;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,GAAyB;AACnD,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,8BAA8B;AACzC,QAAM,KAAK,8BAA8B;AACzC,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,qCAAqC,OAAO,EAAE,YAAY,CAAC,IAAI;AAC1E,aAAW,UAAU,eAAe;AAClC,UAAM,KAAK,KAAK,OAAO,OAAO,EAAE,CAAC,KAAK,OAAO,EAAE,aAAa,MAAM,CAAC,CAAC,EAAE;AAAA,EACxE;AACA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,sDAAsD;AACjE,QAAM,KAAK,mBAAmB,EAAE,QAAQ,IAAI,EAAE;AAC9C,QAAM,KAAK,mBAAmB,EAAE,QAAQ,MAAM,EAAE;AAChD,QAAM,KAAK,mBAAmB,OAAO,EAAE,QAAQ,UAAU,CAAC,EAAE;AAC5D,QAAM,KAAK,EAAE;AAEb,QAAM,KAAK,4CAA4C;AACvD,QAAM,KAAK,mBAAmB,EAAE,QAAQ,IAAI,EAAE;AAC9C,QAAM,KAAK,mBAAmB,EAAE,QAAQ,MAAM,EAAE;AAChD,QAAM,KAAK,mBAAmB,OAAO,EAAE,QAAQ,UAAU,CAAC,EAAE;AAC5D,QAAM,KAAK,mBAAmB,EAAE,QAAQ,eAAe,WAAW,EAAE;AACpE,MAAI,EAAE,QAAQ,WAAW,SAAS,GAAG;AACnC,UAAM,KAAK,iBAAiB;AAC5B,eAAW,OAAO,EAAE,QAAQ,YAAY;AACtC,YAAM,SAAS,IAAI,OAAO,SAAY,OAAO,IAAI,EAAE,KAAK;AACxD,YAAM,KAAK,UAAU,OAAO,IAAI,KAAK,CAAC,IAAI,MAAM,IAAI,IAAI,MAAM,EAAE;AAAA,IAClE;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,iDAAiD;AAC5D,QAAM,KAAK,qBAAqB,OAAO,EAAE,kBAAkB,aAAa,CAAC,EAAE;AAC3E,SAAO,MAAM,KAAK,IAAI;AACxB;AAMA,IAAM,oBAAoB,IAAI,OAAO;AAErC,SAAS,sBAA6C;AACpD,SAAO;AAAA,IACL,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,IACX,UAAU;AAAA,EACZ;AACF;AAOA,eAAe,eACb,QACA,WACmD;AACnD,QAAM,OAAO,MAAM,aAAa,QAAQ,SAAS;AACjD,MAAI,CAAC,KAAK,MAAM,KAAK,SAAS,QAAW;AACvC,WAAO,EAAE,MAAM,mBAAmB,MAAM,KAAK,KAAK,SAAS,SAAS,IAAI,UAAU,EAAE;AAAA,EACtF;AACA,QAAM,MAAM,MAAM,aAAa,GAAG,MAAM,WAAW,SAAS;AAC5D,MAAI,CAAC,IAAI,MAAM,IAAI,SAAS,QAAW;AACrC,WAAO;AAAA,MACL,MAAM,mBAAmB,MAAM,gCAAgC,IAAI,SAAS,SAAS;AAAA,MACrF,UAAU;AAAA,IACZ;AAAA,EACF;AACA,QAAM,WAAW,IAAI,KAAK,KAAK,EAAE,MAAM,KAAK,EAAE,CAAC,KAAK;AACpD,MAAI,aAAa,IAAI;AACnB,WAAO,EAAE,MAAM,qBAAqB,MAAM,oBAAoB,UAAU,EAAE;AAAA,EAC5E;AACA,QAAM,SAAS,WAAW,QAAQ,EAAE,OAAO,KAAK,MAAM,OAAO,EAAE,OAAO,KAAK;AAC3E,MAAI,OAAO,YAAY,MAAM,SAAS,YAAY,GAAG;AACnD,WAAO;AAAA,MACL,MAAM,6BAA6B,QAAQ,SAAS,MAAM;AAAA,MAC1D,UAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO,EAAE,MAAM,KAAK,MAAM,QAAQ,OAAO;AAC3C;AAEA,SAAS,oBACP,MACA,QACA,UACA,MACA,YAA+B,CAAC,GACxB;AACR,SAAO;AAAA,IACL,mBAAmB,KAAK,WAAW,OAAO,IAAI,eAAe,EAAE;AAAA,IAC/D,cAAc,MAAM;AAAA,IACpB,cAAc,SAAS,MAAM;AAAA,IAC7B,cAAc,OAAO,SAAS,KAAK,MAAM,CAAC;AAAA,IAC1C,GAAG,IAAI,KAAK,IAAI;AAAA,IAChB,GAAG;AAAA,EACL,EAAE,KAAK,IAAI;AACb;AAEA,eAAe,eAAe,SAAiE;AAC7F,QAAM,SAAS,QAAQ;AACvB,MAAI,WAAW,UAAa,WAAW,GAAI,QAAO,oBAAoB;AAEtE,QAAM,WAAW,MAAM,eAAe,QAAQ,QAAQ,aAAa,KAAK;AACxE,MAAI,UAAU,SAAU,QAAO;AAE/B,QAAM,OAAO,QAAQ,YAAY,cAAc,+BAA+B;AAC9E,MAAI,QAAQ,WAAW,MAAM;AAC3B,WAAO,EAAE,MAAM,oBAAoB,kBAAkB,QAAQ,UAAU,IAAI,GAAG,UAAU,EAAE;AAAA,EAC5F;AAEA,YAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,gBAAc,MAAM,SAAS,MAAM,OAAO;AAI1C,QAAM,sBAAsB;AAC5B,SAAO;AAAA,IACL,MAAM,oBAAoB,YAAY,QAAQ,UAAU,MAAM;AAAA,MAC5D;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,IACD,UAAU;AAAA,EACZ;AACF;AAQA,IAAM,eAAe,CAAC,WAAuC;AAAA,EAC3D,IAAI;AAAA,EACJ,OACE,UAAU,OACN,uBAAuB,OAAO,iBAAiB,CAAC,4BAChD,WAAW,OAAO,KAAK,CAAC,sBAAsB,OAAO,iBAAiB,CAAC;AAC/E;AAEA,eAAe,aAAa,KAAa,WAA+C;AACtF,MAAI;AACF,UAAM,WAAW,MAAM,UAAU,KAAK;AAAA,MACpC,QAAQ,YAAY,QAAQ,wBAAwB;AAAA,IACtD,CAAC;AACD,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO,EAAE,IAAI,OAAO,OAAO,QAAQ,OAAO,SAAS,MAAM,CAAC,GAAG;AAAA,IAC/D;AAMA,UAAM,WAAW,OAAO,SAAS,QAAQ,IAAI,gBAAgB,CAAC;AAC9D,QAAI,OAAO,SAAS,QAAQ,KAAK,WAAW,mBAAmB;AAC7D,aAAO,aAAa,QAAQ;AAAA,IAC9B;AAKA,QAAI,SAAS,SAAS,MAAM;AAC1B,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO,KAAK,SAAS,oBAAoB,aAAa,KAAK,MAAM,IAAI,EAAE,IAAI,MAAM,KAAK;AAAA,IACxF;AACA,WAAO,MAAM,kBAAkB,SAAS,IAAI;AAAA,EAC9C,SAAS,KAAc;AACrB,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,IAAI,OAAO,OAAO,QAAQ;AAAA,EACrC;AACF;AAOA,eAAe,kBAAkB,QAA0D;AACzF,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,QAAQ;AACZ,MAAI,OAAO;AACX,aAAS;AACP,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AACV,aAAS,MAAM;AACf,QAAI,QAAQ,mBAAmB;AAC7B,YAAM,OAAO,OAAO;AACpB,aAAO,aAAa,IAAI;AAAA,IAC1B;AACA,YAAQ,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAAA,EAChD;AACA,UAAQ,QAAQ,OAAO;AACvB,SAAO,EAAE,IAAI,MAAM,KAAK;AAC1B;AAMO,SAAS,sBAA8B;AAC5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,cAAc,+BAA+B,CAAC;AAAA,IACvD;AAAA,IACA,wBAAwB,wBAAwB,CAAC;AAAA,IACjD,eAAe,qBAAqB,mCAAmC,OAAO,kBAAkB,CAAC;AAAA,EACnG,EAAE,KAAK,IAAI;AACb;","names":[]}
|
|
@@ -3,10 +3,11 @@ import {
|
|
|
3
3
|
buildPlanFromAnalysis,
|
|
4
4
|
generateSecurityPlan,
|
|
5
5
|
resolveScannerData
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3JSDOBOA.js";
|
|
7
7
|
import "./chunk-HFOQKCD2.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-OCJEYHUQ.js";
|
|
9
|
+
import "./chunk-5SXGPX34.js";
|
|
10
|
+
import "./chunk-L4QFWOOQ.js";
|
|
10
11
|
import "./chunk-ZPWHCABL.js";
|
|
11
12
|
export {
|
|
12
13
|
FALLBACK_SCANNER_DATA,
|
|
@@ -14,4 +15,4 @@ export {
|
|
|
14
15
|
generateSecurityPlan,
|
|
15
16
|
resolveScannerData
|
|
16
17
|
};
|
|
17
|
-
//# sourceMappingURL=repo-security-plan-
|
|
18
|
+
//# sourceMappingURL=repo-security-plan-76IXMJNC.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AttributedInsightSchema,
|
|
3
|
+
synthesizeResearch
|
|
4
|
+
} from "./chunk-4GVPON4W.js";
|
|
5
|
+
import "./chunk-ZHCEOIEQ.js";
|
|
6
|
+
import "./chunk-NUBSJGQZ.js";
|
|
7
|
+
import "./chunk-OCJEYHUQ.js";
|
|
8
|
+
import "./chunk-5SXGPX34.js";
|
|
9
|
+
import "./chunk-L4QFWOOQ.js";
|
|
10
|
+
import "./chunk-ZPWHCABL.js";
|
|
11
|
+
export {
|
|
12
|
+
AttributedInsightSchema,
|
|
13
|
+
synthesizeResearch
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=research-helpers-synthesize-WH4IC36H.js.map
|
|
@@ -2,12 +2,13 @@ import {
|
|
|
2
2
|
DEFAULT_ROUTING_MEMORY_CONFIG,
|
|
3
3
|
RoutingMemory,
|
|
4
4
|
createRoutingMemory
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-OCJEYHUQ.js";
|
|
6
|
+
import "./chunk-5SXGPX34.js";
|
|
7
|
+
import "./chunk-L4QFWOOQ.js";
|
|
7
8
|
import "./chunk-ZPWHCABL.js";
|
|
8
9
|
export {
|
|
9
10
|
DEFAULT_ROUTING_MEMORY_CONFIG,
|
|
10
11
|
RoutingMemory,
|
|
11
12
|
createRoutingMemory
|
|
12
13
|
};
|
|
13
|
-
//# sourceMappingURL=routing-memory-
|
|
14
|
+
//# sourceMappingURL=routing-memory-RAYIYIUP.js.map
|
|
@@ -6,9 +6,10 @@ import {
|
|
|
6
6
|
SessionMemory,
|
|
7
7
|
SessionMemoryError,
|
|
8
8
|
createSessionMemory
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-3QH2KWLH.js";
|
|
10
|
+
import "./chunk-OCJEYHUQ.js";
|
|
11
|
+
import "./chunk-5SXGPX34.js";
|
|
12
|
+
import "./chunk-L4QFWOOQ.js";
|
|
12
13
|
import "./chunk-ZPWHCABL.js";
|
|
13
14
|
export {
|
|
14
15
|
CompletedTaskSchema,
|
|
@@ -19,4 +20,4 @@ export {
|
|
|
19
20
|
SessionMemoryError,
|
|
20
21
|
createSessionMemory
|
|
21
22
|
};
|
|
22
|
-
//# sourceMappingURL=session-memory-
|
|
23
|
+
//# sourceMappingURL=session-memory-WZCS7WDH.js.map
|
|
@@ -8,20 +8,21 @@ import {
|
|
|
8
8
|
runWizard,
|
|
9
9
|
setupCommand,
|
|
10
10
|
setupCommandAsync
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-MTE7THMR.js";
|
|
12
|
+
import "./chunk-VY4FZNZA.js";
|
|
13
|
+
import "./chunk-66TXNH4S.js";
|
|
14
14
|
import "./chunk-NUBSJGQZ.js";
|
|
15
15
|
import "./chunk-6T3EPABN.js";
|
|
16
16
|
import "./chunk-ZM4O442V.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-GWOXPCIF.js";
|
|
18
|
+
import "./chunk-ZII5MDUO.js";
|
|
19
|
+
import "./chunk-7E5UXA4U.js";
|
|
20
|
+
import "./chunk-7G63H7ZT.js";
|
|
21
|
+
import "./chunk-KOVTOPEQ.js";
|
|
22
|
+
import "./chunk-FIQSOSQU.js";
|
|
23
|
+
import "./chunk-OCJEYHUQ.js";
|
|
24
|
+
import "./chunk-5SXGPX34.js";
|
|
25
|
+
import "./chunk-L4QFWOOQ.js";
|
|
25
26
|
import "./chunk-ZPWHCABL.js";
|
|
26
27
|
export {
|
|
27
28
|
detectEnvironment,
|
|
@@ -34,4 +35,4 @@ export {
|
|
|
34
35
|
setupCommand,
|
|
35
36
|
setupCommandAsync
|
|
36
37
|
};
|
|
37
|
-
//# sourceMappingURL=setup-command-
|
|
38
|
+
//# sourceMappingURL=setup-command-O62DVQ2U.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runConfigInitSync
|
|
3
|
+
} from "./chunk-VY4FZNZA.js";
|
|
4
|
+
import "./chunk-OCJEYHUQ.js";
|
|
5
|
+
import "./chunk-5SXGPX34.js";
|
|
6
|
+
import "./chunk-L4QFWOOQ.js";
|
|
7
|
+
import "./chunk-ZPWHCABL.js";
|
|
8
|
+
export {
|
|
9
|
+
runConfigInitSync
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=setup-config-KEBEUMC3.js.map
|
|
@@ -3,12 +3,13 @@ import {
|
|
|
3
3
|
CUSTOM_API_BASE_URL_ENV,
|
|
4
4
|
CUSTOM_API_DEFAULT_MODEL,
|
|
5
5
|
validateCustomApiBaseUrl
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7E5UXA4U.js";
|
|
7
7
|
import {
|
|
8
8
|
err,
|
|
9
9
|
ok
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-OCJEYHUQ.js";
|
|
11
|
+
import "./chunk-5SXGPX34.js";
|
|
12
|
+
import "./chunk-L4QFWOOQ.js";
|
|
12
13
|
import "./chunk-ZPWHCABL.js";
|
|
13
14
|
|
|
14
15
|
// src/cli/setup-custom-api.ts
|
|
@@ -104,4 +105,4 @@ function buildShellFragment(params) {
|
|
|
104
105
|
export {
|
|
105
106
|
configureCustomApi
|
|
106
107
|
};
|
|
107
|
-
//# sourceMappingURL=setup-custom-api-
|
|
108
|
+
//# sourceMappingURL=setup-custom-api-2PQP6UOT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/setup-custom-api.ts"],"sourcesContent":["/**\n * Interactive setup for a custom OpenAI-compatible gateway (#2124).\n *\n * Closes the last child of epic #2119. The runtime adapter (#2125) is\n * already live — this module is the ergonomics layer: a single command\n * that validates the URL, probes connectivity, and tells the user\n * exactly what env vars to set for their shell.\n *\n * Writes nothing by default (dry-run is the safe behavior for a CLI\n * that touches shell state). Prints the shell fragment; user copies\n * it into ~/.bashrc / ~/.zshrc / ~/.config/fish/config.fish. Rationale:\n * harness-neutral — we don't know which shell the user runs or where\n * their nexus-agents.yaml lives.\n *\n * @module cli/setup-custom-api\n */\n\nimport { createInterface } from 'node:readline';\nimport { validateCustomApiBaseUrl } from '../adapters/sdk/custom-api-validation.js';\nimport { CUSTOM_API_BASE_URL_ENV, CUSTOM_API_ALLOW_PRIVATE_ENV } from '../adapters/sdk/types.js';\nimport { CUSTOM_API_DEFAULT_MODEL as DEFAULT_MODEL } from '../config/defaults.js';\nimport { ok, err, type Result } from '../core/index.js';\n\n/** Inputs to `configureCustomApi`. */\nexport interface CustomApiSetupInput {\n /** Gateway base URL (required). SSRF guard from adapters/sdk is applied. */\n readonly baseUrl: string;\n /** API key. If absent, `configureCustomApi` will prompt (or fail non-interactively). */\n readonly apiKey?: string;\n /** Model id to default to. Omitted → documented fallback \"gpt-4o\". */\n readonly model?: string;\n /** Skip the TTY prompt for the API key — useful for CI and scripting. */\n readonly nonInteractive?: boolean;\n /** Omit HTTP probe — useful for dry-run / offline verify. */\n readonly skipProbe?: boolean;\n /** Allow private / loopback base URLs (overrides the SSRF guard). */\n readonly allowPrivate?: boolean;\n /** Stream for prompts/output. Defaults to process.stdout / stdin. */\n readonly stream?: { readonly output: NodeJS.WritableStream };\n /**\n * Pluggable HTTP fetcher for tests. Defaults to global fetch.\n * Called as `fetch(url, { headers })`; should return `{ status, body }`.\n */\n readonly fetcher?: HttpFetcher;\n}\n\n/** Minimal HTTP fetcher shape — lets tests inject a mock without network. */\nexport type HttpFetcher = (\n url: string,\n init: { readonly headers: Readonly<Record<string, string>> }\n) => Promise<{ readonly status: number; readonly body: string }>;\n\n/** Outcome of `configureCustomApi`. */\nexport interface CustomApiSetupResult {\n /** Validated base URL (may differ trivially from input — e.g. canonical form). */\n readonly baseUrl: string;\n /** Resolved model id. */\n readonly model: string;\n /** Whether the /v1/models probe succeeded (always true unless skipped). */\n readonly probeSucceeded: boolean;\n /**\n * Shell fragment the user should add to their shell rc so nexus-agents\n * picks up the gateway on subsequent invocations. Already-set env\n * equivalents of these lines are all that's needed at runtime.\n */\n readonly shellFragment: string;\n}\n\n/**\n * Configures a custom OpenAI-compatible gateway.\n *\n * Steps:\n * 1. Validate base URL via the SSRF guard (same as the runtime adapter).\n * 2. Resolve the API key (from input, env, or TTY prompt).\n * 3. Probe `GET {baseUrl}/models` with Bearer auth to confirm connectivity.\n * 4. Emit the shell-fragment the user adds to their shell rc.\n *\n * Returns an `ok` Result on success, or a `ConfigError`-bearing `err`\n * Result on any failure (invalid URL, missing API key in non-interactive,\n * probe failure). Never throws.\n */\nexport async function configureCustomApi(\n input: CustomApiSetupInput\n): Promise<Result<CustomApiSetupResult, Error>> {\n const urlValidation = validateCustomApiBaseUrl(input.baseUrl, {\n ...(input.allowPrivate === true ? { allowPrivate: true } : {}),\n });\n if (!urlValidation.ok) return err(urlValidation.error);\n const baseUrl = urlValidation.value.toString();\n\n const apiKeyResult = await resolveApiKey(input);\n if (!apiKeyResult.ok) return err(apiKeyResult.error);\n const apiKey = apiKeyResult.value;\n\n const probeSucceeded = input.skipProbe === true ? false : await runProbe(baseUrl, apiKey, input);\n if (input.skipProbe !== true && !probeSucceeded) {\n return err(\n new Error(\n `Gateway probe failed: GET ${stripTrailingSlash(baseUrl)}/models did not return 2xx. ` +\n `Check that the URL is the chat-completions base (typically ends with /v1) and the API key has /models read scope.`\n )\n );\n }\n\n const model = input.model ?? DEFAULT_MODEL;\n return ok({\n baseUrl,\n model,\n probeSucceeded,\n shellFragment: buildShellFragment({ baseUrl, apiKey, model, allowPrivate: input.allowPrivate }),\n });\n}\n\nfunction stripTrailingSlash(s: string): string {\n return s.endsWith('/') ? s.slice(0, -1) : s;\n}\n\n/**\n * Performs the /v1/models probe. Returns true on any 2xx response.\n * Swallows errors into `false` — the caller reports the failure.\n */\nasync function runProbe(\n baseUrl: string,\n apiKey: string,\n input: CustomApiSetupInput\n): Promise<boolean> {\n const url = `${stripTrailingSlash(baseUrl)}/models`;\n const fetcher = input.fetcher ?? defaultFetcher;\n try {\n const res = await fetcher(url, {\n headers: { Authorization: `Bearer ${apiKey}`, Accept: 'application/json' },\n });\n return res.status >= 200 && res.status < 300;\n } catch {\n return false;\n }\n}\n\nconst defaultFetcher: HttpFetcher = async (url, init) => {\n const res = await fetch(url, { headers: init.headers });\n const body = await res.text();\n return { status: res.status, body };\n};\n\n/**\n * Resolves the API key in priority order: input → env var → TTY prompt\n * (unless non-interactive, in which case the absence is a fail).\n */\nasync function resolveApiKey(input: CustomApiSetupInput): Promise<Result<string, Error>> {\n if (input.apiKey !== undefined && input.apiKey !== '') return ok(input.apiKey);\n const envKey = process.env['NEXUS_CUSTOM_API_KEY'];\n if (envKey !== undefined && envKey !== '') return ok(envKey);\n if (input.nonInteractive === true) {\n return err(\n new Error(\n 'Custom API key required but not provided. Pass --custom-api-key or set NEXUS_CUSTOM_API_KEY.'\n )\n );\n }\n const prompted = await promptForApiKey(input.stream?.output ?? process.stdout);\n if (prompted === '') {\n return err(new Error('No API key entered; aborting.'));\n }\n return ok(prompted);\n}\n\nasync function promptForApiKey(out: NodeJS.WritableStream): Promise<string> {\n out.write('Enter the API key for your custom gateway: ');\n const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });\n try {\n return await new Promise<string>((resolve) => {\n rl.question('', (answer) => {\n resolve(answer.trim());\n });\n });\n } finally {\n rl.close();\n }\n}\n\n/**\n * Formats the shell fragment the user should paste into their shell rc.\n * Designed to be POSIX-portable; fish users can adapt `export` to `set -gx`.\n */\nfunction buildShellFragment(params: {\n readonly baseUrl: string;\n readonly apiKey: string;\n readonly model: string;\n readonly allowPrivate: boolean | undefined;\n}): string {\n const { baseUrl, apiKey, model, allowPrivate } = params;\n const lines: string[] = [\n '# nexus-agents custom-openai gateway (nexus-agents setup --custom-api)',\n `export ${CUSTOM_API_BASE_URL_ENV}=\"${baseUrl}\"`,\n `export NEXUS_CUSTOM_API_KEY=\"${apiKey}\"`,\n `export NEXUS_CUSTOM_MODEL=\"${model}\"`,\n ];\n if (allowPrivate === true) {\n lines.push(`export ${CUSTOM_API_ALLOW_PRIVATE_ENV}=1 # SSRF-guard bypass`);\n }\n return lines.join('\\n') + '\\n';\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/setup-custom-api.ts"],"sourcesContent":["/**\n * Interactive setup for a custom OpenAI-compatible gateway (#2124).\n *\n * Closes the last child of epic #2119. The runtime adapter (#2125) is\n * already live — this module is the ergonomics layer: a single command\n * that validates the URL, probes connectivity, and tells the user\n * exactly what env vars to set for their shell.\n *\n * Writes nothing by default (dry-run is the safe behavior for a CLI\n * that touches shell state). Prints the shell fragment; user copies\n * it into ~/.bashrc / ~/.zshrc / ~/.config/fish/config.fish. Rationale:\n * harness-neutral — we don't know which shell the user runs or where\n * their nexus-agents.yaml lives.\n *\n * @module cli/setup-custom-api\n */\n\nimport { createInterface } from 'node:readline';\nimport { validateCustomApiBaseUrl } from '../adapters/sdk/custom-api-validation.js';\nimport { CUSTOM_API_BASE_URL_ENV, CUSTOM_API_ALLOW_PRIVATE_ENV } from '../adapters/sdk/types.js';\nimport { CUSTOM_API_DEFAULT_MODEL as DEFAULT_MODEL } from '../config/defaults.js';\nimport { ok, err, type Result } from '../core/index.js';\n\n/** Inputs to `configureCustomApi`. */\nexport interface CustomApiSetupInput {\n /** Gateway base URL (required). SSRF guard from adapters/sdk is applied. */\n readonly baseUrl: string;\n /** API key. If absent, `configureCustomApi` will prompt (or fail non-interactively). */\n readonly apiKey?: string;\n /** Model id to default to. Omitted → documented fallback \"gpt-4o\". */\n readonly model?: string;\n /** Skip the TTY prompt for the API key — useful for CI and scripting. */\n readonly nonInteractive?: boolean;\n /** Omit HTTP probe — useful for dry-run / offline verify. */\n readonly skipProbe?: boolean;\n /** Allow private / loopback base URLs (overrides the SSRF guard). */\n readonly allowPrivate?: boolean;\n /** Stream for prompts/output. Defaults to process.stdout / stdin. */\n readonly stream?: { readonly output: NodeJS.WritableStream };\n /**\n * Pluggable HTTP fetcher for tests. Defaults to global fetch.\n * Called as `fetch(url, { headers })`; should return `{ status, body }`.\n */\n readonly fetcher?: HttpFetcher;\n}\n\n/** Minimal HTTP fetcher shape — lets tests inject a mock without network. */\nexport type HttpFetcher = (\n url: string,\n init: { readonly headers: Readonly<Record<string, string>> }\n) => Promise<{ readonly status: number; readonly body: string }>;\n\n/** Outcome of `configureCustomApi`. */\nexport interface CustomApiSetupResult {\n /** Validated base URL (may differ trivially from input — e.g. canonical form). */\n readonly baseUrl: string;\n /** Resolved model id. */\n readonly model: string;\n /** Whether the /v1/models probe succeeded (always true unless skipped). */\n readonly probeSucceeded: boolean;\n /**\n * Shell fragment the user should add to their shell rc so nexus-agents\n * picks up the gateway on subsequent invocations. Already-set env\n * equivalents of these lines are all that's needed at runtime.\n */\n readonly shellFragment: string;\n}\n\n/**\n * Configures a custom OpenAI-compatible gateway.\n *\n * Steps:\n * 1. Validate base URL via the SSRF guard (same as the runtime adapter).\n * 2. Resolve the API key (from input, env, or TTY prompt).\n * 3. Probe `GET {baseUrl}/models` with Bearer auth to confirm connectivity.\n * 4. Emit the shell-fragment the user adds to their shell rc.\n *\n * Returns an `ok` Result on success, or a `ConfigError`-bearing `err`\n * Result on any failure (invalid URL, missing API key in non-interactive,\n * probe failure). Never throws.\n */\nexport async function configureCustomApi(\n input: CustomApiSetupInput\n): Promise<Result<CustomApiSetupResult, Error>> {\n const urlValidation = validateCustomApiBaseUrl(input.baseUrl, {\n ...(input.allowPrivate === true ? { allowPrivate: true } : {}),\n });\n if (!urlValidation.ok) return err(urlValidation.error);\n const baseUrl = urlValidation.value.toString();\n\n const apiKeyResult = await resolveApiKey(input);\n if (!apiKeyResult.ok) return err(apiKeyResult.error);\n const apiKey = apiKeyResult.value;\n\n const probeSucceeded = input.skipProbe === true ? false : await runProbe(baseUrl, apiKey, input);\n if (input.skipProbe !== true && !probeSucceeded) {\n return err(\n new Error(\n `Gateway probe failed: GET ${stripTrailingSlash(baseUrl)}/models did not return 2xx. ` +\n `Check that the URL is the chat-completions base (typically ends with /v1) and the API key has /models read scope.`\n )\n );\n }\n\n const model = input.model ?? DEFAULT_MODEL;\n return ok({\n baseUrl,\n model,\n probeSucceeded,\n shellFragment: buildShellFragment({ baseUrl, apiKey, model, allowPrivate: input.allowPrivate }),\n });\n}\n\nfunction stripTrailingSlash(s: string): string {\n return s.endsWith('/') ? s.slice(0, -1) : s;\n}\n\n/**\n * Performs the /v1/models probe. Returns true on any 2xx response.\n * Swallows errors into `false` — the caller reports the failure.\n */\nasync function runProbe(\n baseUrl: string,\n apiKey: string,\n input: CustomApiSetupInput\n): Promise<boolean> {\n const url = `${stripTrailingSlash(baseUrl)}/models`;\n const fetcher = input.fetcher ?? defaultFetcher;\n try {\n const res = await fetcher(url, {\n headers: { Authorization: `Bearer ${apiKey}`, Accept: 'application/json' },\n });\n return res.status >= 200 && res.status < 300;\n } catch {\n return false;\n }\n}\n\nconst defaultFetcher: HttpFetcher = async (url, init) => {\n const res = await fetch(url, { headers: init.headers });\n const body = await res.text();\n return { status: res.status, body };\n};\n\n/**\n * Resolves the API key in priority order: input → env var → TTY prompt\n * (unless non-interactive, in which case the absence is a fail).\n */\nasync function resolveApiKey(input: CustomApiSetupInput): Promise<Result<string, Error>> {\n if (input.apiKey !== undefined && input.apiKey !== '') return ok(input.apiKey);\n const envKey = process.env['NEXUS_CUSTOM_API_KEY'];\n if (envKey !== undefined && envKey !== '') return ok(envKey);\n if (input.nonInteractive === true) {\n return err(\n new Error(\n 'Custom API key required but not provided. Pass --custom-api-key or set NEXUS_CUSTOM_API_KEY.'\n )\n );\n }\n const prompted = await promptForApiKey(input.stream?.output ?? process.stdout);\n if (prompted === '') {\n return err(new Error('No API key entered; aborting.'));\n }\n return ok(prompted);\n}\n\nasync function promptForApiKey(out: NodeJS.WritableStream): Promise<string> {\n out.write('Enter the API key for your custom gateway: ');\n const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });\n try {\n return await new Promise<string>((resolve) => {\n rl.question('', (answer) => {\n resolve(answer.trim());\n });\n });\n } finally {\n rl.close();\n }\n}\n\n/**\n * Formats the shell fragment the user should paste into their shell rc.\n * Designed to be POSIX-portable; fish users can adapt `export` to `set -gx`.\n */\nfunction buildShellFragment(params: {\n readonly baseUrl: string;\n readonly apiKey: string;\n readonly model: string;\n readonly allowPrivate: boolean | undefined;\n}): string {\n const { baseUrl, apiKey, model, allowPrivate } = params;\n const lines: string[] = [\n '# nexus-agents custom-openai gateway (nexus-agents setup --custom-api)',\n `export ${CUSTOM_API_BASE_URL_ENV}=\"${baseUrl}\"`,\n `export NEXUS_CUSTOM_API_KEY=\"${apiKey}\"`,\n `export NEXUS_CUSTOM_MODEL=\"${model}\"`,\n ];\n if (allowPrivate === true) {\n lines.push(`export ${CUSTOM_API_ALLOW_PRIVATE_ENV}=1 # SSRF-guard bypass`);\n }\n return lines.join('\\n') + '\\n';\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ToolMemoryManager,
|
|
3
|
+
getToolMemory,
|
|
4
|
+
reinitializeMemoryBackends,
|
|
5
|
+
shutdownToolMemory
|
|
6
|
+
} from "./chunk-ESP6U3LW.js";
|
|
7
|
+
import "./chunk-6T3EPABN.js";
|
|
8
|
+
import "./chunk-3QH2KWLH.js";
|
|
9
|
+
import "./chunk-UGAKYSDO.js";
|
|
10
|
+
import "./chunk-2XRPKJKX.js";
|
|
11
|
+
import "./chunk-FIQSOSQU.js";
|
|
12
|
+
import "./chunk-OCJEYHUQ.js";
|
|
13
|
+
import "./chunk-5SXGPX34.js";
|
|
14
|
+
import "./chunk-L4QFWOOQ.js";
|
|
15
|
+
import "./chunk-ZPWHCABL.js";
|
|
16
|
+
export {
|
|
17
|
+
ToolMemoryManager,
|
|
18
|
+
getToolMemory,
|
|
19
|
+
reinitializeMemoryBackends,
|
|
20
|
+
shutdownToolMemory
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=tool-memory-RAQWOUXV.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StatsOnlyAdapter,
|
|
3
|
+
ensureSharedMemoryRegistry
|
|
4
|
+
} from "./chunk-UGAKYSDO.js";
|
|
5
|
+
import "./chunk-2XRPKJKX.js";
|
|
6
|
+
import "./chunk-L4QFWOOQ.js";
|
|
7
|
+
import "./chunk-ZPWHCABL.js";
|
|
8
|
+
export {
|
|
9
|
+
StatsOnlyAdapter,
|
|
10
|
+
ensureSharedMemoryRegistry
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=tool-memory-registry-adapters-Y4EGADHN.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
UnifiedAdapterRegistry,
|
|
3
|
+
createUnifiedRegistry,
|
|
4
|
+
getGlobalRegistry,
|
|
5
|
+
resetGlobalRegistry,
|
|
6
|
+
withDefaultOnRetirement
|
|
7
|
+
} from "./chunk-HMZT2SJK.js";
|
|
8
|
+
import "./chunk-GWOXPCIF.js";
|
|
9
|
+
import "./chunk-ZII5MDUO.js";
|
|
10
|
+
import "./chunk-7E5UXA4U.js";
|
|
11
|
+
import "./chunk-7G63H7ZT.js";
|
|
12
|
+
import "./chunk-KOVTOPEQ.js";
|
|
13
|
+
import "./chunk-FIQSOSQU.js";
|
|
14
|
+
import "./chunk-OCJEYHUQ.js";
|
|
15
|
+
import "./chunk-5SXGPX34.js";
|
|
16
|
+
import "./chunk-L4QFWOOQ.js";
|
|
17
|
+
import "./chunk-ZPWHCABL.js";
|
|
18
|
+
export {
|
|
19
|
+
UnifiedAdapterRegistry,
|
|
20
|
+
createUnifiedRegistry,
|
|
21
|
+
getGlobalRegistry,
|
|
22
|
+
resetGlobalRegistry,
|
|
23
|
+
withDefaultOnRetirement
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=unified-registry-L5PGLSEI.js.map
|
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
getAdaptiveBonus,
|
|
4
4
|
queryWithLookback,
|
|
5
5
|
shouldExplore
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-OCJEYHUQ.js";
|
|
7
|
+
import "./chunk-5SXGPX34.js";
|
|
8
|
+
import "./chunk-L4QFWOOQ.js";
|
|
8
9
|
import "./chunk-ZPWHCABL.js";
|
|
9
10
|
export {
|
|
10
11
|
generateWeatherReport,
|
|
@@ -12,4 +13,4 @@ export {
|
|
|
12
13
|
queryWithLookback,
|
|
13
14
|
shouldExplore
|
|
14
15
|
};
|
|
15
|
-
//# sourceMappingURL=weather-report-
|
|
16
|
+
//# sourceMappingURL=weather-report-TEBEALS7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-agents",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.136.0",
|
|
4
4
|
"description": "Governance substrate for AI coding agents — adversarial PR review, drift-detected rules, tamper-evident audit, and closed-loop outcome routing for Claude, Codex, Gemini, and OpenCode",
|
|
5
5
|
"mcpName": "io.github.nexus-substrate/nexus-agents",
|
|
6
6
|
"license": "MIT",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"typedoc-plugin-frontmatter": "1.3.1",
|
|
91
91
|
"typedoc-plugin-markdown": "4.12.0",
|
|
92
92
|
"vitest": "4.1.9",
|
|
93
|
-
"nexus-memory": "0.1.
|
|
93
|
+
"nexus-memory": "0.1.3"
|
|
94
94
|
},
|
|
95
95
|
"peerDependencies": {
|
|
96
96
|
"@ai-sdk/anthropic": "^3.0.0",
|