nexus-agents 2.26.1 → 2.28.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/README.md +7 -7
- package/dist/{chunk-X33QNBGA.js → chunk-E7EX2KQJ.js} +3 -5
- package/dist/{chunk-X33QNBGA.js.map → chunk-E7EX2KQJ.js.map} +1 -1
- package/dist/{chunk-BOWNZMPH.js → chunk-L2SHSW4T.js} +3017 -1300
- package/dist/chunk-L2SHSW4T.js.map +1 -0
- package/dist/{chunk-ARNVVQ5W.js → chunk-LKSTILEE.js} +1213 -117
- package/dist/chunk-LKSTILEE.js.map +1 -0
- package/dist/{chunk-L3LQ3RP5.js → chunk-QZEAD6AG.js} +10339 -6289
- package/dist/chunk-QZEAD6AG.js.map +1 -0
- package/dist/{chunk-LCHCASB7.js → chunk-UGNLR4NZ.js} +2 -2
- package/dist/{chunk-UVQ7R4C4.js → chunk-YSDUVCCZ.js} +137 -717
- package/dist/chunk-YSDUVCCZ.js.map +1 -0
- package/dist/cli.d.ts +8 -1
- package/dist/cli.js +644 -216
- package/dist/cli.js.map +1 -1
- package/dist/{dist-Y5F6UM2N.js → dist-H5XNXVAV.js} +1384 -1295
- package/dist/dist-H5XNXVAV.js.map +1 -0
- package/dist/doctor-deep-BDE2PHVX.js +11 -0
- package/dist/index.d.ts +4299 -7411
- package/dist/index.js +588 -132
- package/dist/index.js.map +1 -1
- package/dist/{setup-command-VNF3KTCJ.js → setup-command-SS7LMN7Y.js} +5 -6
- package/dist/setup-config-DSMOOLVW.js +9 -0
- package/dist/workflows/templates/code-review.yaml +1 -1
- package/dist/workflows/templates/refactoring.yaml +1 -1
- package/dist/workflows/templates/research-review.yaml +19 -4
- package/dist/workflows/templates/security-audit.yaml +1 -1
- package/dist/workflows/templates/standards-review.yaml +1 -1
- package/package.json +12 -12
- package/src/workflows/templates/code-review.yaml +1 -1
- package/src/workflows/templates/refactoring.yaml +1 -1
- package/src/workflows/templates/research-review.yaml +19 -4
- package/src/workflows/templates/security-audit.yaml +1 -1
- package/src/workflows/templates/standards-review.yaml +1 -1
- package/dist/chunk-ARNVVQ5W.js.map +0 -1
- package/dist/chunk-BOWNZMPH.js.map +0 -1
- package/dist/chunk-L3LQ3RP5.js.map +0 -1
- package/dist/chunk-LCDOP543.js +0 -365
- package/dist/chunk-LCDOP543.js.map +0 -1
- package/dist/chunk-PGNRXCYY.js +0 -776
- package/dist/chunk-PGNRXCYY.js.map +0 -1
- package/dist/chunk-UVQ7R4C4.js.map +0 -1
- package/dist/dist-Y5F6UM2N.js.map +0 -1
- package/dist/doctor-deep-I2J5CRFG.js +0 -13
- package/dist/setup-config-VQSWWJ5O.js +0 -9
- /package/dist/{chunk-LCHCASB7.js.map → chunk-UGNLR4NZ.js.map} +0 -0
- /package/dist/{doctor-deep-I2J5CRFG.js.map → doctor-deep-BDE2PHVX.js.map} +0 -0
- /package/dist/{setup-command-VNF3KTCJ.js.map → setup-command-SS7LMN7Y.js.map} +0 -0
- /package/dist/{setup-config-VQSWWJ5O.js.map → setup-config-DSMOOLVW.js.map} +0 -0
|
@@ -1,35 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VERSION,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
createServer
|
|
6
|
-
} from "./chunk-ARNVVQ5W.js";
|
|
3
|
+
initDataDirectories
|
|
4
|
+
} from "./chunk-LKSTILEE.js";
|
|
7
5
|
import {
|
|
8
6
|
runConfigInitSync
|
|
9
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-UGNLR4NZ.js";
|
|
10
8
|
import {
|
|
11
|
-
CLI_SUBPROCESS_TIMEOUTS
|
|
12
|
-
} from "./chunk-LCDOP543.js";
|
|
13
|
-
import {
|
|
14
|
-
DEFAULT_CAPABILITIES,
|
|
15
|
-
DEFAULT_MODEL_CAPABILITIES,
|
|
16
|
-
LEARNING_DIR,
|
|
17
|
-
OUTCOMES_FILE,
|
|
18
|
-
RULES_FILE,
|
|
19
|
-
colors,
|
|
9
|
+
CLI_SUBPROCESS_TIMEOUTS,
|
|
20
10
|
createLogger,
|
|
21
11
|
formatCodeBlock,
|
|
22
12
|
formatHeader,
|
|
23
13
|
formatStatus,
|
|
24
14
|
getErrorMessage,
|
|
25
|
-
getTimeProvider
|
|
26
|
-
|
|
27
|
-
symbols,
|
|
28
|
-
writeLine
|
|
29
|
-
} from "./chunk-BOWNZMPH.js";
|
|
15
|
+
getTimeProvider
|
|
16
|
+
} from "./chunk-L2SHSW4T.js";
|
|
30
17
|
|
|
31
18
|
// src/cli/setup-command.ts
|
|
32
|
-
import { existsSync as
|
|
19
|
+
import { existsSync as existsSync4 } from "fs";
|
|
33
20
|
|
|
34
21
|
// src/cli/setup-types.ts
|
|
35
22
|
import { z } from "zod";
|
|
@@ -160,7 +147,8 @@ function detectProjectInfo(root) {
|
|
|
160
147
|
try {
|
|
161
148
|
const content = readFileSync(join(root, "package.json"), "utf-8");
|
|
162
149
|
const pkg = JSON.parse(content);
|
|
163
|
-
|
|
150
|
+
const nameValue = pkg["name"];
|
|
151
|
+
packageName = typeof nameValue === "string" ? nameValue : void 0;
|
|
164
152
|
} catch (parseErr) {
|
|
165
153
|
void parseErr;
|
|
166
154
|
}
|
|
@@ -500,606 +488,11 @@ function isInteractive() {
|
|
|
500
488
|
return true;
|
|
501
489
|
}
|
|
502
490
|
|
|
503
|
-
// src/cli/setup-data-dir.ts
|
|
504
|
-
import { mkdirSync as mkdirSync2, existsSync as existsSync3 } from "fs";
|
|
505
|
-
import { homedir as homedir4 } from "os";
|
|
506
|
-
import { join as join5 } from "path";
|
|
507
|
-
|
|
508
|
-
// src/cli/doctor.ts
|
|
509
|
-
import { existsSync as existsSync2, readFileSync as readFileSync3, accessSync, constants as fsConstants } from "fs";
|
|
510
|
-
import { homedir as homedir3 } from "os";
|
|
511
|
-
import { join as join4 } from "path";
|
|
512
|
-
|
|
513
|
-
// src/cli/doctor-formatting.ts
|
|
514
|
-
var REQUIRED_NODE_MAJOR = 22;
|
|
515
|
-
function formatStatus2(healthy, warn = false) {
|
|
516
|
-
if (healthy) return `${colors.green}${symbols.check}${colors.reset}`;
|
|
517
|
-
if (warn) return `${colors.yellow}${symbols.warn}${colors.reset}`;
|
|
518
|
-
return `${colors.red}${symbols.cross}${colors.reset}`;
|
|
519
|
-
}
|
|
520
|
-
function formatVersionStatus(status) {
|
|
521
|
-
switch (status) {
|
|
522
|
-
case "supported":
|
|
523
|
-
return `${colors.green}supported${colors.reset}`;
|
|
524
|
-
case "outdated":
|
|
525
|
-
return `${colors.yellow}outdated${colors.reset}`;
|
|
526
|
-
case "unsupported":
|
|
527
|
-
case "breaking":
|
|
528
|
-
return `${colors.red}${status}${colors.reset}`;
|
|
529
|
-
default:
|
|
530
|
-
return status;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
function formatCapacity(capacity) {
|
|
534
|
-
if (capacity === void 0) return "Unknown";
|
|
535
|
-
const remaining = 100 - capacity.utilizationPercent;
|
|
536
|
-
const remainingStr = String(remaining);
|
|
537
|
-
if (remaining > 80) return `${colors.green}${remainingStr}% remaining${colors.reset}`;
|
|
538
|
-
if (remaining > 20) return `${colors.yellow}${remainingStr}% remaining${colors.reset}`;
|
|
539
|
-
return `${colors.red}${remainingStr}% remaining${colors.reset}`;
|
|
540
|
-
}
|
|
541
|
-
function printInstalledCliDetails(cli) {
|
|
542
|
-
writeLine(` Version: ${cli.version} (${formatVersionStatus(cli.versionStatus)})`);
|
|
543
|
-
const authText = cli.authenticated ? `${colors.green}${cli.authMethod ?? "Authenticated"}${colors.reset}` : `${colors.red}Not authenticated${colors.reset}`;
|
|
544
|
-
writeLine(` Auth: ${authText}`);
|
|
545
|
-
if (cli.capacity !== void 0) {
|
|
546
|
-
writeLine(` Capacity: ${formatCapacity(cli.capacity)}`);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
function printCliResult(cli) {
|
|
550
|
-
const status = cli.installed && cli.authenticated;
|
|
551
|
-
const warn = cli.installed && (!cli.authenticated || cli.versionStatus === "outdated");
|
|
552
|
-
writeLine(
|
|
553
|
-
`${formatStatus2(status, warn)} ${colors.bold}${capitalize(cli.name)} CLI${colors.reset}`
|
|
554
|
-
);
|
|
555
|
-
if (cli.installed) {
|
|
556
|
-
printInstalledCliDetails(cli);
|
|
557
|
-
} else {
|
|
558
|
-
const errorText = cli.error ?? "Not installed";
|
|
559
|
-
writeLine(` ${colors.red}Error: ${errorText}${colors.reset}`);
|
|
560
|
-
}
|
|
561
|
-
if (cli.fix !== void 0 && cli.fix !== "") {
|
|
562
|
-
writeLine(` ${colors.dim}Fix: ${cli.fix}${colors.reset}`);
|
|
563
|
-
}
|
|
564
|
-
writeLine("");
|
|
565
|
-
}
|
|
566
|
-
function printCapabilities(clis) {
|
|
567
|
-
const installedClis = clis.filter((c) => c.installed);
|
|
568
|
-
if (installedClis.length === 0) {
|
|
569
|
-
writeLine(`${formatStatus2(false)} No CLIs installed`);
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
const caps = DEFAULT_CAPABILITIES;
|
|
573
|
-
const bestReasoning = installedClis.reduce(
|
|
574
|
-
(best, c) => caps[c.name].reasoning > caps[best.name].reasoning ? c : best
|
|
575
|
-
);
|
|
576
|
-
const bestContext = installedClis.reduce(
|
|
577
|
-
(best, c) => caps[c.name].contextWindow > caps[best.name].contextWindow ? c : best
|
|
578
|
-
);
|
|
579
|
-
const bestSpeed = installedClis.reduce(
|
|
580
|
-
(best, c) => caps[c.name].speed > caps[best.name].speed ? c : best
|
|
581
|
-
);
|
|
582
|
-
const contextTokensK = (caps[bestContext.name].contextWindow / 1e3).toFixed(0);
|
|
583
|
-
writeLine(
|
|
584
|
-
`${formatStatus2(true)} Complex reasoning: ${colors.bold}${capitalize(bestReasoning.name)}${colors.reset}`
|
|
585
|
-
);
|
|
586
|
-
writeLine(
|
|
587
|
-
`${formatStatus2(true)} Large context: ${colors.bold}${capitalize(bestContext.name)}${colors.reset} (${contextTokensK}K tokens)`
|
|
588
|
-
);
|
|
589
|
-
writeLine(
|
|
590
|
-
`${formatStatus2(true)} Fast execution: ${colors.bold}${capitalize(bestSpeed.name)}${colors.reset}`
|
|
591
|
-
);
|
|
592
|
-
}
|
|
593
|
-
function printNodeVersionCheck(check) {
|
|
594
|
-
const versionText = check.supported ? `${colors.green}${check.version}${colors.reset}` : `${colors.yellow}${check.version}${colors.reset}`;
|
|
595
|
-
writeLine(`${formatStatus2(check.supported, !check.supported)} Node.js version: ${versionText}`);
|
|
596
|
-
if (!check.supported) {
|
|
597
|
-
writeLine(
|
|
598
|
-
` ${colors.dim}Warning: Node.js ${String(REQUIRED_NODE_MAJOR)}.x LTS required${colors.reset}`
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
function printApiKeysCheck(keys) {
|
|
603
|
-
const configuredCount = keys.filter((k) => k.configured).length;
|
|
604
|
-
const configuredNames = keys.filter((k) => k.configured).map((k) => k.name);
|
|
605
|
-
const hasAny = configuredCount > 0;
|
|
606
|
-
writeLine(
|
|
607
|
-
`${formatStatus2(hasAny, !hasAny)} API keys configured: ${String(configuredCount)} of ${String(keys.length)}`
|
|
608
|
-
);
|
|
609
|
-
if (hasAny) {
|
|
610
|
-
writeLine(` ${colors.dim}Keys: ${configuredNames.join(", ")}${colors.reset}`);
|
|
611
|
-
} else {
|
|
612
|
-
writeLine(
|
|
613
|
-
` ${colors.dim}Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_AI_API_KEY${colors.reset}`
|
|
614
|
-
);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
function printConfigFileCheck(check) {
|
|
618
|
-
if (check.found && check.path !== null) {
|
|
619
|
-
writeLine(`${formatStatus2(true)} Configuration loaded: ${check.path}`);
|
|
620
|
-
} else {
|
|
621
|
-
writeLine(`${formatStatus2(false, true)} Configuration file: Not found`);
|
|
622
|
-
writeLine(` ${colors.dim}Run: nexus-agents config init${colors.reset}`);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
function printRegistryAdvisory(advisory) {
|
|
626
|
-
const allAvailable = advisory.unavailableModels === 0;
|
|
627
|
-
const countText = `${String(advisory.availableModels)} of ${String(advisory.totalModels)}`;
|
|
628
|
-
writeLine(`${formatStatus2(allAvailable, !allAvailable)} Models available: ${countText}`);
|
|
629
|
-
if (advisory.unavailableModels > 0) {
|
|
630
|
-
const missing = advisory.models.filter((m) => !m.available);
|
|
631
|
-
for (const m of missing) {
|
|
632
|
-
writeLine(` ${colors.dim}${m.displayName} \u2014 ${m.reason}${colors.reset}`);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
function printLearningPersistence(check) {
|
|
637
|
-
if (!check.enabled) {
|
|
638
|
-
writeLine(`${formatStatus2(true)} Learning persistence: ${colors.dim}Disabled${colors.reset}`);
|
|
639
|
-
writeLine(` ${colors.dim}Set NEXUS_PERSIST_LEARNING=true to enable${colors.reset}`);
|
|
640
|
-
return;
|
|
641
|
-
}
|
|
642
|
-
const healthy = check.dirExists && check.dirWritable && check.error === null;
|
|
643
|
-
writeLine(`${formatStatus2(healthy, !healthy)} Learning persistence: Enabled`);
|
|
644
|
-
if (check.error !== null) {
|
|
645
|
-
writeLine(` ${colors.red}Error: ${check.error}${colors.reset}`);
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
const dirStatus = check.dirExists ? check.dirWritable ? `${colors.green}writable${colors.reset}` : `${colors.red}not writable${colors.reset}` : `${colors.yellow}not created yet${colors.reset}`;
|
|
649
|
-
writeLine(` Data directory: ${dirStatus}`);
|
|
650
|
-
writeLine(` Outcomes: ${String(check.outcomeCount)} recorded`);
|
|
651
|
-
writeLine(` Distilled rules: ${String(check.ruleCount)} active`);
|
|
652
|
-
if (check.rulesLastSaved !== null) {
|
|
653
|
-
writeLine(` Rules last saved: ${check.rulesLastSaved}`);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
function printSqliteCheck(check) {
|
|
657
|
-
if (check.available) {
|
|
658
|
-
writeLine(
|
|
659
|
-
`${formatStatus2(true)} SQLite (better-sqlite3): ${colors.green}Available${colors.reset}`
|
|
660
|
-
);
|
|
661
|
-
} else {
|
|
662
|
-
writeLine(
|
|
663
|
-
`${formatStatus2(false, true)} SQLite (better-sqlite3): ${colors.yellow}Not available${colors.reset}`
|
|
664
|
-
);
|
|
665
|
-
writeLine(
|
|
666
|
-
` ${colors.dim}Memory backends (agentic, adaptive, typed) require it${colors.reset}`
|
|
667
|
-
);
|
|
668
|
-
writeLine(` ${colors.dim}Fix: npm install -g better-sqlite3${colors.reset}`);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
function printDataDirectory(check) {
|
|
672
|
-
if (check.rootExists) {
|
|
673
|
-
const existCount = check.subdirectories.filter((d) => d.exists).length;
|
|
674
|
-
const totalCount = check.subdirectories.length;
|
|
675
|
-
const allExist = existCount === totalCount;
|
|
676
|
-
writeLine(
|
|
677
|
-
`${formatStatus2(allExist, !allExist)} Data directory: ${check.rootPath} (${String(existCount)}/${String(totalCount)} subdirs)`
|
|
678
|
-
);
|
|
679
|
-
if (!allExist) {
|
|
680
|
-
const missing = check.subdirectories.filter((d) => !d.exists);
|
|
681
|
-
for (const dir of missing) {
|
|
682
|
-
writeLine(` ${colors.dim}Missing: ${dir.name}/${colors.reset}`);
|
|
683
|
-
}
|
|
684
|
-
writeLine(` ${colors.dim}Fix: nexus-agents setup${colors.reset}`);
|
|
685
|
-
}
|
|
686
|
-
} else {
|
|
687
|
-
writeLine(
|
|
688
|
-
`${formatStatus2(false, true)} Data directory: ${colors.yellow}Not created${colors.reset}`
|
|
689
|
-
);
|
|
690
|
-
writeLine(` ${colors.dim}Run: nexus-agents setup${colors.reset}`);
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
function printDoctorSummary(result) {
|
|
694
|
-
const unhealthyCount = result.clis.filter((c) => !c.installed || !c.authenticated).length;
|
|
695
|
-
const nodeIssue = result.nodeVersion.supported ? 0 : 1;
|
|
696
|
-
const totalIssues = unhealthyCount + nodeIssue + (result.mcpServerReady ? 0 : 1);
|
|
697
|
-
const summary = result.allHealthy ? `${colors.green}${colors.bold}Status: Ready${colors.reset}` : `${colors.yellow}${colors.bold}Summary: ${String(totalIssues)} issue(s) found${colors.reset}`;
|
|
698
|
-
writeLine(summary);
|
|
699
|
-
writeLine("");
|
|
700
|
-
}
|
|
701
|
-
function printDoctorResults(result) {
|
|
702
|
-
writeLine("");
|
|
703
|
-
writeLine(`${colors.bold}Nexus Agents Doctor${colors.reset}`);
|
|
704
|
-
writeLine("===================");
|
|
705
|
-
writeLine("");
|
|
706
|
-
writeLine(`${colors.cyan}Checking environment...${colors.reset}`);
|
|
707
|
-
writeLine("");
|
|
708
|
-
printNodeVersionCheck(result.nodeVersion);
|
|
709
|
-
printApiKeysCheck(result.apiKeys);
|
|
710
|
-
printConfigFileCheck(result.configFile);
|
|
711
|
-
writeLine("");
|
|
712
|
-
writeLine(`${colors.cyan}Checking CLI installations...${colors.reset}`);
|
|
713
|
-
writeLine("");
|
|
714
|
-
for (const cli of result.clis) {
|
|
715
|
-
printCliResult(cli);
|
|
716
|
-
}
|
|
717
|
-
writeLine(`${colors.cyan}Checking MCP configuration...${colors.reset}`);
|
|
718
|
-
writeLine("");
|
|
719
|
-
writeLine(
|
|
720
|
-
`${formatStatus2(result.mcpServerReady)} MCP Server mode: ${result.mcpServerReady ? "Ready" : "Not ready"}`
|
|
721
|
-
);
|
|
722
|
-
writeLine(
|
|
723
|
-
`${formatStatus2(result.mcpClientReady)} MCP Client mode: ${result.mcpClientReady ? "Ready (Codex mcp-server)" : "Not ready (Codex not installed)"}`
|
|
724
|
-
);
|
|
725
|
-
writeLine("");
|
|
726
|
-
writeLine(`${colors.cyan}Checking capabilities...${colors.reset}`);
|
|
727
|
-
writeLine("");
|
|
728
|
-
printCapabilities(result.clis);
|
|
729
|
-
writeLine("");
|
|
730
|
-
writeLine(`${colors.cyan}Checking model registry...${colors.reset}`);
|
|
731
|
-
writeLine("");
|
|
732
|
-
printRegistryAdvisory(result.registryAdvisory);
|
|
733
|
-
writeLine("");
|
|
734
|
-
writeLine(`${colors.cyan}Checking learning subsystem...${colors.reset}`);
|
|
735
|
-
writeLine("");
|
|
736
|
-
printLearningPersistence(result.learningPersistence);
|
|
737
|
-
writeLine("");
|
|
738
|
-
writeLine(`${colors.cyan}Checking data storage...${colors.reset}`);
|
|
739
|
-
writeLine("");
|
|
740
|
-
printSqliteCheck(result.sqliteCheck);
|
|
741
|
-
printDataDirectory(result.dataDirectory);
|
|
742
|
-
writeLine("");
|
|
743
|
-
printDoctorSummary(result);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// src/cli/doctor.ts
|
|
747
|
-
var REQUIRED_NODE_MAJOR2 = 22;
|
|
748
|
-
var API_KEY_VARS = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GOOGLE_AI_API_KEY"];
|
|
749
|
-
var CONFIG_FILE_PATHS = ["./nexus-agents.yaml", "./nexus-agents.yml"];
|
|
750
|
-
var DATA_SUBDIRECTORIES = [
|
|
751
|
-
"memory",
|
|
752
|
-
"memory/beliefs",
|
|
753
|
-
"learning",
|
|
754
|
-
"sessions",
|
|
755
|
-
"audit",
|
|
756
|
-
"voting",
|
|
757
|
-
"auth",
|
|
758
|
-
"research",
|
|
759
|
-
"checkpoints"
|
|
760
|
-
];
|
|
761
|
-
function getFixCommand(name, issue) {
|
|
762
|
-
const commands = {
|
|
763
|
-
claude: {
|
|
764
|
-
install: "npm install -g @anthropic-ai/claude-code",
|
|
765
|
-
upgrade: "npm update -g @anthropic-ai/claude-code",
|
|
766
|
-
auth: "claude auth login"
|
|
767
|
-
},
|
|
768
|
-
gemini: {
|
|
769
|
-
install: "npm install -g @google/gemini-cli",
|
|
770
|
-
upgrade: "npm update -g @google/gemini-cli",
|
|
771
|
-
auth: "gemini auth login"
|
|
772
|
-
},
|
|
773
|
-
codex: {
|
|
774
|
-
install: "npm install -g @openai/codex",
|
|
775
|
-
upgrade: "npm update -g @openai/codex",
|
|
776
|
-
auth: "codex auth login"
|
|
777
|
-
},
|
|
778
|
-
opencode: {
|
|
779
|
-
install: "npm install -g opencode-ai",
|
|
780
|
-
upgrade: "npm update -g opencode-ai",
|
|
781
|
-
auth: "opencode auth login"
|
|
782
|
-
}
|
|
783
|
-
};
|
|
784
|
-
return commands[name][issue] ?? "";
|
|
785
|
-
}
|
|
786
|
-
function createNotFoundResult(name, errorMsg) {
|
|
787
|
-
return {
|
|
788
|
-
name,
|
|
789
|
-
installed: false,
|
|
790
|
-
version: "N/A",
|
|
791
|
-
versionStatus: "unsupported",
|
|
792
|
-
authenticated: false,
|
|
793
|
-
error: errorMsg,
|
|
794
|
-
fix: getFixCommand(name, "install")
|
|
795
|
-
};
|
|
796
|
-
}
|
|
797
|
-
function detectAuthMethod(name) {
|
|
798
|
-
const authMethods = {
|
|
799
|
-
claude: "CLI auth",
|
|
800
|
-
gemini: "ADC/CLI auth",
|
|
801
|
-
codex: "CLI auth",
|
|
802
|
-
opencode: "CLI auth"
|
|
803
|
-
};
|
|
804
|
-
return authMethods[name];
|
|
805
|
-
}
|
|
806
|
-
function createHealthyResult(name, health, capacity) {
|
|
807
|
-
const authenticated = health.healthy;
|
|
808
|
-
const result = {
|
|
809
|
-
name,
|
|
810
|
-
installed: true,
|
|
811
|
-
version: health.version,
|
|
812
|
-
versionStatus: health.versionStatus,
|
|
813
|
-
authenticated,
|
|
814
|
-
...authenticated && { authMethod: detectAuthMethod(name) },
|
|
815
|
-
...capacity !== void 0 && { capacity }
|
|
816
|
-
};
|
|
817
|
-
if (health.message !== void 0 && health.message !== "") {
|
|
818
|
-
return { ...result, error: health.message };
|
|
819
|
-
}
|
|
820
|
-
if (!authenticated) {
|
|
821
|
-
return { ...result, fix: getFixCommand(name, "auth") };
|
|
822
|
-
}
|
|
823
|
-
if (health.versionStatus === "outdated") {
|
|
824
|
-
return { ...result, fix: getFixCommand(name, "upgrade") };
|
|
825
|
-
}
|
|
826
|
-
return result;
|
|
827
|
-
}
|
|
828
|
-
async function checkCli(name) {
|
|
829
|
-
const adapters = createAllAdapters();
|
|
830
|
-
const adapter = adapters.get(name);
|
|
831
|
-
if (!adapter) {
|
|
832
|
-
return createNotFoundResult(name, "Adapter not available");
|
|
833
|
-
}
|
|
834
|
-
try {
|
|
835
|
-
const health = await adapter.healthCheck();
|
|
836
|
-
let capacity;
|
|
837
|
-
try {
|
|
838
|
-
capacity = await adapter.getCapacity();
|
|
839
|
-
} catch (capErr) {
|
|
840
|
-
void capErr;
|
|
841
|
-
}
|
|
842
|
-
return createHealthyResult(name, health, capacity);
|
|
843
|
-
} catch (error) {
|
|
844
|
-
const message = getErrorMessage(error);
|
|
845
|
-
const isNotFound = message.includes("ENOENT") || message.includes("not found");
|
|
846
|
-
return createNotFoundResult(name, isNotFound ? "Not found in PATH" : message);
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
function checkNodeVersion() {
|
|
850
|
-
const version = process.version;
|
|
851
|
-
const major = Number(version.slice(1).split(".")[0]);
|
|
852
|
-
return {
|
|
853
|
-
version,
|
|
854
|
-
major,
|
|
855
|
-
supported: major >= REQUIRED_NODE_MAJOR2
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
function checkApiKeys() {
|
|
859
|
-
return API_KEY_VARS.map((name) => ({
|
|
860
|
-
name,
|
|
861
|
-
configured: typeof process.env[name] === "string" && process.env[name] !== ""
|
|
862
|
-
}));
|
|
863
|
-
}
|
|
864
|
-
function checkConfigFile() {
|
|
865
|
-
for (const configPath of CONFIG_FILE_PATHS) {
|
|
866
|
-
if (existsSync2(configPath)) {
|
|
867
|
-
return { found: true, path: configPath };
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return { found: false, path: null };
|
|
871
|
-
}
|
|
872
|
-
function checkMcpServerReady() {
|
|
873
|
-
try {
|
|
874
|
-
const result = createServer({ name: "nexus-agents-doctor-check" });
|
|
875
|
-
return result.ok;
|
|
876
|
-
} catch {
|
|
877
|
-
return false;
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
function buildRegistryAdvisory(cliResults) {
|
|
881
|
-
const installedClis = new Set(cliResults.filter((c) => c.installed).map((c) => c.name));
|
|
882
|
-
const models = DEFAULT_MODEL_CAPABILITIES.models.filter((m) => m.cliName !== void 0).map((m) => {
|
|
883
|
-
const cliName = m.cliName;
|
|
884
|
-
const available = installedClis.has(cliName);
|
|
885
|
-
const reason = available ? `${cliName} CLI is installed` : `${cliName} CLI is not installed`;
|
|
886
|
-
return { modelId: m.id, displayName: m.displayName, cliName, available, reason };
|
|
887
|
-
});
|
|
888
|
-
return {
|
|
889
|
-
totalModels: models.length,
|
|
890
|
-
availableModels: models.filter((m) => m.available).length,
|
|
891
|
-
unavailableModels: models.filter((m) => !m.available).length,
|
|
892
|
-
models
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
function countJsonlLines(filePath) {
|
|
896
|
-
if (!existsSync2(filePath)) return 0;
|
|
897
|
-
return readFileSync3(filePath, "utf-8").split("\n").filter((l) => l.trim().length > 0).length;
|
|
898
|
-
}
|
|
899
|
-
function readRulesMetadata(filePath) {
|
|
900
|
-
if (!existsSync2(filePath)) return { count: 0, savedAt: null };
|
|
901
|
-
try {
|
|
902
|
-
const raw = JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
903
|
-
const rules = raw["rules"];
|
|
904
|
-
const saved = raw["savedAt"];
|
|
905
|
-
return {
|
|
906
|
-
count: Array.isArray(rules) ? rules.length : 0,
|
|
907
|
-
savedAt: typeof saved === "string" ? saved : null
|
|
908
|
-
};
|
|
909
|
-
} catch {
|
|
910
|
-
return { count: 0, savedAt: null };
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
function checkDirAccess(dir) {
|
|
914
|
-
const exists = existsSync2(dir);
|
|
915
|
-
if (!exists) return { exists: false, writable: false };
|
|
916
|
-
try {
|
|
917
|
-
accessSync(dir, fsConstants.W_OK);
|
|
918
|
-
return { exists: true, writable: true };
|
|
919
|
-
} catch {
|
|
920
|
-
return { exists: true, writable: false };
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
var DISABLED_CHECK = {
|
|
924
|
-
enabled: false,
|
|
925
|
-
dirExists: false,
|
|
926
|
-
dirWritable: false,
|
|
927
|
-
outcomeCount: 0,
|
|
928
|
-
ruleCount: 0,
|
|
929
|
-
rulesLastSaved: null,
|
|
930
|
-
error: null
|
|
931
|
-
};
|
|
932
|
-
function checkLearningPersistence() {
|
|
933
|
-
if (!isPersistenceEnabled()) return DISABLED_CHECK;
|
|
934
|
-
try {
|
|
935
|
-
const { exists: dirExists, writable: dirWritable } = checkDirAccess(LEARNING_DIR);
|
|
936
|
-
const outcomeCount = countJsonlLines(OUTCOMES_FILE);
|
|
937
|
-
const { count: ruleCount, savedAt: rulesLastSaved } = readRulesMetadata(RULES_FILE);
|
|
938
|
-
return {
|
|
939
|
-
enabled: true,
|
|
940
|
-
dirExists,
|
|
941
|
-
dirWritable,
|
|
942
|
-
outcomeCount,
|
|
943
|
-
ruleCount,
|
|
944
|
-
rulesLastSaved,
|
|
945
|
-
error: null
|
|
946
|
-
};
|
|
947
|
-
} catch (error) {
|
|
948
|
-
return {
|
|
949
|
-
enabled: true,
|
|
950
|
-
dirExists: false,
|
|
951
|
-
dirWritable: false,
|
|
952
|
-
outcomeCount: 0,
|
|
953
|
-
ruleCount: 0,
|
|
954
|
-
rulesLastSaved: null,
|
|
955
|
-
error: getErrorMessage(error)
|
|
956
|
-
};
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
async function checkSqlite() {
|
|
960
|
-
try {
|
|
961
|
-
await import("better-sqlite3");
|
|
962
|
-
return { available: true, error: null };
|
|
963
|
-
} catch (error) {
|
|
964
|
-
const msg = getErrorMessage(error);
|
|
965
|
-
const isNotFound = msg.includes("Cannot find") || msg.includes("MODULE_NOT_FOUND");
|
|
966
|
-
return {
|
|
967
|
-
available: false,
|
|
968
|
-
error: isNotFound ? "better-sqlite3 not installed \u2014 5 memory backends unavailable" : `better-sqlite3 load error: ${msg}`
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
function checkDataDirectory() {
|
|
973
|
-
const rootPath = join4(homedir3(), ".nexus-agents");
|
|
974
|
-
const rootExists = existsSync2(rootPath);
|
|
975
|
-
const subdirectories = DATA_SUBDIRECTORIES.map((name) => {
|
|
976
|
-
const fullPath = join4(rootPath, name);
|
|
977
|
-
return { name, path: fullPath, exists: existsSync2(fullPath) };
|
|
978
|
-
});
|
|
979
|
-
return { rootExists, rootPath, subdirectories };
|
|
980
|
-
}
|
|
981
|
-
async function runDoctor() {
|
|
982
|
-
const clis = await Promise.all([
|
|
983
|
-
checkCli("claude"),
|
|
984
|
-
checkCli("gemini"),
|
|
985
|
-
checkCli("codex"),
|
|
986
|
-
checkCli("opencode")
|
|
987
|
-
]);
|
|
988
|
-
const nodeVersion = checkNodeVersion();
|
|
989
|
-
const apiKeys = checkApiKeys();
|
|
990
|
-
const configFile = checkConfigFile();
|
|
991
|
-
const mcpServerReady = checkMcpServerReady();
|
|
992
|
-
const codexCheck = clis.find((c) => c.name === "codex");
|
|
993
|
-
const mcpClientReady = codexCheck?.installed ?? false;
|
|
994
|
-
const registryAdvisory = buildRegistryAdvisory(clis);
|
|
995
|
-
const learningPersistence = checkLearningPersistence();
|
|
996
|
-
const sqliteCheck = await checkSqlite();
|
|
997
|
-
const dataDirectory = checkDataDirectory();
|
|
998
|
-
const hasAuthMethod = apiKeys.some((k) => k.configured) || clis.some((c) => c.installed && c.authenticated);
|
|
999
|
-
const allHealthy = nodeVersion.supported && hasAuthMethod && mcpServerReady && clis.every((c) => c.installed && c.authenticated && c.versionStatus !== "unsupported");
|
|
1000
|
-
return {
|
|
1001
|
-
clis,
|
|
1002
|
-
nodeVersion,
|
|
1003
|
-
apiKeys,
|
|
1004
|
-
configFile,
|
|
1005
|
-
mcpServerReady,
|
|
1006
|
-
mcpClientReady,
|
|
1007
|
-
registryAdvisory,
|
|
1008
|
-
learningPersistence,
|
|
1009
|
-
sqliteCheck,
|
|
1010
|
-
dataDirectory,
|
|
1011
|
-
allHealthy,
|
|
1012
|
-
timestamp: new Date(getTimeProvider().now())
|
|
1013
|
-
};
|
|
1014
|
-
}
|
|
1015
|
-
async function doctorCommand(options = {}) {
|
|
1016
|
-
const result = await runDoctor();
|
|
1017
|
-
printDoctorResults(result);
|
|
1018
|
-
if (options.fix === true) {
|
|
1019
|
-
await runDoctorFix(result);
|
|
1020
|
-
}
|
|
1021
|
-
return result.allHealthy ? 0 : 1;
|
|
1022
|
-
}
|
|
1023
|
-
async function runDoctorFix(result) {
|
|
1024
|
-
const writeLine4 = (text) => {
|
|
1025
|
-
process.stdout.write(text + "\n");
|
|
1026
|
-
};
|
|
1027
|
-
writeLine4("");
|
|
1028
|
-
writeLine4("\x1B[1mAuto-fix\x1B[0m");
|
|
1029
|
-
writeLine4("\u2500".repeat(40));
|
|
1030
|
-
let fixCount = 0;
|
|
1031
|
-
if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists)) {
|
|
1032
|
-
const { runSetup: runSetup2 } = await import("./setup-command-VNF3KTCJ.js");
|
|
1033
|
-
const setupResult = runSetup2({
|
|
1034
|
-
skipMcp: true,
|
|
1035
|
-
skipRules: true,
|
|
1036
|
-
skipHooks: true,
|
|
1037
|
-
skipConfig: true,
|
|
1038
|
-
skipOpencode: true
|
|
1039
|
-
});
|
|
1040
|
-
if (setupResult.success) {
|
|
1041
|
-
writeLine4("\u2713 Created missing data directories");
|
|
1042
|
-
fixCount++;
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
if (!result.configFile.found) {
|
|
1046
|
-
const { runConfigInitSync: runConfigInitSync2 } = await import("./setup-config-VQSWWJ5O.js");
|
|
1047
|
-
const configResult = runConfigInitSync2(process.cwd(), false, false);
|
|
1048
|
-
if (configResult.success && configResult.created) {
|
|
1049
|
-
writeLine4(`\u2713 Generated config: ${configResult.path}`);
|
|
1050
|
-
fixCount++;
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
if (!result.sqliteCheck.available) {
|
|
1054
|
-
writeLine4("");
|
|
1055
|
-
writeLine4("\u26A0 better-sqlite3 not installed (manual step required):");
|
|
1056
|
-
writeLine4(" npm install -g better-sqlite3");
|
|
1057
|
-
}
|
|
1058
|
-
if (fixCount > 0) {
|
|
1059
|
-
writeLine4("");
|
|
1060
|
-
writeLine4(
|
|
1061
|
-
`\x1B[32m${String(fixCount)} issue(s) fixed.\x1B[0m Re-run \x1B[1mnexus-agents doctor\x1B[0m to verify.`
|
|
1062
|
-
);
|
|
1063
|
-
} else {
|
|
1064
|
-
writeLine4("No auto-fixable issues found.");
|
|
1065
|
-
}
|
|
1066
|
-
writeLine4("");
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
// src/cli/setup-data-dir.ts
|
|
1070
|
-
var NEXUS_DATA_DIR = join5(homedir4(), ".nexus-agents");
|
|
1071
|
-
var RESTRICTED_DIRS = /* @__PURE__ */ new Set(["auth"]);
|
|
1072
|
-
function initDataDirectories(dryRun = false) {
|
|
1073
|
-
const created = [];
|
|
1074
|
-
const alreadyExisted = [];
|
|
1075
|
-
try {
|
|
1076
|
-
ensureDir(NEXUS_DATA_DIR, dryRun, created, alreadyExisted);
|
|
1077
|
-
for (const subdir of DATA_SUBDIRECTORIES) {
|
|
1078
|
-
const mode = RESTRICTED_DIRS.has(subdir) ? 448 : void 0;
|
|
1079
|
-
ensureDir(join5(NEXUS_DATA_DIR, subdir), dryRun, created, alreadyExisted, mode);
|
|
1080
|
-
}
|
|
1081
|
-
return { success: true, rootPath: NEXUS_DATA_DIR, created, alreadyExisted, error: null };
|
|
1082
|
-
} catch (error) {
|
|
1083
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
1084
|
-
return { success: false, rootPath: NEXUS_DATA_DIR, created, alreadyExisted, error: msg };
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
function ensureDir(dirPath, dryRun, created, alreadyExisted, mode) {
|
|
1088
|
-
if (existsSync3(dirPath)) {
|
|
1089
|
-
alreadyExisted.push(dirPath);
|
|
1090
|
-
return;
|
|
1091
|
-
}
|
|
1092
|
-
if (!dryRun) {
|
|
1093
|
-
mkdirSync2(dirPath, { recursive: true, ...mode !== void 0 ? { mode } : {} });
|
|
1094
|
-
}
|
|
1095
|
-
created.push(dirPath);
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
491
|
// src/cli/setup-opencode.ts
|
|
1099
|
-
import { existsSync as
|
|
492
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
1100
493
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
1101
|
-
import { join as
|
|
1102
|
-
import { homedir as
|
|
494
|
+
import { join as join4, resolve } from "path";
|
|
495
|
+
import { homedir as homedir3, platform } from "os";
|
|
1103
496
|
import { parse as jsoncParse, modify, applyEdits } from "jsonc-parser";
|
|
1104
497
|
var logger = createLogger({ component: "setup-opencode" });
|
|
1105
498
|
function detectOpenCodeCli() {
|
|
@@ -1122,7 +515,7 @@ function detectOpenCodeCli() {
|
|
|
1122
515
|
}
|
|
1123
516
|
}
|
|
1124
517
|
function getOpenCodeConfigDir() {
|
|
1125
|
-
return
|
|
518
|
+
return join4(homedir3(), ".config", "opencode");
|
|
1126
519
|
}
|
|
1127
520
|
function getNexusCommand() {
|
|
1128
521
|
return ["npx", "nexus-agents", "--mode=server"];
|
|
@@ -1133,12 +526,12 @@ var NEXUS_MCP_ENTRY = {
|
|
|
1133
526
|
enabled: true
|
|
1134
527
|
};
|
|
1135
528
|
function resolveOpenCodeConfig(dir) {
|
|
1136
|
-
const jsoncPath =
|
|
1137
|
-
if (
|
|
529
|
+
const jsoncPath = join4(dir, "opencode.jsonc");
|
|
530
|
+
if (existsSync2(jsoncPath)) {
|
|
1138
531
|
return { path: jsoncPath, isJsonc: true, exists: true };
|
|
1139
532
|
}
|
|
1140
|
-
const jsonPath =
|
|
1141
|
-
if (
|
|
533
|
+
const jsonPath = join4(dir, "opencode.json");
|
|
534
|
+
if (existsSync2(jsonPath)) {
|
|
1142
535
|
return { path: jsonPath, isJsonc: false, exists: true };
|
|
1143
536
|
}
|
|
1144
537
|
return { path: jsonPath, isJsonc: false, exists: false };
|
|
@@ -1146,7 +539,7 @@ function resolveOpenCodeConfig(dir) {
|
|
|
1146
539
|
function isAlreadyConfigured(resolved) {
|
|
1147
540
|
if (!resolved.exists) return false;
|
|
1148
541
|
try {
|
|
1149
|
-
const raw =
|
|
542
|
+
const raw = readFileSync3(resolved.path, "utf-8");
|
|
1150
543
|
const config = jsoncParse(raw);
|
|
1151
544
|
const mcp = config?.["mcp"];
|
|
1152
545
|
return mcp?.["nexus-agents"] !== void 0;
|
|
@@ -1169,9 +562,9 @@ function writeJsonConfig(configPath) {
|
|
|
1169
562
|
writeFileSync2(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1170
563
|
}
|
|
1171
564
|
function writeOpenCodeConfig(configDir, resolved) {
|
|
1172
|
-
if (!
|
|
565
|
+
if (!existsSync2(configDir)) mkdirSync2(configDir, { recursive: true });
|
|
1173
566
|
if (resolved.exists) {
|
|
1174
|
-
const raw =
|
|
567
|
+
const raw = readFileSync3(resolved.path, "utf-8");
|
|
1175
568
|
writeJsoncConfig(resolved.path, raw);
|
|
1176
569
|
} else {
|
|
1177
570
|
writeJsonConfig(resolved.path);
|
|
@@ -1179,7 +572,7 @@ function writeOpenCodeConfig(configDir, resolved) {
|
|
|
1179
572
|
}
|
|
1180
573
|
function validateProjectRoot(projectRoot) {
|
|
1181
574
|
const resolved = resolve(projectRoot);
|
|
1182
|
-
if (!
|
|
575
|
+
if (!existsSync2(resolved)) {
|
|
1183
576
|
throw new Error(`Project root does not exist: ${resolved}`);
|
|
1184
577
|
}
|
|
1185
578
|
return resolved;
|
|
@@ -1188,7 +581,7 @@ function configureOpenCode(force, dryRun, options) {
|
|
|
1188
581
|
try {
|
|
1189
582
|
return configureOpenCodeInner(force, dryRun, options);
|
|
1190
583
|
} catch (error) {
|
|
1191
|
-
const fallbackPath =
|
|
584
|
+
const fallbackPath = join4(getOpenCodeConfigDir(), "opencode.json");
|
|
1192
585
|
return {
|
|
1193
586
|
success: false,
|
|
1194
587
|
alreadyConfigured: false,
|
|
@@ -1226,10 +619,10 @@ function configureOpenCodeInner(force, dryRun, options) {
|
|
|
1226
619
|
}
|
|
1227
620
|
|
|
1228
621
|
// src/cli/setup-gemini.ts
|
|
1229
|
-
import { existsSync as
|
|
622
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
1230
623
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
1231
|
-
import { join as
|
|
1232
|
-
import { homedir as
|
|
624
|
+
import { join as join5 } from "path";
|
|
625
|
+
import { homedir as homedir4, platform as platform2 } from "os";
|
|
1233
626
|
var logger2 = createLogger({ component: "setup-gemini" });
|
|
1234
627
|
function detectGeminiCli() {
|
|
1235
628
|
try {
|
|
@@ -1252,9 +645,9 @@ function detectGeminiCli() {
|
|
|
1252
645
|
}
|
|
1253
646
|
function getGeminiConfigDir(scope, projectRoot) {
|
|
1254
647
|
if (scope === "project" && projectRoot !== void 0) {
|
|
1255
|
-
return
|
|
648
|
+
return join5(projectRoot, ".gemini");
|
|
1256
649
|
}
|
|
1257
|
-
return
|
|
650
|
+
return join5(homedir4(), ".gemini");
|
|
1258
651
|
}
|
|
1259
652
|
function getNexusMcpEntry() {
|
|
1260
653
|
return {
|
|
@@ -1264,9 +657,9 @@ function getNexusMcpEntry() {
|
|
|
1264
657
|
};
|
|
1265
658
|
}
|
|
1266
659
|
function isAlreadyConfigured2(configPath) {
|
|
1267
|
-
if (!
|
|
660
|
+
if (!existsSync3(configPath)) return false;
|
|
1268
661
|
try {
|
|
1269
|
-
const config = JSON.parse(
|
|
662
|
+
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
1270
663
|
const servers = config["mcpServers"];
|
|
1271
664
|
return servers?.["nexus-agents"] !== void 0;
|
|
1272
665
|
} catch {
|
|
@@ -1275,15 +668,15 @@ function isAlreadyConfigured2(configPath) {
|
|
|
1275
668
|
}
|
|
1276
669
|
}
|
|
1277
670
|
function readExistingConfig(configPath) {
|
|
1278
|
-
if (!
|
|
671
|
+
if (!existsSync3(configPath)) return {};
|
|
1279
672
|
try {
|
|
1280
|
-
return JSON.parse(
|
|
673
|
+
return JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
1281
674
|
} catch {
|
|
1282
675
|
return {};
|
|
1283
676
|
}
|
|
1284
677
|
}
|
|
1285
678
|
function writeGeminiConfig(configDir, configPath) {
|
|
1286
|
-
if (!
|
|
679
|
+
if (!existsSync3(configDir)) mkdirSync3(configDir, { recursive: true });
|
|
1287
680
|
const config = readExistingConfig(configPath);
|
|
1288
681
|
const servers = config["mcpServers"] ?? {};
|
|
1289
682
|
servers["nexus-agents"] = getNexusMcpEntry();
|
|
@@ -1292,7 +685,7 @@ function writeGeminiConfig(configDir, configPath) {
|
|
|
1292
685
|
}
|
|
1293
686
|
function configureGemini(force, dryRun, scope = "user", projectRoot) {
|
|
1294
687
|
const configDir = getGeminiConfigDir(scope, projectRoot);
|
|
1295
|
-
const configPath =
|
|
688
|
+
const configPath = join5(configDir, "settings.json");
|
|
1296
689
|
if (isAlreadyConfigured2(configPath) && !force) {
|
|
1297
690
|
return {
|
|
1298
691
|
success: true,
|
|
@@ -1442,7 +835,7 @@ function printOptions(options, defaultIndex) {
|
|
|
1442
835
|
const option = options[i];
|
|
1443
836
|
const marker = i === defaultIndex ? ">" : " ";
|
|
1444
837
|
const label = option?.label ?? "";
|
|
1445
|
-
|
|
838
|
+
writeLine(` ${marker} ${String(i + 1)}. ${label}`);
|
|
1446
839
|
}
|
|
1447
840
|
}
|
|
1448
841
|
function getOptionValue(options, index, fallbackIndex) {
|
|
@@ -1454,7 +847,7 @@ function getOptionValue(options, index, fallbackIndex) {
|
|
|
1454
847
|
return fallback?.value ?? "";
|
|
1455
848
|
}
|
|
1456
849
|
async function promptSelect(rl, question, options, defaultIndex = 0) {
|
|
1457
|
-
|
|
850
|
+
writeLine("\n" + question);
|
|
1458
851
|
printOptions(options, defaultIndex);
|
|
1459
852
|
const answer = await promptInput(rl, `
|
|
1460
853
|
Choice [1-${String(options.length)}]: `);
|
|
@@ -1467,7 +860,7 @@ Choice [1-${String(options.length)}]: `);
|
|
|
1467
860
|
}
|
|
1468
861
|
return getOptionValue(options, defaultIndex, 0);
|
|
1469
862
|
}
|
|
1470
|
-
function
|
|
863
|
+
function writeLine(text) {
|
|
1471
864
|
process.stdout.write(text + "\n");
|
|
1472
865
|
}
|
|
1473
866
|
function writeEmptyLine() {
|
|
@@ -1475,21 +868,21 @@ function writeEmptyLine() {
|
|
|
1475
868
|
}
|
|
1476
869
|
function printWizardHeader() {
|
|
1477
870
|
writeEmptyLine();
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
871
|
+
writeLine(formatHeader("Nexus Agents Setup Wizard"));
|
|
872
|
+
writeLine("=".repeat(40));
|
|
873
|
+
writeLine("This wizard will help you configure nexus-agents.");
|
|
1481
874
|
writeEmptyLine();
|
|
1482
875
|
}
|
|
1483
876
|
function printStepProgress(state, stepName) {
|
|
1484
|
-
|
|
877
|
+
writeLine(
|
|
1485
878
|
`
|
|
1486
879
|
${formatHeader(`Step ${String(state.currentStep)}/${String(state.totalSteps)}: ${stepName}`)}`
|
|
1487
880
|
);
|
|
1488
|
-
|
|
881
|
+
writeLine("-".repeat(40));
|
|
1489
882
|
}
|
|
1490
883
|
function printCompletion() {
|
|
1491
884
|
writeEmptyLine();
|
|
1492
|
-
|
|
885
|
+
writeLine(formatStatus("success") + " Wizard completed! Running setup...");
|
|
1493
886
|
writeEmptyLine();
|
|
1494
887
|
}
|
|
1495
888
|
var USAGE_MODE_OPTIONS = [
|
|
@@ -1500,29 +893,29 @@ var USAGE_MODE_OPTIONS = [
|
|
|
1500
893
|
];
|
|
1501
894
|
async function askUsageMode(rl, state) {
|
|
1502
895
|
printStepProgress(state, "Usage Mode");
|
|
1503
|
-
|
|
896
|
+
writeLine("How will you use nexus-agents?");
|
|
1504
897
|
const answer = await promptSelect(rl, "", USAGE_MODE_OPTIONS, 0);
|
|
1505
898
|
return answer;
|
|
1506
899
|
}
|
|
1507
900
|
async function askApiKeys(rl, state) {
|
|
1508
901
|
printStepProgress(state, "API Keys");
|
|
1509
|
-
|
|
1510
|
-
|
|
902
|
+
writeLine("nexus-agents works best with API keys configured.");
|
|
903
|
+
writeLine("Supported providers: Anthropic (Claude), OpenAI, Google (Gemini)");
|
|
1511
904
|
writeEmptyLine();
|
|
1512
905
|
const hasKeys = await promptConfirm(rl, "Do you have at least one API key configured?", false);
|
|
1513
906
|
if (!hasKeys) {
|
|
1514
907
|
writeEmptyLine();
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
908
|
+
writeLine("No worries! You can configure API keys later:");
|
|
909
|
+
writeLine(" - ANTHROPIC_API_KEY for Claude");
|
|
910
|
+
writeLine(" - OPENAI_API_KEY for OpenAI/Codex");
|
|
911
|
+
writeLine(" - GOOGLE_AI_API_KEY for Gemini");
|
|
912
|
+
writeLine("\nRun `nexus-agents doctor` to check your configuration.");
|
|
1520
913
|
}
|
|
1521
914
|
return hasKeys;
|
|
1522
915
|
}
|
|
1523
916
|
async function askConfigDirectory(rl, state) {
|
|
1524
917
|
printStepProgress(state, "Configuration");
|
|
1525
|
-
|
|
918
|
+
writeLine("Where should nexus-agents store its configuration?");
|
|
1526
919
|
writeEmptyLine();
|
|
1527
920
|
const defaultDir = process.cwd();
|
|
1528
921
|
const answer = await promptInput(rl, `Directory [${defaultDir}]: `);
|
|
@@ -1530,33 +923,33 @@ async function askConfigDirectory(rl, state) {
|
|
|
1530
923
|
}
|
|
1531
924
|
async function askConfirmation(rl, state, answers) {
|
|
1532
925
|
printStepProgress(state, "Confirmation");
|
|
1533
|
-
|
|
926
|
+
writeLine("Setup will configure the following:");
|
|
1534
927
|
writeEmptyLine();
|
|
1535
928
|
const modeLabel = USAGE_MODE_OPTIONS.find((o) => o.value === answers.usageMode)?.label ?? "Unknown";
|
|
1536
929
|
const apiKeyStatus = answers.hasApiKeys === true ? "Configured" : "Not yet configured";
|
|
1537
930
|
const configDir = answers.configDirectory ?? process.cwd();
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
931
|
+
writeLine(` Usage mode: ${modeLabel}`);
|
|
932
|
+
writeLine(` API keys: ${apiKeyStatus}`);
|
|
933
|
+
writeLine(` Config directory: ${configDir}`);
|
|
1541
934
|
writeEmptyLine();
|
|
1542
935
|
const skipMcp = answers.usageMode === "standalone";
|
|
1543
936
|
if (!skipMcp) {
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
937
|
+
writeLine("Will configure:");
|
|
938
|
+
writeLine(" - MCP server for Claude integration");
|
|
939
|
+
writeLine(" - Rules file (.claude/rules/nexus-agents.md)");
|
|
940
|
+
writeLine(" - Hooks for session tracking");
|
|
1548
941
|
} else {
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
942
|
+
writeLine("Will configure:");
|
|
943
|
+
writeLine(" - Rules file (.claude/rules/nexus-agents.md)");
|
|
944
|
+
writeLine(" - (Skipping MCP/hooks - not needed for standalone mode)");
|
|
1552
945
|
}
|
|
1553
946
|
writeEmptyLine();
|
|
1554
947
|
return promptConfirm(rl, "Proceed with setup?", true);
|
|
1555
948
|
}
|
|
1556
949
|
async function runWizard() {
|
|
1557
950
|
if (!isInteractive()) {
|
|
1558
|
-
|
|
1559
|
-
|
|
951
|
+
writeLine("Interactive mode not available (TTY required).");
|
|
952
|
+
writeLine("Use --non-interactive flag for automated setup.");
|
|
1560
953
|
return void 0;
|
|
1561
954
|
}
|
|
1562
955
|
const rl = createReadline();
|
|
@@ -1577,7 +970,7 @@ async function runWizard() {
|
|
|
1577
970
|
state.currentStep++;
|
|
1578
971
|
if (!state.answers.confirmProceed) {
|
|
1579
972
|
writeEmptyLine();
|
|
1580
|
-
|
|
973
|
+
writeLine("Setup cancelled.");
|
|
1581
974
|
return void 0;
|
|
1582
975
|
}
|
|
1583
976
|
printCompletion();
|
|
@@ -1604,94 +997,94 @@ function convertAnswersToOptions(answers) {
|
|
|
1604
997
|
}
|
|
1605
998
|
|
|
1606
999
|
// src/cli/setup-command.ts
|
|
1607
|
-
function
|
|
1000
|
+
function writeLine2(text) {
|
|
1608
1001
|
process.stdout.write(text + "\n");
|
|
1609
1002
|
}
|
|
1610
1003
|
function writeEmptyLine2() {
|
|
1611
1004
|
process.stdout.write("\n");
|
|
1612
1005
|
}
|
|
1613
1006
|
function printMcpResult(mcpResult, snippet) {
|
|
1614
|
-
|
|
1615
|
-
|
|
1007
|
+
writeLine2(formatHeader("MCP Configuration"));
|
|
1008
|
+
writeLine2("\u2500".repeat(40));
|
|
1616
1009
|
if (mcpResult.success) {
|
|
1617
|
-
|
|
1618
|
-
|
|
1010
|
+
writeLine2(mcpResult.message);
|
|
1011
|
+
writeLine2("Run `/mcp` in Claude Code to verify.");
|
|
1619
1012
|
} else {
|
|
1620
|
-
|
|
1013
|
+
writeLine2(`Failed: ${mcpResult.message}`);
|
|
1621
1014
|
if (snippet !== void 0) {
|
|
1622
1015
|
writeEmptyLine2();
|
|
1623
|
-
|
|
1016
|
+
writeLine2("Manual fallback - run:");
|
|
1624
1017
|
writeEmptyLine2();
|
|
1625
|
-
|
|
1018
|
+
writeLine2(formatCodeBlock(`claude mcp add-json nexus-agents '${snippet}'`));
|
|
1626
1019
|
}
|
|
1627
1020
|
}
|
|
1628
1021
|
writeEmptyLine2();
|
|
1629
1022
|
}
|
|
1630
1023
|
function printRulesFile(rulesPath) {
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1024
|
+
writeLine2(formatHeader("Rules File"));
|
|
1025
|
+
writeLine2("\u2500".repeat(40));
|
|
1026
|
+
writeLine2(`Created: ${rulesPath}`);
|
|
1027
|
+
writeLine2("Claude will now have context about nexus-agents tools.");
|
|
1635
1028
|
writeEmptyLine2();
|
|
1636
1029
|
}
|
|
1637
1030
|
function printHooksResult(hookResult, snippet) {
|
|
1638
|
-
|
|
1639
|
-
|
|
1031
|
+
writeLine2(formatHeader("Hooks Configuration"));
|
|
1032
|
+
writeLine2("\u2500".repeat(40));
|
|
1640
1033
|
if (hookResult.success) {
|
|
1641
|
-
|
|
1642
|
-
|
|
1034
|
+
writeLine2(hookResult.message);
|
|
1035
|
+
writeLine2("Hooks will track sessions, metrics, and validate tool use.");
|
|
1643
1036
|
} else {
|
|
1644
|
-
|
|
1037
|
+
writeLine2(`Note: ${hookResult.message}`);
|
|
1645
1038
|
if (snippet !== void 0) {
|
|
1646
1039
|
writeEmptyLine2();
|
|
1647
|
-
|
|
1040
|
+
writeLine2("Manual fallback - add to ~/.claude/settings.json:");
|
|
1648
1041
|
writeEmptyLine2();
|
|
1649
|
-
|
|
1042
|
+
writeLine2(formatCodeBlock(snippet));
|
|
1650
1043
|
}
|
|
1651
1044
|
}
|
|
1652
1045
|
writeEmptyLine2();
|
|
1653
1046
|
}
|
|
1654
1047
|
function printWarnings(warnings) {
|
|
1655
|
-
|
|
1656
|
-
|
|
1048
|
+
writeLine2(formatHeader("Warnings"));
|
|
1049
|
+
writeLine2("\u2500".repeat(40));
|
|
1657
1050
|
for (const warning of warnings) {
|
|
1658
|
-
|
|
1051
|
+
writeLine2(`\u26A0 ${warning}`);
|
|
1659
1052
|
}
|
|
1660
1053
|
writeEmptyLine2();
|
|
1661
1054
|
}
|
|
1662
1055
|
function printErrors(errors) {
|
|
1663
|
-
|
|
1664
|
-
|
|
1056
|
+
writeLine2(formatHeader("Errors"));
|
|
1057
|
+
writeLine2("\u2500".repeat(40));
|
|
1665
1058
|
for (const error of errors) {
|
|
1666
|
-
|
|
1059
|
+
writeLine2(`\u2717 ${error}`);
|
|
1667
1060
|
}
|
|
1668
1061
|
writeEmptyLine2();
|
|
1669
1062
|
}
|
|
1670
1063
|
function printNextSteps(mcpConfigured, hasMcpSnippet) {
|
|
1671
|
-
|
|
1672
|
-
|
|
1064
|
+
writeLine2(formatHeader("Next Steps"));
|
|
1065
|
+
writeLine2("\u2500".repeat(40));
|
|
1673
1066
|
if (hasMcpSnippet && !mcpConfigured) {
|
|
1674
|
-
|
|
1675
|
-
|
|
1067
|
+
writeLine2("1. Configure MCP manually (see above)");
|
|
1068
|
+
writeLine2("2. Restart Claude Code");
|
|
1676
1069
|
}
|
|
1677
|
-
|
|
1678
|
-
|
|
1070
|
+
writeLine2("3. Run: nexus-agents doctor");
|
|
1071
|
+
writeLine2('4. Try: nexus-agents orchestrate "Hello World"');
|
|
1679
1072
|
writeEmptyLine2();
|
|
1680
1073
|
}
|
|
1681
1074
|
function printSteps(steps, verbose) {
|
|
1682
1075
|
for (const step of steps) {
|
|
1683
1076
|
const status = formatStatus(step.status);
|
|
1684
1077
|
const duration = step.durationMs !== void 0 ? ` (${String(step.durationMs)}ms)` : "";
|
|
1685
|
-
|
|
1078
|
+
writeLine2(`${status} ${step.name}${verbose ? duration : ""}`);
|
|
1686
1079
|
if (step.message !== void 0 && (verbose || step.status === "failed")) {
|
|
1687
|
-
|
|
1080
|
+
writeLine2(` ${step.message}`);
|
|
1688
1081
|
}
|
|
1689
1082
|
}
|
|
1690
1083
|
writeEmptyLine2();
|
|
1691
1084
|
}
|
|
1692
1085
|
function printSummary(success) {
|
|
1693
1086
|
const summary = success ? "\u2713 Setup completed successfully!" : "\u2717 Setup completed with errors";
|
|
1694
|
-
|
|
1087
|
+
writeLine2(success ? `\x1B[32m${summary}\x1B[0m` : `\x1B[31m${summary}\x1B[0m`);
|
|
1695
1088
|
writeEmptyLine2();
|
|
1696
1089
|
}
|
|
1697
1090
|
function runDetectionStep(projectRoot) {
|
|
@@ -1708,6 +1101,31 @@ function runDetectionStep(projectRoot) {
|
|
|
1708
1101
|
}
|
|
1709
1102
|
};
|
|
1710
1103
|
}
|
|
1104
|
+
var REQUIRED_NODE_MAJOR = 22;
|
|
1105
|
+
function runPrerequisiteStep() {
|
|
1106
|
+
const time = getTimeProvider();
|
|
1107
|
+
const startTime = time.now();
|
|
1108
|
+
const warnings = [];
|
|
1109
|
+
const version = process.version;
|
|
1110
|
+
const major = Number(version.slice(1).split(".")[0]);
|
|
1111
|
+
const nodeOk = major >= REQUIRED_NODE_MAJOR;
|
|
1112
|
+
if (!nodeOk) {
|
|
1113
|
+
warnings.push(
|
|
1114
|
+
`Node.js ${version} detected \u2014 v${String(REQUIRED_NODE_MAJOR)}.x+ required. Some features may not work.`
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
const status = nodeOk ? "success" : "warning";
|
|
1118
|
+
const message = nodeOk ? `Node.js ${version} (meets v${String(REQUIRED_NODE_MAJOR)}.x requirement)` : `Node.js ${version} \u2014 v${String(REQUIRED_NODE_MAJOR)}.x+ required`;
|
|
1119
|
+
return {
|
|
1120
|
+
step: {
|
|
1121
|
+
name: "Prerequisite Check",
|
|
1122
|
+
status,
|
|
1123
|
+
message,
|
|
1124
|
+
durationMs: time.now() - startTime
|
|
1125
|
+
},
|
|
1126
|
+
warnings
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1711
1129
|
function makeMcpResult(status, message, startTime, snippet, mcpResult) {
|
|
1712
1130
|
return {
|
|
1713
1131
|
step: {
|
|
@@ -1775,7 +1193,7 @@ function runRulesStep(env, options) {
|
|
|
1775
1193
|
return makeRulesResult("skipped", "Skipped (--skip-rules)", startTime);
|
|
1776
1194
|
}
|
|
1777
1195
|
const rulesPath = getRulesFilePath(env.projectInfo.root);
|
|
1778
|
-
if (
|
|
1196
|
+
if (existsSync4(rulesPath) && !options.force) {
|
|
1779
1197
|
return makeRulesResult(
|
|
1780
1198
|
"skipped",
|
|
1781
1199
|
"Rules file already exists (use --force to overwrite)",
|
|
@@ -1994,6 +1412,8 @@ function runSetup(options = {}) {
|
|
|
1994
1412
|
const warnings = [];
|
|
1995
1413
|
const { env, step: detectionStep } = runDetectionStep(projectRoot);
|
|
1996
1414
|
addClaudeCliWarnings(warnings, env.claudeCli.installed);
|
|
1415
|
+
const { step: prereqStep, warnings: prereqWarnings } = runPrerequisiteStep();
|
|
1416
|
+
warnings.push(...prereqWarnings);
|
|
1997
1417
|
const { step: mcpStep, snippet, mcpResult } = runMcpConfigStep(env, parsedOptions);
|
|
1998
1418
|
const { step: rulesStep, rulesPath } = runRulesStep(env, parsedOptions);
|
|
1999
1419
|
const { step: hooksStep, hookSnippet, hookResult } = runHooksStep(env, parsedOptions);
|
|
@@ -2004,6 +1424,7 @@ function runSetup(options = {}) {
|
|
|
2004
1424
|
const configStep = runConfigStep(projectRoot, parsedOptions);
|
|
2005
1425
|
const steps = [
|
|
2006
1426
|
detectionStep,
|
|
1427
|
+
prereqStep,
|
|
2007
1428
|
mcpStep,
|
|
2008
1429
|
rulesStep,
|
|
2009
1430
|
hooksStep,
|
|
@@ -2047,17 +1468,17 @@ function printDetailSections(result) {
|
|
|
2047
1468
|
if (result.dataDirPath !== void 0) printDataDirSection(result);
|
|
2048
1469
|
}
|
|
2049
1470
|
function printDataDirSection(result) {
|
|
2050
|
-
|
|
2051
|
-
|
|
1471
|
+
writeLine2(formatHeader("Data Directory"));
|
|
1472
|
+
writeLine2("\u2500".repeat(40));
|
|
2052
1473
|
const count = result.dataDirsCreated ?? 0;
|
|
2053
1474
|
const msg = count > 0 ? `Created ${String(count)} directories under ${result.dataDirPath ?? ""}` : `All directories already exist at ${result.dataDirPath ?? ""}`;
|
|
2054
|
-
|
|
1475
|
+
writeLine2(msg);
|
|
2055
1476
|
writeEmptyLine2();
|
|
2056
1477
|
}
|
|
2057
1478
|
function printSetupResult(result, verbose) {
|
|
2058
1479
|
writeEmptyLine2();
|
|
2059
|
-
|
|
2060
|
-
|
|
1480
|
+
writeLine2(formatHeader(`Nexus Agents Setup v${VERSION}`));
|
|
1481
|
+
writeLine2("\u2550".repeat(40));
|
|
2061
1482
|
writeEmptyLine2();
|
|
2062
1483
|
printSteps(result.steps, verbose);
|
|
2063
1484
|
printDetailSections(result);
|
|
@@ -2069,8 +1490,8 @@ function printSetupResult(result, verbose) {
|
|
|
2069
1490
|
function setupCommand(options = {}) {
|
|
2070
1491
|
const parsedOptions = SetupOptionsSchema.parse(options);
|
|
2071
1492
|
if (!isInteractive() && !parsedOptions.nonInteractive) {
|
|
2072
|
-
|
|
2073
|
-
|
|
1493
|
+
writeLine2("Non-interactive environment detected.");
|
|
1494
|
+
writeLine2("Run with --non-interactive or set CI=true.");
|
|
2074
1495
|
return 1;
|
|
2075
1496
|
}
|
|
2076
1497
|
const result = runSetup(options);
|
|
@@ -2100,7 +1521,6 @@ export {
|
|
|
2100
1521
|
runSetup,
|
|
2101
1522
|
printSetupResult,
|
|
2102
1523
|
setupCommand,
|
|
2103
|
-
setupCommandAsync
|
|
2104
|
-
doctorCommand
|
|
1524
|
+
setupCommandAsync
|
|
2105
1525
|
};
|
|
2106
|
-
//# sourceMappingURL=chunk-
|
|
1526
|
+
//# sourceMappingURL=chunk-YSDUVCCZ.js.map
|