@serkanalgur/opencode-nexus 1.0.3 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +269 -170
- package/dist/tui.js +259 -209
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8514,11 +8514,53 @@ class NexusOrchestrator {
|
|
|
8514
8514
|
memory = new Map;
|
|
8515
8515
|
eventHandlers = new Map;
|
|
8516
8516
|
configManager;
|
|
8517
|
+
ctx = null;
|
|
8518
|
+
onStateChange = null;
|
|
8517
8519
|
constructor(config) {
|
|
8518
8520
|
this.config = this.mergeConfig(config);
|
|
8519
8521
|
this.budget = this.config.budget;
|
|
8520
8522
|
this.configManager = new NexusConfigManager;
|
|
8521
8523
|
}
|
|
8524
|
+
initialize(ctx, onStateChange) {
|
|
8525
|
+
this.ctx = ctx;
|
|
8526
|
+
this.onStateChange = onStateChange ?? null;
|
|
8527
|
+
}
|
|
8528
|
+
getState() {
|
|
8529
|
+
const agents = Array.from(this.agents.values()).map((a) => ({
|
|
8530
|
+
id: a.id,
|
|
8531
|
+
name: a.name,
|
|
8532
|
+
role: a.role,
|
|
8533
|
+
status: a.status,
|
|
8534
|
+
model: `${a.model.provider}/${a.model.model}`,
|
|
8535
|
+
sessionID: a.sessionID,
|
|
8536
|
+
spawnedAt: a.spawnedAt.toISOString(),
|
|
8537
|
+
tasksCompleted: a.metrics.tasksCompleted,
|
|
8538
|
+
tasksFailed: a.metrics.tasksFailed,
|
|
8539
|
+
totalCost: a.metrics.totalCost
|
|
8540
|
+
}));
|
|
8541
|
+
const tasks = Array.from(this.tasks.values()).map((t) => ({
|
|
8542
|
+
id: t.id,
|
|
8543
|
+
name: t.name,
|
|
8544
|
+
role: t.requiredRole,
|
|
8545
|
+
status: t.status,
|
|
8546
|
+
assignedAgent: t.assignedAgent,
|
|
8547
|
+
result: t.result ? {
|
|
8548
|
+
success: t.result.success,
|
|
8549
|
+
output: t.result.output?.slice(0, 500),
|
|
8550
|
+
error: t.result.error,
|
|
8551
|
+
duration: t.result.duration
|
|
8552
|
+
} : undefined
|
|
8553
|
+
}));
|
|
8554
|
+
return {
|
|
8555
|
+
running: this.running,
|
|
8556
|
+
paused: this.paused,
|
|
8557
|
+
agents,
|
|
8558
|
+
tasks,
|
|
8559
|
+
totalSpent: this.totalSpent,
|
|
8560
|
+
budgetRemaining: this.budget.maxTotalCost - this.totalSpent,
|
|
8561
|
+
lastUpdated: new Date().toISOString()
|
|
8562
|
+
};
|
|
8563
|
+
}
|
|
8522
8564
|
mergeConfig(partial) {
|
|
8523
8565
|
const defaults = {
|
|
8524
8566
|
maxConcurrency: 5,
|
|
@@ -8556,7 +8598,7 @@ class NexusOrchestrator {
|
|
|
8556
8598
|
syncInterval: 5000
|
|
8557
8599
|
},
|
|
8558
8600
|
dashboard: {
|
|
8559
|
-
enabled:
|
|
8601
|
+
enabled: true,
|
|
8560
8602
|
port: 4747,
|
|
8561
8603
|
host: "127.0.0.1"
|
|
8562
8604
|
},
|
|
@@ -8584,12 +8626,19 @@ class NexusOrchestrator {
|
|
|
8584
8626
|
learning: { ...defaults.learning, ...partial?.learning }
|
|
8585
8627
|
};
|
|
8586
8628
|
}
|
|
8629
|
+
notifyStateChange() {
|
|
8630
|
+
this.onStateChange?.();
|
|
8631
|
+
}
|
|
8587
8632
|
async execute(request) {
|
|
8588
8633
|
if (this.running) {
|
|
8589
8634
|
throw new Error("Orchestrator is already running");
|
|
8590
8635
|
}
|
|
8636
|
+
if (!this.ctx) {
|
|
8637
|
+
throw new Error("Orchestrator not initialized - call initialize(ctx) first");
|
|
8638
|
+
}
|
|
8591
8639
|
this.running = true;
|
|
8592
8640
|
const startTime = Date.now();
|
|
8641
|
+
this.notifyStateChange();
|
|
8593
8642
|
try {
|
|
8594
8643
|
this.dag = this.buildDAG(request.tasks);
|
|
8595
8644
|
if (request.budget) {
|
|
@@ -8615,6 +8664,7 @@ class NexusOrchestrator {
|
|
|
8615
8664
|
};
|
|
8616
8665
|
} finally {
|
|
8617
8666
|
this.running = false;
|
|
8667
|
+
this.notifyStateChange();
|
|
8618
8668
|
}
|
|
8619
8669
|
}
|
|
8620
8670
|
buildDAG(tasks) {
|
|
@@ -8692,11 +8742,13 @@ class NexusOrchestrator {
|
|
|
8692
8742
|
async executeDAG() {
|
|
8693
8743
|
while (!this.dag.isComplete() && !this.paused) {
|
|
8694
8744
|
const readyNodes = this.dag.getReadyNodes();
|
|
8745
|
+
const spawnPromises = [];
|
|
8695
8746
|
for (const node of readyNodes) {
|
|
8696
8747
|
if (this.agents.size < this.config.maxConcurrency) {
|
|
8697
|
-
|
|
8748
|
+
spawnPromises.push(this.spawnAndExecute(node));
|
|
8698
8749
|
}
|
|
8699
8750
|
}
|
|
8751
|
+
await Promise.all(spawnPromises);
|
|
8700
8752
|
await this.sleep(this.config.schedulerInterval);
|
|
8701
8753
|
}
|
|
8702
8754
|
}
|
|
@@ -8710,86 +8762,150 @@ class NexusOrchestrator {
|
|
|
8710
8762
|
});
|
|
8711
8763
|
node.spawnedAgent = agent;
|
|
8712
8764
|
node.status = "running";
|
|
8713
|
-
|
|
8765
|
+
node.task.assignedAgent = agent.id;
|
|
8766
|
+
this.notifyStateChange();
|
|
8767
|
+
await this.executeTask(agent, node);
|
|
8714
8768
|
}
|
|
8715
|
-
async
|
|
8716
|
-
|
|
8717
|
-
setTimeout(() => {
|
|
8718
|
-
if (node.status === "running") {
|
|
8719
|
-
this.handleAgentTimeout(agent, node);
|
|
8720
|
-
}
|
|
8721
|
-
}, timeout);
|
|
8722
|
-
}
|
|
8723
|
-
handleAgentTimeout(agent, node) {
|
|
8724
|
-
if (this.config.selfHealing.enabled) {
|
|
8725
|
-
this.handleFailure(agent, node, new Error("Agent timed out"));
|
|
8726
|
-
} else {
|
|
8769
|
+
async executeTask(agent, node) {
|
|
8770
|
+
if (!this.ctx || !agent.sessionID) {
|
|
8727
8771
|
node.status = "failed";
|
|
8728
8772
|
node.result = {
|
|
8729
8773
|
success: false,
|
|
8730
|
-
error: "
|
|
8731
|
-
duration:
|
|
8774
|
+
error: "No session available for agent",
|
|
8775
|
+
duration: 0,
|
|
8732
8776
|
tokensUsed: 0,
|
|
8733
8777
|
cost: 0
|
|
8734
8778
|
};
|
|
8779
|
+
this.notifyStateChange();
|
|
8780
|
+
return;
|
|
8735
8781
|
}
|
|
8782
|
+
const startTime = Date.now();
|
|
8783
|
+
const timeout = node.task.timeout || this.config.defaultTimeout;
|
|
8784
|
+
try {
|
|
8785
|
+
const rolePrompt = this.buildRolePrompt(node.task.requiredRole);
|
|
8786
|
+
const taskPrompt = `${rolePrompt}
|
|
8787
|
+
|
|
8788
|
+
## Task
|
|
8789
|
+
${node.task.name}
|
|
8790
|
+
|
|
8791
|
+
${node.task.description}
|
|
8792
|
+
|
|
8793
|
+
## Scope
|
|
8794
|
+
Files: ${node.task.files.include.join(", ")}`;
|
|
8795
|
+
await this.ctx.session.prompt({
|
|
8796
|
+
sessionID: agent.sessionID,
|
|
8797
|
+
text: taskPrompt
|
|
8798
|
+
});
|
|
8799
|
+
const waitPromise = this.ctx.session.wait({ sessionID: agent.sessionID });
|
|
8800
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Task timed out")), timeout));
|
|
8801
|
+
await Promise.race([waitPromise, timeoutPromise]);
|
|
8802
|
+
const messages = await this.ctx.session.context({ sessionID: agent.sessionID });
|
|
8803
|
+
const lastAssistantMsg = messages.filter((m) => m.role === "assistant").pop();
|
|
8804
|
+
const output = lastAssistantMsg?.content || "Task completed";
|
|
8805
|
+
const duration = Date.now() - startTime;
|
|
8806
|
+
const result = {
|
|
8807
|
+
success: true,
|
|
8808
|
+
output: typeof output === "string" ? output : JSON.stringify(output),
|
|
8809
|
+
duration,
|
|
8810
|
+
tokensUsed: 0,
|
|
8811
|
+
cost: this.estimateModelCost(agent.model.model)
|
|
8812
|
+
};
|
|
8813
|
+
this.dag.markComplete(node.id, result);
|
|
8814
|
+
agent.metrics.tasksCompleted++;
|
|
8815
|
+
agent.metrics.totalCost += result.cost;
|
|
8816
|
+
this.totalSpent += result.cost;
|
|
8817
|
+
this.costByAgent.set(agent.id, (this.costByAgent.get(agent.id) || 0) + result.cost);
|
|
8818
|
+
this.checkBudget();
|
|
8819
|
+
} catch (error) {
|
|
8820
|
+
const duration = Date.now() - startTime;
|
|
8821
|
+
const result = {
|
|
8822
|
+
success: false,
|
|
8823
|
+
error: error.message || "Task failed",
|
|
8824
|
+
duration,
|
|
8825
|
+
tokensUsed: 0,
|
|
8826
|
+
cost: 0
|
|
8827
|
+
};
|
|
8828
|
+
this.dag.markFailed(node.id, new Error(result.error));
|
|
8829
|
+
agent.metrics.tasksFailed++;
|
|
8830
|
+
if (this.config.selfHealing.enabled) {
|
|
8831
|
+
await this.handleFailure(agent, node, new Error(result.error));
|
|
8832
|
+
}
|
|
8833
|
+
} finally {
|
|
8834
|
+
agent.status = "idle";
|
|
8835
|
+
node.task.status = node.status === "completed" ? "completed" : "failed";
|
|
8836
|
+
this.notifyStateChange();
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
buildRolePrompt(role) {
|
|
8840
|
+
const rolePrompts = {
|
|
8841
|
+
architect: "You are a software architect. Focus on system design, architecture patterns, and high-level technical decisions. Analyze requirements and propose structured solutions.",
|
|
8842
|
+
coder: "You are a senior software engineer. Write clean, efficient, well-documented code. Follow best practices and coding standards.",
|
|
8843
|
+
reviewer: "You are a code reviewer. Review code for correctness, security, performance, and maintainability. Provide constructive feedback.",
|
|
8844
|
+
tester: "You are a QA engineer. Write comprehensive tests, identify edge cases, and ensure code quality.",
|
|
8845
|
+
explorer: "You are a code explorer. Navigate and analyze codebases, understand architecture, and provide detailed reports.",
|
|
8846
|
+
documenter: "You are a technical writer. Create clear, comprehensive documentation for code and APIs."
|
|
8847
|
+
};
|
|
8848
|
+
return rolePrompts[role] || `You are a ${role}. Complete the assigned task professionally.`;
|
|
8736
8849
|
}
|
|
8737
8850
|
async handleFailure(agent, node, error) {
|
|
8738
8851
|
const failureCount = agent.metrics.tasksFailed + 1;
|
|
8739
|
-
agent.metrics.tasksFailed++;
|
|
8740
8852
|
if (failureCount < this.config.selfHealing.maxRetries) {
|
|
8741
8853
|
const delay = this.config.selfHealing.retryDelay * Math.pow(this.config.selfHealing.backoffMultiplier, failureCount - 1);
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
8745
|
-
|
|
8746
|
-
|
|
8854
|
+
await this.sleep(delay);
|
|
8855
|
+
if (agent.sessionID) {
|
|
8856
|
+
node.status = "running";
|
|
8857
|
+
this.notifyStateChange();
|
|
8858
|
+
await this.executeTask(agent, node);
|
|
8859
|
+
}
|
|
8747
8860
|
} else {
|
|
8748
8861
|
node.status = "failed";
|
|
8749
8862
|
node.result = {
|
|
8750
8863
|
success: false,
|
|
8751
|
-
error: error.message
|
|
8864
|
+
error: `Max retries (${this.config.selfHealing.maxRetries}) exceeded: ${error.message}`,
|
|
8752
8865
|
duration: 0,
|
|
8753
8866
|
tokensUsed: 0,
|
|
8754
8867
|
cost: 0
|
|
8755
8868
|
};
|
|
8869
|
+
this.notifyStateChange();
|
|
8756
8870
|
}
|
|
8757
8871
|
}
|
|
8758
|
-
async retryAgent(agent, node) {
|
|
8759
|
-
agent.status = "working";
|
|
8760
|
-
node.status = "running";
|
|
8761
|
-
this.emit("agent:retry", { agent, node });
|
|
8762
|
-
}
|
|
8763
|
-
async respawnAgent(oldAgent, node) {
|
|
8764
|
-
const newAgent = await this.spawnAgent({
|
|
8765
|
-
role: oldAgent.role,
|
|
8766
|
-
task: node.task,
|
|
8767
|
-
model: oldAgent.model.model
|
|
8768
|
-
});
|
|
8769
|
-
if (this.config.selfHealing.contextTransfer) {
|
|
8770
|
-
await this.transferContext(oldAgent, newAgent);
|
|
8771
|
-
}
|
|
8772
|
-
await this.terminateAgent(oldAgent.id);
|
|
8773
|
-
node.spawnedAgent = newAgent;
|
|
8774
|
-
node.status = "running";
|
|
8775
|
-
this.monitorAgent(newAgent, node);
|
|
8776
|
-
}
|
|
8777
|
-
async transferContext(oldAgent, newAgent) {
|
|
8778
|
-
this.emit("context:transfer", { from: oldAgent, to: newAgent });
|
|
8779
|
-
}
|
|
8780
8872
|
async spawnAgent(config) {
|
|
8873
|
+
if (!this.ctx) {
|
|
8874
|
+
throw new Error("Orchestrator not initialized");
|
|
8875
|
+
}
|
|
8781
8876
|
const agentId = `agent-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
8877
|
+
const displayName = `${config.role}-${agentId.slice(0, 8)}`;
|
|
8878
|
+
const session = await this.ctx.session.create({
|
|
8879
|
+
title: `[Nexus] ${displayName}`
|
|
8880
|
+
});
|
|
8881
|
+
const modelConfig = this.configManager.getModelForRole(config.role);
|
|
8882
|
+
const [provider, ...modelParts] = modelConfig.split("/");
|
|
8883
|
+
const modelName = modelParts.join("/");
|
|
8884
|
+
try {
|
|
8885
|
+
await this.ctx.session.switchAgent({
|
|
8886
|
+
sessionID: session.id,
|
|
8887
|
+
agent: config.role === "architect" ? "build" : config.role === "reviewer" ? "build" : "build"
|
|
8888
|
+
});
|
|
8889
|
+
} catch {}
|
|
8890
|
+
if (modelName) {
|
|
8891
|
+
try {
|
|
8892
|
+
await this.ctx.session.switchModel({
|
|
8893
|
+
sessionID: session.id,
|
|
8894
|
+
model: { providerID: provider, id: modelName }
|
|
8895
|
+
});
|
|
8896
|
+
} catch {}
|
|
8897
|
+
}
|
|
8782
8898
|
const agent = {
|
|
8783
8899
|
id: agentId,
|
|
8784
|
-
name:
|
|
8900
|
+
name: displayName,
|
|
8785
8901
|
role: config.role,
|
|
8786
|
-
status: "
|
|
8902
|
+
status: "idle",
|
|
8787
8903
|
model: {
|
|
8788
|
-
provider
|
|
8789
|
-
model:
|
|
8904
|
+
provider,
|
|
8905
|
+
model: modelName || "default",
|
|
8790
8906
|
estimatedCost: 0,
|
|
8791
8907
|
estimatedQuality: 0.5,
|
|
8792
|
-
reasoning:
|
|
8908
|
+
reasoning: `Configured for ${config.role}`
|
|
8793
8909
|
},
|
|
8794
8910
|
spawnedAt: new Date,
|
|
8795
8911
|
lastActivity: new Date,
|
|
@@ -8800,12 +8916,12 @@ class NexusOrchestrator {
|
|
|
8800
8916
|
totalCost: 0,
|
|
8801
8917
|
averageResponseTime: 0,
|
|
8802
8918
|
errorRate: 0
|
|
8803
|
-
}
|
|
8919
|
+
},
|
|
8920
|
+
sessionID: session.id
|
|
8804
8921
|
};
|
|
8805
8922
|
this.agents.set(agentId, agent);
|
|
8806
8923
|
this.emit("agent:spawned", agent);
|
|
8807
|
-
|
|
8808
|
-
agent.status = "idle";
|
|
8924
|
+
this.notifyStateChange();
|
|
8809
8925
|
return agent;
|
|
8810
8926
|
}
|
|
8811
8927
|
async terminateAgent(agentId) {
|
|
@@ -8814,53 +8930,34 @@ class NexusOrchestrator {
|
|
|
8814
8930
|
agent.status = "terminated";
|
|
8815
8931
|
this.agents.delete(agentId);
|
|
8816
8932
|
this.emit("agent:terminated", agent);
|
|
8933
|
+
this.notifyStateChange();
|
|
8817
8934
|
}
|
|
8818
8935
|
}
|
|
8819
8936
|
analyzeComplexity(task) {
|
|
8820
8937
|
const fileCount = task.files.include.length;
|
|
8821
|
-
const codeLines =
|
|
8938
|
+
const codeLines = task.files.include.length * 50;
|
|
8822
8939
|
const dependencyDepth = task.dependencies.length;
|
|
8823
|
-
|
|
8824
|
-
const riskLevel = this.estimateRiskLevel(task);
|
|
8825
|
-
const overall = Math.min(100, fileCount * 10 + codeLines / 10 + dependencyDepth * 15 + domainKnowledge * 20 + (riskLevel === "high" ? 30 : riskLevel === "medium" ? 15 : 0));
|
|
8826
|
-
return {
|
|
8827
|
-
overall,
|
|
8828
|
-
factors: {
|
|
8829
|
-
fileCount,
|
|
8830
|
-
codeLines,
|
|
8831
|
-
dependencyDepth,
|
|
8832
|
-
domainKnowledge,
|
|
8833
|
-
riskLevel
|
|
8834
|
-
}
|
|
8835
|
-
};
|
|
8836
|
-
}
|
|
8837
|
-
estimateCodeLines(task) {
|
|
8838
|
-
return task.files.include.length * 50;
|
|
8839
|
-
}
|
|
8840
|
-
estimateDomainKnowledge(task) {
|
|
8940
|
+
let domainKnowledge = 0;
|
|
8841
8941
|
const keywords = ["security", "auth", "payment", "crypto", "database"];
|
|
8842
|
-
let score = 0;
|
|
8843
8942
|
for (const keyword of keywords) {
|
|
8844
8943
|
if (task.description.toLowerCase().includes(keyword)) {
|
|
8845
|
-
|
|
8944
|
+
domainKnowledge += 20;
|
|
8846
8945
|
}
|
|
8847
8946
|
}
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
estimateRiskLevel(task) {
|
|
8947
|
+
domainKnowledge = Math.min(100, domainKnowledge);
|
|
8948
|
+
let riskLevel = "low";
|
|
8851
8949
|
const highRiskKeywords = ["migration", "production", "security", "payment"];
|
|
8852
|
-
const mediumRiskKeywords = ["refactor", "update", "modify"];
|
|
8853
8950
|
for (const keyword of highRiskKeywords) {
|
|
8854
8951
|
if (task.description.toLowerCase().includes(keyword)) {
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
}
|
|
8858
|
-
for (const keyword of mediumRiskKeywords) {
|
|
8859
|
-
if (task.description.toLowerCase().includes(keyword)) {
|
|
8860
|
-
return "medium";
|
|
8952
|
+
riskLevel = "high";
|
|
8953
|
+
break;
|
|
8861
8954
|
}
|
|
8862
8955
|
}
|
|
8863
|
-
|
|
8956
|
+
const overall = Math.min(100, fileCount * 10 + codeLines / 10 + dependencyDepth * 15 + domainKnowledge * 20 + (riskLevel === "high" ? 30 : riskLevel === "medium" ? 15 : 0));
|
|
8957
|
+
return {
|
|
8958
|
+
overall,
|
|
8959
|
+
factors: { fileCount, codeLines, dependencyDepth, domainKnowledge, riskLevel }
|
|
8960
|
+
};
|
|
8864
8961
|
}
|
|
8865
8962
|
selectModel(role, complexity) {
|
|
8866
8963
|
const configModel = this.configManager.getModelForRole(role);
|
|
@@ -8915,6 +9012,7 @@ class NexusOrchestrator {
|
|
|
8915
9012
|
const modelCost = this.costByModel.get(model) || 0;
|
|
8916
9013
|
this.costByModel.set(model, modelCost + cost);
|
|
8917
9014
|
this.checkBudget();
|
|
9015
|
+
this.notifyStateChange();
|
|
8918
9016
|
}
|
|
8919
9017
|
checkBudget() {
|
|
8920
9018
|
const remaining = this.budget.maxTotalCost - this.totalSpent;
|
|
@@ -8943,21 +9041,10 @@ class NexusOrchestrator {
|
|
|
8943
9041
|
this.subscribers.set(topic, handlers);
|
|
8944
9042
|
return () => {
|
|
8945
9043
|
const idx = handlers.indexOf(handler);
|
|
8946
|
-
if (idx > -1)
|
|
9044
|
+
if (idx > -1)
|
|
8947
9045
|
handlers.splice(idx, 1);
|
|
8948
|
-
}
|
|
8949
9046
|
};
|
|
8950
9047
|
}
|
|
8951
|
-
send(agentId, message) {
|
|
8952
|
-
const fullMessage = {
|
|
8953
|
-
...message,
|
|
8954
|
-
id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
8955
|
-
to: agentId,
|
|
8956
|
-
timestamp: new Date
|
|
8957
|
-
};
|
|
8958
|
-
this.messageQueue.push(fullMessage);
|
|
8959
|
-
this.emit("message:sent", fullMessage);
|
|
8960
|
-
}
|
|
8961
9048
|
setMemory(scope, key, value, author) {
|
|
8962
9049
|
const entry = {
|
|
8963
9050
|
id: `mem-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
@@ -8975,71 +9062,42 @@ class NexusOrchestrator {
|
|
|
8975
9062
|
getMemory(scope, key) {
|
|
8976
9063
|
return this.memory.get(`${scope}:${key}`);
|
|
8977
9064
|
}
|
|
8978
|
-
searchMemory(query, scope) {
|
|
8979
|
-
const results = [];
|
|
8980
|
-
this.memory.forEach((entry) => {
|
|
8981
|
-
if (scope && entry.scope !== scope)
|
|
8982
|
-
return;
|
|
8983
|
-
if (entry.key.includes(query) || JSON.stringify(entry.value).includes(query)) {
|
|
8984
|
-
results.push(entry);
|
|
8985
|
-
}
|
|
8986
|
-
});
|
|
8987
|
-
return results;
|
|
8988
|
-
}
|
|
8989
9065
|
getStatus(detailed) {
|
|
8990
|
-
const
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
|
|
9001
|
-
agentsByStatus: this.getAgentsByStatus(),
|
|
9002
|
-
costByAgent: Object.fromEntries(this.costByAgent),
|
|
9003
|
-
costByModel: Object.fromEntries(this.costByModel)
|
|
9004
|
-
}, null, 2);
|
|
9005
|
-
}
|
|
9006
|
-
return JSON.stringify(status, null, 2);
|
|
9066
|
+
const state = this.getState();
|
|
9067
|
+
if (detailed)
|
|
9068
|
+
return JSON.stringify(state, null, 2);
|
|
9069
|
+
return JSON.stringify({
|
|
9070
|
+
running: state.running,
|
|
9071
|
+
paused: state.paused,
|
|
9072
|
+
agents: state.agents.length,
|
|
9073
|
+
tasks: state.tasks.length,
|
|
9074
|
+
totalCost: state.totalSpent,
|
|
9075
|
+
budgetRemaining: state.budgetRemaining
|
|
9076
|
+
}, null, 2);
|
|
9007
9077
|
}
|
|
9008
9078
|
listAgents(filter) {
|
|
9009
|
-
const
|
|
9010
|
-
const filtered = filter ? agents.filter((a) => a.status === filter) : agents;
|
|
9079
|
+
const state = this.getState();
|
|
9080
|
+
const filtered = filter ? state.agents.filter((a) => a.status === filter) : state.agents;
|
|
9011
9081
|
return JSON.stringify(filtered, null, 2);
|
|
9012
9082
|
}
|
|
9013
9083
|
getCostReport() {
|
|
9014
|
-
const
|
|
9015
|
-
totalSpent: this.totalSpent,
|
|
9016
|
-
budgetRemaining: this.budget.maxTotalCost - this.totalSpent,
|
|
9017
|
-
byAgent: new Map,
|
|
9018
|
-
byModel: new Map,
|
|
9019
|
-
timeline: []
|
|
9020
|
-
};
|
|
9021
|
-
this.agents.forEach((agent) => {
|
|
9022
|
-
report.byAgent.set(agent.id, {
|
|
9023
|
-
agentId: agent.id,
|
|
9024
|
-
agentName: agent.name,
|
|
9025
|
-
totalCost: agent.metrics.totalCost,
|
|
9026
|
-
tokenCount: agent.metrics.totalTokens,
|
|
9027
|
-
taskCount: agent.metrics.tasksCompleted
|
|
9028
|
-
});
|
|
9029
|
-
});
|
|
9084
|
+
const state = this.getState();
|
|
9030
9085
|
return JSON.stringify({
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9086
|
+
totalSpent: state.totalSpent,
|
|
9087
|
+
budgetRemaining: state.budgetRemaining,
|
|
9088
|
+
byAgent: Object.fromEntries(this.costByAgent),
|
|
9089
|
+
byModel: Object.fromEntries(this.costByModel)
|
|
9034
9090
|
}, null, 2);
|
|
9035
9091
|
}
|
|
9036
9092
|
pause() {
|
|
9037
9093
|
this.paused = true;
|
|
9038
9094
|
this.emit("orchestrator:paused", {});
|
|
9095
|
+
this.notifyStateChange();
|
|
9039
9096
|
}
|
|
9040
9097
|
resume() {
|
|
9041
9098
|
this.paused = false;
|
|
9042
9099
|
this.emit("orchestrator:resumed", {});
|
|
9100
|
+
this.notifyStateChange();
|
|
9043
9101
|
}
|
|
9044
9102
|
shutdown() {
|
|
9045
9103
|
this.agents.forEach((agent) => {
|
|
@@ -9048,25 +9106,18 @@ class NexusOrchestrator {
|
|
|
9048
9106
|
this.agents.clear();
|
|
9049
9107
|
this.running = false;
|
|
9050
9108
|
this.emit("orchestrator:shutdown", {});
|
|
9109
|
+
this.notifyStateChange();
|
|
9051
9110
|
}
|
|
9052
9111
|
collectResults() {
|
|
9053
9112
|
const results = [];
|
|
9054
9113
|
if (this.dag) {
|
|
9055
9114
|
this.dag.nodes.forEach((node) => {
|
|
9056
|
-
if (node.result)
|
|
9115
|
+
if (node.result)
|
|
9057
9116
|
results.push(node.result);
|
|
9058
|
-
}
|
|
9059
9117
|
});
|
|
9060
9118
|
}
|
|
9061
9119
|
return results;
|
|
9062
9120
|
}
|
|
9063
|
-
getAgentsByStatus() {
|
|
9064
|
-
const counts = {};
|
|
9065
|
-
this.agents.forEach((agent) => {
|
|
9066
|
-
counts[agent.status] = (counts[agent.status] || 0) + 1;
|
|
9067
|
-
});
|
|
9068
|
-
return counts;
|
|
9069
|
-
}
|
|
9070
9121
|
sleep(ms) {
|
|
9071
9122
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
9072
9123
|
}
|
|
@@ -9076,9 +9127,8 @@ class NexusOrchestrator {
|
|
|
9076
9127
|
this.eventHandlers.set(event, handlers);
|
|
9077
9128
|
return () => {
|
|
9078
9129
|
const idx = handlers.indexOf(handler);
|
|
9079
|
-
if (idx > -1)
|
|
9130
|
+
if (idx > -1)
|
|
9080
9131
|
handlers.splice(idx, 1);
|
|
9081
|
-
}
|
|
9082
9132
|
};
|
|
9083
9133
|
}
|
|
9084
9134
|
emit(event, data) {
|
|
@@ -9090,22 +9140,21 @@ class NexusOrchestrator {
|
|
|
9090
9140
|
const command = parts[1];
|
|
9091
9141
|
switch (command) {
|
|
9092
9142
|
case "status":
|
|
9093
|
-
|
|
9094
|
-
break;
|
|
9143
|
+
return this.getStatus(true);
|
|
9095
9144
|
case "agents":
|
|
9096
|
-
|
|
9097
|
-
break;
|
|
9145
|
+
return this.listAgents(parts[2]);
|
|
9098
9146
|
case "costs":
|
|
9099
|
-
|
|
9100
|
-
break;
|
|
9147
|
+
return this.getCostReport();
|
|
9101
9148
|
case "pause":
|
|
9102
9149
|
this.pause();
|
|
9103
|
-
|
|
9150
|
+
return "Orchestrator paused";
|
|
9104
9151
|
case "resume":
|
|
9105
9152
|
this.resume();
|
|
9106
|
-
|
|
9153
|
+
return "Orchestrator resumed";
|
|
9154
|
+
case "dashboard":
|
|
9155
|
+
return JSON.stringify(this.getState(), null, 2);
|
|
9107
9156
|
default:
|
|
9108
|
-
|
|
9157
|
+
return "Unknown command. Available: status, agents, costs, pause, resume, dashboard";
|
|
9109
9158
|
}
|
|
9110
9159
|
}
|
|
9111
9160
|
}
|
|
@@ -9115,6 +9164,11 @@ var src_default = define({
|
|
|
9115
9164
|
id: "nexus",
|
|
9116
9165
|
async setup(ctx) {
|
|
9117
9166
|
const orchestrator = new NexusOrchestrator;
|
|
9167
|
+
orchestrator.initialize(ctx, () => {
|
|
9168
|
+
const state = orchestrator.getState();
|
|
9169
|
+
ctx.storage.set("orchestrator-state", JSON.parse(JSON.stringify(state))).catch(() => {});
|
|
9170
|
+
});
|
|
9171
|
+
await ctx.storage.set("orchestrator-state", JSON.parse(JSON.stringify(orchestrator.getState())));
|
|
9118
9172
|
await ctx.tool.transform((editor) => {
|
|
9119
9173
|
editor.namespace({
|
|
9120
9174
|
name: "nexus",
|
|
@@ -9132,7 +9186,9 @@ var src_default = define({
|
|
|
9132
9186
|
},
|
|
9133
9187
|
execute: async (input) => {
|
|
9134
9188
|
const { detailed } = input;
|
|
9135
|
-
|
|
9189
|
+
const status = orchestrator.getStatus(detailed);
|
|
9190
|
+
await ctx.storage.set("orchestrator-state", JSON.parse(JSON.stringify(orchestrator.getState())));
|
|
9191
|
+
return { content: status };
|
|
9136
9192
|
}
|
|
9137
9193
|
});
|
|
9138
9194
|
editor.add({
|
|
@@ -9162,10 +9218,53 @@ var src_default = define({
|
|
|
9162
9218
|
return { content: orchestrator.getCostReport() };
|
|
9163
9219
|
}
|
|
9164
9220
|
});
|
|
9221
|
+
editor.add({
|
|
9222
|
+
name: "dashboard",
|
|
9223
|
+
description: "Get full orchestrator state for dashboard display",
|
|
9224
|
+
input: {
|
|
9225
|
+
type: "object",
|
|
9226
|
+
properties: {},
|
|
9227
|
+
additionalProperties: false
|
|
9228
|
+
},
|
|
9229
|
+
execute: async () => {
|
|
9230
|
+
const state = orchestrator.getState();
|
|
9231
|
+
await ctx.storage.set("orchestrator-state", JSON.parse(JSON.stringify(state)));
|
|
9232
|
+
return { content: JSON.stringify(state, null, 2) };
|
|
9233
|
+
}
|
|
9234
|
+
});
|
|
9235
|
+
editor.add({
|
|
9236
|
+
name: "spawn",
|
|
9237
|
+
description: "Spawn a sub-agent for a task",
|
|
9238
|
+
input: {
|
|
9239
|
+
type: "object",
|
|
9240
|
+
properties: {
|
|
9241
|
+
role: { type: "string", description: "Agent role (architect, coder, reviewer, tester, explorer, documenter)" },
|
|
9242
|
+
task: { type: "string", description: "Task description" },
|
|
9243
|
+
model: { type: "string", description: "Model override (optional)" }
|
|
9244
|
+
},
|
|
9245
|
+
required: ["role", "task"],
|
|
9246
|
+
additionalProperties: false
|
|
9247
|
+
},
|
|
9248
|
+
execute: async (input) => {
|
|
9249
|
+
const { role, task, model } = input;
|
|
9250
|
+
try {
|
|
9251
|
+
const agent = await orchestrator.spawnAgent({ role, model });
|
|
9252
|
+
await orchestrator.ctx.session.prompt({
|
|
9253
|
+
sessionID: agent.sessionID,
|
|
9254
|
+
text: task
|
|
9255
|
+
});
|
|
9256
|
+
await ctx.storage.set("orchestrator-state", JSON.parse(JSON.stringify(orchestrator.getState())));
|
|
9257
|
+
return { content: `Spawned ${role} agent (${agent.id}) on session ${agent.sessionID}. Task sent.` };
|
|
9258
|
+
} catch (error) {
|
|
9259
|
+
return { content: `Failed to spawn agent: ${error.message}` };
|
|
9260
|
+
}
|
|
9261
|
+
}
|
|
9262
|
+
});
|
|
9165
9263
|
});
|
|
9166
9264
|
await ctx.session.hook("prompt", (event) => {
|
|
9167
|
-
if (event.prompt.text.
|
|
9168
|
-
orchestrator.handleCommand(event.prompt.text);
|
|
9265
|
+
if (event.prompt.text.startsWith("/nexus")) {
|
|
9266
|
+
const result = orchestrator.handleCommand(event.prompt.text);
|
|
9267
|
+
event.metadata = { ...event.metadata, nexusResult: result };
|
|
9169
9268
|
}
|
|
9170
9269
|
});
|
|
9171
9270
|
return () => {
|
package/dist/tui.js
CHANGED
|
@@ -62,9 +62,6 @@ function createContext(defaultValue) {
|
|
|
62
62
|
defaultValue
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
-
function useContext(context) {
|
|
66
|
-
return Owner && Owner.context && Owner.context[context.id] !== undefined ? Owner.context[context.id] : context.defaultValue;
|
|
67
|
-
}
|
|
68
65
|
function children(fn) {
|
|
69
66
|
const memo = createMemo(() => resolveChildren(fn()));
|
|
70
67
|
memo.toArray = () => {
|
|
@@ -109,12 +106,6 @@ var SuspenseContext = createContext();
|
|
|
109
106
|
|
|
110
107
|
// node_modules/@opencode/plugin/dist/tui/solid.js
|
|
111
108
|
var PluginContext = createContext();
|
|
112
|
-
function usePlugin() {
|
|
113
|
-
const context = useContext(PluginContext);
|
|
114
|
-
if (!context)
|
|
115
|
-
throw new Error("PluginContextProvider is missing");
|
|
116
|
-
return context;
|
|
117
|
-
}
|
|
118
109
|
// src/config.ts
|
|
119
110
|
var DEFAULT_CONFIG = {
|
|
120
111
|
models: {
|
|
@@ -34140,113 +34131,242 @@ function jsx(type, props = {}) {
|
|
|
34140
34131
|
function jsxDEV(type, props = {}) {
|
|
34141
34132
|
return jsx(type, props);
|
|
34142
34133
|
}
|
|
34134
|
+
function Fragment(props) {
|
|
34135
|
+
return props.children ?? null;
|
|
34136
|
+
}
|
|
34143
34137
|
// src/tui.tsx
|
|
34144
|
-
|
|
34145
|
-
|
|
34146
|
-
|
|
34147
|
-
|
|
34148
|
-
|
|
34149
|
-
|
|
34150
|
-
|
|
34151
|
-
|
|
34152
|
-
|
|
34138
|
+
var tui_default = define({
|
|
34139
|
+
id: "nexus.cli",
|
|
34140
|
+
setup(context) {
|
|
34141
|
+
const configManager = new NexusConfigManager;
|
|
34142
|
+
const handleModelSelect = async (role) => {
|
|
34143
|
+
if (!configManager.getRoles().includes(role)) {
|
|
34144
|
+
context.ui.toast.show({
|
|
34145
|
+
title: "Nexus",
|
|
34146
|
+
message: `Unknown role: ${role}. Valid: ${configManager.getRoles().join(", ")}`,
|
|
34147
|
+
variant: "error"
|
|
34148
|
+
});
|
|
34149
|
+
return;
|
|
34150
|
+
}
|
|
34151
|
+
const location = context.location ?? context.data.location.default();
|
|
34152
|
+
await context.data.location.model.sync(location);
|
|
34153
|
+
const availableModels = context.data.location.model.list(location) ?? [];
|
|
34154
|
+
const options = availableModels.map((m) => ({
|
|
34155
|
+
title: m.name || m.id,
|
|
34156
|
+
value: `${m.providerID}/${m.id}`,
|
|
34157
|
+
description: m.providerID
|
|
34158
|
+
}));
|
|
34159
|
+
options.push({
|
|
34160
|
+
title: "Use default",
|
|
34161
|
+
value: "",
|
|
34162
|
+
description: "Reset to default model"
|
|
34153
34163
|
});
|
|
34154
|
-
|
|
34155
|
-
|
|
34156
|
-
|
|
34157
|
-
|
|
34158
|
-
|
|
34159
|
-
const options = availableModels.map((m) => ({
|
|
34160
|
-
title: m.name || m.id,
|
|
34161
|
-
value: `${m.providerID}/${m.id}`,
|
|
34162
|
-
description: m.providerID
|
|
34163
|
-
}));
|
|
34164
|
-
options.push({
|
|
34165
|
-
title: "Use default",
|
|
34166
|
-
value: "",
|
|
34167
|
-
description: "Reset to default model"
|
|
34168
|
-
});
|
|
34169
|
-
const current = configManager.getModelForRole(role);
|
|
34170
|
-
const selected = await context.ui.dialog.select({
|
|
34171
|
-
title: `${configManager.getRoleDisplayName(role)} Model`,
|
|
34172
|
-
current: current || "",
|
|
34173
|
-
options
|
|
34174
|
-
});
|
|
34175
|
-
if (selected !== null && selected !== undefined) {
|
|
34176
|
-
configManager.setModel(role, selected);
|
|
34177
|
-
context.ui.toast.show({
|
|
34178
|
-
title: "Nexus",
|
|
34179
|
-
message: `${role} → ${selected || "default"}`,
|
|
34180
|
-
variant: "success"
|
|
34164
|
+
const current = configManager.getModelForRole(role);
|
|
34165
|
+
const selected = await context.ui.dialog.select({
|
|
34166
|
+
title: `${configManager.getRoleDisplayName(role)} Model`,
|
|
34167
|
+
current: current || "",
|
|
34168
|
+
options
|
|
34181
34169
|
});
|
|
34182
|
-
|
|
34183
|
-
|
|
34184
|
-
const handleConfigDialog = async () => {
|
|
34185
|
-
const config = configManager.getConfig();
|
|
34186
|
-
const budgetStr = await context.ui.dialog.prompt({
|
|
34187
|
-
title: "Max Total Budget ($)",
|
|
34188
|
-
placeholder: String(config.budget.maxTotalCost)
|
|
34189
|
-
});
|
|
34190
|
-
if (budgetStr !== null && budgetStr !== undefined) {
|
|
34191
|
-
const budget = parseFloat(budgetStr);
|
|
34192
|
-
if (!isNaN(budget) && budget > 0) {
|
|
34193
|
-
configManager.updateStorageConfig({
|
|
34194
|
-
budget: { ...config.budget, maxTotalCost: budget }
|
|
34195
|
-
});
|
|
34170
|
+
if (selected !== null && selected !== undefined) {
|
|
34171
|
+
configManager.setModel(role, selected);
|
|
34196
34172
|
context.ui.toast.show({
|
|
34197
34173
|
title: "Nexus",
|
|
34198
|
-
message:
|
|
34174
|
+
message: `${role} → ${selected || "default"}`,
|
|
34199
34175
|
variant: "success"
|
|
34200
34176
|
});
|
|
34201
34177
|
}
|
|
34202
|
-
}
|
|
34203
|
-
|
|
34204
|
-
|
|
34205
|
-
|
|
34206
|
-
|
|
34207
|
-
|
|
34208
|
-
|
|
34209
|
-
|
|
34210
|
-
|
|
34211
|
-
|
|
34212
|
-
|
|
34213
|
-
|
|
34214
|
-
|
|
34215
|
-
|
|
34216
|
-
|
|
34217
|
-
|
|
34218
|
-
|
|
34219
|
-
|
|
34220
|
-
|
|
34221
|
-
|
|
34222
|
-
|
|
34223
|
-
|
|
34224
|
-
|
|
34225
|
-
|
|
34226
|
-
|
|
34227
|
-
|
|
34228
|
-
|
|
34229
|
-
|
|
34230
|
-
|
|
34231
|
-
|
|
34232
|
-
|
|
34233
|
-
|
|
34234
|
-
|
|
34178
|
+
};
|
|
34179
|
+
const handleConfigDialog = async () => {
|
|
34180
|
+
const config = configManager.getConfig();
|
|
34181
|
+
const budgetStr = await context.ui.dialog.prompt({
|
|
34182
|
+
title: "Max Total Budget ($)",
|
|
34183
|
+
placeholder: String(config.budget.maxTotalCost)
|
|
34184
|
+
});
|
|
34185
|
+
if (budgetStr !== null && budgetStr !== undefined) {
|
|
34186
|
+
const budget = parseFloat(budgetStr);
|
|
34187
|
+
if (!isNaN(budget) && budget > 0) {
|
|
34188
|
+
configManager.updateStorageConfig({
|
|
34189
|
+
budget: { ...config.budget, maxTotalCost: budget }
|
|
34190
|
+
});
|
|
34191
|
+
context.ui.toast.show({
|
|
34192
|
+
title: "Nexus",
|
|
34193
|
+
message: `Budget updated: $${budget}`,
|
|
34194
|
+
variant: "success"
|
|
34195
|
+
});
|
|
34196
|
+
}
|
|
34197
|
+
}
|
|
34198
|
+
};
|
|
34199
|
+
const handleFullConfig = async () => {
|
|
34200
|
+
for (const role of configManager.getRoles()) {
|
|
34201
|
+
await handleModelSelect(role);
|
|
34202
|
+
}
|
|
34203
|
+
await handleConfigDialog();
|
|
34204
|
+
context.ui.toast.show({
|
|
34205
|
+
title: "Nexus",
|
|
34206
|
+
message: "Configuration complete!",
|
|
34207
|
+
variant: "success"
|
|
34208
|
+
});
|
|
34209
|
+
};
|
|
34210
|
+
const handleDashboard = async () => {
|
|
34211
|
+
const config = configManager.getConfig();
|
|
34212
|
+
const lines = [
|
|
34213
|
+
"⚡ Nexus Dashboard",
|
|
34214
|
+
"═══════════════════════════════════",
|
|
34215
|
+
"",
|
|
34216
|
+
"\uD83E\uDD16 Agent Models:"
|
|
34217
|
+
];
|
|
34218
|
+
for (const role of configManager.getRoles()) {
|
|
34219
|
+
const model = config.models[role] || "(not set)";
|
|
34220
|
+
const displayName = configManager.getRoleDisplayName(role);
|
|
34221
|
+
lines.push(` ${displayName}: ${model}`);
|
|
34222
|
+
}
|
|
34223
|
+
lines.push("");
|
|
34224
|
+
lines.push("\uD83D\uDCB0 Budget:");
|
|
34225
|
+
lines.push(` Max Total: $${config.budget.maxTotalCost}`);
|
|
34226
|
+
lines.push(` Max Per Task: $${config.budget.maxCostPerTask}`);
|
|
34227
|
+
lines.push(` Alert Threshold: ${config.budget.alertThreshold * 100}%`);
|
|
34228
|
+
lines.push("");
|
|
34229
|
+
lines.push("\uD83D\uDEE1️ Self-Healing:");
|
|
34230
|
+
lines.push(` Enabled: ${config.selfHealing.enabled ? "✅" : "❌"}`);
|
|
34231
|
+
lines.push(` Max Retries: ${config.selfHealing.maxRetries}`);
|
|
34232
|
+
lines.push("");
|
|
34233
|
+
lines.push("\uD83D\uDCA1 Commands:");
|
|
34234
|
+
lines.push(" /nexus status - Show config summary");
|
|
34235
|
+
lines.push(" /nexus config - Configure models & budget");
|
|
34236
|
+
lines.push(" /nexus model - Select model for role");
|
|
34237
|
+
lines.push(" /nexus reset - Reset to defaults");
|
|
34238
|
+
lines.push("");
|
|
34239
|
+
lines.push("\uD83D\uDD27 Tools (use in agent prompt):");
|
|
34240
|
+
lines.push(" nexus.status - Orchestrator status");
|
|
34241
|
+
lines.push(" nexus.agents - List spawned agents");
|
|
34242
|
+
lines.push(" nexus.costs - Cost report");
|
|
34243
|
+
lines.push(" nexus.spawn - Spawn a sub-agent");
|
|
34244
|
+
context.ui.toast.show({
|
|
34245
|
+
title: "Nexus Dashboard",
|
|
34246
|
+
message: lines.join(`
|
|
34247
|
+
`),
|
|
34248
|
+
variant: "info",
|
|
34249
|
+
duration: 15000
|
|
34250
|
+
});
|
|
34251
|
+
};
|
|
34252
|
+
context.ui.slot({
|
|
34253
|
+
append: "app",
|
|
34254
|
+
render: () => {
|
|
34255
|
+
context.keymap.layer(() => ({
|
|
34256
|
+
mode: "global",
|
|
34257
|
+
priority: 10,
|
|
34258
|
+
commands: [
|
|
34259
|
+
{
|
|
34260
|
+
id: "nexus",
|
|
34261
|
+
title: "Nexus Configuration",
|
|
34262
|
+
group: "Nexus",
|
|
34263
|
+
bind: "ctrl+n",
|
|
34264
|
+
palette: true,
|
|
34265
|
+
slash: { name: "nexus", aliases: [], arguments: true },
|
|
34266
|
+
enabled: () => true,
|
|
34267
|
+
suggested: true,
|
|
34268
|
+
run: async (input) => {
|
|
34269
|
+
if (input) {
|
|
34270
|
+
const parts = input.split(" ");
|
|
34271
|
+
const cmd = parts[0];
|
|
34272
|
+
switch (cmd) {
|
|
34273
|
+
case "config":
|
|
34274
|
+
case "c":
|
|
34275
|
+
await handleFullConfig();
|
|
34276
|
+
break;
|
|
34277
|
+
case "status":
|
|
34278
|
+
case "s":
|
|
34279
|
+
context.ui.toast.show({
|
|
34280
|
+
title: "Nexus Status",
|
|
34281
|
+
message: configManager.getSummary(),
|
|
34282
|
+
variant: "info",
|
|
34283
|
+
duration: 8000
|
|
34284
|
+
});
|
|
34285
|
+
break;
|
|
34286
|
+
case "dashboard":
|
|
34287
|
+
case "d":
|
|
34288
|
+
await handleDashboard();
|
|
34289
|
+
break;
|
|
34290
|
+
case "model":
|
|
34291
|
+
case "m":
|
|
34292
|
+
if (parts[1]) {
|
|
34293
|
+
await handleModelSelect(parts[1]);
|
|
34294
|
+
} else {
|
|
34295
|
+
const role = await context.ui.dialog.select({
|
|
34296
|
+
title: "Select Agent Role",
|
|
34297
|
+
options: configManager.getRoles().map((r) => ({
|
|
34298
|
+
title: configManager.getRoleDisplayName(r),
|
|
34299
|
+
value: r,
|
|
34300
|
+
description: `Current: ${configManager.getModelForRole(r)}`
|
|
34301
|
+
}))
|
|
34302
|
+
});
|
|
34303
|
+
if (role) {
|
|
34304
|
+
await handleModelSelect(role);
|
|
34305
|
+
}
|
|
34306
|
+
}
|
|
34307
|
+
break;
|
|
34308
|
+
case "reset":
|
|
34309
|
+
const confirmed = await context.ui.dialog.confirm({
|
|
34310
|
+
title: "Reset Configuration",
|
|
34311
|
+
message: "Reset all Nexus settings to defaults?",
|
|
34312
|
+
label: { confirm: "Reset", cancel: "Cancel" }
|
|
34313
|
+
});
|
|
34314
|
+
if (confirmed) {
|
|
34315
|
+
configManager.resetToDefaults();
|
|
34316
|
+
context.ui.toast.show({
|
|
34317
|
+
title: "Nexus",
|
|
34318
|
+
message: "Configuration reset to defaults",
|
|
34319
|
+
variant: "success"
|
|
34320
|
+
});
|
|
34321
|
+
}
|
|
34322
|
+
break;
|
|
34323
|
+
default:
|
|
34324
|
+
context.ui.toast.show({
|
|
34325
|
+
title: "Nexus",
|
|
34326
|
+
message: "Commands: config, status, dashboard, model <role>, reset",
|
|
34327
|
+
variant: "info"
|
|
34328
|
+
});
|
|
34329
|
+
}
|
|
34330
|
+
} else {
|
|
34331
|
+
await handleFullConfig();
|
|
34332
|
+
}
|
|
34333
|
+
}
|
|
34334
|
+
},
|
|
34335
|
+
{
|
|
34336
|
+
id: "nexus.config",
|
|
34337
|
+
title: "Nexus Configuration",
|
|
34338
|
+
group: "Nexus",
|
|
34339
|
+
palette: true,
|
|
34340
|
+
slash: { name: "nexus-config", aliases: ["nc"], arguments: true },
|
|
34341
|
+
enabled: () => true,
|
|
34342
|
+
suggested: true,
|
|
34343
|
+
run: async () => {
|
|
34235
34344
|
await handleFullConfig();
|
|
34236
|
-
|
|
34237
|
-
|
|
34238
|
-
|
|
34239
|
-
|
|
34240
|
-
|
|
34241
|
-
|
|
34242
|
-
|
|
34243
|
-
|
|
34244
|
-
|
|
34245
|
-
|
|
34246
|
-
|
|
34247
|
-
|
|
34248
|
-
|
|
34249
|
-
|
|
34345
|
+
}
|
|
34346
|
+
},
|
|
34347
|
+
{
|
|
34348
|
+
id: "nexus.dashboard",
|
|
34349
|
+
title: "Nexus Dashboard",
|
|
34350
|
+
group: "Nexus",
|
|
34351
|
+
palette: true,
|
|
34352
|
+
slash: { name: "nexus-dashboard", aliases: ["nd"], arguments: true },
|
|
34353
|
+
enabled: () => true,
|
|
34354
|
+
suggested: true,
|
|
34355
|
+
run: async () => {
|
|
34356
|
+
await handleDashboard();
|
|
34357
|
+
}
|
|
34358
|
+
},
|
|
34359
|
+
{
|
|
34360
|
+
id: "nexus.model",
|
|
34361
|
+
title: "Select Agent Model",
|
|
34362
|
+
group: "Nexus",
|
|
34363
|
+
palette: true,
|
|
34364
|
+
slash: { name: "nexus-model", aliases: ["nm"], arguments: true },
|
|
34365
|
+
enabled: () => true,
|
|
34366
|
+
suggested: true,
|
|
34367
|
+
run: async (input) => {
|
|
34368
|
+
if (input) {
|
|
34369
|
+
await handleModelSelect(input);
|
|
34250
34370
|
} else {
|
|
34251
34371
|
const role = await context.ui.dialog.select({
|
|
34252
34372
|
title: "Select Agent Role",
|
|
@@ -34260,8 +34380,33 @@ function NexusKeymapSlot() {
|
|
|
34260
34380
|
await handleModelSelect(role);
|
|
34261
34381
|
}
|
|
34262
34382
|
}
|
|
34263
|
-
|
|
34264
|
-
|
|
34383
|
+
}
|
|
34384
|
+
},
|
|
34385
|
+
{
|
|
34386
|
+
id: "nexus.status",
|
|
34387
|
+
title: "Nexus Status",
|
|
34388
|
+
group: "Nexus",
|
|
34389
|
+
palette: true,
|
|
34390
|
+
slash: { name: "nexus-status", aliases: ["ns"], arguments: true },
|
|
34391
|
+
enabled: () => true,
|
|
34392
|
+
suggested: true,
|
|
34393
|
+
run: async () => {
|
|
34394
|
+
context.ui.toast.show({
|
|
34395
|
+
title: "Nexus Status",
|
|
34396
|
+
message: configManager.getSummary(),
|
|
34397
|
+
variant: "info",
|
|
34398
|
+
duration: 8000
|
|
34399
|
+
});
|
|
34400
|
+
}
|
|
34401
|
+
},
|
|
34402
|
+
{
|
|
34403
|
+
id: "nexus.reset",
|
|
34404
|
+
title: "Reset Nexus Config",
|
|
34405
|
+
group: "Nexus",
|
|
34406
|
+
palette: true,
|
|
34407
|
+
slash: { name: "nexus-reset", aliases: [], arguments: true },
|
|
34408
|
+
enabled: () => true,
|
|
34409
|
+
run: async () => {
|
|
34265
34410
|
const confirmed = await context.ui.dialog.confirm({
|
|
34266
34411
|
title: "Reset Configuration",
|
|
34267
34412
|
message: "Reset all Nexus settings to defaults?",
|
|
@@ -34275,108 +34420,13 @@ function NexusKeymapSlot() {
|
|
|
34275
34420
|
variant: "success"
|
|
34276
34421
|
});
|
|
34277
34422
|
}
|
|
34278
|
-
|
|
34279
|
-
default:
|
|
34280
|
-
context.ui.toast.show({
|
|
34281
|
-
title: "Nexus",
|
|
34282
|
-
message: "Commands: config, status, model <role>, reset",
|
|
34283
|
-
variant: "info"
|
|
34284
|
-
});
|
|
34285
|
-
}
|
|
34286
|
-
} else {
|
|
34287
|
-
await handleFullConfig();
|
|
34288
|
-
}
|
|
34289
|
-
}
|
|
34290
|
-
},
|
|
34291
|
-
{
|
|
34292
|
-
id: "nexus.config",
|
|
34293
|
-
title: "Nexus Configuration",
|
|
34294
|
-
group: "Nexus",
|
|
34295
|
-
palette: true,
|
|
34296
|
-
slash: { name: "nexus-config", aliases: ["nc"], arguments: true },
|
|
34297
|
-
enabled: () => true,
|
|
34298
|
-
suggested: true,
|
|
34299
|
-
run: async () => {
|
|
34300
|
-
await handleFullConfig();
|
|
34301
|
-
}
|
|
34302
|
-
},
|
|
34303
|
-
{
|
|
34304
|
-
id: "nexus.model",
|
|
34305
|
-
title: "Select Agent Model",
|
|
34306
|
-
group: "Nexus",
|
|
34307
|
-
palette: true,
|
|
34308
|
-
slash: { name: "nexus-model", aliases: ["nm"], arguments: true },
|
|
34309
|
-
enabled: () => true,
|
|
34310
|
-
suggested: true,
|
|
34311
|
-
run: async (input) => {
|
|
34312
|
-
if (input) {
|
|
34313
|
-
await handleModelSelect(input);
|
|
34314
|
-
} else {
|
|
34315
|
-
const role = await context.ui.dialog.select({
|
|
34316
|
-
title: "Select Agent Role",
|
|
34317
|
-
options: configManager.getRoles().map((r) => ({
|
|
34318
|
-
title: configManager.getRoleDisplayName(r),
|
|
34319
|
-
value: r,
|
|
34320
|
-
description: `Current: ${configManager.getModelForRole(r)}`
|
|
34321
|
-
}))
|
|
34322
|
-
});
|
|
34323
|
-
if (role) {
|
|
34324
|
-
await handleModelSelect(role);
|
|
34423
|
+
}
|
|
34325
34424
|
}
|
|
34326
|
-
|
|
34327
|
-
|
|
34328
|
-
|
|
34329
|
-
|
|
34330
|
-
id: "nexus.status",
|
|
34331
|
-
title: "Nexus Status",
|
|
34332
|
-
group: "Nexus",
|
|
34333
|
-
palette: true,
|
|
34334
|
-
slash: { name: "nexus-status", aliases: ["ns"], arguments: true },
|
|
34335
|
-
enabled: () => true,
|
|
34336
|
-
suggested: true,
|
|
34337
|
-
run: async () => {
|
|
34338
|
-
context.ui.toast.show({
|
|
34339
|
-
title: "Nexus Status",
|
|
34340
|
-
message: configManager.getSummary(),
|
|
34341
|
-
variant: "info",
|
|
34342
|
-
duration: 8000
|
|
34343
|
-
});
|
|
34344
|
-
}
|
|
34345
|
-
},
|
|
34346
|
-
{
|
|
34347
|
-
id: "nexus.reset",
|
|
34348
|
-
title: "Reset Nexus Config",
|
|
34349
|
-
group: "Nexus",
|
|
34350
|
-
palette: true,
|
|
34351
|
-
slash: { name: "nexus-reset", aliases: [], arguments: true },
|
|
34352
|
-
enabled: () => true,
|
|
34353
|
-
run: async () => {
|
|
34354
|
-
const confirmed = await context.ui.dialog.confirm({
|
|
34355
|
-
title: "Reset Configuration",
|
|
34356
|
-
message: "Reset all Nexus settings to defaults?",
|
|
34357
|
-
label: { confirm: "Reset", cancel: "Cancel" }
|
|
34358
|
-
});
|
|
34359
|
-
if (confirmed) {
|
|
34360
|
-
configManager.resetToDefaults();
|
|
34361
|
-
context.ui.toast.show({
|
|
34362
|
-
title: "Nexus",
|
|
34363
|
-
message: "Configuration reset to defaults",
|
|
34364
|
-
variant: "success"
|
|
34365
|
-
});
|
|
34366
|
-
}
|
|
34367
|
-
}
|
|
34425
|
+
],
|
|
34426
|
+
bindings: ["nexus"]
|
|
34427
|
+
}));
|
|
34428
|
+
return /* @__PURE__ */ jsxDEV(Fragment, {}, undefined, false, undefined, this);
|
|
34368
34429
|
}
|
|
34369
|
-
],
|
|
34370
|
-
bindings: ["nexus"]
|
|
34371
|
-
}));
|
|
34372
|
-
return null;
|
|
34373
|
-
}
|
|
34374
|
-
var tui_default = define({
|
|
34375
|
-
id: "nexus.cli",
|
|
34376
|
-
setup(context) {
|
|
34377
|
-
context.ui.slot({
|
|
34378
|
-
append: "app",
|
|
34379
|
-
render: () => /* @__PURE__ */ jsxDEV(NexusKeymapSlot, {}, undefined, false, undefined, this)
|
|
34380
34430
|
});
|
|
34381
34431
|
context.ui.toast.show({
|
|
34382
34432
|
title: "⚡ Nexus Loaded",
|