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.
Files changed (49) hide show
  1. package/README.md +7 -7
  2. package/dist/{chunk-X33QNBGA.js → chunk-E7EX2KQJ.js} +3 -5
  3. package/dist/{chunk-X33QNBGA.js.map → chunk-E7EX2KQJ.js.map} +1 -1
  4. package/dist/{chunk-BOWNZMPH.js → chunk-L2SHSW4T.js} +3017 -1300
  5. package/dist/chunk-L2SHSW4T.js.map +1 -0
  6. package/dist/{chunk-ARNVVQ5W.js → chunk-LKSTILEE.js} +1213 -117
  7. package/dist/chunk-LKSTILEE.js.map +1 -0
  8. package/dist/{chunk-L3LQ3RP5.js → chunk-QZEAD6AG.js} +10339 -6289
  9. package/dist/chunk-QZEAD6AG.js.map +1 -0
  10. package/dist/{chunk-LCHCASB7.js → chunk-UGNLR4NZ.js} +2 -2
  11. package/dist/{chunk-UVQ7R4C4.js → chunk-YSDUVCCZ.js} +137 -717
  12. package/dist/chunk-YSDUVCCZ.js.map +1 -0
  13. package/dist/cli.d.ts +8 -1
  14. package/dist/cli.js +644 -216
  15. package/dist/cli.js.map +1 -1
  16. package/dist/{dist-Y5F6UM2N.js → dist-H5XNXVAV.js} +1384 -1295
  17. package/dist/dist-H5XNXVAV.js.map +1 -0
  18. package/dist/doctor-deep-BDE2PHVX.js +11 -0
  19. package/dist/index.d.ts +4299 -7411
  20. package/dist/index.js +588 -132
  21. package/dist/index.js.map +1 -1
  22. package/dist/{setup-command-VNF3KTCJ.js → setup-command-SS7LMN7Y.js} +5 -6
  23. package/dist/setup-config-DSMOOLVW.js +9 -0
  24. package/dist/workflows/templates/code-review.yaml +1 -1
  25. package/dist/workflows/templates/refactoring.yaml +1 -1
  26. package/dist/workflows/templates/research-review.yaml +19 -4
  27. package/dist/workflows/templates/security-audit.yaml +1 -1
  28. package/dist/workflows/templates/standards-review.yaml +1 -1
  29. package/package.json +12 -12
  30. package/src/workflows/templates/code-review.yaml +1 -1
  31. package/src/workflows/templates/refactoring.yaml +1 -1
  32. package/src/workflows/templates/research-review.yaml +19 -4
  33. package/src/workflows/templates/security-audit.yaml +1 -1
  34. package/src/workflows/templates/standards-review.yaml +1 -1
  35. package/dist/chunk-ARNVVQ5W.js.map +0 -1
  36. package/dist/chunk-BOWNZMPH.js.map +0 -1
  37. package/dist/chunk-L3LQ3RP5.js.map +0 -1
  38. package/dist/chunk-LCDOP543.js +0 -365
  39. package/dist/chunk-LCDOP543.js.map +0 -1
  40. package/dist/chunk-PGNRXCYY.js +0 -776
  41. package/dist/chunk-PGNRXCYY.js.map +0 -1
  42. package/dist/chunk-UVQ7R4C4.js.map +0 -1
  43. package/dist/dist-Y5F6UM2N.js.map +0 -1
  44. package/dist/doctor-deep-I2J5CRFG.js +0 -13
  45. package/dist/setup-config-VQSWWJ5O.js +0 -9
  46. /package/dist/{chunk-LCHCASB7.js.map → chunk-UGNLR4NZ.js.map} +0 -0
  47. /package/dist/{doctor-deep-I2J5CRFG.js.map → doctor-deep-BDE2PHVX.js.map} +0 -0
  48. /package/dist/{setup-command-VNF3KTCJ.js.map → setup-command-SS7LMN7Y.js.map} +0 -0
  49. /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
- capitalize,
4
- createAllAdapters,
5
- createServer
6
- } from "./chunk-ARNVVQ5W.js";
3
+ initDataDirectories
4
+ } from "./chunk-LKSTILEE.js";
7
5
  import {
8
6
  runConfigInitSync
9
- } from "./chunk-LCHCASB7.js";
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
- isPersistenceEnabled,
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 existsSync6 } from "fs";
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
- packageName = pkg["name"];
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 existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
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 join6, resolve } from "path";
1102
- import { homedir as homedir5, platform } from "os";
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 join6(homedir5(), ".config", "opencode");
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 = join6(dir, "opencode.jsonc");
1137
- if (existsSync4(jsoncPath)) {
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 = join6(dir, "opencode.json");
1141
- if (existsSync4(jsonPath)) {
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 = readFileSync4(resolved.path, "utf-8");
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 (!existsSync4(configDir)) mkdirSync3(configDir, { recursive: true });
565
+ if (!existsSync2(configDir)) mkdirSync2(configDir, { recursive: true });
1173
566
  if (resolved.exists) {
1174
- const raw = readFileSync4(resolved.path, "utf-8");
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 (!existsSync4(resolved)) {
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 = join6(getOpenCodeConfigDir(), "opencode.json");
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 existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "fs";
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 join7 } from "path";
1232
- import { homedir as homedir6, platform as platform2 } from "os";
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 join7(projectRoot, ".gemini");
648
+ return join5(projectRoot, ".gemini");
1256
649
  }
1257
- return join7(homedir6(), ".gemini");
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 (!existsSync5(configPath)) return false;
660
+ if (!existsSync3(configPath)) return false;
1268
661
  try {
1269
- const config = JSON.parse(readFileSync5(configPath, "utf-8"));
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 (!existsSync5(configPath)) return {};
671
+ if (!existsSync3(configPath)) return {};
1279
672
  try {
1280
- return JSON.parse(readFileSync5(configPath, "utf-8"));
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 (!existsSync5(configDir)) mkdirSync4(configDir, { recursive: true });
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 = join7(configDir, "settings.json");
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
- writeLine2(` ${marker} ${String(i + 1)}. ${label}`);
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
- writeLine2("\n" + question);
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 writeLine2(text) {
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
- writeLine2(formatHeader("Nexus Agents Setup Wizard"));
1479
- writeLine2("=".repeat(40));
1480
- writeLine2("This wizard will help you configure nexus-agents.");
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
- writeLine2(
877
+ writeLine(
1485
878
  `
1486
879
  ${formatHeader(`Step ${String(state.currentStep)}/${String(state.totalSteps)}: ${stepName}`)}`
1487
880
  );
1488
- writeLine2("-".repeat(40));
881
+ writeLine("-".repeat(40));
1489
882
  }
1490
883
  function printCompletion() {
1491
884
  writeEmptyLine();
1492
- writeLine2(formatStatus("success") + " Wizard completed! Running setup...");
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
- writeLine2("How will you use nexus-agents?");
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
- writeLine2("nexus-agents works best with API keys configured.");
1510
- writeLine2("Supported providers: Anthropic (Claude), OpenAI, Google (Gemini)");
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
- writeLine2("No worries! You can configure API keys later:");
1516
- writeLine2(" - ANTHROPIC_API_KEY for Claude");
1517
- writeLine2(" - OPENAI_API_KEY for OpenAI/Codex");
1518
- writeLine2(" - GOOGLE_AI_API_KEY for Gemini");
1519
- writeLine2("\nRun `nexus-agents doctor` to check your configuration.");
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
- writeLine2("Where should nexus-agents store its configuration?");
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
- writeLine2("Setup will configure the following:");
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
- writeLine2(` Usage mode: ${modeLabel}`);
1539
- writeLine2(` API keys: ${apiKeyStatus}`);
1540
- writeLine2(` Config directory: ${configDir}`);
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
- writeLine2("Will configure:");
1545
- writeLine2(" - MCP server for Claude integration");
1546
- writeLine2(" - Rules file (.claude/rules/nexus-agents.md)");
1547
- writeLine2(" - Hooks for session tracking");
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
- writeLine2("Will configure:");
1550
- writeLine2(" - Rules file (.claude/rules/nexus-agents.md)");
1551
- writeLine2(" - (Skipping MCP/hooks - not needed for standalone mode)");
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
- writeLine2("Interactive mode not available (TTY required).");
1559
- writeLine2("Use --non-interactive flag for automated setup.");
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
- writeLine2("Setup cancelled.");
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 writeLine3(text) {
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
- writeLine3(formatHeader("MCP Configuration"));
1615
- writeLine3("\u2500".repeat(40));
1007
+ writeLine2(formatHeader("MCP Configuration"));
1008
+ writeLine2("\u2500".repeat(40));
1616
1009
  if (mcpResult.success) {
1617
- writeLine3(mcpResult.message);
1618
- writeLine3("Run `/mcp` in Claude Code to verify.");
1010
+ writeLine2(mcpResult.message);
1011
+ writeLine2("Run `/mcp` in Claude Code to verify.");
1619
1012
  } else {
1620
- writeLine3(`Failed: ${mcpResult.message}`);
1013
+ writeLine2(`Failed: ${mcpResult.message}`);
1621
1014
  if (snippet !== void 0) {
1622
1015
  writeEmptyLine2();
1623
- writeLine3("Manual fallback - run:");
1016
+ writeLine2("Manual fallback - run:");
1624
1017
  writeEmptyLine2();
1625
- writeLine3(formatCodeBlock(`claude mcp add-json nexus-agents '${snippet}'`));
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
- writeLine3(formatHeader("Rules File"));
1632
- writeLine3("\u2500".repeat(40));
1633
- writeLine3(`Created: ${rulesPath}`);
1634
- writeLine3("Claude will now have context about nexus-agents tools.");
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
- writeLine3(formatHeader("Hooks Configuration"));
1639
- writeLine3("\u2500".repeat(40));
1031
+ writeLine2(formatHeader("Hooks Configuration"));
1032
+ writeLine2("\u2500".repeat(40));
1640
1033
  if (hookResult.success) {
1641
- writeLine3(hookResult.message);
1642
- writeLine3("Hooks will track sessions, metrics, and validate tool use.");
1034
+ writeLine2(hookResult.message);
1035
+ writeLine2("Hooks will track sessions, metrics, and validate tool use.");
1643
1036
  } else {
1644
- writeLine3(`Note: ${hookResult.message}`);
1037
+ writeLine2(`Note: ${hookResult.message}`);
1645
1038
  if (snippet !== void 0) {
1646
1039
  writeEmptyLine2();
1647
- writeLine3("Manual fallback - add to ~/.claude/settings.json:");
1040
+ writeLine2("Manual fallback - add to ~/.claude/settings.json:");
1648
1041
  writeEmptyLine2();
1649
- writeLine3(formatCodeBlock(snippet));
1042
+ writeLine2(formatCodeBlock(snippet));
1650
1043
  }
1651
1044
  }
1652
1045
  writeEmptyLine2();
1653
1046
  }
1654
1047
  function printWarnings(warnings) {
1655
- writeLine3(formatHeader("Warnings"));
1656
- writeLine3("\u2500".repeat(40));
1048
+ writeLine2(formatHeader("Warnings"));
1049
+ writeLine2("\u2500".repeat(40));
1657
1050
  for (const warning of warnings) {
1658
- writeLine3(`\u26A0 ${warning}`);
1051
+ writeLine2(`\u26A0 ${warning}`);
1659
1052
  }
1660
1053
  writeEmptyLine2();
1661
1054
  }
1662
1055
  function printErrors(errors) {
1663
- writeLine3(formatHeader("Errors"));
1664
- writeLine3("\u2500".repeat(40));
1056
+ writeLine2(formatHeader("Errors"));
1057
+ writeLine2("\u2500".repeat(40));
1665
1058
  for (const error of errors) {
1666
- writeLine3(`\u2717 ${error}`);
1059
+ writeLine2(`\u2717 ${error}`);
1667
1060
  }
1668
1061
  writeEmptyLine2();
1669
1062
  }
1670
1063
  function printNextSteps(mcpConfigured, hasMcpSnippet) {
1671
- writeLine3(formatHeader("Next Steps"));
1672
- writeLine3("\u2500".repeat(40));
1064
+ writeLine2(formatHeader("Next Steps"));
1065
+ writeLine2("\u2500".repeat(40));
1673
1066
  if (hasMcpSnippet && !mcpConfigured) {
1674
- writeLine3("1. Configure MCP manually (see above)");
1675
- writeLine3("2. Restart Claude Code");
1067
+ writeLine2("1. Configure MCP manually (see above)");
1068
+ writeLine2("2. Restart Claude Code");
1676
1069
  }
1677
- writeLine3("3. Run: nexus-agents doctor");
1678
- writeLine3('4. Try: nexus-agents orchestrate "Hello World"');
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
- writeLine3(`${status} ${step.name}${verbose ? duration : ""}`);
1078
+ writeLine2(`${status} ${step.name}${verbose ? duration : ""}`);
1686
1079
  if (step.message !== void 0 && (verbose || step.status === "failed")) {
1687
- writeLine3(` ${step.message}`);
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
- writeLine3(success ? `\x1B[32m${summary}\x1B[0m` : `\x1B[31m${summary}\x1B[0m`);
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 (existsSync6(rulesPath) && !options.force) {
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
- writeLine3(formatHeader("Data Directory"));
2051
- writeLine3("\u2500".repeat(40));
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
- writeLine3(msg);
1475
+ writeLine2(msg);
2055
1476
  writeEmptyLine2();
2056
1477
  }
2057
1478
  function printSetupResult(result, verbose) {
2058
1479
  writeEmptyLine2();
2059
- writeLine3(formatHeader(`Nexus Agents Setup v${VERSION}`));
2060
- writeLine3("\u2550".repeat(40));
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
- writeLine3("Non-interactive environment detected.");
2073
- writeLine3("Run with --non-interactive or set CI=true.");
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-UVQ7R4C4.js.map
1526
+ //# sourceMappingURL=chunk-YSDUVCCZ.js.map