nexus-agents 2.71.0 → 2.72.1
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/{adaptive-memory-MKSYEBST.js → adaptive-memory-UPE76IP6.js} +5 -5
- package/dist/{chunk-DWLATKBK.js → child-mcp-config-5HRJGLCR.js} +6 -4
- package/dist/child-mcp-config-5HRJGLCR.js.map +1 -0
- package/dist/{chunk-ZPPX2K57.js → chunk-2KB63QGE.js} +2 -2
- package/dist/{chunk-L2LQ3TSV.js → chunk-2MD5MWCK.js} +2 -2
- package/dist/{chunk-ANC3HU6F.js → chunk-345KMHWH.js} +6 -6
- package/dist/chunk-345KMHWH.js.map +1 -0
- package/dist/{chunk-NER7H3RJ.js → chunk-3FIDMWFC.js} +2 -2
- package/dist/{chunk-POQQ7A5E.js → chunk-53K3KEKT.js} +51 -707
- package/dist/chunk-53K3KEKT.js.map +1 -0
- package/dist/chunk-5MHIWRKB.js +691 -0
- package/dist/chunk-5MHIWRKB.js.map +1 -0
- package/dist/{chunk-VGZJIR22.js → chunk-5WQ3SRSE.js} +2 -2
- package/dist/{chunk-TOYPY5XA.js → chunk-A35XORXU.js} +73 -10
- package/dist/chunk-A35XORXU.js.map +1 -0
- package/dist/chunk-BVETPIOQ.js +556 -0
- package/dist/chunk-BVETPIOQ.js.map +1 -0
- package/dist/{chunk-7LHQBMBM.js → chunk-C3JGKBL2.js} +25 -12
- package/dist/{chunk-7LHQBMBM.js.map → chunk-C3JGKBL2.js.map} +1 -1
- package/dist/{chunk-OF7CYMMA.js → chunk-DA5UDQYW.js} +2 -2
- package/dist/{chunk-XATH462F.js → chunk-ES6GFP35.js} +186 -34
- package/dist/chunk-ES6GFP35.js.map +1 -0
- package/dist/chunk-GOT7OAL5.js +59 -0
- package/dist/chunk-GOT7OAL5.js.map +1 -0
- package/dist/{chunk-LJT65EA7.js → chunk-I7ORMAO7.js} +2 -2
- package/dist/{chunk-AGVLFRN7.js → chunk-J4VR2WNI.js} +2998 -7188
- package/dist/chunk-J4VR2WNI.js.map +1 -0
- package/dist/{chunk-LMRKHQG5.js → chunk-L6N2S3UB.js} +2 -2
- package/dist/{chunk-7OBFO4GF.js → chunk-O4KUCF5S.js} +125 -40
- package/dist/chunk-O4KUCF5S.js.map +1 -0
- package/dist/chunk-P5OFZWDW.js +303 -0
- package/dist/chunk-P5OFZWDW.js.map +1 -0
- package/dist/{chunk-MJHOSM5U.js → chunk-QECRZ3YA.js} +2 -2
- package/dist/{chunk-WYSHXPKK.js → chunk-QL4HCYRD.js} +4 -44
- package/dist/chunk-QL4HCYRD.js.map +1 -0
- package/dist/{chunk-E66KFRSJ.js → chunk-TF3GROMO.js} +2 -2
- package/dist/{chunk-U3HZQTUF.js → chunk-TQFRPFMG.js} +2 -2
- package/dist/{chunk-KJCSRP34.js → chunk-V7ATY4BG.js} +3 -3
- package/dist/{chunk-32RIOULO.js → chunk-VPC3YNFR.js} +2 -2
- package/dist/{chunk-3BKVYSY6.js → chunk-VTVKC4FS.js} +4 -4
- package/dist/{chunk-U6BK5DQU.js → chunk-YOREAPF6.js} +315 -31
- package/dist/chunk-YOREAPF6.js.map +1 -0
- package/dist/cli-circuit-breaker-GFF2RLBZ.js +14 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +1038 -1581
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-AYVJPIOS.js → composite-router-33F3F74I.js} +4 -4
- package/dist/{consensus-vote-EXWACBMR.js → consensus-vote-5V4KVHBE.js} +12 -11
- package/dist/doctor-deep-AHDTNURD.js +13 -0
- package/dist/expert-bridge-DMDHHDEU.js +11 -0
- package/dist/factory-FVD7PZ6S.js +15 -0
- package/dist/{factory-KMBWFIX2.js → factory-VQS3HJ7V.js} +6 -6
- package/dist/index.d.ts +997 -3517
- package/dist/index.js +74 -807
- package/dist/index.js.map +1 -1
- package/dist/init-opencode-EIOIPVWL.js +158 -0
- package/dist/init-opencode-EIOIPVWL.js.map +1 -0
- package/dist/issue-triage-HJUJWGAD.js +16 -0
- package/dist/{learning-persistence-FILWP3IR.js → learning-persistence-N6ILD2HX.js} +3 -3
- package/dist/{mobimem-77W5ED4Z.js → mobimem-BOJFXQ7B.js} +4 -4
- package/dist/{nexus-data-dir-M6DYKIHJ.js → nexus-data-dir-77UO7N6J.js} +2 -2
- package/dist/{registry-command-BBLIXULQ.js → registry-command-NCWUJKAF.js} +4 -4
- package/dist/{repo-security-plan-7SNM7JQN.js → repo-security-plan-3J45VAD6.js} +5 -5
- package/dist/research-helpers-synthesize-UGQHZZJN.js +12 -0
- package/dist/{routing-memory-DCIZEEVC.js → routing-memory-NO7QEH7T.js} +4 -4
- package/dist/{session-memory-5TSAASQW.js → session-memory-DOXLEWEU.js} +5 -5
- package/dist/{setup-command-5VGIQETA.js → setup-command-BWUFMZ7U.js} +10 -10
- package/dist/setup-config-E3JZYSLR.js +11 -0
- package/dist/{setup-custom-api-IQX3GD2D.js → setup-custom-api-DHJ5DRH2.js} +6 -6
- package/dist/{weather-report-NETGWTJX.js → weather-report-FNN4OX3N.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-7OBFO4GF.js.map +0 -1
- package/dist/chunk-AGVLFRN7.js.map +0 -1
- package/dist/chunk-ANC3HU6F.js.map +0 -1
- package/dist/chunk-DWLATKBK.js.map +0 -1
- package/dist/chunk-FDNWRZNJ.js +0 -22
- package/dist/chunk-FDNWRZNJ.js.map +0 -1
- package/dist/chunk-POQQ7A5E.js.map +0 -1
- package/dist/chunk-TOYPY5XA.js.map +0 -1
- package/dist/chunk-U6BK5DQU.js.map +0 -1
- package/dist/chunk-WYSHXPKK.js.map +0 -1
- package/dist/chunk-XATH462F.js.map +0 -1
- package/dist/cli-circuit-breaker-2CJ6NV52.js +0 -14
- package/dist/doctor-deep-BJFDBGPO.js +0 -13
- package/dist/expert-bridge-75WNNWI4.js +0 -11
- package/dist/factory-H5BYL4V5.js +0 -15
- package/dist/issue-triage-4SEP4WID.js +0 -16
- package/dist/mcp-config-OCWIXE2Y.js +0 -13
- package/dist/research-helpers-synthesize-7CI2FJE5.js +0 -12
- package/dist/setup-config-EA5RDIO2.js +0 -11
- package/dist/weather-report-NETGWTJX.js.map +0 -1
- /package/dist/{adaptive-memory-MKSYEBST.js.map → adaptive-memory-UPE76IP6.js.map} +0 -0
- /package/dist/{chunk-ZPPX2K57.js.map → chunk-2KB63QGE.js.map} +0 -0
- /package/dist/{chunk-L2LQ3TSV.js.map → chunk-2MD5MWCK.js.map} +0 -0
- /package/dist/{chunk-NER7H3RJ.js.map → chunk-3FIDMWFC.js.map} +0 -0
- /package/dist/{chunk-VGZJIR22.js.map → chunk-5WQ3SRSE.js.map} +0 -0
- /package/dist/{chunk-OF7CYMMA.js.map → chunk-DA5UDQYW.js.map} +0 -0
- /package/dist/{chunk-LJT65EA7.js.map → chunk-I7ORMAO7.js.map} +0 -0
- /package/dist/{chunk-LMRKHQG5.js.map → chunk-L6N2S3UB.js.map} +0 -0
- /package/dist/{chunk-MJHOSM5U.js.map → chunk-QECRZ3YA.js.map} +0 -0
- /package/dist/{chunk-E66KFRSJ.js.map → chunk-TF3GROMO.js.map} +0 -0
- /package/dist/{chunk-U3HZQTUF.js.map → chunk-TQFRPFMG.js.map} +0 -0
- /package/dist/{chunk-KJCSRP34.js.map → chunk-V7ATY4BG.js.map} +0 -0
- /package/dist/{chunk-32RIOULO.js.map → chunk-VPC3YNFR.js.map} +0 -0
- /package/dist/{chunk-3BKVYSY6.js.map → chunk-VTVKC4FS.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-2CJ6NV52.js.map → cli-circuit-breaker-GFF2RLBZ.js.map} +0 -0
- /package/dist/{composite-router-AYVJPIOS.js.map → composite-router-33F3F74I.js.map} +0 -0
- /package/dist/{consensus-vote-EXWACBMR.js.map → consensus-vote-5V4KVHBE.js.map} +0 -0
- /package/dist/{doctor-deep-BJFDBGPO.js.map → doctor-deep-AHDTNURD.js.map} +0 -0
- /package/dist/{expert-bridge-75WNNWI4.js.map → expert-bridge-DMDHHDEU.js.map} +0 -0
- /package/dist/{factory-H5BYL4V5.js.map → factory-FVD7PZ6S.js.map} +0 -0
- /package/dist/{factory-KMBWFIX2.js.map → factory-VQS3HJ7V.js.map} +0 -0
- /package/dist/{issue-triage-4SEP4WID.js.map → issue-triage-HJUJWGAD.js.map} +0 -0
- /package/dist/{learning-persistence-FILWP3IR.js.map → learning-persistence-N6ILD2HX.js.map} +0 -0
- /package/dist/{mcp-config-OCWIXE2Y.js.map → mobimem-BOJFXQ7B.js.map} +0 -0
- /package/dist/{mobimem-77W5ED4Z.js.map → nexus-data-dir-77UO7N6J.js.map} +0 -0
- /package/dist/{registry-command-BBLIXULQ.js.map → registry-command-NCWUJKAF.js.map} +0 -0
- /package/dist/{nexus-data-dir-M6DYKIHJ.js.map → repo-security-plan-3J45VAD6.js.map} +0 -0
- /package/dist/{repo-security-plan-7SNM7JQN.js.map → research-helpers-synthesize-UGQHZZJN.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-7CI2FJE5.js.map → routing-memory-NO7QEH7T.js.map} +0 -0
- /package/dist/{routing-memory-DCIZEEVC.js.map → session-memory-DOXLEWEU.js.map} +0 -0
- /package/dist/{session-memory-5TSAASQW.js.map → setup-command-BWUFMZ7U.js.map} +0 -0
- /package/dist/{setup-command-5VGIQETA.js.map → setup-config-E3JZYSLR.js.map} +0 -0
- /package/dist/{setup-custom-api-IQX3GD2D.js.map → setup-custom-api-DHJ5DRH2.js.map} +0 -0
- /package/dist/{setup-config-EA5RDIO2.js.map → weather-report-FNN4OX3N.js.map} +0 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULTS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2MD5MWCK.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveInsideRoot
|
|
6
6
|
} from "./chunk-NUBSJGQZ.js";
|
|
7
7
|
import {
|
|
8
8
|
createAllAdapters
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ES6GFP35.js";
|
|
10
10
|
import {
|
|
11
11
|
capitalize
|
|
12
12
|
} from "./chunk-633WH2ML.js";
|
|
13
13
|
import {
|
|
14
|
+
CLI_SUBPROCESS_TIMEOUTS,
|
|
14
15
|
CliNameSchema,
|
|
15
16
|
DEFAULT_CAPABILITIES,
|
|
16
17
|
DEFAULT_COMPOSITE_CONFIG,
|
|
@@ -26,19 +27,20 @@ import {
|
|
|
26
27
|
ok,
|
|
27
28
|
symbols,
|
|
28
29
|
writeLine
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-O4KUCF5S.js";
|
|
30
31
|
import {
|
|
31
32
|
getLearningDir,
|
|
32
33
|
getOutcomesFile,
|
|
33
34
|
getRulesFile,
|
|
34
35
|
isPersistenceEnabled
|
|
35
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-I7ORMAO7.js";
|
|
36
37
|
import {
|
|
38
|
+
detectSandbox,
|
|
37
39
|
getNexusDataDir
|
|
38
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-GOT7OAL5.js";
|
|
39
41
|
|
|
40
42
|
// src/version.ts
|
|
41
|
-
var VERSION = true ? "2.
|
|
43
|
+
var VERSION = true ? "2.72.1" : "dev";
|
|
42
44
|
|
|
43
45
|
// src/config/schemas-core.ts
|
|
44
46
|
import { z } from "zod";
|
|
@@ -1295,12 +1297,18 @@ function getConfig(options) {
|
|
|
1295
1297
|
}
|
|
1296
1298
|
|
|
1297
1299
|
// src/cli/setup-data-dir.ts
|
|
1298
|
-
import { mkdirSync, existsSync as
|
|
1299
|
-
import { join as
|
|
1300
|
+
import { mkdirSync, existsSync as existsSync4 } from "fs";
|
|
1301
|
+
import { join as join4 } from "path";
|
|
1300
1302
|
|
|
1301
1303
|
// src/cli/doctor.ts
|
|
1302
|
-
import {
|
|
1303
|
-
|
|
1304
|
+
import {
|
|
1305
|
+
existsSync as existsSync3,
|
|
1306
|
+
readFileSync as readFileSync3,
|
|
1307
|
+
readdirSync,
|
|
1308
|
+
accessSync,
|
|
1309
|
+
constants as fsConstants
|
|
1310
|
+
} from "fs";
|
|
1311
|
+
import { join as join3 } from "path";
|
|
1304
1312
|
|
|
1305
1313
|
// src/mcp/server.ts
|
|
1306
1314
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -1600,7 +1608,12 @@ function printRegistryAdvisory(advisory) {
|
|
|
1600
1608
|
writeLine(
|
|
1601
1609
|
`${colors.yellow}${symbols.warn}${colors.reset} Model registry is ${ageText} \u2014 may have stale model data`
|
|
1602
1610
|
);
|
|
1603
|
-
writeLine(
|
|
1611
|
+
writeLine(
|
|
1612
|
+
` ${colors.dim}Update with 'npm update -g nexus-agents' to pick up the latest registry,${colors.reset}`
|
|
1613
|
+
);
|
|
1614
|
+
writeLine(
|
|
1615
|
+
` ${colors.dim}or run 'nexus-agents registry refresh' to probe currently-installed models.${colors.reset}`
|
|
1616
|
+
);
|
|
1604
1617
|
} else {
|
|
1605
1618
|
writeLine(`${formatStatus(true)} Model registry: ${ageText}`);
|
|
1606
1619
|
}
|
|
@@ -1670,6 +1683,42 @@ function printDataDirectory(check) {
|
|
|
1670
1683
|
writeLine(` ${colors.dim}Run: nexus-agents setup${colors.reset}`);
|
|
1671
1684
|
}
|
|
1672
1685
|
}
|
|
1686
|
+
function printSandboxHeader(check) {
|
|
1687
|
+
if (check.active) {
|
|
1688
|
+
writeLine(`${formatStatus(true)} Sandbox flavor: ${check.flavor ?? "(unknown)"}`);
|
|
1689
|
+
writeLine(` ${colors.dim}NEXUS_SANDBOX_ROOT: ${check.root ?? "(unset)"}${colors.reset}`);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
writeLine(
|
|
1693
|
+
`${formatStatus(false, true)} Container detected (${check.heuristicMatch ?? "unknown"}) but ${colors.yellow}NEXUS_SANDBOX is unset${colors.reset}`
|
|
1694
|
+
);
|
|
1695
|
+
writeLine(
|
|
1696
|
+
` ${colors.dim}Set NEXUS_SANDBOX=<flavor> in the image to opt into sandbox-aware behaviour.${colors.reset}`
|
|
1697
|
+
);
|
|
1698
|
+
}
|
|
1699
|
+
function printSandboxWarnings(check) {
|
|
1700
|
+
if (check.mismatch && check.active) {
|
|
1701
|
+
writeLine(
|
|
1702
|
+
` ${colors.yellow}Mismatch: NEXUS_SANDBOX is set but no container heuristic matched (heuristic=${String(check.heuristicMatch)}).${colors.reset}`
|
|
1703
|
+
);
|
|
1704
|
+
}
|
|
1705
|
+
if (check.dataDirInsideRepo) {
|
|
1706
|
+
writeLine(
|
|
1707
|
+
` ${colors.yellow}NEXUS_DATA_DIR resolves inside a single repo subfolder of NEXUS_SANDBOX_ROOT \u2014 state will be lost when switching repos. Set NEXUS_DATA_DIR at the multi-repo root.${colors.reset}`
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
function printSandbox(check) {
|
|
1712
|
+
const heuristicSaysContainer = check.heuristicMatch === "docker" || check.heuristicMatch === "podman";
|
|
1713
|
+
if (!check.active && !heuristicSaysContainer) {
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
writeLine(`${colors.cyan}Checking sandbox awareness...${colors.reset}`);
|
|
1717
|
+
writeLine("");
|
|
1718
|
+
printSandboxHeader(check);
|
|
1719
|
+
printSandboxWarnings(check);
|
|
1720
|
+
writeLine("");
|
|
1721
|
+
}
|
|
1673
1722
|
function printDoctorSummary(result) {
|
|
1674
1723
|
const unhealthyCount = result.clis.filter((c) => !c.installed || !c.authenticated).length;
|
|
1675
1724
|
const nodeIssue = result.nodeVersion.supported ? 0 : 1;
|
|
@@ -1720,9 +1769,197 @@ function printDoctorResults(result) {
|
|
|
1720
1769
|
printSqliteCheck(result.sqliteCheck);
|
|
1721
1770
|
printDataDirectory(result.dataDirectory);
|
|
1722
1771
|
writeLine("");
|
|
1772
|
+
printSandbox(result.sandbox);
|
|
1723
1773
|
printDoctorSummary(result);
|
|
1724
1774
|
}
|
|
1725
1775
|
|
|
1776
|
+
// src/cli/cli-auth-probe.ts
|
|
1777
|
+
import { execFile } from "child_process";
|
|
1778
|
+
import { promisify } from "util";
|
|
1779
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
1780
|
+
import { homedir } from "os";
|
|
1781
|
+
import { join as join2 } from "path";
|
|
1782
|
+
var execFileAsync = promisify(execFile);
|
|
1783
|
+
var HOME = homedir();
|
|
1784
|
+
function claudeNeedsLogin(reason) {
|
|
1785
|
+
return {
|
|
1786
|
+
cli: "claude",
|
|
1787
|
+
state: "needs-login",
|
|
1788
|
+
reason,
|
|
1789
|
+
fixCommand: "claude /login",
|
|
1790
|
+
envFallback: "ANTHROPIC_API_KEY",
|
|
1791
|
+
fixUrl: "https://console.anthropic.com/account/keys"
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
function probeClaude() {
|
|
1795
|
+
if (process.env["ANTHROPIC_API_KEY"] !== void 0 && process.env["ANTHROPIC_API_KEY"] !== "") {
|
|
1796
|
+
return { cli: "claude", state: "authenticated", via: "env-var" };
|
|
1797
|
+
}
|
|
1798
|
+
const credPath = join2(HOME, ".claude", ".credentials.json");
|
|
1799
|
+
if (!existsSync2(credPath)) {
|
|
1800
|
+
return claudeNeedsLogin(
|
|
1801
|
+
"No credentials at ~/.claude/.credentials.json and ANTHROPIC_API_KEY is not set"
|
|
1802
|
+
);
|
|
1803
|
+
}
|
|
1804
|
+
try {
|
|
1805
|
+
const parsed = JSON.parse(readFileSync2(credPath, "utf-8"));
|
|
1806
|
+
if (!isClaudeCredsShape(parsed)) {
|
|
1807
|
+
return claudeNeedsLogin(
|
|
1808
|
+
"Credentials file present but not in expected shape (missing claudeAiOauth.accessToken)"
|
|
1809
|
+
);
|
|
1810
|
+
}
|
|
1811
|
+
const expiresAt = parsed.claudeAiOauth.expiresAt;
|
|
1812
|
+
if (typeof expiresAt === "number" && expiresAt < Date.now()) {
|
|
1813
|
+
return claudeNeedsLogin(`OAuth token expired ${new Date(expiresAt).toISOString()}`);
|
|
1814
|
+
}
|
|
1815
|
+
return {
|
|
1816
|
+
cli: "claude",
|
|
1817
|
+
state: "authenticated",
|
|
1818
|
+
via: "cli-credentials",
|
|
1819
|
+
...typeof expiresAt === "number" ? { meta: { expiresAt } } : {}
|
|
1820
|
+
};
|
|
1821
|
+
} catch (e) {
|
|
1822
|
+
return {
|
|
1823
|
+
cli: "claude",
|
|
1824
|
+
state: "error",
|
|
1825
|
+
reason: `Failed to read claude credentials: ${e instanceof Error ? e.message : String(e)}`
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
function codexNeedsLogin(reason) {
|
|
1830
|
+
return {
|
|
1831
|
+
cli: "codex",
|
|
1832
|
+
state: "needs-login",
|
|
1833
|
+
reason,
|
|
1834
|
+
fixCommand: "codex login",
|
|
1835
|
+
envFallback: "OPENAI_API_KEY",
|
|
1836
|
+
fixUrl: "https://platform.openai.com/api-keys"
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
function classifyCodexStdout(stdout) {
|
|
1840
|
+
if (/not logged/i.test(stdout) || /no.*token/i.test(stdout)) {
|
|
1841
|
+
return codexNeedsLogin(stdout.trim().split("\n")[0] ?? "Not logged in");
|
|
1842
|
+
}
|
|
1843
|
+
return { cli: "codex", state: "authenticated", via: "cli-credentials" };
|
|
1844
|
+
}
|
|
1845
|
+
async function probeCodex() {
|
|
1846
|
+
if (process.env["OPENAI_API_KEY"] !== void 0 && process.env["OPENAI_API_KEY"] !== "") {
|
|
1847
|
+
return { cli: "codex", state: "authenticated", via: "env-var" };
|
|
1848
|
+
}
|
|
1849
|
+
try {
|
|
1850
|
+
const { stdout } = await execFileAsync("codex", ["login", "status"], {
|
|
1851
|
+
timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs
|
|
1852
|
+
});
|
|
1853
|
+
return classifyCodexStdout(stdout);
|
|
1854
|
+
} catch (e) {
|
|
1855
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1856
|
+
if (/ENOENT|not found/i.test(msg)) {
|
|
1857
|
+
return { cli: "codex", state: "not-installed", reason: "codex binary not on PATH" };
|
|
1858
|
+
}
|
|
1859
|
+
return codexNeedsLogin("Not logged in (codex login status returned non-zero)");
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
function geminiNeedsLogin(reason) {
|
|
1863
|
+
return {
|
|
1864
|
+
cli: "gemini",
|
|
1865
|
+
state: "needs-login",
|
|
1866
|
+
reason,
|
|
1867
|
+
fixCommand: "gemini",
|
|
1868
|
+
envFallback: "GOOGLE_AI_API_KEY",
|
|
1869
|
+
fixUrl: "https://aistudio.google.com/apikey"
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1872
|
+
function classifyGeminiCreds(parsed) {
|
|
1873
|
+
if (!isGeminiCredsShape(parsed)) {
|
|
1874
|
+
return geminiNeedsLogin("OAuth credentials file present but not in expected shape");
|
|
1875
|
+
}
|
|
1876
|
+
if (typeof parsed.expiry_date === "number" && parsed.expiry_date < Date.now()) {
|
|
1877
|
+
return geminiNeedsLogin(
|
|
1878
|
+
`OAuth access token expired ${new Date(parsed.expiry_date).toISOString()} (refresh may still work)`
|
|
1879
|
+
);
|
|
1880
|
+
}
|
|
1881
|
+
return {
|
|
1882
|
+
cli: "gemini",
|
|
1883
|
+
state: "authenticated",
|
|
1884
|
+
via: "cli-credentials",
|
|
1885
|
+
...typeof parsed.expiry_date === "number" ? { meta: { expiresAt: parsed.expiry_date } } : {}
|
|
1886
|
+
};
|
|
1887
|
+
}
|
|
1888
|
+
function probeGemini() {
|
|
1889
|
+
const env = process.env["GOOGLE_AI_API_KEY"] ?? process.env["GEMINI_API_KEY"];
|
|
1890
|
+
if (env !== void 0 && env !== "") {
|
|
1891
|
+
return { cli: "gemini", state: "authenticated", via: "env-var" };
|
|
1892
|
+
}
|
|
1893
|
+
const credPath = join2(HOME, ".gemini", "oauth_creds.json");
|
|
1894
|
+
if (!existsSync2(credPath)) {
|
|
1895
|
+
return geminiNeedsLogin(
|
|
1896
|
+
"No OAuth credentials at ~/.gemini/oauth_creds.json and GOOGLE_AI_API_KEY/GEMINI_API_KEY are not set"
|
|
1897
|
+
);
|
|
1898
|
+
}
|
|
1899
|
+
try {
|
|
1900
|
+
return classifyGeminiCreds(JSON.parse(readFileSync2(credPath, "utf-8")));
|
|
1901
|
+
} catch (e) {
|
|
1902
|
+
return {
|
|
1903
|
+
cli: "gemini",
|
|
1904
|
+
state: "error",
|
|
1905
|
+
reason: `Failed to read gemini credentials: ${e instanceof Error ? e.message : String(e)}`
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
async function probeOpencode() {
|
|
1910
|
+
try {
|
|
1911
|
+
const { stdout } = await execFileAsync("opencode", ["auth", "list"], {
|
|
1912
|
+
timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs
|
|
1913
|
+
});
|
|
1914
|
+
if (/0 credentials/i.test(stdout)) {
|
|
1915
|
+
return {
|
|
1916
|
+
cli: "opencode",
|
|
1917
|
+
state: "needs-login",
|
|
1918
|
+
reason: "No providers configured in opencode",
|
|
1919
|
+
fixCommand: "opencode auth login",
|
|
1920
|
+
fixUrl: "https://opencode.ai/docs/config"
|
|
1921
|
+
};
|
|
1922
|
+
}
|
|
1923
|
+
return { cli: "opencode", state: "authenticated", via: "cli-credentials" };
|
|
1924
|
+
} catch (e) {
|
|
1925
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1926
|
+
if (/ENOENT|not found/i.test(msg)) {
|
|
1927
|
+
return { cli: "opencode", state: "not-installed", reason: "opencode binary not on PATH" };
|
|
1928
|
+
}
|
|
1929
|
+
return {
|
|
1930
|
+
cli: "opencode",
|
|
1931
|
+
state: "error",
|
|
1932
|
+
reason: msg.split("\n")[0] ?? "opencode auth list failed"
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
function isClaudeCredsShape(v) {
|
|
1937
|
+
if (typeof v !== "object" || v === null) return false;
|
|
1938
|
+
const oauth = v.claudeAiOauth;
|
|
1939
|
+
if (typeof oauth !== "object" || oauth === null) return false;
|
|
1940
|
+
return typeof oauth.accessToken === "string";
|
|
1941
|
+
}
|
|
1942
|
+
function isGeminiCredsShape(v) {
|
|
1943
|
+
if (typeof v !== "object" || v === null) return false;
|
|
1944
|
+
return typeof v.access_token === "string";
|
|
1945
|
+
}
|
|
1946
|
+
async function probeCli(cli) {
|
|
1947
|
+
switch (cli) {
|
|
1948
|
+
case "claude":
|
|
1949
|
+
return Promise.resolve(probeClaude());
|
|
1950
|
+
case "codex":
|
|
1951
|
+
return probeCodex();
|
|
1952
|
+
case "gemini":
|
|
1953
|
+
return Promise.resolve(probeGemini());
|
|
1954
|
+
case "opencode":
|
|
1955
|
+
return probeOpencode();
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
async function probeAllClis() {
|
|
1959
|
+
const clis = ["claude", "gemini", "codex", "opencode"];
|
|
1960
|
+
return Promise.all(clis.map((c) => probeCli(c)));
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1726
1963
|
// src/cli/doctor.ts
|
|
1727
1964
|
var REQUIRED_NODE_MAJOR2 = 22;
|
|
1728
1965
|
var API_KEY_VARS = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GOOGLE_AI_API_KEY"];
|
|
@@ -1783,8 +2020,9 @@ function detectAuthMethod(name) {
|
|
|
1783
2020
|
};
|
|
1784
2021
|
return authMethods[name];
|
|
1785
2022
|
}
|
|
1786
|
-
function createHealthyResult(name, health, capacity) {
|
|
1787
|
-
const
|
|
2023
|
+
function createHealthyResult(name, health, authProbe, capacity) {
|
|
2024
|
+
const versionOk = health.healthy;
|
|
2025
|
+
const authenticated = versionOk && authProbe.state === "authenticated";
|
|
1788
2026
|
const result = {
|
|
1789
2027
|
name,
|
|
1790
2028
|
installed: true,
|
|
@@ -1797,6 +2035,13 @@ function createHealthyResult(name, health, capacity) {
|
|
|
1797
2035
|
if (health.message !== void 0 && health.message !== "") {
|
|
1798
2036
|
return { ...result, error: health.message };
|
|
1799
2037
|
}
|
|
2038
|
+
if (!authenticated && authProbe.state === "needs-login") {
|
|
2039
|
+
return {
|
|
2040
|
+
...result,
|
|
2041
|
+
error: authProbe.reason,
|
|
2042
|
+
fix: authProbe.fixCommand
|
|
2043
|
+
};
|
|
2044
|
+
}
|
|
1800
2045
|
if (!authenticated) {
|
|
1801
2046
|
return { ...result, fix: getFixCommand(name, "auth") };
|
|
1802
2047
|
}
|
|
@@ -1812,14 +2057,14 @@ async function checkCli(name) {
|
|
|
1812
2057
|
return createNotFoundResult(name, "Adapter not available");
|
|
1813
2058
|
}
|
|
1814
2059
|
try {
|
|
1815
|
-
const health = await adapter.healthCheck();
|
|
2060
|
+
const [health, authProbe] = await Promise.all([adapter.healthCheck(), probeCli(name)]);
|
|
1816
2061
|
let capacity;
|
|
1817
2062
|
try {
|
|
1818
2063
|
capacity = await adapter.getCapacity();
|
|
1819
2064
|
} catch (capErr) {
|
|
1820
2065
|
void capErr;
|
|
1821
2066
|
}
|
|
1822
|
-
return createHealthyResult(name, health, capacity);
|
|
2067
|
+
return createHealthyResult(name, health, authProbe, capacity);
|
|
1823
2068
|
} catch (error) {
|
|
1824
2069
|
const message = getErrorMessage(error);
|
|
1825
2070
|
const isNotFound = message.includes("ENOENT") || message.includes("not found");
|
|
@@ -1843,7 +2088,7 @@ function checkApiKeys() {
|
|
|
1843
2088
|
}
|
|
1844
2089
|
function checkConfigFile() {
|
|
1845
2090
|
for (const configPath of CONFIG_FILE_PATHS) {
|
|
1846
|
-
if (
|
|
2091
|
+
if (existsSync3(configPath)) {
|
|
1847
2092
|
return { found: true, path: configPath };
|
|
1848
2093
|
}
|
|
1849
2094
|
}
|
|
@@ -1865,27 +2110,45 @@ function buildRegistryAdvisory(cliResults) {
|
|
|
1865
2110
|
const reason = available ? `${cliName} CLI is installed` : `${cliName} CLI is not installed`;
|
|
1866
2111
|
return { modelId: m.id, displayName: m.displayName, cliName, available, reason };
|
|
1867
2112
|
});
|
|
1868
|
-
const STALE_THRESHOLD_DAYS =
|
|
2113
|
+
const STALE_THRESHOLD_DAYS = 90;
|
|
1869
2114
|
const updatedAt = new Date(DEFAULT_MODEL_CAPABILITIES.updatedAt);
|
|
1870
2115
|
const nowMs = getTimeProvider().now();
|
|
1871
2116
|
const ageDays = Math.floor((nowMs - updatedAt.getTime()) / (1e3 * 60 * 60 * 24));
|
|
2117
|
+
const isFreshInstall = !hasPriorUsage();
|
|
2118
|
+
const exceedsThreshold = ageDays > STALE_THRESHOLD_DAYS;
|
|
1872
2119
|
return {
|
|
1873
2120
|
totalModels: models.length,
|
|
1874
2121
|
availableModels: models.filter((m) => m.available).length,
|
|
1875
2122
|
unavailableModels: models.filter((m) => !m.available).length,
|
|
1876
2123
|
models,
|
|
1877
2124
|
registryAgeDays: ageDays,
|
|
1878
|
-
registryStale:
|
|
2125
|
+
registryStale: exceedsThreshold && !isFreshInstall
|
|
1879
2126
|
};
|
|
1880
2127
|
}
|
|
2128
|
+
function hasPriorUsage() {
|
|
2129
|
+
try {
|
|
2130
|
+
const root = getNexusDataDir();
|
|
2131
|
+
if (!existsSync3(root)) return false;
|
|
2132
|
+
for (const sub of ["audit", "learning", "sessions", "voting"]) {
|
|
2133
|
+
const p = `${root}/${sub}`;
|
|
2134
|
+
try {
|
|
2135
|
+
if (existsSync3(p) && readdirSync(p).length > 0) return true;
|
|
2136
|
+
} catch {
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
return false;
|
|
2140
|
+
} catch {
|
|
2141
|
+
return false;
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
1881
2144
|
function countJsonlLines(filePath) {
|
|
1882
|
-
if (!
|
|
1883
|
-
return
|
|
2145
|
+
if (!existsSync3(filePath)) return 0;
|
|
2146
|
+
return readFileSync3(filePath, "utf-8").split("\n").filter((l) => l.trim().length > 0).length;
|
|
1884
2147
|
}
|
|
1885
2148
|
function readRulesMetadata(filePath) {
|
|
1886
|
-
if (!
|
|
2149
|
+
if (!existsSync3(filePath)) return { count: 0, savedAt: null };
|
|
1887
2150
|
try {
|
|
1888
|
-
const raw = JSON.parse(
|
|
2151
|
+
const raw = JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
1889
2152
|
const rules = raw["rules"];
|
|
1890
2153
|
const saved = raw["savedAt"];
|
|
1891
2154
|
return {
|
|
@@ -1897,7 +2160,7 @@ function readRulesMetadata(filePath) {
|
|
|
1897
2160
|
}
|
|
1898
2161
|
}
|
|
1899
2162
|
function checkDirAccess(dir) {
|
|
1900
|
-
const exists =
|
|
2163
|
+
const exists = existsSync3(dir);
|
|
1901
2164
|
if (!exists) return { exists: false, writable: false };
|
|
1902
2165
|
try {
|
|
1903
2166
|
accessSync(dir, fsConstants.W_OK);
|
|
@@ -1957,10 +2220,10 @@ async function checkSqlite() {
|
|
|
1957
2220
|
}
|
|
1958
2221
|
function checkDataDirectory() {
|
|
1959
2222
|
const rootPath = getNexusDataDir();
|
|
1960
|
-
const rootExists =
|
|
2223
|
+
const rootExists = existsSync3(rootPath);
|
|
1961
2224
|
const subdirectories = DATA_SUBDIRECTORIES.map((name) => {
|
|
1962
|
-
const fullPath =
|
|
1963
|
-
const exists =
|
|
2225
|
+
const fullPath = join3(rootPath, name);
|
|
2226
|
+
const exists = existsSync3(fullPath);
|
|
1964
2227
|
return { name, path: fullPath, exists, writable: exists && isWritable(fullPath) };
|
|
1965
2228
|
});
|
|
1966
2229
|
return { rootExists, rootPath, subdirectories };
|
|
@@ -1973,6 +2236,24 @@ function isWritable(dirPath) {
|
|
|
1973
2236
|
return false;
|
|
1974
2237
|
}
|
|
1975
2238
|
}
|
|
2239
|
+
function checkSandbox() {
|
|
2240
|
+
const info = detectSandbox();
|
|
2241
|
+
const dataDir = getNexusDataDir();
|
|
2242
|
+
const root = info.root;
|
|
2243
|
+
const dataDirInsideRepo = info.active && root !== void 0 && dataDir.startsWith(`${root.replace(/\/$/, "")}/`) && // path segments BETWEEN root and `.nexus-agents/` indicate the data dir
|
|
2244
|
+
// lives in a subfolder rather than at the multi-repo root.
|
|
2245
|
+
dataDir.replace(`${root.replace(/\/$/, "")}/`, "").split("/").length > 1;
|
|
2246
|
+
const heuristicSaysContainer = info.heuristicMatch === "docker" || info.heuristicMatch === "podman";
|
|
2247
|
+
const mismatch = info.active && info.heuristicMatch === "unknown" || !info.active && heuristicSaysContainer;
|
|
2248
|
+
return {
|
|
2249
|
+
active: info.active,
|
|
2250
|
+
flavor: info.flavor,
|
|
2251
|
+
root: info.root,
|
|
2252
|
+
heuristicMatch: info.heuristicMatch,
|
|
2253
|
+
mismatch,
|
|
2254
|
+
dataDirInsideRepo
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
1976
2257
|
async function runDoctor() {
|
|
1977
2258
|
const clis = await Promise.all([
|
|
1978
2259
|
checkCli("claude"),
|
|
@@ -1990,6 +2271,7 @@ async function runDoctor() {
|
|
|
1990
2271
|
const learningPersistence = checkLearningPersistence();
|
|
1991
2272
|
const sqliteCheck = await checkSqlite();
|
|
1992
2273
|
const dataDirectory = checkDataDirectory();
|
|
2274
|
+
const sandbox = checkSandbox();
|
|
1993
2275
|
const hasAuthMethod = apiKeys.some((k) => k.configured) || clis.some((c) => c.installed && c.authenticated);
|
|
1994
2276
|
const allHealthy = nodeVersion.supported && hasAuthMethod && mcpServerReady && clis.every((c) => c.installed && c.authenticated && c.versionStatus !== "unsupported");
|
|
1995
2277
|
return {
|
|
@@ -2003,6 +2285,7 @@ async function runDoctor() {
|
|
|
2003
2285
|
learningPersistence,
|
|
2004
2286
|
sqliteCheck,
|
|
2005
2287
|
dataDirectory,
|
|
2288
|
+
sandbox,
|
|
2006
2289
|
allHealthy,
|
|
2007
2290
|
timestamp: new Date(getTimeProvider().now())
|
|
2008
2291
|
};
|
|
@@ -2024,7 +2307,7 @@ async function runDoctorFix(result) {
|
|
|
2024
2307
|
writeLine2("\u2500".repeat(40));
|
|
2025
2308
|
let fixCount = 0;
|
|
2026
2309
|
if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
|
|
2027
|
-
const { runSetup } = await import("./setup-command-
|
|
2310
|
+
const { runSetup } = await import("./setup-command-BWUFMZ7U.js");
|
|
2028
2311
|
const setupResult = runSetup({
|
|
2029
2312
|
skipMcp: true,
|
|
2030
2313
|
skipRules: true,
|
|
@@ -2038,7 +2321,7 @@ async function runDoctorFix(result) {
|
|
|
2038
2321
|
}
|
|
2039
2322
|
}
|
|
2040
2323
|
if (!result.configFile.found) {
|
|
2041
|
-
const { runConfigInitSync } = await import("./setup-config-
|
|
2324
|
+
const { runConfigInitSync } = await import("./setup-config-E3JZYSLR.js");
|
|
2042
2325
|
const configResult = runConfigInitSync(process.cwd(), false, false);
|
|
2043
2326
|
if (configResult.success && configResult.created) {
|
|
2044
2327
|
writeLine2(`\u2713 Generated config: ${configResult.path}`);
|
|
@@ -2071,7 +2354,7 @@ function initDataDirectories(dryRun = false) {
|
|
|
2071
2354
|
ensureDir(NEXUS_DATA_DIR, dryRun, created, alreadyExisted);
|
|
2072
2355
|
for (const subdir of DATA_SUBDIRECTORIES) {
|
|
2073
2356
|
const mode = RESTRICTED_DIRS.has(subdir) ? 448 : void 0;
|
|
2074
|
-
ensureDir(
|
|
2357
|
+
ensureDir(join4(NEXUS_DATA_DIR, subdir), dryRun, created, alreadyExisted, mode);
|
|
2075
2358
|
}
|
|
2076
2359
|
return { success: true, rootPath: NEXUS_DATA_DIR, created, alreadyExisted, error: null };
|
|
2077
2360
|
} catch (error) {
|
|
@@ -2080,7 +2363,7 @@ function initDataDirectories(dryRun = false) {
|
|
|
2080
2363
|
}
|
|
2081
2364
|
}
|
|
2082
2365
|
function ensureDir(dirPath, dryRun, created, alreadyExisted, mode) {
|
|
2083
|
-
if (
|
|
2366
|
+
if (existsSync4(dirPath)) {
|
|
2084
2367
|
alreadyExisted.push(dirPath);
|
|
2085
2368
|
return;
|
|
2086
2369
|
}
|
|
@@ -2122,6 +2405,7 @@ export {
|
|
|
2122
2405
|
filterAvailableModels,
|
|
2123
2406
|
DEFAULT_TASK_TTL_MS,
|
|
2124
2407
|
clampTaskTtl,
|
|
2408
|
+
probeAllClis,
|
|
2125
2409
|
DATA_SUBDIRECTORIES,
|
|
2126
2410
|
checkApiKeys,
|
|
2127
2411
|
checkSqlite,
|
|
@@ -2134,4 +2418,4 @@ export {
|
|
|
2134
2418
|
startStdioServer,
|
|
2135
2419
|
closeServer
|
|
2136
2420
|
};
|
|
2137
|
-
//# sourceMappingURL=chunk-
|
|
2421
|
+
//# sourceMappingURL=chunk-YOREAPF6.js.map
|