Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions .activate

This file was deleted.

1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
module.exports = { extends: "eslint:recommended", env: { node: true, es6: true }, parserOptions: { ecmaVersion: 2022, sourceType: "module" } };
6 changes: 3 additions & 3 deletions .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
[submodule "integrations/mcp-constraint-monitor"]
path = integrations/mcp-constraint-monitor
url = git@github.com:fwornle/mcp-constraint-monitor.git
url = https://github.com/fwornle/mcp-constraint-monitor.git
[submodule "integrations/memory-visualizer"]
path = integrations/memory-visualizer
url = git@github.com:fwornle/memory-visualizer.git
url = https://github.com/fwornle/memory-visualizer.git
[submodule "integrations/mcp-server-semantic-analysis"]
path = integrations/mcp-server-semantic-analysis
url = git@github.com:fwornle/mcp-server-semantic-analysis.git
url = https://github.com/fwornle/mcp-server-semantic-analysis.git
[submodule "integrations/serena"]
path = integrations/serena
url = https://github.com/oraios/serena.git
4 changes: 2 additions & 2 deletions .lsl/config.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@
"log_level": "info"
},
"deployment": {
"deployment_id": "lsl-20251115-105627",
"deployed_at": "2025-11-15T09:56:27Z",
"deployment_id": "lsl-20251201-123841",
"deployed_at": "2025-12-01T11:38:41Z",
"version": "2.0.0",
"components": [
"enhanced-redaction-system",
Expand Down
11 changes: 11 additions & 0 deletions bin/coding
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@ set -e
AGENT=""
FORCE_AGENT=""
ARGS=()
SERVICE_ARGS=()
VERBOSE=false
CONFIG_FILE=""
PROJECT_DIR=""
Expand DownExpand Up@@ -105,6 +106,14 @@ while [[ $# -gt 0 ]]; do
--lsl-validate)
exec node "$SCRIPT_DIR/../tests/integration/full-system-validation.test.js"
;;
board|consensus)
shift
exec node "$SCRIPT_DIR/../scripts/run-board-meeting.js" "$@"
;;
--no-vkb|--no-constraints|--no-transcript|--no-logging|--no-health)
SERVICE_ARGS+=("$1")
shift
;;
--help|-h)
show_help
exit 0
Expand DownExpand Up@@ -177,6 +186,8 @@ export CODING_AGENT="$AGENT"
export CODING_TOOLS_PATH="$SCRIPT_DIR/.."
export CODING_REPO="$SCRIPT_DIR/.."
export CODING_PROJECT_DIR="$PROJECT_DIR"
# Pass service args as a space-separated string
export SERVICE_ARGS_STR="${SERVICE_ARGS[*]}"

# Launch appropriate agent
case "$AGENT" in
Expand Down
4 changes: 2 additions & 2 deletions enhanced-lsl-deployment-report.md
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
# Enhanced LSL System Deployment Report

**Deployment ID:** lsl-20251115-105627
**Deployment Date:** 2025-11-15 09:56:28 UTC
**Deployment ID:** lsl-20251201-123841
**Deployment Date:** 2025-12-01 11:38:41 UTC
**Deployment Mode:** Development

## Executive Summary
Expand Down
3 changes: 3 additions & 0 deletions integrations/browser-access/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

146 changes: 146 additions & 0 deletions lib/consensus/board-meeting.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
import LLMClient from './llm-client.js';
import DIRECTORS from './directors.js';

class BoardMeeting {
constructor() {
this.llm = new LLMClient();
this.directors = Object.values(DIRECTORS);
}

async conductMeeting(topic) {
console.log(`\n📢 Board Meeting Called: "${topic}"\n`);

// Phase 1: Proposal Generation
console.log("Phase 1: Generating Proposals...");
const proposals = await this.generateProposals(topic);

// Phase 2: Anonymization
console.log("Phase 2: Anonymizing Proposals...");
const anonymizedProposals = this.anonymizeProposals(proposals);

// Phase 3: Voting
console.log("Phase 3: Voting...");
const votes = await this.collectVotes(topic, anonymizedProposals);

// Phase 4: Tally
const result = this.tallyVotes(votes, anonymizedProposals);

return result;
}

async generateProposals(topic) {
const proposalPromises = this.directors.map(async (director) => {
try {
console.log(` - ${director.name} is thinking...`);
const response = await this.llm.complete(
director.systemPrompt,
`Please provide your perspective and a concrete proposal on the following topic:\n"${topic}"\nKeep your response concise (under 200 words).`
);
return { director: director.name, content: response };
} catch (error) {
console.error(`Error from ${director.name}:`, error.message);
return { director: director.name, content: "Abstained due to technical difficulties." };
}
});

return Promise.all(proposalPromises);
}

anonymizeProposals(proposals) {
return proposals.map((p, index) => ({
id: String.fromCharCode(65 + index), // A, B, C, D, E
originalDirector: p.director,
content: p.content
}));
}

async collectVotes(topic, anonymizedProposals) {
// Format proposals for reading
const proposalsText = anonymizedProposals
.map(p => `Proposal ${p.id}:\n${p.content}\n---`)
.join('\n');

const votePromises = this.directors.map(async (director) => {
try {
// Find their own proposal ID to exclude (optional, but good for fairness)
const ownProposal = anonymizedProposals.find(p => p.originalDirector === director.name);
const ownId = ownProposal ? ownProposal.id : null;

const prompt = `
Topic: "${topic}"

Here are 5 anonymous proposals from the board:

${proposalsText}

Your Task:
1. Evaluate these proposals based on your core values (${director.role}).
2. Vote for the single best proposal.
3. You CANNOT vote for Proposal ${ownId} (which is your own).
4. Provide a brief 1-sentence reason.

Format your response exactly like this:
VOTE: [Proposal ID]
REASON: [Your reason]
`;
console.log(` - ${director.name} is voting...`);
const response = await this.llm.complete(director.systemPrompt, prompt);
return this.parseVote(response, director.name);
} catch (error) {
console.error(`Error collecting vote from ${director.name}:`, error.message);
return null;
}
});

return Promise.all(votePromises);
}

parseVote(response, voterName) {
const voteMatch = response.match(/VOTE:\s*([A-E])/i);
const reasonMatch = response.match(/REASON:\s*(.*)/i);

return {
voter: voterName,
choice: voteMatch ? voteMatch[1].toUpperCase() : null,
reason: reasonMatch ? reasonMatch[1] : "No reason provided."
};
}

tallyVotes(votes, anonymizedProposals) {
const validVotes = votes.filter(v => v && v.choice);
const scores = {};

// Initialize scores
anonymizedProposals.forEach(p => scores[p.id] = 0);

// Tally
validVotes.forEach(v => {
if (scores[v.choice] !== undefined) {
scores[v.choice]++;
}
});

// Find winner
let maxScore = -1;
let winnerId = null;

Object.entries(scores).forEach(([id, score]) => {
if (score > maxScore) {
maxScore = score;
winnerId = id;
}
});

const winner = anonymizedProposals.find(p => p.id === winnerId);

return {
topic: "",
winner: winner,
scores: scores,
votes: validVotes,
proposals: anonymizedProposals
};
}
}

export default BoardMeeting;
49 changes: 49 additions & 0 deletions lib/consensus/directors.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
export const DIRECTORS = {
PRAGMATIST: {
name: "The Pragmatist",
role: "Senior Engineer focused on delivery",
systemPrompt: `You are The Pragmatist.
Your core values are: Simplicity, Speed, MVP, YAGNI (You Ain't Gonna Need It).
You dislike over-engineering, complex abstractions, and premature optimization.
When analyzing a problem, propose the simplest, most direct solution that works.
Focus on "boring" technology and proven patterns.`
},
ARCHITECT: {
name: "The Architect",
role: "Principal Software Architect",
systemPrompt: `You are The Architect.
Your core values are: Scalability, Maintainability, Design Patterns, SOLID principles.
You think in terms of systems, interfaces, and long-term evolution.
When analyzing a problem, propose a solution that is robust, decoupled, and extensible.
You are willing to accept initial complexity for future flexibility.`
},
SECURITY: {
name: "The Security Officer",
role: "Security Engineer",
systemPrompt: `You are The Security Officer.
Your core values are: Zero Trust, Data Privacy, Input Validation, Secure Defaults.
You view every feature as a potential attack vector.
When analyzing a problem, focus on how it could be exploited and how to prevent it.
Prioritize safety over convenience or speed.`
},
PERFORMANCE: {
name: "The Performance Zealot",
role: "Performance Engineer",
systemPrompt: `You are The Performance Zealot.
Your core values are: Latency, Throughput, Memory Usage, O(n).
You obsess over CPU cycles and database queries.
When analyzing a problem, propose the solution that is most efficient.
You are willing to sacrifice readability for raw speed if necessary.`
},
USER_ADVOCATE: {
name: "The User Advocate",
role: "Product Engineer / DX Specialist",
systemPrompt: `You are The User Advocate.
Your core values are: User Experience (UX), Developer Experience (DX), Clarity, Documentation.
You care about how the code feels to use and read.
When analyzing a problem, propose the solution that is most intuitive and well-documented.
You believe code is for humans first, machines second.`
}
};

export default DIRECTORS;
78 changes: 78 additions & 0 deletions lib/consensus/llm-client.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
import { spawn } from 'child_process';

/**
* Lightweight wrapper to call an LLM.
* Since specific SDKs might not be installed, we'll try to use fetch if API keys are present.
* If not, we'll warn the user.
*/
export class LLMClient {
constructor() {
this.anthropicKey = process.env.ANTHROPIC_API_KEY;
this.openaiKey = process.env.OPENAI_API_KEY;
this.provider = this.anthropicKey ? 'anthropic' : (this.openaiKey ? 'openai' : null);
}

async complete(systemPrompt, userPrompt) {
if (!this.provider) {
throw new Error('No API keys found. Please set ANTHROPIC_API_KEY or OPENAI_API_KEY.');
}

if (this.provider === 'anthropic') {
return this.callAnthropic(systemPrompt, userPrompt);
} else {
return this.callOpenAI(systemPrompt, userPrompt);
}
}

async callAnthropic(systemPrompt, userPrompt) {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'x-api-key': this.anthropicKey,
'anthropic-version': '2023-06-01',
'content-type': 'application/json'
},
body: JSON.stringify({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 4000,
system: systemPrompt,
messages: [{ role: 'user', content: userPrompt }]
})
});

if (!response.ok) {
const errorText = await response.text();
throw new Error(`Anthropic API error: ${response.status} ${response.statusText} - ${errorText}`);
}

const data = await response.json();
return data.content[0].text;
}

async callOpenAI(systemPrompt, userPrompt) {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.openaiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-4o',
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
]
})
});

if (!response.ok) {
const errorText = await response.text();
throw new Error(`OpenAI API error: ${response.status} ${response.statusText} - ${errorText}`);
}

const data = await response.json();
return data.choices[0].message.content;
}
}

export default LLMClient;
2 changes: 0 additions & 2 deletions scripts/cleanup-aliases.sh
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
#!/bin/bash
# Cleanup aliases from current shell session
unalias ukb 2>/dev/null || true
unalias vkb 2>/dev/null || true
unalias claude-mcp 2>/dev/null || true
unset -f ukb 2>/dev/null || true
unset -f vkb 2>/dev/null || true
unset -f claude-mcp 2>/dev/null || true
Loading