@serkanalgur/opencode-nexus 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +479 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9695,6 +9695,255 @@ class SecurityScanner {
9695
9695
  }
9696
9696
  }
9697
9697
 
9698
+ // src/performance.ts
9699
+ class PerformanceTracker {
9700
+ entries = [];
9701
+ maxEntries;
9702
+ constructor(maxEntries = 1000) {
9703
+ this.maxEntries = maxEntries;
9704
+ }
9705
+ record(entry) {
9706
+ this.entries.push({ ...entry, timestamp: new Date });
9707
+ if (this.entries.length > this.maxEntries) {
9708
+ this.entries = this.entries.slice(-this.maxEntries);
9709
+ }
9710
+ }
9711
+ getScores() {
9712
+ const groups = new Map;
9713
+ for (const entry of this.entries) {
9714
+ const key = `${entry.model}::${entry.role}`;
9715
+ const group = groups.get(key) || [];
9716
+ group.push(entry);
9717
+ groups.set(key, group);
9718
+ }
9719
+ const scores = [];
9720
+ for (const [key, entries] of groups) {
9721
+ const [model, role] = key.split("::");
9722
+ const total = entries.length;
9723
+ const successful = entries.filter((e) => e.success).length;
9724
+ const successRate = total > 0 ? successful / total : 0;
9725
+ const avgDuration = entries.reduce((s, e) => s + e.duration, 0) / total;
9726
+ const avgCost = entries.reduce((s, e) => s + e.cost, 0) / total;
9727
+ const costEfficiency = avgCost > 0 ? successRate / avgCost : 0;
9728
+ const speedScore = Math.max(0, 1 - avgDuration / 30000);
9729
+ const costScore = Math.min(1, costEfficiency * 100);
9730
+ const overallScore = successRate * 40 + speedScore * 30 + costScore * 30;
9731
+ scores.push({ model, role, totalTasks: total, successRate, avgDuration, avgCost, costEfficiency, overallScore });
9732
+ }
9733
+ return scores.sort((a, b) => b.overallScore - a.overallScore);
9734
+ }
9735
+ getBestModel(role) {
9736
+ const scores = this.getScores().filter((s) => s.role === role);
9737
+ return scores[0] || null;
9738
+ }
9739
+ getStats() {
9740
+ const unique = new Set(this.entries.map((e) => `${e.model}::${e.role}`));
9741
+ const successRate = this.entries.length > 0 ? this.entries.filter((e) => e.success).length / this.entries.length : 0;
9742
+ return { totalEntries: this.entries.length, uniqueCombinations: unique.size, avgSuccessRate: successRate };
9743
+ }
9744
+ clear() {
9745
+ this.entries = [];
9746
+ }
9747
+ }
9748
+
9749
+ // src/history.ts
9750
+ class ExecutionHistory {
9751
+ records = [];
9752
+ maxRecords;
9753
+ constructor(maxRecords = 500) {
9754
+ this.maxRecords = maxRecords;
9755
+ }
9756
+ record(entry) {
9757
+ const full = {
9758
+ ...entry,
9759
+ id: `exec-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`
9760
+ };
9761
+ this.records.push(full);
9762
+ if (this.records.length > this.maxRecords) {
9763
+ this.records = this.records.slice(-this.maxRecords);
9764
+ }
9765
+ return full;
9766
+ }
9767
+ getAll() {
9768
+ return [...this.records];
9769
+ }
9770
+ getRecent(count) {
9771
+ return this.records.slice(-count);
9772
+ }
9773
+ getByRole(role) {
9774
+ return this.records.filter((r) => r.role === role);
9775
+ }
9776
+ getByStatus(status) {
9777
+ return this.records.filter((r) => r.status === status);
9778
+ }
9779
+ getStats() {
9780
+ const total = this.records.length;
9781
+ const successful = this.records.filter((r) => r.status === "success").length;
9782
+ const totalCost = this.records.reduce((sum, r) => sum + r.cost, 0);
9783
+ const avgDuration = total > 0 ? this.records.reduce((sum, r) => sum + r.duration, 0) / total : 0;
9784
+ const byRole = {};
9785
+ for (const r of this.records) {
9786
+ byRole[r.role] = (byRole[r.role] || 0) + 1;
9787
+ }
9788
+ return { total, successRate: total > 0 ? successful / total : 0, totalCost, avgDuration, byRole };
9789
+ }
9790
+ clear() {
9791
+ this.records = [];
9792
+ }
9793
+ }
9794
+
9795
+ // src/custom-roles.ts
9796
+ class CustomRoleManager {
9797
+ roles = new Map;
9798
+ register(role) {
9799
+ this.roles.set(role.name, role);
9800
+ }
9801
+ unregister(name) {
9802
+ return this.roles.delete(name);
9803
+ }
9804
+ get(name) {
9805
+ return this.roles.get(name);
9806
+ }
9807
+ list() {
9808
+ return [...this.roles.values()];
9809
+ }
9810
+ getPrompt(name) {
9811
+ return this.roles.get(name)?.prompt ?? null;
9812
+ }
9813
+ getEmoji(name) {
9814
+ return this.roles.get(name)?.emoji ?? "\uD83E\uDD16";
9815
+ }
9816
+ has(name) {
9817
+ return this.roles.has(name);
9818
+ }
9819
+ loadFromConfig(config) {
9820
+ if (config.customRoles && Array.isArray(config.customRoles)) {
9821
+ for (const role of config.customRoles) {
9822
+ this.register(role);
9823
+ }
9824
+ }
9825
+ }
9826
+ }
9827
+
9828
+ // src/forecast.ts
9829
+ class CostForecaster {
9830
+ modelPricing = new Map;
9831
+ constructor() {
9832
+ this.modelPricing.set("claude-sonnet-4-6", { input: 0.000015, output: 0.000075 });
9833
+ this.modelPricing.set("claude-opus-4-7", { input: 0.000075, output: 0.000375 });
9834
+ this.modelPricing.set("claude-haiku-4-5", { input: 0.000001, output: 0.000005 });
9835
+ this.modelPricing.set("gpt-5-mini", { input: 0.00000015, output: 0.0000006 });
9836
+ this.modelPricing.set("gpt-5", { input: 0.0000025, output: 0.00001 });
9837
+ this.modelPricing.set("gemini-2.5-flash", { input: 0.000000075, output: 0.0000003 });
9838
+ }
9839
+ updatePricing(modelId, input, output) {
9840
+ this.modelPricing.set(modelId, { input, output });
9841
+ }
9842
+ estimateTokens(task, complexity) {
9843
+ const baseInput = 700;
9844
+ const complexityMultiplier = 1 + complexity.overall / 100 * 3;
9845
+ const fileMultiplier = 1 + task.files.include.length * 0.2;
9846
+ const input = Math.round(baseInput * complexityMultiplier * fileMultiplier);
9847
+ const output = Math.round(input * 0.5);
9848
+ return { input, output };
9849
+ }
9850
+ forecastTask(task, role, modelId, complexity) {
9851
+ const { input, output } = this.estimateTokens(task, complexity);
9852
+ const pricing = this.modelPricing.get(modelId) || { input: 0.00001, output: 0.00005 };
9853
+ const inputCost = input * pricing.input;
9854
+ const outputCost = output * pricing.output;
9855
+ const overhead = 0.0001;
9856
+ return {
9857
+ taskId: task.id,
9858
+ taskName: task.name,
9859
+ role,
9860
+ model: modelId,
9861
+ estimatedInputTokens: input,
9862
+ estimatedOutputTokens: output,
9863
+ estimatedCost: inputCost + outputCost + overhead,
9864
+ confidence: 0.6 + Math.random() * 0.3,
9865
+ breakdown: { inputCost, outputCost, overhead }
9866
+ };
9867
+ }
9868
+ forecastAll(tasks, budgetRemaining) {
9869
+ const estimates = tasks.map((t) => this.forecastTask(t.task, t.role, t.model, t.complexity));
9870
+ const totalEstimatedCost = estimates.reduce((sum, e) => sum + e.estimatedCost, 0);
9871
+ return {
9872
+ estimates,
9873
+ totalEstimatedCost,
9874
+ budgetRemaining,
9875
+ withinBudget: totalEstimatedCost <= budgetRemaining
9876
+ };
9877
+ }
9878
+ }
9879
+
9880
+ // src/worktree.ts
9881
+ import { execSync } from "node:child_process";
9882
+ import { existsSync as existsSync2 } from "node:fs";
9883
+ import { join as join4 } from "node:path";
9884
+
9885
+ class WorktreeManager {
9886
+ worktrees = new Map;
9887
+ baseDir;
9888
+ repoRoot;
9889
+ constructor(repoRoot, baseDir) {
9890
+ this.repoRoot = repoRoot;
9891
+ this.baseDir = baseDir || join4(repoRoot, ".worktrees", "nexus-agents");
9892
+ }
9893
+ create(agentId) {
9894
+ const branch = `nexus-agent-${agentId}`;
9895
+ const path = join4(this.baseDir, agentId);
9896
+ try {
9897
+ if (!existsSync2(this.baseDir)) {
9898
+ execSync(`mkdir -p "${this.baseDir}"`, { cwd: this.repoRoot });
9899
+ }
9900
+ execSync(`git worktree add "${path}" -b "${branch}" 2>/dev/null || git worktree add "${path}" "${branch}" 2>/dev/null || echo "Worktree exists"`, {
9901
+ cwd: this.repoRoot,
9902
+ timeout: 1e4
9903
+ });
9904
+ const wt = { agentId, branch, path, createdAt: new Date };
9905
+ this.worktrees.set(agentId, wt);
9906
+ return wt;
9907
+ } catch (error) {
9908
+ throw new Error(`Failed to create worktree for ${agentId}: ${error.message}`);
9909
+ }
9910
+ }
9911
+ remove(agentId) {
9912
+ const wt = this.worktrees.get(agentId);
9913
+ if (!wt)
9914
+ return false;
9915
+ try {
9916
+ execSync(`git worktree remove "${wt.path}" --force 2>/dev/null`, {
9917
+ cwd: this.repoRoot,
9918
+ timeout: 1e4
9919
+ });
9920
+ execSync(`git branch -D "${wt.branch}" 2>/dev/null`, {
9921
+ cwd: this.repoRoot,
9922
+ timeout: 5000
9923
+ });
9924
+ this.worktrees.delete(agentId);
9925
+ return true;
9926
+ } catch {
9927
+ this.worktrees.delete(agentId);
9928
+ return false;
9929
+ }
9930
+ }
9931
+ get(agentId) {
9932
+ return this.worktrees.get(agentId);
9933
+ }
9934
+ list() {
9935
+ return [...this.worktrees.values()];
9936
+ }
9937
+ cleanupAll() {
9938
+ for (const [id] of this.worktrees) {
9939
+ this.remove(id);
9940
+ }
9941
+ }
9942
+ getPath(agentId) {
9943
+ return this.worktrees.get(agentId)?.path ?? null;
9944
+ }
9945
+ }
9946
+
9698
9947
  // src/orchestrator.ts
9699
9948
  var DEFAULT_ESCALATION = {
9700
9949
  maxRetries: 3,
@@ -9732,6 +9981,11 @@ class NexusOrchestrator {
9732
9981
  nodeRetryCounts = new Map;
9733
9982
  moduleRegistry;
9734
9983
  securityScanner;
9984
+ performanceTracker;
9985
+ executionHistory;
9986
+ customRoles;
9987
+ forecaster;
9988
+ worktreeManager = null;
9735
9989
  onStateChange = null;
9736
9990
  stateChangeTimer = null;
9737
9991
  costHistory = [];
@@ -9757,6 +10011,10 @@ class NexusOrchestrator {
9757
10011
  };
9758
10012
  this.learning = new LearningModule(this.config.learning.minConfidence);
9759
10013
  this.securityScanner = new SecurityScanner;
10014
+ this.performanceTracker = new PerformanceTracker;
10015
+ this.executionHistory = new ExecutionHistory;
10016
+ this.customRoles = new CustomRoleManager;
10017
+ this.forecaster = new CostForecaster;
9760
10018
  }
9761
10019
  async initialize(ctx, onStateChange) {
9762
10020
  this.ctx = ctx;
@@ -9852,6 +10110,9 @@ class NexusOrchestrator {
9852
10110
  this.dashboard = null;
9853
10111
  }
9854
10112
  }
10113
+ enableWorktrees(repoRoot) {
10114
+ this.worktreeManager = new WorktreeManager(repoRoot || process.cwd());
10115
+ }
9855
10116
  getState() {
9856
10117
  const agents = Array.from(this.agents.values()).map((a) => ({
9857
10118
  id: a.id,
@@ -10176,6 +10437,26 @@ Please continue from where the previous agent left off.`;
10176
10437
  this.totalSpent += result.cost;
10177
10438
  this.costByAgent.set(agent.id, (this.costByAgent.get(agent.id) || 0) + result.cost);
10178
10439
  this.checkBudget();
10440
+ this.performanceTracker.record({
10441
+ model: agent.model.model,
10442
+ role: node.task.requiredRole,
10443
+ success: result.success,
10444
+ duration: result.duration,
10445
+ cost: result.cost,
10446
+ tokensUsed: result.tokensUsed
10447
+ });
10448
+ this.executionHistory.record({
10449
+ taskId: node.id,
10450
+ taskName: node.task.name,
10451
+ role: node.task.requiredRole,
10452
+ model: agent.model.model,
10453
+ status: "success",
10454
+ cost: result.cost,
10455
+ duration: result.duration,
10456
+ tokensUsed: result.tokensUsed,
10457
+ startedAt: new Date(startTime),
10458
+ completedAt: new Date
10459
+ });
10179
10460
  if (this.notifications?.isEnabled()) {
10180
10461
  this.notifications.notify({ title: "Nexus: Task Complete", body: `${node.task.name} completed successfully` });
10181
10462
  }
@@ -10205,6 +10486,27 @@ Please continue from where the previous agent left off.`;
10205
10486
  };
10206
10487
  this.dag.markFailed(node.id, new Error(result.error));
10207
10488
  agent.metrics.tasksFailed++;
10489
+ this.performanceTracker.record({
10490
+ model: agent.model.model,
10491
+ role: node.task.requiredRole,
10492
+ success: result.success,
10493
+ duration: result.duration,
10494
+ cost: result.cost,
10495
+ tokensUsed: result.tokensUsed
10496
+ });
10497
+ this.executionHistory.record({
10498
+ taskId: node.id,
10499
+ taskName: node.task.name,
10500
+ role: node.task.requiredRole,
10501
+ model: agent.model.model,
10502
+ status: "failed",
10503
+ cost: result.cost,
10504
+ duration: result.duration,
10505
+ tokensUsed: result.tokensUsed,
10506
+ startedAt: new Date(startTime),
10507
+ completedAt: new Date,
10508
+ error: result.error
10509
+ });
10208
10510
  if (this.config.selfHealing.enabled) {
10209
10511
  await this.handleFailure(agent, node, new Error(result.error));
10210
10512
  }
@@ -10215,6 +10517,9 @@ Please continue from where the previous agent left off.`;
10215
10517
  }
10216
10518
  }
10217
10519
  buildRolePrompt(role) {
10520
+ if (this.customRoles.has(role)) {
10521
+ return this.customRoles.getPrompt(role) || `You are a ${role}. Complete the assigned task professionally.`;
10522
+ }
10218
10523
  const rolePrompts = {
10219
10524
  architect: "You are a software architect. Focus on system design, architecture patterns, and high-level technical decisions. Analyze requirements and propose structured solutions.",
10220
10525
  coder: "You are a senior software engineer. Write clean, efficient, well-documented code. Follow best practices and coding standards.",
@@ -10317,10 +10622,10 @@ Please continue from where the previous agent left off.`;
10317
10622
  const roleEmoji = this.configManager.getRoleEmoji(config.role);
10318
10623
  const title = `${roleEmoji} ${this.configManager.getRoleDisplayName(config.role)} — ${modelConfig}`;
10319
10624
  const agentTypeMap = {
10320
- architect: "build",
10321
- coder: "build",
10625
+ architect: "architect",
10626
+ coder: "build-orchestrator",
10322
10627
  reviewer: "code-reviewer",
10323
- tester: "build",
10628
+ tester: "build-orchestrator",
10324
10629
  explorer: "explore",
10325
10630
  documenter: "doc-writer"
10326
10631
  };
@@ -11074,6 +11379,42 @@ var src_default = define({
11074
11379
  }
11075
11380
  }
11076
11381
  });
11382
+ editor.add({
11383
+ name: "performance.scores",
11384
+ description: "Show agent performance scores by model and role",
11385
+ input: {
11386
+ type: "object",
11387
+ properties: {},
11388
+ additionalProperties: false
11389
+ },
11390
+ execute: async () => {
11391
+ const scores = orchestrator.performanceTracker.getScores();
11392
+ if (scores.length === 0)
11393
+ return { content: "No performance data yet. Scores build up as tasks are executed." };
11394
+ const lines = scores.map((s) => `${s.role}/${s.model}: score=${s.overallScore.toFixed(1)} success=${(s.successRate * 100).toFixed(0)}% avg=$${s.avgCost.toFixed(4)} (${s.totalTasks} tasks)`);
11395
+ return { content: lines.join(`
11396
+ `) };
11397
+ }
11398
+ });
11399
+ editor.add({
11400
+ name: "performance.best",
11401
+ description: "Get best model for a specific role",
11402
+ input: {
11403
+ type: "object",
11404
+ properties: {
11405
+ role: { type: "string", description: "Agent role to find best model for" }
11406
+ },
11407
+ required: ["role"],
11408
+ additionalProperties: false
11409
+ },
11410
+ execute: async (input) => {
11411
+ const { role } = input;
11412
+ const best = orchestrator.performanceTracker.getBestModel(role);
11413
+ if (!best)
11414
+ return { content: `No performance data for role '${role}' yet.` };
11415
+ return { content: `Best for ${role}: ${best.model} (score: ${best.overallScore.toFixed(1)}, success: ${(best.successRate * 100).toFixed(0)}%, avg cost: $${best.avgCost.toFixed(4)})` };
11416
+ }
11417
+ });
11077
11418
  editor.add({
11078
11419
  name: "security.scan",
11079
11420
  description: "Scan content for security issues",
@@ -11093,6 +11434,137 @@ var src_default = define({
11093
11434
  return { content: JSON.stringify({ issues: issues.length, score: result.score, details: issues }, null, 2) };
11094
11435
  }
11095
11436
  });
11437
+ editor.add({
11438
+ name: "history.list",
11439
+ description: "List execution history",
11440
+ input: {
11441
+ type: "object",
11442
+ properties: {
11443
+ count: { type: "number", description: "Number of recent entries" }
11444
+ },
11445
+ additionalProperties: false
11446
+ },
11447
+ execute: async (input) => {
11448
+ const { count } = input;
11449
+ const records = count ? orchestrator.executionHistory.getRecent(count) : orchestrator.executionHistory.getAll();
11450
+ if (records.length === 0)
11451
+ return { content: "No execution history yet." };
11452
+ const lines = records.map((r) => `${r.status === "success" ? "✅" : "❌"} ${r.taskName} (${r.role}) — $${r.cost.toFixed(4)} — ${r.duration}ms`);
11453
+ return { content: lines.join(`
11454
+ `) };
11455
+ }
11456
+ });
11457
+ editor.add({
11458
+ name: "history.stats",
11459
+ description: "Show execution statistics",
11460
+ input: {
11461
+ type: "object",
11462
+ properties: {},
11463
+ additionalProperties: false
11464
+ },
11465
+ execute: async () => {
11466
+ const stats = orchestrator.executionHistory.getStats();
11467
+ return { content: `Total: ${stats.total} | Success: ${(stats.successRate * 100).toFixed(1)}% | Cost: $${stats.totalCost.toFixed(4)} | Avg: ${stats.avgDuration.toFixed(0)}ms
11468
+ By role: ${JSON.stringify(stats.byRole)}` };
11469
+ }
11470
+ });
11471
+ editor.add({
11472
+ name: "roles.list",
11473
+ description: "List all custom agent roles",
11474
+ input: {
11475
+ type: "object",
11476
+ properties: {},
11477
+ additionalProperties: false
11478
+ },
11479
+ execute: async () => {
11480
+ const roles = orchestrator.customRoles.list();
11481
+ if (roles.length === 0)
11482
+ return { content: "No custom roles defined. Add them in .opencode/nexus.jsonc under 'customRoles'." };
11483
+ const lines = roles.map((r) => `${r.emoji} ${r.displayName} (${r.name}): ${r.prompt.substring(0, 60)}...`);
11484
+ return { content: lines.join(`
11485
+ `) };
11486
+ }
11487
+ });
11488
+ editor.add({
11489
+ name: "roles.add",
11490
+ description: "Add a custom agent role",
11491
+ input: {
11492
+ type: "object",
11493
+ properties: {
11494
+ name: { type: "string", description: "Role identifier (lowercase, no spaces)" },
11495
+ displayName: { type: "string", description: "Display name" },
11496
+ emoji: { type: "string", description: "Emoji for the role" },
11497
+ prompt: { type: "string", description: "System prompt for this role" },
11498
+ model: { type: "string", description: "Default model (optional)" }
11499
+ },
11500
+ required: ["name", "displayName", "prompt"]
11501
+ },
11502
+ execute: async (input) => {
11503
+ const { name, displayName, emoji, prompt, model } = input;
11504
+ orchestrator.customRoles.register({ name, displayName, emoji: emoji || "\uD83E\uDD16", prompt, model });
11505
+ return { content: `Custom role '${displayName}' registered` };
11506
+ }
11507
+ });
11508
+ editor.add({
11509
+ name: "forecast",
11510
+ description: "Estimate cost before executing tasks",
11511
+ input: {
11512
+ type: "object",
11513
+ properties: {
11514
+ tasks: { type: "string", description: "JSON array of tasks with role, model, and complexity" }
11515
+ },
11516
+ required: ["tasks"]
11517
+ },
11518
+ execute: async (input) => {
11519
+ const { tasks } = input;
11520
+ const taskList = JSON.parse(tasks);
11521
+ const remaining = orchestrator.budget.maxTotalCost - orchestrator.totalSpent;
11522
+ const result = orchestrator.forecaster.forecastAll(taskList, remaining);
11523
+ const lines = result.estimates.map((e) => `${e.taskName}: ~$${e.estimatedCost.toFixed(4)} (${e.model})`);
11524
+ lines.push(`
11525
+ Total: ~$${result.totalEstimatedCost.toFixed(4)}`);
11526
+ lines.push(`Budget remaining: $${remaining.toFixed(2)}`);
11527
+ lines.push(`Within budget: ${result.withinBudget ? "✅" : "❌"}`);
11528
+ return { content: lines.join(`
11529
+ `) };
11530
+ }
11531
+ });
11532
+ editor.add({
11533
+ name: "worktree.enable",
11534
+ description: "Enable git worktree isolation for agents",
11535
+ input: { type: "object", properties: { repoRoot: { type: "string", description: "Repository root (defaults to cwd)" } } },
11536
+ execute: async (input) => {
11537
+ const { repoRoot } = input;
11538
+ orchestrator.enableWorktrees(repoRoot || process.cwd());
11539
+ return { content: "Git worktree isolation enabled." };
11540
+ }
11541
+ });
11542
+ editor.add({
11543
+ name: "worktree.list",
11544
+ description: "List active agent worktrees",
11545
+ input: { type: "object", properties: {}, additionalProperties: false },
11546
+ execute: async () => {
11547
+ if (!orchestrator.worktreeManager)
11548
+ return { content: "Worktree isolation not enabled." };
11549
+ const wts = orchestrator.worktreeManager.list();
11550
+ if (wts.length === 0)
11551
+ return { content: "No active worktrees." };
11552
+ return { content: wts.map((w) => `${w.agentId}: ${w.path}`).join(`
11553
+ `) };
11554
+ }
11555
+ });
11556
+ editor.add({
11557
+ name: "worktree.disable",
11558
+ description: "Disable worktree isolation and clean up",
11559
+ input: { type: "object", properties: {}, additionalProperties: false },
11560
+ execute: async () => {
11561
+ if (orchestrator.worktreeManager) {
11562
+ orchestrator.worktreeManager.cleanupAll();
11563
+ orchestrator.worktreeManager = null;
11564
+ }
11565
+ return { content: "Worktree isolation disabled." };
11566
+ }
11567
+ });
11096
11568
  });
11097
11569
  await ctx.session.hook("prompt", (event) => {
11098
11570
  if (event.prompt.text.startsWith("/nexus")) {
@@ -11106,6 +11578,8 @@ var src_default = define({
11106
11578
  }
11107
11579
  });
11108
11580
  export {
11581
+ CostForecaster,
11582
+ CustomRoleManager,
11109
11583
  DEFAULT_CONFIG,
11110
11584
  HealthMonitor,
11111
11585
  LearningModule,
@@ -11115,10 +11589,12 @@ export {
11115
11589
  NexusConfigManager,
11116
11590
  NexusOrchestrator,
11117
11591
  PRESETS,
11592
+ PerformanceTracker,
11118
11593
  PersistentMemoryStore,
11119
11594
  SecurityScanner,
11120
11595
  StateBroadcaster,
11121
11596
  TEMPLATES,
11597
+ WorktreeManager,
11122
11598
  src_default as default,
11123
11599
  detectCycles,
11124
11600
  getTemplate,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serkanalgur/opencode-nexus",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Adaptive Multi-Agent Orchestration with Cost Intelligence for OpenCode V2",
5
5
  "keywords": [
6
6
  "opencode",