nexus-agents 2.28.0 → 2.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/README.md +11 -10
  2. package/dist/adaptive-memory-RST6DZYR.js +15 -0
  3. package/dist/chunk-2UR7YN6T.js +700 -0
  4. package/dist/chunk-2UR7YN6T.js.map +1 -0
  5. package/dist/chunk-2UUUKVNR.js +61 -0
  6. package/dist/chunk-2UUUKVNR.js.map +1 -0
  7. package/dist/chunk-3EVVQ32X.js +838 -0
  8. package/dist/chunk-3EVVQ32X.js.map +1 -0
  9. package/dist/{chunk-UGNLR4NZ.js → chunk-3GXDN4AX.js} +2 -2
  10. package/dist/{chunk-LKSTILEE.js → chunk-4AGPR6XZ.js} +194 -1461
  11. package/dist/chunk-4AGPR6XZ.js.map +1 -0
  12. package/dist/chunk-4HA5PAL7.js +246 -0
  13. package/dist/chunk-4HA5PAL7.js.map +1 -0
  14. package/dist/chunk-633WH2ML.js +127 -0
  15. package/dist/chunk-633WH2ML.js.map +1 -0
  16. package/dist/chunk-7SKAKA4I.js +90 -0
  17. package/dist/chunk-7SKAKA4I.js.map +1 -0
  18. package/dist/chunk-AP2FD37C.js +127 -0
  19. package/dist/chunk-AP2FD37C.js.map +1 -0
  20. package/dist/chunk-BC3M4VLP.js +359 -0
  21. package/dist/chunk-BC3M4VLP.js.map +1 -0
  22. package/dist/chunk-BQ4YXGGQ.js +127 -0
  23. package/dist/chunk-BQ4YXGGQ.js.map +1 -0
  24. package/dist/chunk-C2C5ONFR.js +195 -0
  25. package/dist/chunk-C2C5ONFR.js.map +1 -0
  26. package/dist/chunk-CGWRJ4EM.js +12661 -0
  27. package/dist/chunk-CGWRJ4EM.js.map +1 -0
  28. package/dist/chunk-CLYZ7FWP.js +30 -0
  29. package/dist/chunk-CLYZ7FWP.js.map +1 -0
  30. package/dist/chunk-ED6VQWNG.js +63 -0
  31. package/dist/chunk-ED6VQWNG.js.map +1 -0
  32. package/dist/{chunk-L2SHSW4T.js → chunk-ELIFTCYM.js} +2705 -2473
  33. package/dist/chunk-ELIFTCYM.js.map +1 -0
  34. package/dist/chunk-FYJVXQHX.js +944 -0
  35. package/dist/chunk-FYJVXQHX.js.map +1 -0
  36. package/dist/{chunk-QZEAD6AG.js → chunk-FZFZ77UJ.js} +19434 -38182
  37. package/dist/chunk-FZFZ77UJ.js.map +1 -0
  38. package/dist/chunk-IECE6DBS.js +1585 -0
  39. package/dist/chunk-IECE6DBS.js.map +1 -0
  40. package/dist/chunk-LLGUX44Z.js +356 -0
  41. package/dist/chunk-LLGUX44Z.js.map +1 -0
  42. package/dist/chunk-MRU6L7YJ.js +931 -0
  43. package/dist/chunk-MRU6L7YJ.js.map +1 -0
  44. package/dist/chunk-N5SY7V45.js +44 -0
  45. package/dist/chunk-N5SY7V45.js.map +1 -0
  46. package/dist/chunk-OOIPRRPX.js +3790 -0
  47. package/dist/chunk-OOIPRRPX.js.map +1 -0
  48. package/dist/chunk-SRECH7OQ.js +354 -0
  49. package/dist/chunk-SRECH7OQ.js.map +1 -0
  50. package/dist/{chunk-YSDUVCCZ.js → chunk-VKRMXD62.js} +6 -6
  51. package/dist/{chunk-E7EX2KQJ.js → chunk-XU3NADFE.js} +2 -2
  52. package/dist/chunk-YSTJEMQX.js +122 -0
  53. package/dist/chunk-YSTJEMQX.js.map +1 -0
  54. package/dist/cli-circuit-breaker-5FAODXVY.js +13 -0
  55. package/dist/cli.d.ts +2 -2
  56. package/dist/cli.js +1485 -683
  57. package/dist/cli.js.map +1 -1
  58. package/dist/codebase-search-CZUA37RU.js +9 -0
  59. package/dist/composite-router-FNW7ZWL7.js +17 -0
  60. package/dist/composite-router-FNW7ZWL7.js.map +1 -0
  61. package/dist/consensus-vote-757YULIP.js +25 -0
  62. package/dist/consensus-vote-757YULIP.js.map +1 -0
  63. package/dist/{dist-H5XNXVAV.js → dist-CV74KUT7.js} +1521 -972
  64. package/dist/dist-CV74KUT7.js.map +1 -0
  65. package/dist/{doctor-deep-BDE2PHVX.js → doctor-deep-LMCEAFU4.js} +4 -3
  66. package/dist/doctor-deep-LMCEAFU4.js.map +1 -0
  67. package/dist/expert-bridge-L2D4OXOR.js +10 -0
  68. package/dist/expert-bridge-L2D4OXOR.js.map +1 -0
  69. package/dist/expert-config-A5CHKUGI.js +22 -0
  70. package/dist/expert-config-A5CHKUGI.js.map +1 -0
  71. package/dist/factory-ELEDP2WD.js +17 -0
  72. package/dist/factory-ELEDP2WD.js.map +1 -0
  73. package/dist/factory-IDTIBX6B.js +14 -0
  74. package/dist/factory-IDTIBX6B.js.map +1 -0
  75. package/dist/index.d.ts +1814 -777
  76. package/dist/index.js +785 -355
  77. package/dist/index.js.map +1 -1
  78. package/dist/issue-triage-SJPKJLXH.js +15 -0
  79. package/dist/issue-triage-SJPKJLXH.js.map +1 -0
  80. package/dist/learning-persistence-WMWZJZ35.js +16 -0
  81. package/dist/learning-persistence-WMWZJZ35.js.map +1 -0
  82. package/dist/mcp-config-2OXIOMJ6.js +12 -0
  83. package/dist/mcp-config-2OXIOMJ6.js.map +1 -0
  84. package/dist/mobimem-5S3VLNSU.js +13 -0
  85. package/dist/mobimem-5S3VLNSU.js.map +1 -0
  86. package/dist/{model-capabilities-types-CSWO27YN.d.ts → model-capabilities-types-B57GZryc.d.ts} +1 -1
  87. package/dist/repo-analyze-HWMXSK5C.js +24 -0
  88. package/dist/repo-analyze-HWMXSK5C.js.map +1 -0
  89. package/dist/repo-security-plan-MUFDGWSQ.js +17 -0
  90. package/dist/repo-security-plan-MUFDGWSQ.js.map +1 -0
  91. package/dist/research-helpers-synthesize-OBQJ5BGX.js +10 -0
  92. package/dist/research-helpers-synthesize-OBQJ5BGX.js.map +1 -0
  93. package/dist/routing-memory-3QBQTS4A.js +13 -0
  94. package/dist/routing-memory-3QBQTS4A.js.map +1 -0
  95. package/dist/session-memory-VXWLOFRC.js +22 -0
  96. package/dist/session-memory-VXWLOFRC.js.map +1 -0
  97. package/dist/{setup-command-SS7LMN7Y.js → setup-command-E6MXO5RZ.js} +9 -5
  98. package/dist/setup-command-E6MXO5RZ.js.map +1 -0
  99. package/dist/setup-config-O5F3AZBL.js +10 -0
  100. package/dist/setup-config-O5F3AZBL.js.map +1 -0
  101. package/dist/shared-memory-AEO2HJLC.js +8 -0
  102. package/dist/shared-memory-AEO2HJLC.js.map +1 -0
  103. package/dist/symbol-extractor-UEBANFSN.js +10 -0
  104. package/dist/symbol-extractor-UEBANFSN.js.map +1 -0
  105. package/dist/weather-report-MUGSIOU5.js +15 -0
  106. package/dist/weather-report-MUGSIOU5.js.map +1 -0
  107. package/package.json +18 -19
  108. package/dist/chunk-L2SHSW4T.js.map +0 -1
  109. package/dist/chunk-LKSTILEE.js.map +0 -1
  110. package/dist/chunk-QZEAD6AG.js.map +0 -1
  111. package/dist/dist-H5XNXVAV.js.map +0 -1
  112. package/dist/setup-config-DSMOOLVW.js +0 -9
  113. /package/dist/{doctor-deep-BDE2PHVX.js.map → adaptive-memory-RST6DZYR.js.map} +0 -0
  114. /package/dist/{chunk-UGNLR4NZ.js.map → chunk-3GXDN4AX.js.map} +0 -0
  115. /package/dist/{chunk-YSDUVCCZ.js.map → chunk-VKRMXD62.js.map} +0 -0
  116. /package/dist/{chunk-E7EX2KQJ.js.map → chunk-XU3NADFE.js.map} +0 -0
  117. /package/dist/{setup-command-SS7LMN7Y.js.map → cli-circuit-breaker-5FAODXVY.js.map} +0 -0
  118. /package/dist/{setup-config-DSMOOLVW.js.map → codebase-search-CZUA37RU.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -1,44 +1,52 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ calculateConsensus,
4
+ countByCategory,
5
+ countBySeverity,
6
+ createFailedReview,
7
+ determineApproval,
8
+ determineDecision,
9
+ extractSummary,
10
+ formatReviewComment,
11
+ generateSummary,
12
+ parseFindings,
13
+ sumFindings
14
+ } from "./chunk-6E3NMMEY.js";
15
+ import "./chunk-XU3NADFE.js";
16
+ import {
17
+ setupCommandAsync
18
+ } from "./chunk-VKRMXD62.js";
19
+ import "./chunk-3GXDN4AX.js";
2
20
  import {
3
21
  AuthHandler,
4
- BUILT_IN_EXPERTS,
5
22
  CustomExpertDefinitionSchema,
6
23
  DEFAULTS,
7
24
  DEFAULT_EXPERTS,
8
25
  DEFAULT_SWE_BENCH_CONFIG,
9
- DEFAULT_VOTE_TIMEOUT_MS,
10
26
  DEVELOPMENT_POLICY,
11
27
  ExpertFactory,
12
28
  FeedbackIntegration,
13
29
  MAX_SYSTEM_PROMPT_LENGTH,
14
- MemoryError,
15
30
  Orchestrator,
16
31
  PuppeteerOrchestrator,
17
32
  READONLY_POLICY,
18
- RestApiServer,
19
- SwarmObserver2 as SwarmObserver,
20
- THRESHOLD_MAP,
33
+ SwarmObserver,
21
34
  VALID_EXPERT_DOMAINS,
22
35
  VALID_EXPERT_TIERS,
23
- VOTER_ROLES,
24
36
  ValidationDashboard,
25
37
  WorkflowDefinitionSchema,
26
38
  adaptRoutingConfig,
27
39
  addResearchPaper,
28
40
  analyzeTools,
29
- classifyTrust,
30
- collectRealVotes,
41
+ createAgentStages,
31
42
  createAnnotationsProxy,
32
43
  createAuditLogger,
33
44
  createCodeExpert,
34
- createConsensusEngine,
35
45
  createDefaultDeps,
36
46
  createDefaultPolicyEngine,
37
- createDefaultPolicyFirewall,
38
47
  createEventBusBridge,
39
48
  createExecutor,
40
49
  createFeedbackIntegration,
41
- createFullGitHubProvider,
42
50
  createGatewayServerProxy,
43
51
  createHarnessExecutor,
44
52
  createLearnablePolicy,
@@ -48,12 +56,13 @@ import {
48
56
  createRuleBasedPolicy,
49
57
  createSecurityExpert,
50
58
  createSkillLibrary,
59
+ createTaskTracker,
51
60
  createTemplateRegistry,
52
61
  createTestingExpert,
53
62
  createToolObservabilityProxy,
54
63
  createToolRateLimiterFactory,
55
- createUnifiedRegistry,
56
64
  defaultConfig,
65
+ detectBackend,
57
66
  discoverDeepMind,
58
67
  discoverGitHubRepos,
59
68
  discoverGoogleAI,
@@ -62,8 +71,8 @@ import {
62
71
  discoverOpenAlex,
63
72
  discoverPapersWithCode,
64
73
  discoverSemanticScholar,
65
- evaluatePolicy3 as evaluatePolicy,
66
74
  findOverlaps,
75
+ flushPipelineMemory,
67
76
  formatOverlapResult,
68
77
  formatResearchIssueBody,
69
78
  formatStatusResult,
@@ -80,7 +89,6 @@ import {
80
89
  getDefaultTokenPath,
81
90
  getEventBusStats,
82
91
  getExpertRegistry,
83
- getPipelineEventBus,
84
92
  getPipelinePluginRegistry,
85
93
  getResearchStatus,
86
94
  getSandboxMode,
@@ -97,16 +105,15 @@ import {
97
105
  loadAllExternalPacks,
98
106
  loadConfig,
99
107
  loadDataset,
100
- loadTechniquesRegistry,
108
+ loadSourcesRegistry,
101
109
  loadWorkflowFile,
102
- parsePRUrl,
103
110
  rankDiscoveredItems,
104
111
  readStoredToken,
105
- registerConsensusVoteTool,
106
112
  registerCreateExpertTool,
107
113
  registerDelegateToModelTool,
108
114
  registerExecuteExpertTool,
109
115
  registerExecuteSpecTool,
116
+ registerExtractSymbolsTool,
110
117
  registerIssueTriageTool,
111
118
  registerListExpertsTool,
112
119
  registerListWorkflowsTool,
@@ -114,11 +121,13 @@ import {
114
121
  registerMemoryStatsTool,
115
122
  registerMemoryWriteTool,
116
123
  registerOrchestrateTool,
124
+ registerPipelineTool,
117
125
  registerPrompts,
118
126
  registerQueryTraceTool,
119
127
  registerRegistryImportTool,
120
128
  registerRepoAnalyzeTool,
121
129
  registerRepoSecurityPlanTool,
130
+ registerResearchAddSourceTool,
122
131
  registerResearchAddTool,
123
132
  registerResearchAnalyzeTool,
124
133
  registerResearchCatalogReviewTool,
@@ -128,58 +137,88 @@ import {
128
137
  registerResources,
129
138
  registerRunGraphWorkflowTool,
130
139
  registerRunWorkflowTool,
140
+ registerSearchCodebaseTool,
131
141
  registerTools,
132
142
  registerWeatherReportTool,
133
- resolveToken,
134
143
  resolveV2Config,
135
144
  runBenchmarkInstances,
136
- sanitizeInput,
145
+ runDevPipeline,
146
+ saveSourcesRegistry,
137
147
  setGlobalToolRateLimiterFactory,
138
- shutdownToolMemory,
139
- synthesizeResearch,
140
148
  validateArgs,
141
149
  validateCommand,
142
150
  validateNexusEnv,
143
- validateTimeout,
144
151
  validateWorkflow,
145
152
  wrapInMarkdownFence
146
- } from "./chunk-QZEAD6AG.js";
153
+ } from "./chunk-FZFZ77UJ.js";
147
154
  import {
148
- setupCommandAsync
149
- } from "./chunk-YSDUVCCZ.js";
155
+ resolveToken
156
+ } from "./chunk-7SKAKA4I.js";
157
+ import {
158
+ CATEGORY_DISPLAY_NAMES,
159
+ DEFAULT_PR_REVIEW_CONFIG
160
+ } from "./chunk-X2M7OF27.js";
161
+ import {
162
+ DEFAULT_VOTE_TIMEOUT_MS,
163
+ THRESHOLD_MAP,
164
+ VOTER_ROLES,
165
+ collectRealVotes,
166
+ createConsensusEngine,
167
+ createDefaultPolicyFirewall,
168
+ createUnifiedRegistry,
169
+ registerConsensusVoteTool,
170
+ shutdownToolMemory,
171
+ validateTimeout
172
+ } from "./chunk-CGWRJ4EM.js";
173
+ import {
174
+ loadPapersRegistry,
175
+ loadTechniquesRegistry,
176
+ savePapersRegistry,
177
+ synthesizeResearch
178
+ } from "./chunk-MRU6L7YJ.js";
179
+ import {
180
+ classifyTrust,
181
+ createFullGitHubProvider,
182
+ evaluatePolicy,
183
+ parsePRUrl,
184
+ sanitizeInput
185
+ } from "./chunk-IECE6DBS.js";
186
+ import "./chunk-4HA5PAL7.js";
187
+ import "./chunk-2UR7YN6T.js";
188
+ import "./chunk-BC3M4VLP.js";
189
+ import "./chunk-AP2FD37C.js";
190
+ import "./chunk-BQ4YXGGQ.js";
191
+ import "./chunk-ED6VQWNG.js";
192
+ import {
193
+ BUILT_IN_EXPERTS
194
+ } from "./chunk-OOIPRRPX.js";
150
195
  import {
151
196
  VERSION,
152
- capitalize,
153
- capitalizeKebab,
154
197
  closeServer,
155
198
  connectTransport,
156
- createAllAdapters,
157
199
  createServer,
158
200
  doctorCommand,
159
- getAvailableClis,
160
201
  initDataDirectories,
161
- isRecord,
162
- truncateSentence
163
- } from "./chunk-LKSTILEE.js";
164
- import "./chunk-UGNLR4NZ.js";
202
+ runDoctor
203
+ } from "./chunk-3EVVQ32X.js";
204
+ import "./chunk-SRECH7OQ.js";
165
205
  import {
166
- calculateConsensus,
167
- countByCategory,
168
- countBySeverity,
169
- createFailedReview,
170
- determineApproval,
171
- determineDecision,
172
- extractSummary,
173
- formatReviewComment,
174
- generateSummary,
175
- parseFindings,
176
- sumFindings
177
- } from "./chunk-6E3NMMEY.js";
206
+ MemoryError
207
+ } from "./chunk-FYJVXQHX.js";
178
208
  import {
179
- CATEGORY_DISPLAY_NAMES,
180
- DEFAULT_PR_REVIEW_CONFIG
181
- } from "./chunk-X2M7OF27.js";
182
- import "./chunk-E7EX2KQJ.js";
209
+ capitalize,
210
+ capitalizeKebab,
211
+ truncateSentence
212
+ } from "./chunk-633WH2ML.js";
213
+ import "./chunk-2UUUKVNR.js";
214
+ import "./chunk-C2C5ONFR.js";
215
+ import "./chunk-YSTJEMQX.js";
216
+ import {
217
+ createAllAdapters,
218
+ getAvailableClis,
219
+ isRecord
220
+ } from "./chunk-4AGPR6XZ.js";
221
+ import "./chunk-LLGUX44Z.js";
183
222
  import {
184
223
  API_TIMEOUTS,
185
224
  AgentCapability,
@@ -224,6 +263,7 @@ import {
224
263
  getErrorMessage,
225
264
  getModelCapabilities,
226
265
  getOutcomeStore,
266
+ getPipelineEventBus,
227
267
  getRandomProvider,
228
268
  getTimeProvider,
229
269
  logger,
@@ -239,7 +279,8 @@ import {
239
279
  toError,
240
280
  writeEmptyLine,
241
281
  writeLine
242
- } from "./chunk-L2SHSW4T.js";
282
+ } from "./chunk-ELIFTCYM.js";
283
+ import "./chunk-CLYZ7FWP.js";
243
284
  import "./chunk-UP2VWCW5.js";
244
285
 
245
286
  // src/cli.ts
@@ -423,8 +464,8 @@ function resolveOutputPath(output2) {
423
464
  }
424
465
  return resolve(process.cwd(), DEFAULT_CONFIG_FILE);
425
466
  }
426
- function fileExists(path24) {
427
- return existsSync(path24);
467
+ function fileExists(path23) {
468
+ return existsSync(path23);
428
469
  }
429
470
  async function ensureDirectory(filePath) {
430
471
  const dir = dirname(filePath);
@@ -432,9 +473,9 @@ async function ensureDirectory(filePath) {
432
473
  await mkdir(dir, { recursive: true });
433
474
  }
434
475
  }
435
- async function writeConfigFile(path24) {
436
- await ensureDirectory(path24);
437
- await writeFile(path24, CONFIG_TEMPLATE, "utf-8");
476
+ async function writeConfigFile(path23) {
477
+ await ensureDirectory(path23);
478
+ await writeFile(path23, CONFIG_TEMPLATE, "utf-8");
438
479
  }
439
480
  async function runConfigInit(options = {}) {
440
481
  const outputPath = resolveOutputPath(options.output);
@@ -993,14 +1034,14 @@ Hint: Ensure the file exists and the path is correct relative to ${cwd}`
993
1034
  try {
994
1035
  return JSON.parse(content);
995
1036
  } catch (e) {
996
- const msg = e instanceof Error ? e.message : String(e);
1037
+ const msg = getErrorMessage(e);
997
1038
  throw new Error(`Invalid JSON in input file "${inputArg}": ${msg}`);
998
1039
  }
999
1040
  }
1000
1041
  try {
1001
1042
  return JSON.parse(inputArg);
1002
1043
  } catch (e) {
1003
- const msg = e instanceof Error ? e.message : String(e);
1044
+ const msg = getErrorMessage(e);
1004
1045
  throw new Error(
1005
1046
  `Invalid JSON input: ${msg}
1006
1047
  Hint: Provide a valid JSON string or path to a .json file.`
@@ -1403,14 +1444,14 @@ ${colors.dim}Session ended.${colors.reset}
1403
1444
  });
1404
1445
  });
1405
1446
  rl.prompt();
1406
- return new Promise((resolve12) => {
1447
+ return new Promise((resolve14) => {
1407
1448
  rl.on("line", (line) => {
1408
1449
  void (async () => {
1409
1450
  try {
1410
1451
  const shouldExit = await processLine(line, session, logger17);
1411
1452
  if (shouldExit) {
1412
1453
  rl.close();
1413
- resolve12();
1454
+ resolve14();
1414
1455
  return;
1415
1456
  }
1416
1457
  } catch (error) {
@@ -1422,7 +1463,7 @@ ${colors.dim}Session ended.${colors.reset}
1422
1463
  })();
1423
1464
  });
1424
1465
  rl.on("close", () => {
1425
- resolve12();
1466
+ resolve14();
1426
1467
  });
1427
1468
  });
1428
1469
  }
@@ -2416,9 +2457,9 @@ async function evaluateDirectory(target, timeoutMs) {
2416
2457
  }
2417
2458
  const aggregator = createAggregator();
2418
2459
  const results = [];
2419
- for (const [path24, evaluations] of evaluationsByComponent) {
2460
+ for (const [path23, evaluations] of evaluationsByComponent) {
2420
2461
  if (evaluations.length > 0) {
2421
- results.push(aggregator.aggregate(path24, evaluations));
2462
+ results.push(aggregator.aggregate(path23, evaluations));
2422
2463
  }
2423
2464
  }
2424
2465
  const priority = { deprecate: 0, refactor: 1, review: 2, retain: 3 };
@@ -3930,27 +3971,27 @@ var CliAdapterAgent = class {
3930
3971
  };
3931
3972
 
3932
3973
  // src/cli/orchestrate-puppeteer.ts
3933
- function loadPolicyParameters(path24, logger17) {
3974
+ function loadPolicyParameters(path23, logger17) {
3934
3975
  try {
3935
- if (fs2.existsSync(path24)) {
3936
- const content = fs2.readFileSync(path24, "utf-8");
3976
+ if (fs2.existsSync(path23)) {
3977
+ const content = fs2.readFileSync(path23, "utf-8");
3937
3978
  const params = JSON.parse(content);
3938
- logger17.info("Loaded policy parameters", { path: path24 });
3979
+ logger17.info("Loaded policy parameters", { path: path23 });
3939
3980
  return params;
3940
3981
  }
3941
3982
  } catch (error) {
3942
3983
  const message = getErrorMessage(error);
3943
- logger17.warn("Failed to load policy parameters", { path: path24, error: message });
3984
+ logger17.warn("Failed to load policy parameters", { path: path23, error: message });
3944
3985
  }
3945
3986
  return void 0;
3946
3987
  }
3947
- function savePolicyParameters(path24, params, logger17) {
3988
+ function savePolicyParameters(path23, params, logger17) {
3948
3989
  try {
3949
- fs2.writeFileSync(path24, JSON.stringify(params, null, 2));
3950
- logger17.info("Saved policy parameters", { path: path24 });
3990
+ fs2.writeFileSync(path23, JSON.stringify(params, null, 2));
3991
+ logger17.info("Saved policy parameters", { path: path23 });
3951
3992
  } catch (error) {
3952
3993
  const message = getErrorMessage(error);
3953
- logger17.warn("Failed to save policy parameters", { path: path24, error: message });
3994
+ logger17.warn("Failed to save policy parameters", { path: path23, error: message });
3954
3995
  }
3955
3996
  }
3956
3997
  function createAgentsFromAdapters(adapters) {
@@ -6754,15 +6795,7 @@ import * as yaml3 from "yaml";
6754
6795
 
6755
6796
  // src/research/research-schemas.ts
6756
6797
  import { z as z2 } from "zod";
6757
- var ResearchTopicSchema = z2.enum([
6758
- "consensus",
6759
- "routing",
6760
- "memory",
6761
- "code-generation",
6762
- "cli-tools",
6763
- "orchestration",
6764
- "security"
6765
- ]);
6798
+ var ResearchTopicSchema = z2.string().min(1);
6766
6799
  var RESEARCH_TOPICS = [
6767
6800
  "consensus",
6768
6801
  "routing",
@@ -6770,16 +6803,26 @@ var RESEARCH_TOPICS = [
6770
6803
  "code-generation",
6771
6804
  "cli-tools",
6772
6805
  "orchestration",
6773
- "security"
6806
+ "security",
6807
+ "evaluation",
6808
+ "safety",
6809
+ "planning",
6810
+ "tool-use",
6811
+ "reasoning"
6774
6812
  ];
6775
6813
  var TOPIC_DESCRIPTIONS = {
6776
- consensus: "Multi-agent decision protocols",
6777
- routing: "Cost-efficient model routing",
6778
- memory: "Context and long-term memory",
6779
- "code-generation": "Self-improvement and skill learning",
6780
- "cli-tools": "External CLI integration",
6781
- orchestration: "Multi-agent coordination",
6782
- security: "Safety analysis and evaluation"
6814
+ consensus: "Multi-agent decision protocols and voting",
6815
+ routing: "Cost-efficient model routing and selection",
6816
+ memory: "Context, long-term memory, and compression",
6817
+ "code-generation": "Code generation, repair, and self-improvement",
6818
+ "cli-tools": "External CLI integration and protocols",
6819
+ orchestration: "Multi-agent coordination and workflows",
6820
+ security: "Security analysis, prompt injection defense",
6821
+ evaluation: "Benchmarks, metrics, and testing methodologies",
6822
+ safety: "AI safety, alignment, and reward hacking",
6823
+ planning: "Task planning, decomposition, and reasoning chains",
6824
+ "tool-use": "Tool augmentation, function calling, and MCP",
6825
+ reasoning: "Reasoning, self-reflection, and search strategies"
6783
6826
  };
6784
6827
  var TechniqueStatusSchema = z2.enum([
6785
6828
  "implemented",
@@ -6814,7 +6857,8 @@ var ResearchPaperSchema = z2.object({
6814
6857
  /** arXiv ID (e.g., '2501.06322') */
6815
6858
  arxiv_id: z2.string().optional(),
6816
6859
  /** URL to the paper */
6817
- url: z2.url().optional(),
6860
+ // eslint-disable-next-line @typescript-eslint/no-deprecated -- z.url() fails at runtime despite being recommended
6861
+ url: z2.string().url().optional(),
6818
6862
  /** Publication date (YYYY-MM format) */
6819
6863
  publication_date: z2.string().optional(),
6820
6864
  /** Publication venue */
@@ -6823,7 +6867,7 @@ var ResearchPaperSchema = z2.object({
6823
6867
  * Research topics (array).
6824
6868
  * First topic is considered primary for counting purposes.
6825
6869
  */
6826
- topics: z2.array(ResearchTopicSchema).optional().default([]),
6870
+ topics: z2.array(z2.string()).optional().default([]),
6827
6871
  /** Tags for searching */
6828
6872
  tags: z2.array(z2.string()).optional().default([]),
6829
6873
  /** Date when the paper was reviewed (YYYY-MM-DD) */
@@ -6841,7 +6885,28 @@ var ResearchPaperSchema = z2.object({
6841
6885
  /** Related GitHub issues */
6842
6886
  related_issues: z2.array(z2.number().int().positive()).optional().default([]),
6843
6887
  /** Implementation status */
6844
- implementation_status: PaperStatusSchema.optional().default("not-started")
6888
+ implementation_status: PaperStatusSchema.optional().default("not-started"),
6889
+ // ── Quality Assessment (Issue #1571) ──────────────────────────
6890
+ /** Citation count from Semantic Scholar (auto-fetched) */
6891
+ citation_count: z2.number().nonnegative().optional(),
6892
+ /** Venue quality tier: 3=top (NeurIPS/ICML/ICLR), 2=good, 1=workshop, 0=preprint */
6893
+ venue_tier: z2.number().min(0).max(3).optional(),
6894
+ /** Whether the paper links to a code repository */
6895
+ has_code: z2.boolean().optional(),
6896
+ /** Code repository URL (from Papers With Code or manual) */
6897
+ code_url: z2.string().optional(),
6898
+ /** Rigor assessment tags (factual, verifiable signals) */
6899
+ rigor_tags: z2.array(
6900
+ z2.enum(["has-code", "has-dataset", "has-baselines", "peer-reviewed", "single-model-eval"])
6901
+ ).optional().default([]),
6902
+ /** Composite quality score (0-10, auto-computed from signals) */
6903
+ quality_score: z2.number().min(0).max(10).optional(),
6904
+ /** Evidence confidence tier for extracted techniques */
6905
+ evidence_tier: z2.enum(["high", "medium", "low"]).optional(),
6906
+ /** Why this paper scored low — enables future re-review when conditions change */
6907
+ quality_notes: z2.string().optional(),
6908
+ /** When quality was last assessed (ISO date) — enables periodic re-review */
6909
+ last_quality_check: z2.string().optional()
6845
6910
  });
6846
6911
  var IntegrationFileObjectSchema = z2.object({
6847
6912
  path: z2.string(),
@@ -6879,7 +6944,17 @@ var ResearchTechniqueSchema = z2.object({
6879
6944
  /** Dependent techniques */
6880
6945
  dependencies: z2.array(z2.string()).optional().default([]),
6881
6946
  /** Decision history */
6882
- decision_history: z2.array(DecisionHistoryEntrySchema).optional().default([])
6947
+ decision_history: z2.array(DecisionHistoryEntrySchema).optional().default([]),
6948
+ // ── Evaluation Plan (Issue #1576 Wave 6) ──────────────────────
6949
+ /** Structured evaluation plan for keeping or removing the technique */
6950
+ evaluation_plan: z2.object({
6951
+ success_criteria: z2.string().optional(),
6952
+ evaluation_method: z2.string().optional(),
6953
+ evaluation_deadline: z2.string().optional(),
6954
+ removal_criteria: z2.string().optional()
6955
+ }).optional(),
6956
+ /** Evaluation status: pending (not yet evaluated), passed, failed, deferred */
6957
+ evaluation_status: z2.enum(["pending", "passed", "failed", "deferred"]).optional()
6883
6958
  });
6884
6959
  var PapersRegistrySchema = z2.object({
6885
6960
  schema_version: z2.string(),
@@ -6976,7 +7051,7 @@ function generateTopicsTable(stats) {
6976
7051
  const topicDisplay = capitalizeKebab(ts.topic);
6977
7052
  const topicLink = `[${topicDisplay}](topics/${ts.topic}/README.md)`;
6978
7053
  const desc = TOPIC_DESCRIPTIONS[ts.topic];
6979
- return `| ${topicLink} | ${String(ts.papers)} | ${String(ts.techniques)} | ${desc} |`;
7054
+ return `| ${topicLink} | ${String(ts.papers)} | ${String(ts.techniques)} | ${desc ?? ""} |`;
6980
7055
  });
6981
7056
  return `## Topics
6982
7057
 
@@ -7810,6 +7885,267 @@ async function researchIndexCommand(options) {
7810
7885
  }
7811
7886
  }
7812
7887
 
7888
+ // src/cli/research-import-command.ts
7889
+ import * as fs9 from "fs/promises";
7890
+ import { resolve as resolve5 } from "path";
7891
+ var VALID_TYPES = ["paper", "repo", "tool", "blog"];
7892
+ function parseCsvLine(line) {
7893
+ const fields = [];
7894
+ let current = "";
7895
+ let inQuotes = false;
7896
+ for (let i = 0; i < line.length; i++) {
7897
+ const ch = line[i];
7898
+ if (inQuotes) {
7899
+ if (ch === '"') {
7900
+ const next = line[i + 1];
7901
+ if (next === '"') {
7902
+ current += '"';
7903
+ i++;
7904
+ } else {
7905
+ inQuotes = false;
7906
+ }
7907
+ } else {
7908
+ current += ch;
7909
+ }
7910
+ } else if (ch === '"') {
7911
+ inQuotes = true;
7912
+ } else if (ch === ",") {
7913
+ fields.push(current.trim());
7914
+ current = "";
7915
+ } else {
7916
+ current += ch;
7917
+ }
7918
+ }
7919
+ fields.push(current.trim());
7920
+ return fields;
7921
+ }
7922
+ function isValidUrl(value) {
7923
+ return /^https?:\/\/.+/.test(value);
7924
+ }
7925
+ function isValidType(value) {
7926
+ return VALID_TYPES.includes(value);
7927
+ }
7928
+ function validateRow(fields, colIndex, rowNum) {
7929
+ const title = fields[colIndex["title"]] ?? "";
7930
+ const url = fields[colIndex["url"]] ?? "";
7931
+ const rawType = (fields[colIndex["type"]] ?? "").toLowerCase();
7932
+ const topic = fields[colIndex["topic"]] ?? "";
7933
+ const description = fields[colIndex["description"]] ?? "";
7934
+ if (title === "") return `Row ${String(rowNum)}: missing title`;
7935
+ if (!isValidUrl(url)) return `Row ${String(rowNum)}: invalid URL "${url}"`;
7936
+ if (!isValidType(rawType)) {
7937
+ return `Row ${String(rowNum)}: invalid type "${rawType}" (expected: ${VALID_TYPES.join(", ")})`;
7938
+ }
7939
+ if (topic === "") return `Row ${String(rowNum)}: missing topic`;
7940
+ return { title, url, type: rawType, topic, description };
7941
+ }
7942
+ function parseHeader(headerLine) {
7943
+ const header = parseCsvLine(headerLine).map((h) => h.toLowerCase());
7944
+ const required = ["title", "url", "type", "topic", "description"];
7945
+ const missing = required.filter((col) => !header.includes(col));
7946
+ if (missing.length > 0) {
7947
+ return { ok: false, error: { message: `Missing CSV columns: ${missing.join(", ")}` } };
7948
+ }
7949
+ const colIndex = Object.fromEntries(required.map((col) => [col, header.indexOf(col)]));
7950
+ return { ok: true, value: colIndex };
7951
+ }
7952
+ function parseCsvContent(content) {
7953
+ const lines = content.split(/\r?\n/).filter((l) => l.trim() !== "");
7954
+ if (lines.length < 2) {
7955
+ return {
7956
+ ok: false,
7957
+ error: { message: "CSV must have a header row and at least one data row" }
7958
+ };
7959
+ }
7960
+ const headerResult = parseHeader(lines[0]);
7961
+ if (!headerResult.ok) return headerResult;
7962
+ const rows = [];
7963
+ const errors = [];
7964
+ for (let i = 1; i < lines.length; i++) {
7965
+ const fields = parseCsvLine(lines[i]);
7966
+ const result = validateRow(fields, headerResult.value, i + 1);
7967
+ if (typeof result === "string") {
7968
+ errors.push(result);
7969
+ } else {
7970
+ rows.push(result);
7971
+ }
7972
+ }
7973
+ if (errors.length > 0 && rows.length === 0) {
7974
+ return { ok: false, error: { message: errors.join("\n") } };
7975
+ }
7976
+ return { ok: true, value: rows };
7977
+ }
7978
+ function generateIdFromTitle(title) {
7979
+ return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
7980
+ }
7981
+ function mapToSourceType(csvType) {
7982
+ switch (csvType) {
7983
+ case "repo":
7984
+ return "open_source_repo";
7985
+ case "tool":
7986
+ return "code_analysis";
7987
+ case "blog":
7988
+ return "research_blog";
7989
+ default:
7990
+ return "code_analysis";
7991
+ }
7992
+ }
7993
+ async function executeImport(options) {
7994
+ const csvPath = resolve5(options.csvPath);
7995
+ let content;
7996
+ try {
7997
+ content = await fs9.readFile(csvPath, "utf-8");
7998
+ } catch {
7999
+ return buildResult(
8000
+ [],
8001
+ [{ row: 0, title: "", status: "error", reason: `Cannot read file: ${csvPath}` }]
8002
+ );
8003
+ }
8004
+ const parseResult = parseCsvContent(content);
8005
+ if (!parseResult.ok) {
8006
+ return buildResult(
8007
+ [],
8008
+ [{ row: 0, title: "", status: "error", reason: parseResult.error.message }]
8009
+ );
8010
+ }
8011
+ const rows = parseResult.value;
8012
+ const outcomes = [];
8013
+ const rootDir = options.rootDir;
8014
+ const paperRows = rows.filter((r) => r.type === "paper");
8015
+ const sourceRows = rows.filter((r) => r.type !== "paper");
8016
+ if (paperRows.length > 0) {
8017
+ await processPaperRows(paperRows, outcomes, options.dryRun === true, rootDir);
8018
+ }
8019
+ if (sourceRows.length > 0) {
8020
+ await processSourceRows(sourceRows, outcomes, options.dryRun === true, rootDir);
8021
+ }
8022
+ return buildResult(rows, outcomes);
8023
+ }
8024
+ function buildPaperEntry(row) {
8025
+ return {
8026
+ title: row.title,
8027
+ url: row.url,
8028
+ source: "preprint",
8029
+ arxiv_id: "",
8030
+ publication_date: "",
8031
+ venue: null,
8032
+ reviewed_date: "",
8033
+ reviewed_in: "",
8034
+ topics: [row.topic],
8035
+ summary: row.description,
8036
+ relevance: "medium",
8037
+ implementation_status: "not-started",
8038
+ tags: [],
8039
+ authors: [],
8040
+ key_findings: [],
8041
+ techniques_extracted: [],
8042
+ related_issues: []
8043
+ };
8044
+ }
8045
+ function collectNewPapers(rows, existingUrls, existingTitles, outcomes) {
8046
+ const newPapers = {};
8047
+ for (const row of rows) {
8048
+ if (existingUrls.has(row.url) || existingTitles.has(row.title.toLowerCase())) {
8049
+ outcomes.push({ row: 0, title: row.title, status: "skipped", reason: "Already exists" });
8050
+ continue;
8051
+ }
8052
+ newPapers[generateIdFromTitle(row.title)] = buildPaperEntry(row);
8053
+ existingTitles.add(row.title.toLowerCase());
8054
+ outcomes.push({ row: 0, title: row.title, status: "added" });
8055
+ }
8056
+ return newPapers;
8057
+ }
8058
+ async function processPaperRows(rows, outcomes, dryRun, rootDir) {
8059
+ const loadResult = await loadPapersRegistry(rootDir);
8060
+ if (!loadResult.ok) {
8061
+ for (const row of rows) {
8062
+ outcomes.push({
8063
+ row: 0,
8064
+ title: row.title,
8065
+ status: "error",
8066
+ reason: "Failed to load papers registry"
8067
+ });
8068
+ }
8069
+ return;
8070
+ }
8071
+ const registry = loadResult.value;
8072
+ const existingUrls = new Set(
8073
+ Object.values(registry.papers).map((p) => p.url).filter(Boolean)
8074
+ );
8075
+ const existingTitles = new Set(Object.values(registry.papers).map((p) => p.title.toLowerCase()));
8076
+ const newPapers = collectNewPapers(rows, existingUrls, existingTitles, outcomes);
8077
+ if (!dryRun && Object.keys(newPapers).length > 0) {
8078
+ const updated = { ...registry, papers: { ...registry.papers, ...newPapers } };
8079
+ await savePapersRegistry(updated, rootDir);
8080
+ }
8081
+ }
8082
+ async function processSourceRows(rows, outcomes, dryRun, rootDir) {
8083
+ const loadResult = await loadSourcesRegistry(rootDir);
8084
+ if (!loadResult.ok) {
8085
+ for (const row of rows) {
8086
+ outcomes.push({
8087
+ row: 0,
8088
+ title: row.title,
8089
+ status: "error",
8090
+ reason: "Failed to load sources registry"
8091
+ });
8092
+ }
8093
+ return;
8094
+ }
8095
+ const registry = loadResult.value;
8096
+ const existingUrls = new Set(Object.values(registry.sources).map((s) => s.url));
8097
+ const newSources = {};
8098
+ for (const row of rows) {
8099
+ if (existingUrls.has(row.url)) {
8100
+ outcomes.push({ row: 0, title: row.title, status: "skipped", reason: "Already exists" });
8101
+ continue;
8102
+ }
8103
+ const sourceId = generateIdFromTitle(row.title);
8104
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8105
+ newSources[sourceId] = {
8106
+ name: row.title,
8107
+ type: mapToSourceType(row.type),
8108
+ url: row.url,
8109
+ topics: [row.topic],
8110
+ reviewed_date: today
8111
+ };
8112
+ existingUrls.add(row.url);
8113
+ outcomes.push({ row: 0, title: row.title, status: "added" });
8114
+ }
8115
+ if (!dryRun && Object.keys(newSources).length > 0) {
8116
+ const updated = {
8117
+ ...registry,
8118
+ sources: { ...registry.sources, ...newSources }
8119
+ };
8120
+ await saveSourcesRegistry(updated, rootDir);
8121
+ }
8122
+ }
8123
+ function buildResult(_rows, outcomes) {
8124
+ const added = outcomes.filter((o) => o.status === "added").length;
8125
+ const skipped = outcomes.filter((o) => o.status === "skipped").length;
8126
+ const errors = outcomes.filter((o) => o.status === "error").length;
8127
+ const lines = [
8128
+ `Import complete: ${String(added)} added, ${String(skipped)} skipped, ${String(errors)} errors`
8129
+ ];
8130
+ for (const o of outcomes) {
8131
+ const suffix = o.reason !== void 0 ? ` (${o.reason})` : "";
8132
+ lines.push(` [${o.status}] ${o.title}${suffix}`);
8133
+ }
8134
+ return { added, skipped, errors, outcomes, message: lines.join("\n") };
8135
+ }
8136
+ async function handleImportCommand(args, options) {
8137
+ const csvPath = args[0];
8138
+ if (csvPath === void 0 || csvPath === "") {
8139
+ return "Error: CSV file path is required. Usage: nexus-agents research import <csv-file> [--dryRun]";
8140
+ }
8141
+ const dryRun = options["dryRun"] === true;
8142
+ const result = await executeImport({ csvPath, dryRun });
8143
+ if (dryRun) {
8144
+ return `[DRY RUN] ${result.message}`;
8145
+ }
8146
+ return result.message;
8147
+ }
8148
+
7813
8149
  // src/cli/research-command.ts
7814
8150
  function optString(options, key) {
7815
8151
  const val = options[key];
@@ -8023,7 +8359,8 @@ var VALID_SUBCOMMANDS = [
8023
8359
  "discover",
8024
8360
  "review",
8025
8361
  "prioritize",
8026
- "synthesize"
8362
+ "synthesize",
8363
+ "import"
8027
8364
  ];
8028
8365
  function isValidResearchSubcommand(value) {
8029
8366
  return value !== void 0 && VALID_SUBCOMMANDS.includes(value);
@@ -8044,7 +8381,8 @@ var SUBCOMMAND_HANDLERS = {
8044
8381
  discover: handleDiscoverCommand,
8045
8382
  review: handleReviewCommand,
8046
8383
  prioritize: handlePrioritizeCommand,
8047
- synthesize: handleSynthesizeCommand
8384
+ synthesize: handleSynthesizeCommand,
8385
+ import: handleImportCommand
8048
8386
  };
8049
8387
  async function researchCommand(subcommand, args, options) {
8050
8388
  const handler = SUBCOMMAND_HANDLERS[subcommand];
@@ -8055,8 +8393,8 @@ async function researchCommand(subcommand, args, options) {
8055
8393
  }
8056
8394
 
8057
8395
  // src/cli/index-command.ts
8058
- import * as fs12 from "fs/promises";
8059
- import * as path18 from "path";
8396
+ import * as fs13 from "fs/promises";
8397
+ import * as path17 from "path";
8060
8398
  import * as yaml6 from "yaml";
8061
8399
 
8062
8400
  // src/indexer/types.ts
@@ -8558,7 +8896,7 @@ function buildIndex(files) {
8558
8896
  }
8559
8897
 
8560
8898
  // src/indexer/generator.ts
8561
- import * as fs9 from "fs/promises";
8899
+ import * as fs10 from "fs/promises";
8562
8900
  import * as path11 from "path";
8563
8901
  import * as yaml4 from "yaml";
8564
8902
  function indexToYaml(index) {
@@ -8721,33 +9059,22 @@ var McpToolSpecSchema = z4.object({
8721
9059
  source_file: z4.string(),
8722
9060
  source_line: z4.number().int().positive()
8723
9061
  });
8724
- var RestEndpointSpecSchema = z4.object({
8725
- method: z4.string(),
8726
- path: z4.string(),
8727
- description: z4.string(),
8728
- body_params: z4.array(ParameterSpecSchema).readonly().optional(),
8729
- query_params: z4.array(ParameterSpecSchema).readonly().optional(),
8730
- source_file: z4.string(),
8731
- source_line: z4.number().int().positive()
8732
- });
8733
9062
  var EntrypointManifestSchema = z4.object({
8734
9063
  schema_version: z4.literal(ENTRYPOINT_SCHEMA_VERSION),
8735
9064
  generated_at: z4.string(),
8736
9065
  cli_commands: z4.array(CliCommandSpecSchema).readonly(),
8737
- mcp_tools: z4.array(McpToolSpecSchema).readonly(),
8738
- rest_endpoints: z4.array(RestEndpointSpecSchema).readonly()
9066
+ mcp_tools: z4.array(McpToolSpecSchema).readonly()
8739
9067
  });
8740
9068
  var DEFAULT_ENTRYPOINT_EXTRACTOR_OPTIONS = {
8741
9069
  packageRoot: "packages/nexus-agents",
8742
9070
  cliCommandsPath: "src/cli-commands.ts",
8743
9071
  mcpToolsPath: "src/mcp/tools",
8744
- restRoutesPath: "src/api/routes",
8745
9072
  sanitize: true
8746
9073
  };
8747
9074
 
8748
9075
  // src/indexer/entrypoint-extractor.ts
8749
9076
  import { Project as Project2 } from "ts-morph";
8750
- import * as path15 from "path";
9077
+ import * as path14 from "path";
8751
9078
  import * as yaml5 from "yaml";
8752
9079
 
8753
9080
  // src/indexer/entrypoint-sanitizer.ts
@@ -8841,22 +9168,6 @@ function sanitizeTool(tool) {
8841
9168
  source_line: tool.source_line
8842
9169
  };
8843
9170
  }
8844
- function sanitizeEndpoint(endpoint) {
8845
- const result = {
8846
- method: endpoint.method,
8847
- path: endpoint.path,
8848
- description: sanitizeValue(endpoint.description),
8849
- source_file: endpoint.source_file,
8850
- source_line: endpoint.source_line
8851
- };
8852
- if (endpoint.body_params !== void 0) {
8853
- result.body_params = endpoint.body_params.map(sanitizeParameter);
8854
- }
8855
- if (endpoint.query_params !== void 0) {
8856
- result.query_params = endpoint.query_params.map(sanitizeParameter);
8857
- }
8858
- return result;
8859
- }
8860
9171
 
8861
9172
  // src/indexer/entrypoint-cli-extractor.ts
8862
9173
  import { SyntaxKind } from "ts-morph";
@@ -9173,159 +9484,6 @@ function extractParametersFromSchema(schemaArg, sourceFile) {
9173
9484
  return [];
9174
9485
  }
9175
9486
 
9176
- // src/indexer/entrypoint-rest-extractor.ts
9177
- import { SyntaxKind as SyntaxKind3 } from "ts-morph";
9178
- import * as path14 from "path";
9179
- function extractJsonSchemaParams(schemaObj) {
9180
- const params = [];
9181
- const objLiteral = schemaObj.asKind(SyntaxKind3.ObjectLiteralExpression);
9182
- if (objLiteral === void 0) return params;
9183
- const propertiesProp = objLiteral.getProperty("properties");
9184
- if (propertiesProp === void 0) return params;
9185
- const propsObj = propertiesProp.asKind(SyntaxKind3.PropertyAssignment)?.getInitializer()?.asKind(SyntaxKind3.ObjectLiteralExpression);
9186
- if (propsObj === void 0) return params;
9187
- const requiredFields = extractRequiredFields(objLiteral);
9188
- for (const prop of propsObj.getProperties()) {
9189
- const param = extractParameterFromProperty(prop, requiredFields);
9190
- if (param !== void 0) {
9191
- params.push(param);
9192
- }
9193
- }
9194
- return params;
9195
- }
9196
- function extractRequiredFields(objLiteral) {
9197
- const requiredFields = /* @__PURE__ */ new Set();
9198
- const obj = objLiteral.asKind(SyntaxKind3.ObjectLiteralExpression);
9199
- if (obj === void 0) return requiredFields;
9200
- const requiredProp = obj.getProperty("required");
9201
- if (requiredProp === void 0) return requiredFields;
9202
- const requiredArr = requiredProp.asKind(SyntaxKind3.PropertyAssignment)?.getInitializer()?.asKind(SyntaxKind3.ArrayLiteralExpression);
9203
- if (requiredArr !== void 0) {
9204
- for (const elem of requiredArr.getElements()) {
9205
- requiredFields.add(elem.getText().replace(/['"]/g, ""));
9206
- }
9207
- }
9208
- return requiredFields;
9209
- }
9210
- function extractParameterFromProperty(prop, requiredFields) {
9211
- const propAssign = prop.asKind(SyntaxKind3.PropertyAssignment);
9212
- if (propAssign === void 0) return void 0;
9213
- const paramName = propAssign.getName().replace(/['"]/g, "");
9214
- const propValue = propAssign.getInitializer()?.asKind(SyntaxKind3.ObjectLiteralExpression);
9215
- if (propValue === void 0) return void 0;
9216
- const spec = {
9217
- name: paramName,
9218
- type: "string",
9219
- required: requiredFields.has(paramName)
9220
- };
9221
- const typeProp = propValue.getProperty("type");
9222
- if (typeProp !== void 0) {
9223
- const typeValue = typeProp.asKind(SyntaxKind3.PropertyAssignment)?.getInitializer()?.getText().replace(/['"]/g, "");
9224
- if (typeValue !== void 0 && typeValue !== "") {
9225
- spec.type = typeValue;
9226
- }
9227
- }
9228
- const descProp = propValue.getProperty("description");
9229
- if (descProp !== void 0) {
9230
- const descValue = descProp.asKind(SyntaxKind3.PropertyAssignment)?.getInitializer()?.getText().replace(/^['"]|['"]$/g, "");
9231
- if (descValue !== void 0 && descValue !== "") {
9232
- spec.description = descValue;
9233
- }
9234
- }
9235
- return spec;
9236
- }
9237
- function extractRestEndpoints(project, packageRoot, restRoutesPath) {
9238
- const endpoints = [];
9239
- const routesDir = path14.join(packageRoot, restRoutesPath);
9240
- const routeFiles = project.getSourceFiles(`${routesDir}/*.ts`);
9241
- for (const sourceFile of routeFiles) {
9242
- const filePath = sourceFile.getFilePath();
9243
- const fileName = path14.basename(filePath);
9244
- if (fileName.endsWith(".test.ts") || fileName === "index.ts") continue;
9245
- const relativePath = path14.relative(process.cwd(), filePath);
9246
- const extractedEndpoints = extractEndpointsFromFile(sourceFile, relativePath);
9247
- endpoints.push(...extractedEndpoints);
9248
- }
9249
- return endpoints;
9250
- }
9251
- function extractEndpointsFromFile(sourceFile, relativePath) {
9252
- const endpoints = [];
9253
- if (sourceFile === void 0) return endpoints;
9254
- const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind3.CallExpression);
9255
- for (const callExpr of callExpressions) {
9256
- const callText = callExpr.getExpression().getText();
9257
- const methodMatch = callText.match(/\.(get|post|put|delete|patch)$/i);
9258
- if (methodMatch === null) continue;
9259
- const method = methodMatch[1]?.toUpperCase();
9260
- if (method === void 0) continue;
9261
- const endpoint = extractEndpointFromCall(callExpr, method, relativePath);
9262
- if (endpoint !== void 0) {
9263
- endpoints.push(endpoint);
9264
- }
9265
- }
9266
- return endpoints;
9267
- }
9268
- function extractEndpointFromCall(callExpr, method, relativePath) {
9269
- const typedCall = callExpr;
9270
- const args = typedCall.getArguments();
9271
- if (args.length < 2) return void 0;
9272
- const pathArgNode = args[0];
9273
- if (pathArgNode === void 0) return void 0;
9274
- const pathArg = pathArgNode.getText().replace(/['"]/g, "");
9275
- const { description, bodyParams } = extractEndpointMeta(args, method, pathArg);
9276
- const endpointSpec = {
9277
- method,
9278
- path: pathArg,
9279
- description,
9280
- source_file: relativePath,
9281
- source_line: typedCall.getStartLineNumber()
9282
- };
9283
- if (bodyParams.length > 0) {
9284
- endpointSpec.body_params = bodyParams;
9285
- }
9286
- return endpointSpec;
9287
- }
9288
- function extractEndpointMeta(args, method, pathArg) {
9289
- let description = `${method} ${pathArg}`;
9290
- let bodyParams = [];
9291
- const schemaArg = args[1];
9292
- if (schemaArg === void 0) {
9293
- return { description, bodyParams };
9294
- }
9295
- if (schemaArg.getKind() !== SyntaxKind3.ObjectLiteralExpression) {
9296
- return { description, bodyParams };
9297
- }
9298
- const schemaObj = schemaArg.asKind(SyntaxKind3.ObjectLiteralExpression);
9299
- if (schemaObj === void 0) {
9300
- return { description, bodyParams };
9301
- }
9302
- const schemaProp = schemaObj.getProperty("schema");
9303
- if (schemaProp === void 0) {
9304
- return { description, bodyParams };
9305
- }
9306
- const schemaValue = schemaProp.asKind(SyntaxKind3.PropertyAssignment)?.getInitializer()?.asKind(SyntaxKind3.ObjectLiteralExpression);
9307
- if (schemaValue === void 0) {
9308
- return { description, bodyParams };
9309
- }
9310
- const descProp = schemaValue.getProperty("description");
9311
- if (descProp !== void 0) {
9312
- const descValue = descProp.asKind(SyntaxKind3.PropertyAssignment)?.getInitializer()?.getText().replace(/^['"]|['"]$/g, "");
9313
- if (descValue !== void 0 && descValue !== "") {
9314
- description = descValue;
9315
- }
9316
- }
9317
- if (["POST", "PUT", "PATCH"].includes(method)) {
9318
- const bodyProp = schemaValue.getProperty("body");
9319
- if (bodyProp !== void 0) {
9320
- const bodyObj = bodyProp.asKind(SyntaxKind3.PropertyAssignment)?.getInitializer()?.asKind(SyntaxKind3.ObjectLiteralExpression);
9321
- if (bodyObj !== void 0) {
9322
- bodyParams = extractJsonSchemaParams(bodyObj);
9323
- }
9324
- }
9325
- }
9326
- return { description, bodyParams };
9327
- }
9328
-
9329
9487
  // src/indexer/entrypoint-extractor.ts
9330
9488
  function generateTimestamp() {
9331
9489
  return new Date(getTimeProvider().now()).toLocaleString("en-US", {
@@ -9341,14 +9499,13 @@ function generateTimestamp() {
9341
9499
  }
9342
9500
  function createProject(opts) {
9343
9501
  const project = new Project2({
9344
- tsConfigFilePath: path15.join(opts.packageRoot, "tsconfig.json"),
9502
+ tsConfigFilePath: path14.join(opts.packageRoot, "tsconfig.json"),
9345
9503
  skipAddingFilesFromTsConfig: true
9346
9504
  });
9347
9505
  project.addSourceFilesAtPaths([
9348
- path15.join(opts.packageRoot, opts.cliCommandsPath),
9349
- path15.join(opts.packageRoot, "src/cli-types.ts"),
9350
- path15.join(opts.packageRoot, opts.mcpToolsPath, "*.ts"),
9351
- path15.join(opts.packageRoot, opts.restRoutesPath, "*.ts")
9506
+ path14.join(opts.packageRoot, opts.cliCommandsPath),
9507
+ path14.join(opts.packageRoot, "src/cli-types.ts"),
9508
+ path14.join(opts.packageRoot, opts.mcpToolsPath, "*.ts")
9352
9509
  ]);
9353
9510
  return project;
9354
9511
  }
@@ -9365,16 +9522,13 @@ function extractEntrypoints(options = {}) {
9365
9522
  "src/cli-types.ts"
9366
9523
  );
9367
9524
  const mcpTools = extractMcpTools(project, opts.packageRoot, opts.mcpToolsPath);
9368
- const restEndpoints = extractRestEndpoints(project, opts.packageRoot, opts.restRoutesPath);
9369
9525
  const finalCommands = opts.sanitize ? cliCommands.map(sanitizeCommand) : cliCommands;
9370
9526
  const finalTools = opts.sanitize ? mcpTools.map(sanitizeTool) : mcpTools;
9371
- const finalEndpoints = opts.sanitize ? restEndpoints.map(sanitizeEndpoint) : restEndpoints;
9372
9527
  const manifest = {
9373
9528
  schema_version: ENTRYPOINT_SCHEMA_VERSION,
9374
9529
  generated_at: generateTimestamp(),
9375
9530
  cli_commands: finalCommands,
9376
- mcp_tools: finalTools,
9377
- rest_endpoints: finalEndpoints
9531
+ mcp_tools: finalTools
9378
9532
  };
9379
9533
  return { success: true, manifest, errors, warnings };
9380
9534
  } catch (error) {
@@ -9396,20 +9550,20 @@ function manifestToJson(manifest) {
9396
9550
  }
9397
9551
 
9398
9552
  // src/cli/index-command-link-validator.ts
9399
- import * as fs11 from "fs/promises";
9400
- import * as path17 from "path";
9553
+ import * as fs12 from "fs/promises";
9554
+ import * as path16 from "path";
9401
9555
 
9402
9556
  // src/cli/index-command-link-validation-helpers.ts
9403
- import * as fs10 from "fs/promises";
9404
- import * as path16 from "path";
9557
+ import * as fs11 from "fs/promises";
9558
+ import * as path15 from "path";
9405
9559
  async function validateInternalLink(url, sourceFile) {
9406
9560
  const [filePath, anchor] = url.split("#");
9407
9561
  if (filePath === void 0 || filePath === "") {
9408
9562
  return { valid: true };
9409
9563
  }
9410
- const resolvedPath = path16.resolve(path16.dirname(sourceFile), filePath);
9564
+ const resolvedPath = path15.resolve(path15.dirname(sourceFile), filePath);
9411
9565
  try {
9412
- await fs10.access(resolvedPath);
9566
+ await fs11.access(resolvedPath);
9413
9567
  if (anchor !== void 0 && anchor !== "") {
9414
9568
  const anchorResult = await validateAnchorInFile(anchor, resolvedPath);
9415
9569
  if (!anchorResult.valid) {
@@ -9483,7 +9637,7 @@ function headingToAnchor(heading) {
9483
9637
  }
9484
9638
  async function validateAnchorInFile(anchor, targetFile) {
9485
9639
  try {
9486
- const content = await fs10.readFile(targetFile, "utf-8");
9640
+ const content = await fs11.readFile(targetFile, "utf-8");
9487
9641
  const headingRegex = /^#{1,6}\s+(.+)$/gm;
9488
9642
  let match;
9489
9643
  while ((match = headingRegex.exec(content)) !== null) {
@@ -9492,9 +9646,9 @@ async function validateAnchorInFile(anchor, targetFile) {
9492
9646
  return { valid: true };
9493
9647
  }
9494
9648
  }
9495
- return { valid: false, error: `Anchor '#${anchor}' not found in ${path16.basename(targetFile)}` };
9649
+ return { valid: false, error: `Anchor '#${anchor}' not found in ${path15.basename(targetFile)}` };
9496
9650
  } catch {
9497
- return { valid: false, error: `Failed to read ${path16.basename(targetFile)} for anchor check` };
9651
+ return { valid: false, error: `Failed to read ${path15.basename(targetFile)} for anchor check` };
9498
9652
  }
9499
9653
  }
9500
9654
  async function validateAnchorLink(anchor, sourceFile) {
@@ -9584,9 +9738,9 @@ var REFERENCE_DEF_REGEX = /^\[([^\]]+)\]:\s*(.+)$/gm;
9584
9738
  async function findMarkdownFiles(dir) {
9585
9739
  const files = [];
9586
9740
  try {
9587
- const entries = await fs11.readdir(dir, { withFileTypes: true });
9741
+ const entries = await fs12.readdir(dir, { withFileTypes: true });
9588
9742
  for (const entry of entries) {
9589
- const fullPath = path17.join(dir, entry.name);
9743
+ const fullPath = path16.join(dir, entry.name);
9590
9744
  if (entry.name === "node_modules" || entry.name === "dist") {
9591
9745
  continue;
9592
9746
  }
@@ -9680,7 +9834,7 @@ function extractLinks(content) {
9680
9834
  }
9681
9835
  async function validateFileLinks(filePath, checkExternal, counters) {
9682
9836
  try {
9683
- const content = await fs11.readFile(filePath, "utf-8");
9837
+ const content = await fs12.readFile(filePath, "utf-8");
9684
9838
  const links = extractLinks(content);
9685
9839
  const brokenLinksInFile = [];
9686
9840
  for (const link of links) {
@@ -9781,10 +9935,10 @@ async function generateIndex(options) {
9781
9935
  `Extracted ${String(extraction.files.length)} files in ${String(extraction.durationMs)}ms`
9782
9936
  );
9783
9937
  const index = buildIndex(extraction.files);
9784
- const outputDir = path18.dirname(outputPath);
9785
- await fs12.mkdir(outputDir, { recursive: true });
9938
+ const outputDir = path17.dirname(outputPath);
9939
+ await fs13.mkdir(outputDir, { recursive: true });
9786
9940
  const content = format === "yaml" ? indexToYaml(index) : indexToJson(index);
9787
- await fs12.writeFile(outputPath, content, "utf-8");
9941
+ await fs13.writeFile(outputPath, content, "utf-8");
9788
9942
  logger9.info(`Wrote index to ${outputPath}`);
9789
9943
  return {
9790
9944
  success: true,
@@ -9799,14 +9953,14 @@ async function generateIndex(options) {
9799
9953
  async function checkIndex(options) {
9800
9954
  const indexPath = options.output ?? "docs/codebase-index.yaml";
9801
9955
  try {
9802
- await fs12.access(indexPath);
9956
+ await fs13.access(indexPath);
9803
9957
  } catch {
9804
9958
  return {
9805
9959
  success: false,
9806
9960
  message: `Index file not found: ${indexPath}. Run 'nexus-agents index generate' first.`
9807
9961
  };
9808
9962
  }
9809
- const content = await fs12.readFile(indexPath, "utf-8");
9963
+ const content = await fs13.readFile(indexPath, "utf-8");
9810
9964
  let existingIndex;
9811
9965
  try {
9812
9966
  const parsed = indexPath.endsWith(".json") ? JSON.parse(content) : yaml6.parse(content);
@@ -9842,18 +9996,18 @@ async function generateDiagram(options) {
9842
9996
  const indexPath = options.output ?? "docs/codebase-index.yaml";
9843
9997
  const diagramPath = "docs/dependency-graph.md";
9844
9998
  try {
9845
- await fs12.access(indexPath);
9999
+ await fs13.access(indexPath);
9846
10000
  } catch {
9847
10001
  logger9.info("Index not found, generating...");
9848
10002
  await generateIndex({ ...options, subcommand: "generate" });
9849
10003
  }
9850
- const content = await fs12.readFile(indexPath, "utf-8");
10004
+ const content = await fs13.readFile(indexPath, "utf-8");
9851
10005
  const parsed = indexPath.endsWith(".json") ? JSON.parse(content) : yaml6.parse(content);
9852
10006
  CodebaseIndexSchema.parse(parsed);
9853
10007
  const index = parsed;
9854
10008
  const diagram = generateDiagramMarkdown(index);
9855
- await fs12.mkdir(path18.dirname(diagramPath), { recursive: true });
9856
- await fs12.writeFile(diagramPath, diagram, "utf-8");
10009
+ await fs13.mkdir(path17.dirname(diagramPath), { recursive: true });
10010
+ await fs13.writeFile(diagramPath, diagram, "utf-8");
9857
10011
  logger9.info(`Wrote diagram to ${diagramPath}`);
9858
10012
  return {
9859
10013
  success: true,
@@ -9882,7 +10036,7 @@ function extractDocumentedModules(architectureContent) {
9882
10036
  }
9883
10037
  async function getActualModules(srcPath) {
9884
10038
  try {
9885
- const entries = await fs12.readdir(srcPath, { withFileTypes: true });
10039
+ const entries = await fs13.readdir(srcPath, { withFileTypes: true });
9886
10040
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("__")).map((e) => e.name);
9887
10041
  } catch (error) {
9888
10042
  logger9.debug("Failed to read source modules", { srcPath, error: getErrorMessage(error) });
@@ -9918,12 +10072,12 @@ async function validateArchitecture(options) {
9918
10072
  const srcPath = "packages/nexus-agents/src";
9919
10073
  let architectureContent;
9920
10074
  try {
9921
- architectureContent = await fs12.readFile(architecturePath, "utf-8");
10075
+ architectureContent = await fs13.readFile(architecturePath, "utf-8");
9922
10076
  } catch {
9923
10077
  return { success: false, message: `ARCHITECTURE.md not found at ${architecturePath}` };
9924
10078
  }
9925
10079
  try {
9926
- await fs12.access(srcPath);
10080
+ await fs13.access(srcPath);
9927
10081
  } catch {
9928
10082
  return { success: false, message: `Source directory not found: ${srcPath}` };
9929
10083
  }
@@ -9945,7 +10099,6 @@ async function entrypointsCommand(options) {
9945
10099
  packageRoot: "packages/nexus-agents",
9946
10100
  cliCommandsPath: "src/cli-commands.ts",
9947
10101
  mcpToolsPath: "src/mcp/tools",
9948
- restRoutesPath: "src/api/routes",
9949
10102
  sanitize: true
9950
10103
  });
9951
10104
  if (!result.success || result.manifest === void 0) {
@@ -9959,15 +10112,15 @@ async function entrypointsCommand(options) {
9959
10112
  for (const warning of result.warnings) {
9960
10113
  logger9.warn(warning);
9961
10114
  }
9962
- const outputDir = path18.dirname(outputPath);
9963
- await fs12.mkdir(outputDir, { recursive: true });
10115
+ const outputDir = path17.dirname(outputPath);
10116
+ await fs13.mkdir(outputDir, { recursive: true });
9964
10117
  const content = format === "yaml" ? manifestToYaml(manifest) : manifestToJson(manifest);
9965
- await fs12.writeFile(outputPath, content, "utf-8");
10118
+ await fs13.writeFile(outputPath, content, "utf-8");
9966
10119
  logger9.info(`Wrote entrypoints manifest to ${outputPath}`);
9967
- const total = manifest.cli_commands.length + manifest.mcp_tools.length + manifest.rest_endpoints.length;
10120
+ const total = manifest.cli_commands.length + manifest.mcp_tools.length;
9968
10121
  return {
9969
10122
  success: true,
9970
- message: `Extracted ${String(total)} entrypoints (${String(manifest.cli_commands.length)} CLI, ${String(manifest.mcp_tools.length)} MCP, ${String(manifest.rest_endpoints.length)} REST)`,
10123
+ message: `Extracted ${String(total)} entrypoints (${String(manifest.cli_commands.length)} CLI, ${String(manifest.mcp_tools.length)} MCP)`,
9971
10124
  data: {
9972
10125
  outputPath
9973
10126
  }
@@ -9980,9 +10133,9 @@ async function freshnessCommand(options) {
9980
10133
  const hasIssues = summary.stale > 0 || summary.warning > 0;
9981
10134
  const output2 = options.format === "json" ? formatFreshnessJson(result) : formatFreshnessTable(result);
9982
10135
  if (options.output !== void 0) {
9983
- const outputDir = path18.dirname(options.output);
9984
- await fs12.mkdir(outputDir, { recursive: true });
9985
- await fs12.writeFile(options.output, output2, "utf-8");
10136
+ const outputDir = path17.dirname(options.output);
10137
+ await fs13.mkdir(outputDir, { recursive: true });
10138
+ await fs13.writeFile(options.output, output2, "utf-8");
9986
10139
  logger9.info(`Wrote freshness report to ${options.output}`);
9987
10140
  } else {
9988
10141
  process.stdout.write(output2 + "\n");
@@ -10005,9 +10158,9 @@ async function linksCommand(options) {
10005
10158
  const hasBrokenLinks = summary.brokenLinks > 0;
10006
10159
  const output2 = options.format === "json" ? formatLinkValidationJson(result) : formatLinkValidationTable(result);
10007
10160
  if (options.output !== void 0) {
10008
- const outputDir = path18.dirname(options.output);
10009
- await fs12.mkdir(outputDir, { recursive: true });
10010
- await fs12.writeFile(options.output, output2, "utf-8");
10161
+ const outputDir = path17.dirname(options.output);
10162
+ await fs13.mkdir(outputDir, { recursive: true });
10163
+ await fs13.writeFile(options.output, output2, "utf-8");
10011
10164
  logger9.info(`Wrote link validation report to ${options.output}`);
10012
10165
  } else {
10013
10166
  process.stdout.write(output2 + "\n");
@@ -10348,7 +10501,7 @@ async function verifyCommand(options) {
10348
10501
 
10349
10502
  // src/cli/swe-bench-command.ts
10350
10503
  import * as os2 from "os";
10351
- import * as path19 from "path";
10504
+ import * as path18 from "path";
10352
10505
  function runInfo(options) {
10353
10506
  console.log(`
10354
10507
  SWE-bench Dataset: ${options.variant}`);
@@ -10415,7 +10568,8 @@ Error loading dataset: ${error.message}`);
10415
10568
  }
10416
10569
  async function loadAndSelectInstances(options) {
10417
10570
  console.log("Loading dataset...");
10418
- const loadOptions = options.limit !== void 0 ? { limit: options.limit } : {};
10571
+ const hasInstanceFilter = options.instances.length > 0;
10572
+ const loadOptions = !hasInstanceFilter && options.limit !== void 0 ? { limit: options.limit } : {};
10419
10573
  const loadResult = await loadDataset(options.variant, loadOptions);
10420
10574
  if (!loadResult.ok) {
10421
10575
  logDatasetError(loadResult.error);
@@ -10464,8 +10618,8 @@ function isValidRunId(runId) {
10464
10618
  return /^[a-zA-Z0-9_-]{1,64}$/.test(runId);
10465
10619
  }
10466
10620
  function isValidOutputDir(dir) {
10467
- const resolved = path19.resolve(dir);
10468
- return !resolved.includes("..") && resolved === path19.normalize(resolved);
10621
+ const resolved = path18.resolve(dir);
10622
+ return !resolved.includes("..") && resolved === path18.normalize(resolved);
10469
10623
  }
10470
10624
  function formatProgress(progress) {
10471
10625
  const pct = progress.totalCount > 0 ? Math.round(progress.completedCount / progress.totalCount * 100) : 0;
@@ -10479,12 +10633,12 @@ function buildHarnessConfig(options) {
10479
10633
  const predictionsPath = options.predictions ?? options.output;
10480
10634
  const runId = options.runId ?? `eval-${String(Date.now())}`;
10481
10635
  return {
10482
- predictionsPath: path19.resolve(predictionsPath),
10636
+ predictionsPath: path18.resolve(predictionsPath),
10483
10637
  datasetName: options.variant,
10484
10638
  maxWorkers: options.maxWorkers,
10485
10639
  runId,
10486
10640
  timeoutSeconds: 1800,
10487
- outputDir: path19.resolve(options.outputDir),
10641
+ outputDir: path18.resolve(options.outputDir),
10488
10642
  useDocker: true,
10489
10643
  cacheLevel: options.cacheLevel
10490
10644
  };
@@ -11066,8 +11220,8 @@ function isValidConfigAction(value) {
11066
11220
  }
11067
11221
 
11068
11222
  // src/cli/config-command-helpers.ts
11069
- import * as fs13 from "fs/promises";
11070
- import * as path20 from "path";
11223
+ import * as fs14 from "fs/promises";
11224
+ import * as path19 from "path";
11071
11225
  import { existsSync as existsSync10 } from "fs";
11072
11226
 
11073
11227
  // src/cli/config-command-formatting.ts
@@ -11335,10 +11489,10 @@ function parseValueFromString(stringValue, defaultValue) {
11335
11489
  }
11336
11490
  function resolveFilePath(filePath, allowedBase) {
11337
11491
  const base = allowedBase ?? process.cwd();
11338
- const resolved = path20.isAbsolute(filePath) ? filePath : path20.resolve(base, filePath);
11339
- const normalizedResolved = path20.normalize(resolved);
11340
- const normalizedBase = path20.normalize(base);
11341
- const isWithinBase = normalizedResolved === normalizedBase || normalizedResolved.startsWith(normalizedBase + path20.sep);
11492
+ const resolved = path19.isAbsolute(filePath) ? filePath : path19.resolve(base, filePath);
11493
+ const normalizedResolved = path19.normalize(resolved);
11494
+ const normalizedBase = path19.normalize(base);
11495
+ const isWithinBase = normalizedResolved === normalizedBase || normalizedResolved.startsWith(normalizedBase + path19.sep);
11342
11496
  if (!isWithinBase) {
11343
11497
  throw new ConfigCommandError(
11344
11498
  "PATH_TRAVERSAL",
@@ -11349,11 +11503,11 @@ function resolveFilePath(filePath, allowedBase) {
11349
11503
  }
11350
11504
  function getDefaultExportPath(format) {
11351
11505
  const extension = format === "json" ? "json" : "yaml";
11352
- return path20.resolve(process.cwd(), `nexus-config.${extension}`);
11506
+ return path19.resolve(process.cwd(), `nexus-config.${extension}`);
11353
11507
  }
11354
11508
 
11355
11509
  // src/cli/config-command-handlers.ts
11356
- import * as fs14 from "fs/promises";
11510
+ import * as fs15 from "fs/promises";
11357
11511
  import { existsSync as existsSync11 } from "fs";
11358
11512
  async function handleGet(key) {
11359
11513
  const parsed = parseConfigKey(key);
@@ -11455,7 +11609,7 @@ function buildConfigEntries() {
11455
11609
  }
11456
11610
  async function writeConfigFile2(filePath, content) {
11457
11611
  try {
11458
- await fs14.writeFile(filePath, content, "utf-8");
11612
+ await fs15.writeFile(filePath, content, "utf-8");
11459
11613
  } catch (error) {
11460
11614
  const message = getErrorMessage(error);
11461
11615
  throw new ConfigCommandError("WRITE_ERROR", `Failed to write file: ${message}`);
@@ -11481,7 +11635,7 @@ async function readImportFile(filePath) {
11481
11635
  }
11482
11636
  const format = filePath.endsWith(".yaml") || filePath.endsWith(".yml") ? "yaml" : "json";
11483
11637
  try {
11484
- const content = await fs14.readFile(filePath, "utf-8");
11638
+ const content = await fs15.readFile(filePath, "utf-8");
11485
11639
  return { content, format };
11486
11640
  } catch (error) {
11487
11641
  const message = getErrorMessage(error);
@@ -11979,7 +12133,7 @@ function writeResultAndExit(result) {
11979
12133
 
11980
12134
  // src/cli/hooks/hook-router.ts
11981
12135
  async function readStdin() {
11982
- return new Promise((resolve12, reject) => {
12136
+ return new Promise((resolve14, reject) => {
11983
12137
  let data = "";
11984
12138
  process.stdin.setEncoding("utf8");
11985
12139
  process.stdin.on("readable", () => {
@@ -11990,24 +12144,24 @@ async function readStdin() {
11990
12144
  }
11991
12145
  });
11992
12146
  process.stdin.on("end", () => {
11993
- resolve12(data);
12147
+ resolve14(data);
11994
12148
  });
11995
12149
  process.stdin.on("error", (err2) => {
11996
12150
  reject(err2);
11997
12151
  });
11998
12152
  if (process.stdin.isTTY) {
11999
- resolve12("");
12153
+ resolve14("");
12000
12154
  }
12001
12155
  });
12002
12156
  }
12003
12157
  async function readStdinWithTimeout(timeoutMs = 5e3) {
12004
- return new Promise((resolve12, reject) => {
12158
+ return new Promise((resolve14, reject) => {
12005
12159
  const timeout2 = setTimeout(() => {
12006
12160
  reject(new Error(`Stdin read timeout after ${String(timeoutMs)}ms`));
12007
12161
  }, timeoutMs);
12008
12162
  readStdin().then((data) => {
12009
12163
  clearTimeout(timeout2);
12010
- resolve12(data);
12164
+ resolve14(data);
12011
12165
  }).catch((err2) => {
12012
12166
  clearTimeout(timeout2);
12013
12167
  reject(err2 instanceof Error ? err2 : new Error(String(err2)));
@@ -12139,9 +12293,9 @@ function setStringOption(options, key, value) {
12139
12293
 
12140
12294
  // src/cli/hooks/handlers/handler-utils.ts
12141
12295
  import { homedir as homedir2 } from "os";
12142
- import { join as join14 } from "path";
12296
+ import { join as join13 } from "path";
12143
12297
  function getDefaultDbPath2() {
12144
- return join14(homedir2(), ".nexus-agents", "sessions.db");
12298
+ return join13(homedir2(), ".nexus-agents", "sessions.db");
12145
12299
  }
12146
12300
  var HookEnvVars = {
12147
12301
  /** Override the default database path */
@@ -13324,6 +13478,72 @@ async function demoCommand(subcommand, args, options) {
13324
13478
  }
13325
13479
 
13326
13480
  // src/governance/fitness-score.ts
13481
+ import { existsSync as existsSync12, readFileSync as readFileSync6, readdirSync, statSync } from "fs";
13482
+ import { join as join14 } from "path";
13483
+ function findPkgRoot() {
13484
+ let dir = import.meta.dirname;
13485
+ for (let i = 0; i < 10; i++) {
13486
+ const pkgPath = join14(dir, "package.json");
13487
+ if (existsSync12(pkgPath)) {
13488
+ const content = readFileSync6(pkgPath, "utf-8");
13489
+ if (content.includes('"nexus-agents"')) return dir;
13490
+ }
13491
+ dir = join14(dir, "..");
13492
+ }
13493
+ return join14(import.meta.dirname, "../..");
13494
+ }
13495
+ var PKG_ROOT = findPkgRoot();
13496
+ var SRC_ROOT = join14(PKG_ROOT, "src");
13497
+ var REPO_ROOT = join14(PKG_ROOT, "../..");
13498
+ var DOCS_ROOT = join14(REPO_ROOT, "docs");
13499
+ var DETERMINISM_EXCLUDES = [
13500
+ /\.test\.ts$/,
13501
+ /\.spec\.ts$/,
13502
+ /random-provider\.ts$/,
13503
+ /time-provider\.ts$/
13504
+ ];
13505
+ function countFiles(dir, pattern) {
13506
+ if (!existsSync12(dir)) return 0;
13507
+ let count = 0;
13508
+ for (const entry of readdirSync(dir)) {
13509
+ const fullPath = join14(dir, entry);
13510
+ const stat2 = statSync(fullPath);
13511
+ if (stat2.isDirectory() && !entry.startsWith(".")) {
13512
+ count += countFiles(fullPath, pattern);
13513
+ } else if (pattern.test(entry)) {
13514
+ count++;
13515
+ }
13516
+ }
13517
+ return count;
13518
+ }
13519
+ function fileContains(filePath, pattern) {
13520
+ if (!existsSync12(filePath)) return false;
13521
+ return pattern.test(readFileSync6(filePath, "utf-8"));
13522
+ }
13523
+ function isExcluded(entry, excludePatterns) {
13524
+ return excludePatterns?.some((p) => p.test(entry)) ?? false;
13525
+ }
13526
+ function countMatchesInFile(fullPath, contentPattern) {
13527
+ const matches = readFileSync6(fullPath, "utf-8").match(contentPattern);
13528
+ return matches?.length ?? 0;
13529
+ }
13530
+ function countPatternInDir(dir, filePattern, contentPattern, excludePatterns) {
13531
+ if (!existsSync12(dir)) return 0;
13532
+ let count = 0;
13533
+ for (const entry of readdirSync(dir)) {
13534
+ const fullPath = join14(dir, entry);
13535
+ const stat2 = statSync(fullPath);
13536
+ if (stat2.isDirectory() && !entry.startsWith(".") && entry !== "node_modules") {
13537
+ count += countPatternInDir(fullPath, filePattern, contentPattern, excludePatterns);
13538
+ } else if (filePattern.test(entry) && !isExcluded(entry, excludePatterns)) {
13539
+ count += countMatchesInFile(fullPath, contentPattern);
13540
+ }
13541
+ }
13542
+ return count;
13543
+ }
13544
+ function clamp2(score, max) {
13545
+ return Math.max(0, Math.min(max, score));
13546
+ }
13327
13547
  var FitnessScoreCalculator = class {
13328
13548
  logger;
13329
13549
  checks = [];
@@ -13331,62 +13551,26 @@ var FitnessScoreCalculator = class {
13331
13551
  this.logger = logger17 ?? createLogger({ component: "FitnessScoreCalculator" });
13332
13552
  this.registerDefaultChecks();
13333
13553
  }
13334
- /**
13335
- * Register default fitness checks.
13336
- */
13554
+ /** Register default fitness checks. */
13337
13555
  registerDefaultChecks() {
13338
- this.checks.push({
13339
- dimension: "canonicalPaths",
13340
- maxPoints: 20,
13341
- name: "Canonical Path Analysis",
13342
- check: () => this.checkCanonicalPaths()
13343
- });
13344
- this.checks.push({
13345
- dimension: "explicitBehavior",
13346
- maxPoints: 15,
13347
- name: "Explicit Behavior Analysis",
13348
- check: () => this.checkExplicitBehavior()
13349
- });
13350
- this.checks.push({
13351
- dimension: "determinism",
13352
- maxPoints: 15,
13353
- name: "Determinism Analysis",
13354
- check: () => this.checkDeterminism()
13355
- });
13356
- this.checks.push({
13357
- dimension: "observability",
13358
- maxPoints: 15,
13359
- name: "Observability Analysis",
13360
- check: () => this.checkObservability()
13361
- });
13362
- this.checks.push({
13363
- dimension: "configSimplicity",
13364
- maxPoints: 10,
13365
- name: "Config Simplicity Analysis",
13366
- check: () => this.checkConfigSimplicity()
13367
- });
13368
- this.checks.push({
13369
- dimension: "layerSeparation",
13370
- maxPoints: 10,
13371
- name: "Layer Separation Analysis",
13372
- check: () => this.checkLayerSeparation()
13373
- });
13374
- this.checks.push({
13375
- dimension: "operatorErgonomics",
13376
- maxPoints: 10,
13377
- name: "Operator Ergonomics Analysis",
13378
- check: () => this.checkOperatorErgonomics()
13379
- });
13380
- this.checks.push({
13381
- dimension: "governanceIntegration",
13382
- maxPoints: 5,
13383
- name: "Governance Integration Analysis",
13384
- check: () => this.checkGovernanceIntegration()
13385
- });
13556
+ const reg = (dimension, maxPoints, name, check) => {
13557
+ this.checks.push({ dimension, maxPoints, name, check });
13558
+ };
13559
+ reg("canonicalPaths", 20, "Canonical Paths", () => this.checkCanonicalPaths());
13560
+ reg("explicitBehavior", 15, "Explicit Behavior", () => this.checkExplicitBehavior());
13561
+ reg("determinism", 15, "Determinism", () => this.checkDeterminism());
13562
+ reg("observability", 15, "Observability", () => this.checkObservability());
13563
+ reg("configSimplicity", 10, "Config Simplicity", () => this.checkConfigSimplicity());
13564
+ reg("layerSeparation", 10, "Layer Separation", () => this.checkLayerSeparation());
13565
+ reg("operatorErgonomics", 10, "Operator Ergonomics", () => this.checkOperatorErgonomics());
13566
+ reg(
13567
+ "governanceIntegration",
13568
+ 5,
13569
+ "Governance Integration",
13570
+ () => this.checkGovernanceIntegration()
13571
+ );
13386
13572
  }
13387
- /**
13388
- * Run full fitness audit.
13389
- */
13573
+ /** Run full fitness audit. */
13390
13574
  audit(version) {
13391
13575
  const findings = [];
13392
13576
  const dimensions = {};
@@ -13407,80 +13591,391 @@ var FitnessScoreCalculator = class {
13407
13591
  };
13408
13592
  }
13409
13593
  // =========================================================================
13410
- // Individual Checks
13594
+ // Individual Checks — real filesystem analysis
13411
13595
  // =========================================================================
13412
- /**
13413
- * Check canonical paths - penalize duplicate paths to same workflow.
13414
- * Target: 18/20 after consolidation (per Issue #574)
13415
- */
13596
+ /** Check canonical paths: penalize duplicate router implementations. */
13416
13597
  checkCanonicalPaths() {
13417
13598
  const findings = [];
13418
- const score = 20;
13419
- return { score: Math.max(0, score), findings };
13599
+ let score = 20;
13600
+ const routerCount = countFiles(join14(SRC_ROOT, "cli-adapters"), /router\.ts$/);
13601
+ if (routerCount > 5) {
13602
+ const excess = routerCount - 5;
13603
+ const deduction = Math.min(5, excess);
13604
+ score -= deduction;
13605
+ findings.push(
13606
+ this.finding(
13607
+ "canonicalPaths",
13608
+ "warning",
13609
+ `${String(routerCount)} router implementations found (target: <=5)`,
13610
+ deduction,
13611
+ "Consolidate duplicate routers into CompositeRouter"
13612
+ )
13613
+ );
13614
+ }
13615
+ if (existsSync12(join14(SRC_ROOT, "cli-adapters/composite-router.ts"))) {
13616
+ score += 2;
13617
+ } else {
13618
+ score -= 3;
13619
+ findings.push(
13620
+ this.finding(
13621
+ "canonicalPaths",
13622
+ "critical",
13623
+ "CompositeRouter missing \u2014 no unified routing entry point",
13624
+ 3
13625
+ )
13626
+ );
13627
+ }
13628
+ score = this.checkOrchestratorInterface(score, findings);
13629
+ return { score: clamp2(score, 20), findings };
13630
+ }
13631
+ /** Sub-check for IOrchestrator interface and adapter wiring. */
13632
+ checkOrchestratorInterface(score, findings) {
13633
+ const orchPath = join14(SRC_ROOT, "core/types/orchestrator.ts");
13634
+ if (existsSync12(orchPath) && fileContains(orchPath, /interface IOrchestrator/)) {
13635
+ score += 3;
13636
+ } else {
13637
+ score -= 2;
13638
+ findings.push(
13639
+ this.finding("canonicalPaths", "warning", "No IOrchestrator interface in core/types", 2)
13640
+ );
13641
+ }
13642
+ const adapterPath = join14(SRC_ROOT, "orchestration/orchestrator-adapters.ts");
13643
+ if (existsSync12(adapterPath) && fileContains(adapterPath, /TechLeadAdapter|PuppeteerAdapter/)) {
13644
+ score += 2;
13645
+ }
13646
+ return score;
13420
13647
  }
13421
13648
  /**
13422
- * Check explicit behavior - penalize hidden/magic behavior.
13649
+ * Check explicit behavior: penalize hidden/magic behavior.
13650
+ * TODO: This dimension lacks strong filesystem signals. Currently checks
13651
+ * for NEXUS_ALLOW_MOCK_ORCHESTRATION guard and magic routing patterns.
13652
+ * Future: add AST-based detection of implicit fallbacks.
13423
13653
  */
13424
13654
  checkExplicitBehavior() {
13425
13655
  const findings = [];
13426
- const score = 15;
13427
- return { score, findings };
13656
+ let score = 15;
13657
+ const mockGuardCount = countPatternInDir(
13658
+ SRC_ROOT,
13659
+ /\.ts$/,
13660
+ /NEXUS_ALLOW_MOCK_ORCHESTRATION/g,
13661
+ DETERMINISM_EXCLUDES
13662
+ );
13663
+ if (mockGuardCount === 0) {
13664
+ score -= 3;
13665
+ findings.push(
13666
+ this.finding(
13667
+ "explicitBehavior",
13668
+ "warning",
13669
+ "No NEXUS_ALLOW_MOCK_ORCHESTRATION guard found \u2014 mock fallback may be implicit",
13670
+ 3,
13671
+ "Require explicit env var for mock orchestration"
13672
+ )
13673
+ );
13674
+ }
13675
+ const magicRouting = countPatternInDir(
13676
+ SRC_ROOT,
13677
+ /\.ts$/,
13678
+ /fallback.*=.*true|implicitRoute/g,
13679
+ DETERMINISM_EXCLUDES
13680
+ );
13681
+ if (magicRouting > 5) {
13682
+ const deduction = Math.min(3, Math.floor(magicRouting / 3));
13683
+ score -= deduction;
13684
+ findings.push(
13685
+ this.finding(
13686
+ "explicitBehavior",
13687
+ "info",
13688
+ `${String(magicRouting)} implicit fallback/routing patterns detected`,
13689
+ deduction
13690
+ )
13691
+ );
13692
+ }
13693
+ return { score: clamp2(score, 15), findings };
13428
13694
  }
13429
- /**
13430
- * Check determinism - reward deterministic execution.
13431
- */
13695
+ /** Check determinism: penalize unseeded random and raw Date.now(). */
13432
13696
  checkDeterminism() {
13433
13697
  const findings = [];
13434
13698
  let score = 15;
13435
- score -= 2;
13436
- findings.push({
13437
- dimension: "determinism",
13438
- severity: "info",
13439
- description: "Consensus voting uses LLM responses which are non-deterministic",
13440
- pointsDeducted: 2,
13441
- suggestion: "Consider caching/memoization for repeated proposals"
13442
- });
13443
- return { score: Math.max(0, score), findings };
13699
+ score = this.checkRandomDeterminism(score, findings);
13700
+ score = this.checkTimeDeterminism(score, findings);
13701
+ return { score: clamp2(score, 15), findings };
13702
+ }
13703
+ /** Sub-check for Math.random() and injectable random provider. */
13704
+ checkRandomDeterminism(score, findings) {
13705
+ const randomCount = countPatternInDir(
13706
+ SRC_ROOT,
13707
+ /\.ts$/,
13708
+ /Math\.random\(\)/g,
13709
+ DETERMINISM_EXCLUDES
13710
+ );
13711
+ if (randomCount > 10) {
13712
+ const deduction = Math.min(5, Math.floor(randomCount / 5));
13713
+ score -= deduction;
13714
+ findings.push(
13715
+ this.finding(
13716
+ "determinism",
13717
+ "warning",
13718
+ `${String(randomCount)} unseeded Math.random() calls in production code`,
13719
+ deduction,
13720
+ "Use getRandomProvider() for injectable randomness"
13721
+ )
13722
+ );
13723
+ } else if (randomCount === 0) {
13724
+ score += 2;
13725
+ }
13726
+ if (existsSync12(join14(SRC_ROOT, "core/random-provider.ts"))) {
13727
+ score += 1;
13728
+ }
13729
+ const randomUsage = countPatternInDir(
13730
+ SRC_ROOT,
13731
+ /\.ts$/,
13732
+ /getRandomProvider\(\)/g,
13733
+ DETERMINISM_EXCLUDES
13734
+ );
13735
+ if (randomUsage > 5) {
13736
+ score += 1;
13737
+ }
13738
+ return score;
13444
13739
  }
13445
- /**
13446
- * Check observability - reward telemetry coverage.
13447
- */
13740
+ /** Sub-check for Date.now() and injectable time provider. */
13741
+ checkTimeDeterminism(score, findings) {
13742
+ const dateNowCount = countPatternInDir(
13743
+ SRC_ROOT,
13744
+ /\.ts$/,
13745
+ /Date\.now\(\)/g,
13746
+ DETERMINISM_EXCLUDES
13747
+ );
13748
+ if (dateNowCount > 50) {
13749
+ score -= 2;
13750
+ findings.push(
13751
+ this.finding(
13752
+ "determinism",
13753
+ "info",
13754
+ `${String(dateNowCount)} Date.now() calls in production code`,
13755
+ 2,
13756
+ "Use getTimeProvider() for injectable time"
13757
+ )
13758
+ );
13759
+ }
13760
+ if (existsSync12(join14(SRC_ROOT, "core/time-provider.ts"))) {
13761
+ score += 1;
13762
+ }
13763
+ const timeUsage = countPatternInDir(
13764
+ SRC_ROOT,
13765
+ /\.ts$/,
13766
+ /getTimeProvider\(\)/g,
13767
+ DETERMINISM_EXCLUDES
13768
+ );
13769
+ if (timeUsage > 10) {
13770
+ score += 1;
13771
+ }
13772
+ return score;
13773
+ }
13774
+ /** Check observability: reward tracing, logging, and audit coverage. */
13448
13775
  checkObservability() {
13449
13776
  const findings = [];
13450
- const score = 15;
13451
- return { score: Math.max(0, score), findings };
13777
+ let score = 15;
13778
+ if (existsSync12(join14(SRC_ROOT, "observability/swarm-observer.ts"))) {
13779
+ score += 3;
13780
+ } else {
13781
+ score -= 3;
13782
+ findings.push(
13783
+ this.finding(
13784
+ "observability",
13785
+ "warning",
13786
+ "No SwarmObserver found",
13787
+ 3,
13788
+ "Add observability/swarm-observer.ts"
13789
+ )
13790
+ );
13791
+ }
13792
+ if (existsSync12(join14(SRC_ROOT, "core/trace.ts"))) {
13793
+ score += 2;
13794
+ }
13795
+ const loggerCount = countPatternInDir(SRC_ROOT, /\.ts$/, /createLogger\(/g);
13796
+ if (loggerCount > 50) {
13797
+ score += 2;
13798
+ } else {
13799
+ findings.push(
13800
+ this.finding(
13801
+ "observability",
13802
+ "info",
13803
+ `Only ${String(loggerCount)} createLogger() calls (target: >50)`,
13804
+ 0
13805
+ )
13806
+ );
13807
+ }
13808
+ if (existsSync12(join14(SRC_ROOT, "audit"))) {
13809
+ score += 2;
13810
+ }
13811
+ return { score: clamp2(score, 15), findings };
13452
13812
  }
13453
- /**
13454
- * Check config simplicity - penalize too many config surfaces.
13455
- */
13813
+ /** Check config simplicity: penalize excessive schema sprawl. */
13456
13814
  checkConfigSimplicity() {
13457
13815
  const findings = [];
13458
- const score = 10;
13459
- return { score: Math.max(0, score), findings };
13816
+ let score = 10;
13817
+ const schemaCount = countFiles(join14(SRC_ROOT, "config"), /schema.*\.ts$/);
13818
+ if (schemaCount > 10) {
13819
+ score -= 2;
13820
+ findings.push(
13821
+ this.finding(
13822
+ "configSimplicity",
13823
+ "info",
13824
+ `${String(schemaCount)} config schemas (target: <=10)`,
13825
+ 2,
13826
+ "Consolidate related schemas"
13827
+ )
13828
+ );
13829
+ } else {
13830
+ score += 1;
13831
+ }
13832
+ if (existsSync12(join14(SRC_ROOT, "config/config-loader.ts"))) {
13833
+ score += 2;
13834
+ }
13835
+ if (existsSync12(join14(SRC_ROOT, "config/config-manager.ts"))) {
13836
+ score += 1;
13837
+ }
13838
+ return { score: clamp2(score, 10), findings };
13460
13839
  }
13461
- /**
13462
- * Check layer separation - penalize cross-layer coupling.
13463
- */
13840
+ /** Check layer separation: penalize cross-layer imports. */
13464
13841
  checkLayerSeparation() {
13465
13842
  const findings = [];
13466
- const score = 10;
13467
- return { score: Math.max(0, score), findings };
13843
+ let score = 10;
13844
+ const adapterAgentImports = countPatternInDir(
13845
+ join14(SRC_ROOT, "adapters"),
13846
+ /\.ts$/,
13847
+ /from ['"]\.\.\/agents\//g
13848
+ );
13849
+ if (adapterAgentImports > 0) {
13850
+ const deduction = Math.min(5, adapterAgentImports);
13851
+ score -= deduction;
13852
+ findings.push(
13853
+ this.finding(
13854
+ "layerSeparation",
13855
+ "warning",
13856
+ `${String(adapterAgentImports)} adapter->agent import violations`,
13857
+ deduction,
13858
+ "Adapters should not import from agents layer"
13859
+ )
13860
+ );
13861
+ } else {
13862
+ score += 2;
13863
+ }
13864
+ const coreMcpImports = countPatternInDir(
13865
+ join14(SRC_ROOT, "core"),
13866
+ /\.ts$/,
13867
+ /from ['"]\.\.\/mcp\//g
13868
+ );
13869
+ if (coreMcpImports > 0) {
13870
+ const deduction = Math.min(3, coreMcpImports);
13871
+ score -= deduction;
13872
+ findings.push(
13873
+ this.finding(
13874
+ "layerSeparation",
13875
+ "critical",
13876
+ `${String(coreMcpImports)} core->MCP import violations`,
13877
+ deduction,
13878
+ "Core must not depend on MCP layer"
13879
+ )
13880
+ );
13881
+ } else {
13882
+ score += 1;
13883
+ }
13884
+ return { score: clamp2(score, 10), findings };
13468
13885
  }
13469
- /**
13470
- * Check operator ergonomics - reward minimal CLI steps.
13471
- */
13886
+ /** Check operator ergonomics: reward rich CLI commands. */
13472
13887
  checkOperatorErgonomics() {
13473
13888
  const findings = [];
13474
- const score = 10;
13475
- return { score: Math.max(0, score), findings };
13889
+ let score = 10;
13890
+ const commandCount = countFiles(join14(SRC_ROOT, "cli"), /\.ts$/);
13891
+ if (commandCount >= 20) {
13892
+ score += 3;
13893
+ } else {
13894
+ findings.push(
13895
+ this.finding(
13896
+ "operatorErgonomics",
13897
+ "info",
13898
+ `${String(commandCount)} CLI commands (target: >=20)`,
13899
+ 0
13900
+ )
13901
+ );
13902
+ }
13903
+ score = this.checkCliCommands(score, findings);
13904
+ return { score: clamp2(score, 10), findings };
13476
13905
  }
13477
- /**
13478
- * Check governance integration - reward governance injection.
13479
- */
13906
+ /** Sub-check for essential CLI commands (doctor, setup, demo, config). */
13907
+ checkCliCommands(score, findings) {
13908
+ const commands = [
13909
+ ["cli/doctor.ts", "Doctor command", 2],
13910
+ ["cli/setup-command.ts", "Setup wizard", 2],
13911
+ ["cli/demo-command.ts", "Demo command", 1],
13912
+ ["cli/config-command.ts", "Config command", 1]
13913
+ ];
13914
+ for (const [path23, name, bonus] of commands) {
13915
+ if (existsSync12(join14(SRC_ROOT, path23))) {
13916
+ score += bonus;
13917
+ } else {
13918
+ findings.push(this.finding("operatorErgonomics", "info", `Missing ${name} (${path23})`, 0));
13919
+ }
13920
+ }
13921
+ return score;
13922
+ }
13923
+ /** Check governance integration: policy firewall, rate limiter, docs. */
13480
13924
  checkGovernanceIntegration() {
13481
13925
  const findings = [];
13482
- const score = 5;
13483
- return { score, findings };
13926
+ let score = 5;
13927
+ score = this.checkGovernanceDocs(score, findings);
13928
+ score = this.checkGovernanceInfra(score, findings);
13929
+ return { score: clamp2(score, 5), findings };
13930
+ }
13931
+ /** Sub-check for governance documentation artifacts. */
13932
+ checkGovernanceDocs(score, findings) {
13933
+ if (!existsSync12(join14(REPO_ROOT, "CLAUDE.md"))) {
13934
+ score -= 3;
13935
+ findings.push(
13936
+ this.finding("governanceIntegration", "critical", "No CLAUDE.md governance document", 3)
13937
+ );
13938
+ } else {
13939
+ score += 1;
13940
+ }
13941
+ if (existsSync12(join14(DOCS_ROOT, "architecture/wiring-graph.json"))) {
13942
+ score += 1;
13943
+ }
13944
+ if (existsSync12(join14(DOCS_ROOT, "adr"))) {
13945
+ score += 1;
13946
+ } else {
13947
+ findings.push(this.finding("governanceIntegration", "info", "No ADR directory", 0));
13948
+ }
13949
+ return score;
13950
+ }
13951
+ /** Sub-check for governance runtime infrastructure. */
13952
+ checkGovernanceInfra(score, findings) {
13953
+ const hasPolicyFirewall = countPatternInDir(join14(SRC_ROOT, "security"), /\.ts$/, /PolicyGate|policyFirewall/g) > 0;
13954
+ if (hasPolicyFirewall) {
13955
+ score += 1;
13956
+ } else {
13957
+ findings.push(
13958
+ this.finding(
13959
+ "governanceIntegration",
13960
+ "warning",
13961
+ "No policy firewall detected in security layer",
13962
+ 0
13963
+ )
13964
+ );
13965
+ }
13966
+ const hasRateLimiter = countPatternInDir(SRC_ROOT, /\.ts$/, /RateLimiter|rateLimiter/g) > 0;
13967
+ if (hasRateLimiter) {
13968
+ score += 1;
13969
+ }
13970
+ return score;
13971
+ }
13972
+ /** Helper to create a FitnessFinding with defaults. */
13973
+ finding(dimension, severity, description, pointsDeducted, suggestion) {
13974
+ const base = { dimension, severity, description, pointsDeducted };
13975
+ if (suggestion !== void 0) {
13976
+ return { ...base, suggestion };
13977
+ }
13978
+ return base;
13484
13979
  }
13485
13980
  };
13486
13981
  function createFitnessScoreCalculator(logger17) {
@@ -13658,10 +14153,10 @@ var CATEGORY_ORDER = [
13658
14153
  ];
13659
14154
 
13660
14155
  // src/cli/release-notes-helpers.ts
13661
- import { execSync as execSync2 } from "child_process";
14156
+ import { execFileSync } from "child_process";
13662
14157
  function getLatestTag() {
13663
14158
  try {
13664
- const result = execSync2("git describe --tags --abbrev=0", {
14159
+ const result = execFileSync("git", ["describe", "--tags", "--abbrev=0"], {
13665
14160
  encoding: "utf-8",
13666
14161
  stdio: ["pipe", "pipe", "pipe"],
13667
14162
  timeout: CLI_SUBPROCESS_TIMEOUTS.ghCommandMs
@@ -13672,8 +14167,12 @@ function getLatestTag() {
13672
14167
  }
13673
14168
  }
13674
14169
  function getCommitsBetween(from, to = "HEAD") {
14170
+ const SAFE_REF = /^[a-zA-Z0-9._\-/~^]+$/;
14171
+ if (!SAFE_REF.test(from) || !SAFE_REF.test(to)) {
14172
+ return [];
14173
+ }
13675
14174
  try {
13676
- const result = execSync2(`git log ${from}..${to} --oneline --format="%h %s"`, {
14175
+ const result = execFileSync("git", ["log", `${from}..${to}`, "--oneline", "--format=%h %s"], {
13677
14176
  encoding: "utf-8",
13678
14177
  stdio: ["pipe", "pipe", "pipe"],
13679
14178
  timeout: CLI_SUBPROCESS_TIMEOUTS.ghCommandMs
@@ -13920,16 +14419,16 @@ async function releaseNotesCommand(args) {
13920
14419
  }
13921
14420
 
13922
14421
  // src/cli/release-validate-command.ts
13923
- import { readFileSync as readFileSync7 } from "fs";
14422
+ import { readFileSync as readFileSync8 } from "fs";
13924
14423
 
13925
14424
  // src/cli/release-validate-helpers.ts
13926
- import { execSync as execSync3 } from "child_process";
13927
- import { existsSync as existsSync12, readFileSync as readFileSync6 } from "fs";
14425
+ import { execSync as execSync2 } from "child_process";
14426
+ import { existsSync as existsSync13, readFileSync as readFileSync7 } from "fs";
13928
14427
  async function validateSecurity(options) {
13929
14428
  const startTime = Date.now();
13930
14429
  const findings = [];
13931
14430
  try {
13932
- execSync3("npm audit --audit-level=high 2>/dev/null", {
14431
+ execSync2("npm audit --audit-level=high 2>/dev/null", {
13933
14432
  encoding: "utf-8",
13934
14433
  stdio: ["pipe", "pipe", "pipe"],
13935
14434
  timeout: CLI_SUBPROCESS_TIMEOUTS.ghCommandMs
@@ -13943,7 +14442,7 @@ async function validateSecurity(options) {
13943
14442
  remediation: "Run npm audit fix or review and update vulnerable dependencies."
13944
14443
  });
13945
14444
  }
13946
- if (existsSync12(".env")) {
14445
+ if (existsSync13(".env")) {
13947
14446
  findings.push({
13948
14447
  severity: "error",
13949
14448
  category: "security",
@@ -13953,7 +14452,7 @@ async function validateSecurity(options) {
13953
14452
  });
13954
14453
  }
13955
14454
  try {
13956
- const result = execSync3(
14455
+ const result = execSync2(
13957
14456
  'git diff HEAD~10..HEAD -- "*.ts" "*.js" | grep -iE "(api[_-]?key|secret|password|token)" | head -5',
13958
14457
  {
13959
14458
  encoding: "utf-8",
@@ -13984,7 +14483,7 @@ async function validateArchitecture2(options) {
13984
14483
  const startTime = Date.now();
13985
14484
  const findings = [];
13986
14485
  try {
13987
- const result = execSync3("npx nexus-agents fitness-audit --format=json 2>/dev/null", {
14486
+ const result = execSync2("npx nexus-agents fitness-audit --format=json 2>/dev/null", {
13988
14487
  encoding: "utf-8",
13989
14488
  stdio: ["pipe", "pipe", "pipe"],
13990
14489
  timeout: CLI_SUBPROCESS_TIMEOUTS.releaseValidateMs
@@ -14039,7 +14538,7 @@ async function validateArchitecture2(options) {
14039
14538
  async function validateDocumentation(options) {
14040
14539
  const startTime = Date.now();
14041
14540
  const findings = [];
14042
- if (!existsSync12("CHANGELOG.md")) {
14541
+ if (!existsSync13("CHANGELOG.md")) {
14043
14542
  findings.push({
14044
14543
  severity: "error",
14045
14544
  category: "docs",
@@ -14047,7 +14546,7 @@ async function validateDocumentation(options) {
14047
14546
  description: "No CHANGELOG.md found in repository root.",
14048
14547
  remediation: "Create CHANGELOG.md following Keep a Changelog format."
14049
14548
  });
14050
- } else if (!readFileSync6("CHANGELOG.md", "utf-8").includes(options.version)) {
14549
+ } else if (!readFileSync7("CHANGELOG.md", "utf-8").includes(options.version)) {
14051
14550
  findings.push({
14052
14551
  severity: "warning",
14053
14552
  category: "docs",
@@ -14057,7 +14556,7 @@ async function validateDocumentation(options) {
14057
14556
  });
14058
14557
  }
14059
14558
  const pkgCl = "packages/nexus-agents/CHANGELOG.md";
14060
- if (existsSync12(pkgCl) && !readFileSync6(pkgCl, "utf-8").includes(options.version)) {
14559
+ if (existsSync13(pkgCl) && !readFileSync7(pkgCl, "utf-8").includes(options.version)) {
14061
14560
  findings.push({
14062
14561
  severity: "warning",
14063
14562
  category: "docs",
@@ -14066,7 +14565,7 @@ async function validateDocumentation(options) {
14066
14565
  remediation: "Run pnpm changeset:version to generate changelog from pending changesets."
14067
14566
  });
14068
14567
  }
14069
- if (!existsSync12("README.md")) {
14568
+ if (!existsSync13("README.md")) {
14070
14569
  findings.push({
14071
14570
  severity: "error",
14072
14571
  category: "docs",
@@ -14075,8 +14574,8 @@ async function validateDocumentation(options) {
14075
14574
  remediation: "Create README.md with project overview and usage instructions."
14076
14575
  });
14077
14576
  }
14078
- if (existsSync12("CLAUDE.md")) {
14079
- const claudeMd = readFileSync6("CLAUDE.md", "utf-8");
14577
+ if (existsSync13("CLAUDE.md")) {
14578
+ const claudeMd = readFileSync7("CLAUDE.md", "utf-8");
14080
14579
  const match = claudeMd.match(/Governance Version: (\d{4}-\d{2}-\d{2})/);
14081
14580
  if (match?.[1]) {
14082
14581
  const governanceDate = new Date(match[1]);
@@ -14105,7 +14604,7 @@ async function validateDevOps(options) {
14105
14604
  const startTime = Date.now();
14106
14605
  const findings = [];
14107
14606
  try {
14108
- execSync3("pnpm build 2>/dev/null", {
14607
+ execSync2("pnpm build 2>/dev/null", {
14109
14608
  encoding: "utf-8",
14110
14609
  stdio: ["pipe", "pipe", "pipe"],
14111
14610
  timeout: CLI_SUBPROCESS_TIMEOUTS.releaseValidateMs
@@ -14126,7 +14625,7 @@ async function validateDevOps(options) {
14126
14625
  });
14127
14626
  }
14128
14627
  try {
14129
- execSync3("pnpm lint 2>/dev/null", {
14628
+ execSync2("pnpm lint 2>/dev/null", {
14130
14629
  encoding: "utf-8",
14131
14630
  stdio: ["pipe", "pipe", "pipe"],
14132
14631
  timeout: CLI_SUBPROCESS_TIMEOUTS.releaseBuildMs
@@ -14147,7 +14646,7 @@ async function validateDevOps(options) {
14147
14646
  });
14148
14647
  }
14149
14648
  try {
14150
- execSync3("pnpm typecheck 2>/dev/null", {
14649
+ execSync2("pnpm typecheck 2>/dev/null", {
14151
14650
  encoding: "utf-8",
14152
14651
  stdio: ["pipe", "pipe", "pipe"],
14153
14652
  timeout: CLI_SUBPROCESS_TIMEOUTS.releaseValidateMs
@@ -14184,7 +14683,7 @@ var DEFAULT_OPTIONS2 = {
14184
14683
  };
14185
14684
  function readVersionFromPackage() {
14186
14685
  try {
14187
- const raw = JSON.parse(readFileSync7("package.json", "utf-8"));
14686
+ const raw = JSON.parse(readFileSync8("package.json", "utf-8"));
14188
14687
  if (typeof raw === "object" && raw !== null && "version" in raw) {
14189
14688
  const pkg = raw;
14190
14689
  return typeof pkg.version === "string" ? pkg.version : "unknown";
@@ -14298,7 +14797,7 @@ async function releaseValidateCommand(args) {
14298
14797
  }
14299
14798
 
14300
14799
  // src/cli/release-announce-command.ts
14301
- import { readFileSync as readFileSync8, existsSync as existsSync13 } from "fs";
14800
+ import { readFileSync as readFileSync9, existsSync as existsSync14 } from "fs";
14302
14801
 
14303
14802
  // src/cli/release-announce-types.ts
14304
14803
  var BLUESKY_LIMITS = {
@@ -14323,7 +14822,7 @@ function getBlueskyConfig() {
14323
14822
  }
14324
14823
  async function loadAtproto() {
14325
14824
  try {
14326
- const mod = await import("./dist-H5XNXVAV.js");
14825
+ const mod = await import("./dist-CV74KUT7.js");
14327
14826
  return { AtpAgent: mod.AtpAgent, RichText: mod.RichText };
14328
14827
  } catch {
14329
14828
  return void 0;
@@ -14365,8 +14864,8 @@ var DEFAULT_OPTIONS3 = {
14365
14864
  verbose: false
14366
14865
  };
14367
14866
  function extractHighlightsFromChangelog(version) {
14368
- if (!existsSync13("CHANGELOG.md")) return [];
14369
- const changelog = readFileSync8("CHANGELOG.md", "utf-8");
14867
+ if (!existsSync14("CHANGELOG.md")) return [];
14868
+ const changelog = readFileSync9("CHANGELOG.md", "utf-8");
14370
14869
  const escaped = version.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
14371
14870
  const versionRegex = new RegExp(`## \\[${escaped}\\][^#]*`, "s");
14372
14871
  const match = changelog.match(versionRegex);
@@ -14628,7 +15127,7 @@ async function releaseAnnounceCommand(args) {
14628
15127
  version = args.options.version;
14629
15128
  } else {
14630
15129
  try {
14631
- const pkg = JSON.parse(readFileSync8("package.json", "utf-8"));
15130
+ const pkg = JSON.parse(readFileSync9("package.json", "utf-8"));
14632
15131
  if (!pkg.version) {
14633
15132
  console.error(`${colors.red}Error: Could not determine version${colors.reset}`);
14634
15133
  return 1;
@@ -14655,8 +15154,8 @@ async function releaseAnnounceCommand(args) {
14655
15154
  }
14656
15155
 
14657
15156
  // src/cli/scaffold.ts
14658
- import * as fs15 from "fs";
14659
- import * as path21 from "path";
15157
+ import * as fs16 from "fs";
15158
+ import * as path20 from "path";
14660
15159
 
14661
15160
  // src/cli/scaffold-templates.ts
14662
15161
  function toolImportsAndSchema(name, pascal) {
@@ -14992,17 +15491,17 @@ ${lines}`;
14992
15491
  function writeFiles(files) {
14993
15492
  const createdPaths = [];
14994
15493
  for (const file of files) {
14995
- const fullPath = path21.resolve(process.cwd(), file.path);
14996
- const dir = path21.dirname(fullPath);
14997
- fs15.mkdirSync(dir, { recursive: true });
14998
- if (fs15.existsSync(fullPath)) {
15494
+ const fullPath = path20.resolve(process.cwd(), file.path);
15495
+ const dir = path20.dirname(fullPath);
15496
+ fs16.mkdirSync(dir, { recursive: true });
15497
+ if (fs16.existsSync(fullPath)) {
14999
15498
  return {
15000
15499
  success: false,
15001
15500
  filesCreated: createdPaths,
15002
15501
  message: `File already exists: ${file.path}. Use a different name.`
15003
15502
  };
15004
15503
  }
15005
- fs15.writeFileSync(fullPath, file.content, "utf-8");
15504
+ fs16.writeFileSync(fullPath, file.content, "utf-8");
15006
15505
  createdPaths.push(file.path);
15007
15506
  }
15008
15507
  const lines = createdPaths.map((p) => ` ${p}`).join("\n");
@@ -15079,8 +15578,18 @@ var LATENCY_RANGES = {
15079
15578
  secondary: { min: 3e3, max: 8e3 },
15080
15579
  other: { min: 5e3, max: 15e3 }
15081
15580
  };
15082
- function pickCategory() {
15083
- const roll = Math.random();
15581
+ function createRng(seed) {
15582
+ if (seed === void 0) return Math.random;
15583
+ let s = seed | 0;
15584
+ return () => {
15585
+ s = s + 1831565813 | 0;
15586
+ let t = Math.imul(s ^ s >>> 15, 1 | s);
15587
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
15588
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
15589
+ };
15590
+ }
15591
+ function pickCategory(rng) {
15592
+ const roll = rng();
15084
15593
  let cumulative = 0;
15085
15594
  for (const [category, weight] of DEFAULT_TASK_DISTRIBUTION) {
15086
15595
  cumulative += weight;
@@ -15088,12 +15597,12 @@ function pickCategory() {
15088
15597
  }
15089
15598
  return "code_generation";
15090
15599
  }
15091
- function pickCli(category) {
15600
+ function pickCli(category, rng) {
15092
15601
  const primary = PRIMARY_CLI.get(category) ?? "claude";
15093
- const roll = Math.random();
15602
+ const roll = rng();
15094
15603
  if (roll < 0.5) return primary;
15095
15604
  if (roll < 0.75) return CLI_NAMES3.find((c) => c !== primary) ?? "gemini";
15096
- return CLI_NAMES3[Math.floor(Math.random() * CLI_NAMES3.length)] ?? "claude";
15605
+ return CLI_NAMES3[Math.floor(rng() * CLI_NAMES3.length)] ?? "claude";
15097
15606
  }
15098
15607
  function getCliRole(cli, category) {
15099
15608
  const primary = PRIMARY_CLI.get(category);
@@ -15112,12 +15621,12 @@ function getCliRole(cli, category) {
15112
15621
  ]);
15113
15622
  return cli === secondaryMap.get(category) ? "secondary" : "other";
15114
15623
  }
15115
- function simulateTask(taskIndex, category, cli) {
15624
+ function simulateTask(taskIndex, category, cli, rng) {
15116
15625
  const role = getCliRole(cli, category);
15117
15626
  const successRate = SUCCESS_RATES[role];
15118
15627
  const latency = LATENCY_RANGES[role];
15119
- const success = Math.random() < successRate;
15120
- const durationMs = latency.min + Math.random() * (latency.max - latency.min);
15628
+ const success = rng() < successRate;
15629
+ const durationMs = latency.min + rng() * (latency.max - latency.min);
15121
15630
  return {
15122
15631
  id: `e2e-${String(taskIndex)}-${cli}-${category}`,
15123
15632
  cli,
@@ -15130,7 +15639,7 @@ function simulateTask(taskIndex, category, cli) {
15130
15639
  source: "manual"
15131
15640
  };
15132
15641
  }
15133
- function generateOutcomes(taskCount) {
15642
+ function generateOutcomes(taskCount, rng) {
15134
15643
  const store = getOutcomeStore();
15135
15644
  const success = /* @__PURE__ */ new Map();
15136
15645
  const total = /* @__PURE__ */ new Map();
@@ -15139,9 +15648,9 @@ function generateOutcomes(taskCount) {
15139
15648
  total.set(cli, 0);
15140
15649
  }
15141
15650
  for (let i = 0; i < taskCount; i++) {
15142
- const category = pickCategory();
15143
- const cli = pickCli(category);
15144
- const outcome = simulateTask(i, category, cli);
15651
+ const category = pickCategory(rng);
15652
+ const cli = pickCli(category, rng);
15653
+ const outcome = simulateTask(i, category, cli, rng);
15145
15654
  store.append(outcome);
15146
15655
  total.set(cli, (total.get(cli) ?? 0) + 1);
15147
15656
  if (outcome.success) success.set(cli, (success.get(cli) ?? 0) + 1);
@@ -15192,7 +15701,8 @@ function runE2EEval(config, logger17) {
15192
15701
  resetOutcomeStore();
15193
15702
  setOutcomeStore(new OutcomeStore());
15194
15703
  }
15195
- const counts = generateOutcomes(taskCount);
15704
+ const rng = createRng(config?.seed);
15705
+ const counts = generateOutcomes(taskCount, rng);
15196
15706
  log.info("E2E eval: outcomes recorded", { taskCount });
15197
15707
  const { bonuses, nonZeroCount } = checkAdaptiveBonuses();
15198
15708
  const convergenceScore = computeConvergence(counts, nonZeroCount);
@@ -15549,13 +16059,13 @@ function formatEvalDetails(baseline, reflective, improvement, datasetSize) {
15549
16059
  }
15550
16060
 
15551
16061
  // src/cli/auth-command.ts
15552
- import { existsSync as existsSync15, statSync, chmodSync } from "fs";
16062
+ import { existsSync as existsSync16, statSync as statSync2, chmodSync } from "fs";
15553
16063
  function isValidAuthSubcommand(value) {
15554
16064
  return value === "init" || value === "show" || value === "rotate" || value === "help";
15555
16065
  }
15556
16066
  function getFilePermissions(filePath) {
15557
16067
  try {
15558
- const stats = statSync(filePath);
16068
+ const stats = statSync2(filePath);
15559
16069
  return (stats.mode & 511).toString(8);
15560
16070
  } catch {
15561
16071
  return void 0;
@@ -15569,7 +16079,7 @@ function fixPermissions(filePath) {
15569
16079
  }
15570
16080
  function runAuthInit(options) {
15571
16081
  const tokenFile = options.tokenFile ?? getDefaultTokenPath();
15572
- const tokenExists = existsSync15(tokenFile);
16082
+ const tokenExists = existsSync16(tokenFile);
15573
16083
  if (tokenExists && options.force !== true) {
15574
16084
  return {
15575
16085
  success: false,
@@ -15593,7 +16103,7 @@ function runAuthInit(options) {
15593
16103
  }
15594
16104
  function runAuthShow(options) {
15595
16105
  const tokenFile = options.tokenFile ?? getDefaultTokenPath();
15596
- const tokenExists = existsSync15(tokenFile);
16106
+ const tokenExists = existsSync16(tokenFile);
15597
16107
  const token = readStoredToken(tokenFile);
15598
16108
  if (!tokenExists || token === void 0) {
15599
16109
  return {
@@ -15614,7 +16124,7 @@ function runAuthShow(options) {
15614
16124
  }
15615
16125
  function runAuthRotate(options) {
15616
16126
  const tokenFile = options.tokenFile ?? getDefaultTokenPath();
15617
- const tokenExists = existsSync15(tokenFile);
16127
+ const tokenExists = existsSync16(tokenFile);
15618
16128
  if (!tokenExists) {
15619
16129
  return {
15620
16130
  success: false,
@@ -15650,14 +16160,14 @@ function runAuthCommand(options) {
15650
16160
  success: true,
15651
16161
  operation: "help",
15652
16162
  tokenFile: getDefaultTokenPath(),
15653
- tokenExists: existsSync15(getDefaultTokenPath())
16163
+ tokenExists: existsSync16(getDefaultTokenPath())
15654
16164
  };
15655
16165
  default:
15656
16166
  return {
15657
16167
  success: false,
15658
16168
  operation: "help",
15659
16169
  tokenFile: getDefaultTokenPath(),
15660
- tokenExists: existsSync15(getDefaultTokenPath()),
16170
+ tokenExists: existsSync16(getDefaultTokenPath()),
15661
16171
  error: `Unknown subcommand: ${String(subcommand)}`
15662
16172
  };
15663
16173
  }
@@ -15773,7 +16283,7 @@ function authCommand(subcommand, options) {
15773
16283
 
15774
16284
  // src/cli-help-text.ts
15775
16285
  var HELP_TEXT = `
15776
- nexus-agents - Multi-agent orchestration MCP server
16286
+ nexus-agents - Intelligent orchestration platform for AI coding tools
15777
16287
 
15778
16288
  USAGE:
15779
16289
  nexus-agents [OPTIONS]
@@ -15814,6 +16324,7 @@ COMMANDS:
15814
16324
  capabilities Show model capabilities matrix (modalities, tools, features)
15815
16325
  status At-a-glance project health dashboard (fitness, adapters, version)
15816
16326
  health Swarm health metrics dashboard (utilization, routing accuracy, failures)
16327
+ validate Run unified validation (doctor + fitness + config)
15817
16328
  auth Manage MCP authentication tokens (init, show, rotate)
15818
16329
 
15819
16330
  OPTIONS:
@@ -16415,15 +16926,142 @@ function isValidCommand(value) {
16415
16926
  "e2e-eval",
16416
16927
  "routing-ab",
16417
16928
  "memory-eval",
16418
- "health"
16929
+ "health",
16930
+ "validate"
16419
16931
  ];
16420
16932
  return validCommands.includes(value);
16421
16933
  }
16422
16934
 
16423
16935
  // src/cli-commands-handlers.ts
16424
- import { existsSync as existsSync17 } from "fs";
16425
- import { join as join17 } from "path";
16426
- import { homedir as homedir5 } from "os";
16936
+ import { existsSync as existsSync18 } from "fs";
16937
+ import { join as join16 } from "path";
16938
+ import { homedir as homedir4 } from "os";
16939
+
16940
+ // src/mcp/tools/dev-pipeline-tool.ts
16941
+ import { z as z7 } from "zod";
16942
+ import * as fs17 from "fs";
16943
+ import * as path21 from "path";
16944
+ var DevPipelineInputSchema = z7.object({
16945
+ /** Direct task instructions. */
16946
+ task: z7.string().max(1e4).optional().describe("Direct task instructions (what to build)"),
16947
+ /** Path to a plan file (.md, .yaml, .txt) to use as input. */
16948
+ planFile: z7.string().max(500).optional().describe("Path to a plan/spec file to use as input"),
16949
+ /** Whether to run in dry-run mode (plan+vote only, no implementation). */
16950
+ dryRun: z7.boolean().default(false).describe("If true, stop after plan+vote (no implementation)"),
16951
+ /** Maximum vote iterations before proceeding (default: 3). */
16952
+ maxVoteIterations: z7.number().int().min(1).max(5).default(3).describe("Max plan\u2192vote iterations"),
16953
+ /** Maximum QA iterations per task (default: 3). */
16954
+ maxQaIterations: z7.number().int().min(1).max(5).default(3).describe("Max QA review iterations per task"),
16955
+ /** Working directory for the pipeline (default: cwd). Used for security scan and context. */
16956
+ workingDir: z7.string().max(500).optional().describe("Working directory (default: cwd)"),
16957
+ /** GitHub issue number to track progress on. Updates posted as comments. */
16958
+ issueNumber: z7.number().int().positive().optional().describe("GitHub issue to post progress to"),
16959
+ /** GitHub repo (owner/name) for issue tracking. */
16960
+ repo: z7.string().max(200).optional().describe("GitHub repo for issue tracking (e.g., owner/repo)"),
16961
+ /** Task tracking backend: github, gitlab, or json (default: json). */
16962
+ trackerBackend: z7.enum(["github", "gitlab", "json"]).default("json").describe("Task tracking backend for issue creation"),
16963
+ /** Labels to apply to created issues. */
16964
+ labels: z7.array(z7.string()).optional().describe("Labels for created issues"),
16965
+ /** Session ID for checkpoint/resume. Enables crash recovery. */
16966
+ sessionId: z7.string().max(128).regex(/^[a-zA-Z0-9_-]+$/).optional().describe("Session ID for checkpoint/resume (crash recovery)"),
16967
+ /** When true, use simulated votes instead of real CLI consensus (for testing). */
16968
+ simulateVotes: z7.boolean().default(false).describe("Use simulated votes (for testing without real CLIs)"),
16969
+ /** Voting strategy for consensus stages. */
16970
+ votingStrategy: z7.enum([
16971
+ "simple_majority",
16972
+ "supermajority",
16973
+ "unanimous",
16974
+ "higher_order",
16975
+ "proof_of_learning",
16976
+ "opinion_wise"
16977
+ ]).optional().describe("Voting strategy for plan approval (default: higher_order)"),
16978
+ /** Use 3 agents instead of 6 for faster voting. */
16979
+ quickMode: z7.boolean().default(false).describe("Use 3 agents instead of 6 for faster consensus voting"),
16980
+ /** Maximum execution time per stage in milliseconds (min 30s, max 600s). */
16981
+ timeoutMs: z7.number().int().min(3e4).max(6e5).optional().describe("Max time per stage in ms (30000-600000). Default: varies by stage complexity"),
16982
+ /** Pipeline execution mode. */
16983
+ mode: z7.enum(["autonomous", "harness"]).default("autonomous").describe(
16984
+ "'autonomous': full pipeline. 'harness': stops after decompose, returns tasks for caller to implement."
16985
+ )
16986
+ });
16987
+ function resolveTaskInput(input) {
16988
+ if (input.task !== void 0 && input.task.trim() !== "") {
16989
+ return input.task;
16990
+ }
16991
+ if (input.planFile !== void 0) {
16992
+ const resolved = path21.resolve(input.planFile);
16993
+ const cwdRoot = path21.resolve(".");
16994
+ if (!resolved.startsWith(cwdRoot)) {
16995
+ throw new Error(`Path traversal denied: planFile must be within ${cwdRoot}`);
16996
+ }
16997
+ if (!fs17.existsSync(resolved)) {
16998
+ throw new Error(`Plan file not found: ${resolved}`);
16999
+ }
17000
+ return fs17.readFileSync(resolved, "utf-8");
17001
+ }
17002
+ throw new Error("Either task or planFile must be provided");
17003
+ }
17004
+ async function createStages(input) {
17005
+ const backendChoice = input.trackerBackend;
17006
+ const backend = backendChoice === "json" && input.repo !== void 0 ? await detectBackend() : backendChoice;
17007
+ const tracker = input.repo !== void 0 ? createTaskTracker({ backend, repo: input.repo, labels: input.labels }) : void 0;
17008
+ return createAgentStages({
17009
+ scanTarget: input.workingDir,
17010
+ simulateVotes: input.simulateVotes,
17011
+ votingStrategy: input.votingStrategy,
17012
+ quickMode: input.quickMode,
17013
+ issueNumber: input.issueNumber,
17014
+ repo: input.repo,
17015
+ tracker
17016
+ });
17017
+ }
17018
+ function buildStructuredOutput(result) {
17019
+ return {
17020
+ completed: result.completed,
17021
+ securityPassed: result.securityPassed,
17022
+ voteIterations: result.voteIterations,
17023
+ qaIterations: result.qaIterations,
17024
+ plan: result.plan,
17025
+ tasks: result.tasks.map((t) => ({
17026
+ id: t.id,
17027
+ title: t.title,
17028
+ status: t.status,
17029
+ implementation: t.implementation ?? null,
17030
+ feedback: t.feedback ?? null
17031
+ }))
17032
+ };
17033
+ }
17034
+ function registerDevPipelineTool(server, _deps) {
17035
+ server.tool("run_dev_pipeline", DevPipelineInputSchema.shape, async (args) => {
17036
+ const input = DevPipelineInputSchema.parse(args);
17037
+ try {
17038
+ const taskText = resolveTaskInput(input);
17039
+ const stages = await createStages(input);
17040
+ const pipelineOptions = {
17041
+ ...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
17042
+ ...input.dryRun ? { dryRun: true } : {},
17043
+ ...input.mode === "harness" ? { mode: "harness" } : {}
17044
+ };
17045
+ const hasOptions = Object.keys(pipelineOptions).length > 0;
17046
+ const result = await runDevPipeline(
17047
+ taskText,
17048
+ stages,
17049
+ hasOptions ? pipelineOptions : void 0
17050
+ );
17051
+ flushPipelineMemory();
17052
+ const structured = buildStructuredOutput(result);
17053
+ return {
17054
+ content: [{ type: "text", text: JSON.stringify(structured, null, 2) }],
17055
+ structuredContent: structured
17056
+ };
17057
+ } catch (error) {
17058
+ return {
17059
+ content: [{ type: "text", text: `Pipeline error: ${getErrorMessage(error)}` }],
17060
+ isError: true
17061
+ };
17062
+ }
17063
+ });
17064
+ }
16427
17065
 
16428
17066
  // src/cli-server-stpa.ts
16429
17067
  var TOOL_DEFINITIONS = [
@@ -16605,6 +17243,206 @@ function runStpaSafetyAnalysis(logger17, failOnHighSeverity) {
16605
17243
  }
16606
17244
  }
16607
17245
 
17246
+ // src/mcp/gateway/upstream-client.ts
17247
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
17248
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
17249
+ function resolveEnv(env) {
17250
+ if (env === void 0) return {};
17251
+ const resolved = {};
17252
+ for (const [key, val] of Object.entries(env)) {
17253
+ const match = /^\{env:(\w+)\}$/.exec(val);
17254
+ if (match?.[1] !== void 0) {
17255
+ const envKey = match[1];
17256
+ const envVal = process.env[envKey];
17257
+ if (envVal !== void 0) resolved[key] = envVal;
17258
+ } else {
17259
+ resolved[key] = val;
17260
+ }
17261
+ }
17262
+ return resolved;
17263
+ }
17264
+ var UpstreamClient = class {
17265
+ name;
17266
+ config;
17267
+ log;
17268
+ client = null;
17269
+ transport = null;
17270
+ state = "disconnected";
17271
+ tools = [];
17272
+ constructor(config, logger17) {
17273
+ this.name = config.name;
17274
+ this.config = config;
17275
+ this.log = logger17 ?? createLogger({ component: `upstream:${config.name}` });
17276
+ }
17277
+ /** Connect to the upstream server. Idempotent. */
17278
+ async connect() {
17279
+ if (this.state === "connected") return;
17280
+ if (this.state === "connecting") return;
17281
+ this.state = "connecting";
17282
+ try {
17283
+ const resolvedEnv = resolveEnv(this.config.env);
17284
+ const baseEnv = {};
17285
+ for (const [k, v] of Object.entries(process.env)) {
17286
+ if (v !== void 0) baseEnv[k] = v;
17287
+ }
17288
+ this.transport = new StdioClientTransport({
17289
+ command: this.config.command,
17290
+ args: [...this.config.args],
17291
+ env: { ...baseEnv, ...resolvedEnv }
17292
+ });
17293
+ this.client = new Client(
17294
+ { name: `nexus-upstream-${this.name}`, version: "1.0.0" },
17295
+ { capabilities: {} }
17296
+ );
17297
+ await this.client.connect(this.transport);
17298
+ const result = await this.client.listTools();
17299
+ this.tools = result.tools;
17300
+ this.state = "connected";
17301
+ this.log.info("Upstream server connected", {
17302
+ name: this.name,
17303
+ toolCount: this.tools.length,
17304
+ tools: this.tools.map((t) => t.name)
17305
+ });
17306
+ } catch (error) {
17307
+ this.state = "failed";
17308
+ const msg = error instanceof Error ? error.message : String(error);
17309
+ this.log.warn("Upstream server connection failed", {
17310
+ name: this.name,
17311
+ error: msg
17312
+ });
17313
+ throw error;
17314
+ }
17315
+ }
17316
+ /** Get available tools (prefixed with server name). */
17317
+ getTools() {
17318
+ return this.tools.map((t) => ({
17319
+ ...t,
17320
+ name: `${this.name}.${t.name}`,
17321
+ description: `[${this.name}] ${t.description ?? ""}`
17322
+ }));
17323
+ }
17324
+ /** Call a tool on the upstream server. Returns the raw SDK result. */
17325
+ async callTool(toolName, args) {
17326
+ if (this.client === null || this.state !== "connected") {
17327
+ if (this.config.lazy) {
17328
+ await this.connect();
17329
+ } else {
17330
+ throw new Error(`Upstream server ${this.name} not connected`);
17331
+ }
17332
+ }
17333
+ const activeClient = this.client;
17334
+ if (activeClient === null) throw new Error(`Upstream server ${this.name} not connected`);
17335
+ return activeClient.callTool({ name: toolName, arguments: args });
17336
+ }
17337
+ /** Check if the server is healthy. */
17338
+ async ping() {
17339
+ if (this.client === null || this.state !== "connected") return false;
17340
+ try {
17341
+ await this.client.ping();
17342
+ return true;
17343
+ } catch {
17344
+ return false;
17345
+ }
17346
+ }
17347
+ /** Gracefully shut down the connection. */
17348
+ async shutdown() {
17349
+ if (this.client !== null) {
17350
+ try {
17351
+ await this.client.close();
17352
+ } catch {
17353
+ }
17354
+ this.client = null;
17355
+ }
17356
+ if (this.transport !== null) {
17357
+ try {
17358
+ await this.transport.close();
17359
+ } catch {
17360
+ }
17361
+ this.transport = null;
17362
+ }
17363
+ this.state = "disconnected";
17364
+ this.tools = [];
17365
+ this.log.info("Upstream server disconnected", { name: this.name });
17366
+ }
17367
+ /** Get current connection state. */
17368
+ getState() {
17369
+ return this.state;
17370
+ }
17371
+ };
17372
+ var UpstreamClientManager = class {
17373
+ clients = /* @__PURE__ */ new Map();
17374
+ log;
17375
+ constructor(logger17) {
17376
+ this.log = logger17 ?? createLogger({ component: "UpstreamClientManager" });
17377
+ }
17378
+ /** Register upstream servers from config. */
17379
+ registerServers(configs) {
17380
+ for (const config of configs) {
17381
+ if (this.clients.has(config.name)) {
17382
+ this.log.warn("Duplicate upstream server name", { name: config.name });
17383
+ continue;
17384
+ }
17385
+ this.clients.set(config.name, new UpstreamClient(config, this.log));
17386
+ this.log.info("Registered upstream server", {
17387
+ name: config.name,
17388
+ command: config.command,
17389
+ lazy: config.lazy
17390
+ });
17391
+ }
17392
+ }
17393
+ /** Connect all non-lazy servers. */
17394
+ async connectEager() {
17395
+ for (const client of this.clients.values()) {
17396
+ if (client.getState() === "disconnected") {
17397
+ try {
17398
+ await client.connect();
17399
+ } catch {
17400
+ }
17401
+ }
17402
+ }
17403
+ }
17404
+ /** Get all available tools across all connected upstream servers. */
17405
+ getAllTools() {
17406
+ const tools = [];
17407
+ for (const client of this.clients.values()) {
17408
+ if (client.getState() === "connected") {
17409
+ tools.push(...client.getTools());
17410
+ }
17411
+ }
17412
+ return tools;
17413
+ }
17414
+ /** Route a prefixed tool call to the appropriate upstream server. */
17415
+ async callTool(prefixedName, args) {
17416
+ const dotIndex = prefixedName.indexOf(".");
17417
+ if (dotIndex === -1) return null;
17418
+ const serverName = prefixedName.slice(0, dotIndex);
17419
+ const toolName = prefixedName.slice(dotIndex + 1);
17420
+ const client = this.clients.get(serverName);
17421
+ if (client === void 0) return null;
17422
+ return client.callTool(toolName, args);
17423
+ }
17424
+ /** Check if a tool name is an upstream prefixed tool. */
17425
+ isUpstreamTool(name) {
17426
+ const dotIndex = name.indexOf(".");
17427
+ if (dotIndex === -1) return false;
17428
+ return this.clients.has(name.slice(0, dotIndex));
17429
+ }
17430
+ /** Shut down all upstream connections. */
17431
+ async shutdownAll() {
17432
+ const promises = [...this.clients.values()].map((c) => c.shutdown());
17433
+ await Promise.allSettled(promises);
17434
+ this.clients.clear();
17435
+ this.log.info("All upstream servers shut down");
17436
+ }
17437
+ /** Get health status of all upstream servers. */
17438
+ getStatus() {
17439
+ return [...this.clients.entries()].map(([name, client]) => ({
17440
+ name,
17441
+ state: client.getState()
17442
+ }));
17443
+ }
17444
+ };
17445
+
16608
17446
  // src/cli-server-tools.ts
16609
17447
  var OrchestratorUnavailableError = class extends NexusError {
16610
17448
  constructor(message) {
@@ -16718,6 +17556,10 @@ function registerResearchTools(ctx) {
16718
17556
  ...researchDeps,
16719
17557
  rateLimiter: ctx.rateLimiterFactory.getForTool("research_add")
16720
17558
  });
17559
+ registerResearchAddSourceTool(ctx.server, {
17560
+ ...researchDeps,
17561
+ rateLimiter: ctx.rateLimiterFactory.getForTool("research_add_source")
17562
+ });
16721
17563
  registerResearchDiscoverTool(ctx.server, {
16722
17564
  ...researchDeps,
16723
17565
  rateLimiter: ctx.rateLimiterFactory.getForTool("research_discover")
@@ -16785,6 +17627,33 @@ function registerOrchestrateToolSafe(ctx) {
16785
17627
  });
16786
17628
  }
16787
17629
  }
17630
+ async function initUpstreamServers(gatewayConfig, server, logger17) {
17631
+ const upstreamServers = gatewayConfig?.["upstreamServers"];
17632
+ if (upstreamServers === void 0 || upstreamServers.length === 0) return;
17633
+ const manager = new UpstreamClientManager(logger17);
17634
+ manager.registerServers(upstreamServers);
17635
+ await manager.connectEager();
17636
+ const tools = manager.getAllTools();
17637
+ logger17.info("Upstream MCP servers initialized", {
17638
+ servers: upstreamServers.length,
17639
+ tools: tools.length
17640
+ });
17641
+ const { z: z8 } = await import("zod");
17642
+ const passthroughSchema = z8.looseObject({});
17643
+ for (const tool of tools) {
17644
+ const toolName = tool.name;
17645
+ const desc = tool.description ?? `Upstream tool: ${toolName}`;
17646
+ server.registerTool(
17647
+ toolName,
17648
+ { description: desc, inputSchema: passthroughSchema },
17649
+ async (args) => {
17650
+ const upstreamResult = await manager.callTool(toolName, args);
17651
+ const text = upstreamResult !== null ? JSON.stringify(upstreamResult) : "Upstream tool not found";
17652
+ return { content: [{ type: "text", text }] };
17653
+ }
17654
+ );
17655
+ }
17656
+ }
16788
17657
  function maybeRunStpaAnalysis(options, logger17) {
16789
17658
  const enableStpa = options.enableStpaSafetyAnalysis ?? false;
16790
17659
  if (!enableStpa) return;
@@ -16859,7 +17728,11 @@ var STANDALONE_TOOLS = [
16859
17728
  { name: "run_graph_workflow", register: registerRunGraphWorkflowTool },
16860
17729
  { name: "execute_spec", register: registerExecuteSpecTool },
16861
17730
  { name: "list_experts", register: registerListExpertsTool },
16862
- { name: "query_trace", register: registerQueryTraceTool }
17731
+ { name: "query_trace", register: registerQueryTraceTool },
17732
+ { name: "extract_symbols", register: registerExtractSymbolsTool },
17733
+ { name: "search_codebase", register: registerSearchCodebaseTool },
17734
+ { name: "run_dev_pipeline", register: registerDevPipelineTool },
17735
+ { name: "run_pipeline", register: registerPipelineTool }
16863
17736
  ];
16864
17737
  function registerToolCategories(ctx) {
16865
17738
  const allowlist = ctx.toolAllowlist;
@@ -16914,6 +17787,7 @@ function registerMcpTools(options) {
16914
17787
  const gatewayOptions = { ...options, server: observableServer };
16915
17788
  const ctx = createToolContext(gatewayOptions, toolInfra, rateLimiterFactory);
16916
17789
  registerToolCategories(ctx);
17790
+ void initUpstreamServers(gatewayConfig, observableServer, logger17);
16917
17791
  registerPrompts(observableServer, logger17);
16918
17792
  registerResources(observableServer, logger17);
16919
17793
  logToolRegistration(logger17, ctx.toolAllowlist, {
@@ -17017,7 +17891,7 @@ function logFinalEventBusStats(logger17) {
17017
17891
  // src/cli-orchestrator.ts
17018
17892
  import * as readline2 from "readline";
17019
17893
  function runOrchestratorRepl(options, logger17) {
17020
- return new Promise((resolve12) => {
17894
+ return new Promise((resolve14) => {
17021
17895
  const rl = readline2.createInterface({
17022
17896
  input: process.stdin,
17023
17897
  output: process.stdout,
@@ -17053,7 +17927,7 @@ function runOrchestratorRepl(options, logger17) {
17053
17927
  });
17054
17928
  rl.on("close", () => {
17055
17929
  logger17.info("Orchestrator REPL closed");
17056
- resolve12();
17930
+ resolve14();
17057
17931
  });
17058
17932
  });
17059
17933
  }
@@ -18198,127 +19072,6 @@ function initializeFeedbackIntegration(options) {
18198
19072
  }
18199
19073
  }
18200
19074
 
18201
- // src/cli-server-rest.ts
18202
- import * as fs16 from "fs";
18203
- import * as path22 from "path";
18204
- import * as crypto3 from "crypto";
18205
- import { homedir as homedir3 } from "os";
18206
- var DEFAULT_REST_CONFIG = {
18207
- enabled: false,
18208
- port: 3e3,
18209
- host: "0.0.0.0",
18210
- cors: true,
18211
- swagger: true
18212
- };
18213
- var configLogger = createLogger({ component: "RestApiConfig" });
18214
- function parseValidPort(value) {
18215
- const port = parseInt(value, 10);
18216
- if (isNaN(port) || port < 1 || port > 65535) {
18217
- configLogger.warn("Invalid NEXUS_REST_PORT value, using default", {
18218
- value,
18219
- default: DEFAULT_REST_CONFIG.port
18220
- });
18221
- return DEFAULT_REST_CONFIG.port;
18222
- }
18223
- return port;
18224
- }
18225
- function extractRestConfig(_config) {
18226
- const portEnv = process.env["NEXUS_REST_PORT"];
18227
- const hostEnv = process.env["NEXUS_REST_HOST"];
18228
- return {
18229
- enabled: process.env["NEXUS_REST_ENABLED"] === "true",
18230
- port: portEnv !== void 0 ? parseValidPort(portEnv) : DEFAULT_REST_CONFIG.port,
18231
- host: hostEnv ?? DEFAULT_REST_CONFIG.host,
18232
- cors: DEFAULT_REST_CONFIG.cors,
18233
- swagger: DEFAULT_REST_CONFIG.swagger
18234
- };
18235
- }
18236
- var AUTH_DIR = "auth";
18237
- var API_KEY_FILE = "rest-api-key";
18238
- function getAuthDir(baseDir) {
18239
- const home = baseDir ?? path22.join(homedir3(), ".nexus-agents");
18240
- return path22.join(home, AUTH_DIR);
18241
- }
18242
- function loadOrGenerateApiKey(logger17, baseDir) {
18243
- const authDir = getAuthDir(baseDir);
18244
- const keyPath = path22.join(authDir, API_KEY_FILE);
18245
- if (fs16.existsSync(keyPath)) {
18246
- const key2 = fs16.readFileSync(keyPath, "utf-8").trim();
18247
- if (key2.length > 0) {
18248
- logger17.info("Loaded REST API key from disk", { keyFile: keyPath });
18249
- return { key: key2, name: "auto-generated" };
18250
- }
18251
- }
18252
- const key = "nxa-" + crypto3.randomBytes(24).toString("hex");
18253
- if (!fs16.existsSync(authDir)) {
18254
- fs16.mkdirSync(authDir, { recursive: true, mode: 448 });
18255
- }
18256
- fs16.writeFileSync(keyPath, key + "\n", { mode: 384 });
18257
- logger17.info("Generated new REST API key", { keyFile: keyPath });
18258
- logger17.warn("REST API key stored at: " + keyPath + " \u2014 keep this file secure");
18259
- return { key, name: "auto-generated" };
18260
- }
18261
- function buildApiKeys(logger17, authHandler) {
18262
- const keys = [loadOrGenerateApiKey(logger17)];
18263
- if (authHandler?.isEnabled() === true && authHandler.hasToken()) {
18264
- const token = authHandler.getStoredTokenForIntegration();
18265
- if (token !== void 0) {
18266
- keys.push({ key: token, name: "mcp-bearer-token" });
18267
- logger17.info("REST API also accepts MCP bearer token for authentication");
18268
- }
18269
- }
18270
- return keys;
18271
- }
18272
- async function startRestApiServer(config, logger17, authHandler) {
18273
- if (!config.enabled) {
18274
- logger17.debug("REST API disabled (set NEXUS_REST_ENABLED=true to enable)");
18275
- return null;
18276
- }
18277
- const restLogger = createLogger({ component: "RestApiServer" });
18278
- const apiKeys = buildApiKeys(logger17, authHandler);
18279
- const serverOptions = {
18280
- config: {
18281
- port: config.port,
18282
- host: config.host,
18283
- enableCors: config.cors,
18284
- enableSwagger: config.swagger
18285
- },
18286
- logger: restLogger,
18287
- apiKeys
18288
- };
18289
- const server = new RestApiServer(serverOptions);
18290
- await server.start();
18291
- logger17.info("REST API server started", {
18292
- address: `http://${config.host}:${String(config.port)}`,
18293
- swagger: config.swagger ? `http://${config.host}:${String(config.port)}/docs` : "disabled"
18294
- });
18295
- return server;
18296
- }
18297
- async function stopRestApiServer(server, logger17) {
18298
- if (server === null) {
18299
- return;
18300
- }
18301
- try {
18302
- await server.stop();
18303
- logger17.info("REST API server stopped");
18304
- } catch (error) {
18305
- logger17.error(
18306
- "Error stopping REST API server",
18307
- error instanceof Error ? error : new Error(String(error))
18308
- );
18309
- }
18310
- }
18311
- function logRestApiConfig(config, logger17) {
18312
- if (config.enabled) {
18313
- logger17.info("REST API configuration", {
18314
- port: config.port,
18315
- host: config.host,
18316
- cors: config.cors,
18317
- swagger: config.swagger
18318
- });
18319
- }
18320
- }
18321
-
18322
19075
  // src/cli-server-auth.ts
18323
19076
  function resolveAuthEnabled(config) {
18324
19077
  const envValue = process.env["NEXUS_AUTH_ENABLED"];
@@ -18363,9 +19116,9 @@ function initializeAuth(config, logger17) {
18363
19116
  }
18364
19117
 
18365
19118
  // src/cli-server-audit.ts
18366
- import { join as join16 } from "path";
18367
- import { homedir as homedir4 } from "os";
18368
- var DEFAULT_AUDIT_DIR = join16(homedir4(), ".nexus-agents", "audit");
19119
+ import { join as join15 } from "path";
19120
+ import { homedir as homedir3 } from "os";
19121
+ var DEFAULT_AUDIT_DIR = join15(homedir3(), ".nexus-agents", "audit");
18369
19122
  function initializeAuditLogger(securityConfig, logger17) {
18370
19123
  if (securityConfig?.audit?.enabled !== true) {
18371
19124
  logger17.debug("Audit logging disabled (set security.audit.enabled: true to enable)");
@@ -18535,18 +19288,8 @@ function loadAndLogConfig(logger17) {
18535
19288
  return configResult;
18536
19289
  }
18537
19290
  function createShutdownCleanup(options) {
18538
- const {
18539
- eventBusBridge,
18540
- observer,
18541
- eventContext,
18542
- server,
18543
- serverLogger,
18544
- logger: logger17,
18545
- restServer,
18546
- auditLogger
18547
- } = options;
19291
+ const { eventBusBridge, observer, eventContext, server, serverLogger, logger: logger17, auditLogger } = options;
18548
19292
  return async () => {
18549
- await stopRestApiServer(restServer, logger17);
18550
19293
  await shutdownAuditLogger(auditLogger, logger17);
18551
19294
  if (eventBusBridge.initialized) {
18552
19295
  logFinalEventBusStats(logger17);
@@ -18703,11 +19446,8 @@ async function startServer(verbose, mode, modeWasExplicit = false, orchestratorO
18703
19446
  const configResult = loadAndLogConfig(logger17);
18704
19447
  applyLoggingConfig(logger17, verbose, configResult.config);
18705
19448
  validateNexusEnv(logger17);
18706
- const { server, serverLogger, observer, eventBusBridge, auditLogger, authInit } = await initializeSubsystems(configResult.config, logger17);
19449
+ const { server, serverLogger, observer, eventBusBridge, auditLogger } = await initializeSubsystems(configResult.config, logger17);
18707
19450
  await connectToStdioTransport(server, logger17, serverLogger);
18708
- const restConfig = extractRestConfig(configResult.config);
18709
- logRestApiConfig(restConfig, logger17);
18710
- const restServer = await startRestApiServer(restConfig, logger17, authInit.handler);
18711
19451
  const eventContext = recordServerStartup(observer);
18712
19452
  const stdinMonitor = getStdinLifecycleMonitor();
18713
19453
  stdinMonitor.start();
@@ -18722,7 +19462,6 @@ async function startServer(verbose, mode, modeWasExplicit = false, orchestratorO
18722
19462
  server,
18723
19463
  serverLogger,
18724
19464
  logger: logger17,
18725
- restServer,
18726
19465
  auditLogger
18727
19466
  });
18728
19467
  setupShutdownHandlers(cleanup, logger17);
@@ -18973,9 +19712,9 @@ function buildOrchestratorOptions(args) {
18973
19712
  function printFirstRunHint() {
18974
19713
  const isTTY = process.stderr.isTTY;
18975
19714
  if (!isTTY) return;
18976
- const dataDir = join17(homedir5(), ".nexus-agents");
18977
- const hasConfig = existsSync17("./nexus-agents.yaml") || existsSync17("./nexus-agents.yml");
18978
- if (existsSync17(dataDir) || hasConfig) return;
19715
+ const dataDir = join16(homedir4(), ".nexus-agents");
19716
+ const hasConfig = existsSync18("./nexus-agents.yaml") || existsSync18("./nexus-agents.yml");
19717
+ if (existsSync18(dataDir) || hasConfig) return;
18979
19718
  process.stderr.write(
18980
19719
  "\n\x1B[36mnexus-agents\x1B[0m: First time? Run \x1B[1mnexus-agents setup\x1B[0m to configure.\n\n"
18981
19720
  );
@@ -19109,7 +19848,7 @@ async function handleVerifyCommand(args) {
19109
19848
  async function handleDoctorCommand(args) {
19110
19849
  const exitCode = await doctorCommand({ fix: args.options.fix });
19111
19850
  if (args.options.deep) {
19112
- const { runDeepDiagnostics: runDeepDiagnostics2, formatDeepDiagnostics: formatDeepDiagnostics2 } = await import("./doctor-deep-BDE2PHVX.js");
19851
+ const { runDeepDiagnostics: runDeepDiagnostics2, formatDeepDiagnostics: formatDeepDiagnostics2 } = await import("./doctor-deep-LMCEAFU4.js");
19113
19852
  const diag = runDeepDiagnostics2();
19114
19853
  process.stdout.write(formatDeepDiagnostics2(diag) + "\n");
19115
19854
  }
@@ -19360,25 +20099,25 @@ function handleScaffoldCommand(args) {
19360
20099
  }
19361
20100
 
19362
20101
  // src/cli/visualize-summary.ts
19363
- import * as fs17 from "fs";
19364
- import * as path23 from "path";
20102
+ import * as fs18 from "fs";
20103
+ import * as path22 from "path";
19365
20104
  import { fileURLToPath } from "url";
19366
20105
  function findPackageRoot(startDir) {
19367
20106
  let dir = startDir;
19368
20107
  for (let i = 0; i < 5; i++) {
19369
- if (fs17.existsSync(path23.join(dir, "package.json"))) return dir;
19370
- const parent = path23.dirname(dir);
20108
+ if (fs18.existsSync(path22.join(dir, "package.json"))) return dir;
20109
+ const parent = path22.dirname(dir);
19371
20110
  if (parent === dir) break;
19372
20111
  dir = parent;
19373
20112
  }
19374
20113
  return startDir;
19375
20114
  }
19376
- function countFiles(dir, pattern) {
19377
- if (!fs17.existsSync(dir)) return 0;
20115
+ function countFiles2(dir, pattern) {
20116
+ if (!fs18.existsSync(dir)) return 0;
19378
20117
  let count = 0;
19379
- for (const entry of fs17.readdirSync(dir, { withFileTypes: true })) {
20118
+ for (const entry of fs18.readdirSync(dir, { withFileTypes: true })) {
19380
20119
  if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist") {
19381
- count += countFiles(path23.join(dir, entry.name), pattern);
20120
+ count += countFiles2(path22.join(dir, entry.name), pattern);
19382
20121
  } else if (entry.isFile() && pattern.test(entry.name)) {
19383
20122
  count++;
19384
20123
  }
@@ -19387,7 +20126,7 @@ function countFiles(dir, pattern) {
19387
20126
  }
19388
20127
  function readVersion(pkgRoot) {
19389
20128
  try {
19390
- const raw = fs17.readFileSync(path23.join(pkgRoot, "package.json"), "utf-8");
20129
+ const raw = fs18.readFileSync(path22.join(pkgRoot, "package.json"), "utf-8");
19391
20130
  const pkg = JSON.parse(raw);
19392
20131
  return pkg.version ?? "unknown";
19393
20132
  } catch {
@@ -19408,13 +20147,13 @@ var LAYER_DIRS = [
19408
20147
  ];
19409
20148
  function gatherSystemSummary() {
19410
20149
  const thisFile = fileURLToPath(import.meta.url);
19411
- const pkgRoot = findPackageRoot(path23.dirname(thisFile));
19412
- const srcDir = path23.resolve(pkgRoot, "src");
19413
- const allTs = countFiles(srcDir, /\.ts$/);
19414
- const testTs = countFiles(srcDir, /\.test\.ts$/);
20150
+ const pkgRoot = findPackageRoot(path22.dirname(thisFile));
20151
+ const srcDir = path22.resolve(pkgRoot, "src");
20152
+ const allTs = countFiles2(srcDir, /\.ts$/);
20153
+ const testTs = countFiles2(srcDir, /\.test\.ts$/);
19415
20154
  const layers = LAYER_DIRS.map(({ name, dir }) => ({
19416
20155
  name,
19417
- files: countFiles(path23.join(srcDir, dir), /\.ts$/)
20156
+ files: countFiles2(path22.join(srcDir, dir), /\.ts$/)
19418
20157
  })).filter((l) => l.files > 0);
19419
20158
  return {
19420
20159
  version: readVersion(pkgRoot),
@@ -19664,8 +20403,8 @@ function generateDiagramOutput(subcommand, format) {
19664
20403
  }
19665
20404
  function writeOutput(output2, outputPath) {
19666
20405
  if (outputPath !== void 0) {
19667
- import("fs").then((fs18) => {
19668
- fs18.writeFileSync(outputPath, output2 + "\n", "utf-8");
20406
+ import("fs").then((fs19) => {
20407
+ fs19.writeFileSync(outputPath, output2 + "\n", "utf-8");
19669
20408
  process.stdout.write(`Diagram written to ${outputPath}
19670
20409
  `);
19671
20410
  }).catch((e) => {
@@ -20456,7 +21195,7 @@ async function handleMemoryBenchmarkCommand(args) {
20456
21195
  }
20457
21196
 
20458
21197
  // src/cli/status-command.ts
20459
- import { execFileSync } from "child_process";
21198
+ import { execFileSync as execFileSync2 } from "child_process";
20460
21199
  var FITNESS_TARGET = 90;
20461
21200
  var API_ADAPTER_CHECKS = [
20462
21201
  { name: "Claude", envVar: "ANTHROPIC_API_KEY" },
@@ -20478,7 +21217,7 @@ function checkApiAdapters() {
20478
21217
  function detectCliTools() {
20479
21218
  return CLI_TOOL_CHECKS.map((check) => {
20480
21219
  try {
20481
- const version = execFileSync(check.binary, ["--version"], {
21220
+ const version = execFileSync2(check.binary, ["--version"], {
20482
21221
  timeout: CLI_SUBPROCESS_TIMEOUTS.statusProbeMs,
20483
21222
  stdio: ["ignore", "pipe", "ignore"],
20484
21223
  encoding: "utf-8"
@@ -20563,10 +21302,10 @@ function handleStatusCommand2(args) {
20563
21302
 
20564
21303
  // src/cli/scenario-command.ts
20565
21304
  import { readdir as readdir4 } from "fs/promises";
20566
- import { join as join19, resolve as resolve11 } from "path";
21305
+ import { join as join18, resolve as resolve13 } from "path";
20567
21306
 
20568
21307
  // src/testing/e2e/scenario-runner.ts
20569
- import { readFile as readFile6 } from "fs/promises";
21308
+ import { readFile as readFile7 } from "fs/promises";
20570
21309
  import * as yaml7 from "yaml";
20571
21310
 
20572
21311
  // src/testing/e2e/types.ts
@@ -20694,9 +21433,9 @@ function checkCircularDependencies(workflow) {
20694
21433
  for (const step of workflow.steps) {
20695
21434
  stepMap.set(step.id, step);
20696
21435
  }
20697
- const visit = (stepId, path24) => {
21436
+ const visit = (stepId, path23) => {
20698
21437
  if (visiting.has(stepId)) {
20699
- errors.push(`Circular dependency detected: ${[...path24, stepId].join(" -> ")}`);
21438
+ errors.push(`Circular dependency detected: ${[...path23, stepId].join(" -> ")}`);
20700
21439
  return false;
20701
21440
  }
20702
21441
  if (visited.has(stepId)) return true;
@@ -20704,7 +21443,7 @@ function checkCircularDependencies(workflow) {
20704
21443
  const step = stepMap.get(stepId);
20705
21444
  if (step?.dependsOn) {
20706
21445
  for (const dep of step.dependsOn) {
20707
- if (!visit(dep, [...path24, stepId])) {
21446
+ if (!visit(dep, [...path23, stepId])) {
20708
21447
  return false;
20709
21448
  }
20710
21449
  }
@@ -20723,7 +21462,7 @@ function checkCircularDependencies(workflow) {
20723
21462
  var defaultStubFactory = {
20724
21463
  createAgentStub(agentType, action) {
20725
21464
  return async (inputs) => {
20726
- await new Promise((resolve12) => setTimeout(resolve12, 10));
21465
+ await new Promise((resolve14) => setTimeout(resolve14, 10));
20727
21466
  return {
20728
21467
  stepId: `${agentType}-${action}`,
20729
21468
  status: "success",
@@ -20748,8 +21487,8 @@ var ScenarioRunner = class {
20748
21487
  /**
20749
21488
  * Load a scenario fixture from a YAML file.
20750
21489
  */
20751
- async loadFixture(path24) {
20752
- const content = await readFile6(path24, "utf-8");
21490
+ async loadFixture(path23) {
21491
+ const content = await readFile7(path23, "utf-8");
20753
21492
  const data = yaml7.parse(content);
20754
21493
  return ScenarioFixtureSchema.parse(data);
20755
21494
  }
@@ -20882,7 +21621,7 @@ function createScenarioRunner(stubFactory) {
20882
21621
  }
20883
21622
 
20884
21623
  // src/cli/scenario-command.ts
20885
- var FIXTURES_DIR = resolve11(import.meta.dirname, "../testing/e2e/fixtures");
21624
+ var FIXTURES_DIR = resolve13(import.meta.dirname, "../testing/e2e/fixtures");
20886
21625
  var SCENARIO_SUFFIX = ".scenario.yaml";
20887
21626
  async function listScenarios() {
20888
21627
  try {
@@ -20933,7 +21672,7 @@ async function handleRun(args) {
20933
21672
  process.exit(EXIT_CODES.SERVER_START_FAILED);
20934
21673
  }
20935
21674
  const runner = createScenarioRunner();
20936
- const fixturePath = join19(FIXTURES_DIR, `${name}${SCENARIO_SUFFIX}`);
21675
+ const fixturePath = join18(FIXTURES_DIR, `${name}${SCENARIO_SUFFIX}`);
20937
21676
  try {
20938
21677
  const fixture = await runner.loadFixture(fixturePath);
20939
21678
  const result = await runner.run(fixture);
@@ -21094,6 +21833,67 @@ function handleHealthCommand(args) {
21094
21833
  }
21095
21834
  }
21096
21835
 
21836
+ // src/cli/validate-command.ts
21837
+ var MIN_FITNESS_SCORE = 90;
21838
+ function evaluateDoctor(doctor) {
21839
+ const installedCount = doctor.clis.filter((c) => c.installed).length;
21840
+ const total = doctor.clis.length;
21841
+ const summary = doctor.allHealthy ? `All systems healthy (${String(installedCount)}/${String(total)} CLIs installed)` : `Issues detected (${String(installedCount)}/${String(total)} CLIs installed)`;
21842
+ return { name: "Doctor", passed: doctor.allHealthy, summary };
21843
+ }
21844
+ function evaluateFitness(audit) {
21845
+ const passed = audit.score >= MIN_FITNESS_SCORE;
21846
+ const summary = `Score ${String(audit.score)}/100 (minimum: ${String(MIN_FITNESS_SCORE)})`;
21847
+ return { name: "Fitness Audit", passed, summary };
21848
+ }
21849
+ function evaluateConfig(doctor) {
21850
+ const found = doctor.configFile.found;
21851
+ const summary = found ? `Config found: ${doctor.configFile.path ?? "unknown"}` : "No nexus-agents.yaml found (optional)";
21852
+ return { name: "Config", passed: true, summary };
21853
+ }
21854
+ function printReport2(result) {
21855
+ writeLine();
21856
+ writeLine(`${colors.bold}nexus-agents validate${colors.reset}`);
21857
+ writeLine("\u2500".repeat(50));
21858
+ writeLine();
21859
+ for (const phase of result.phases) {
21860
+ const icon = phase.passed ? `${colors.green}${symbols.check}${colors.reset}` : `${colors.red}${symbols.cross}${colors.reset}`;
21861
+ writeLine(` ${icon} ${colors.bold}${phase.name}${colors.reset}: ${phase.summary}`);
21862
+ }
21863
+ writeLine();
21864
+ if (result.allPassed) {
21865
+ writeLine(`${colors.green}${colors.bold}PASS${colors.reset}: All validation checks passed.`);
21866
+ } else {
21867
+ writeLine(
21868
+ `${colors.red}${colors.bold}FAIL${colors.reset}: One or more validation checks failed.`
21869
+ );
21870
+ }
21871
+ writeLine();
21872
+ }
21873
+ async function runValidate() {
21874
+ const doctor = await runDoctor();
21875
+ const audit = calculateFitnessScore(`v${VERSION}`);
21876
+ const phases = [
21877
+ evaluateDoctor(doctor),
21878
+ evaluateFitness(audit),
21879
+ evaluateConfig(doctor)
21880
+ ];
21881
+ return {
21882
+ phases,
21883
+ allPassed: phases.every((p) => p.passed)
21884
+ };
21885
+ }
21886
+ async function handleValidateCommand(args) {
21887
+ const result = await runValidate();
21888
+ const isJson = args.options.format === "json";
21889
+ if (isJson) {
21890
+ writeLine(JSON.stringify(result, null, 2));
21891
+ } else {
21892
+ printReport2(result);
21893
+ }
21894
+ process.exit(result.allPassed ? 0 : 1);
21895
+ }
21896
+
21097
21897
  // src/cli-commands.ts
21098
21898
  function printHelp() {
21099
21899
  process.stdout.write(HELP_TEXT + "\n");
@@ -21175,7 +21975,9 @@ var ASYNC_COMMAND_HANDLERS = {
21175
21975
  // Issue #748: Memory Benchmark Command
21176
21976
  "memory-benchmark": handleMemoryBenchmarkCommand,
21177
21977
  // Epic #952: Scenario Command
21178
- scenario: handleScenarioCommand
21978
+ scenario: handleScenarioCommand,
21979
+ // Issue #1598: Validate Command
21980
+ validate: handleValidateCommand
21179
21981
  };
21180
21982
  async function handleAsyncCommand(args) {
21181
21983
  const handler = ASYNC_COMMAND_HANDLERS[args.command];