From 184f822c5f2d6ec0e7293c98a14c861b48ef748b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 29 Nov 2025 11:16:20 +0000 Subject: [PATCH 1/5] feat: add CLI options to configure service startup - Added support for `--no-vkb`, `--no-constraints`, `--no-transcript`, `--no-logging`, and `--no-health` flags in `bin/coding` - Updated `scripts/launch-claude.sh` and `scripts/launch-copilot.sh` to forward service arguments - Modified `scripts/start-services-robust.js` to conditionally start services based on CLI flags - Default behavior remains unchanged (all services start by default) --- bin/coding | 7 + scripts/launch-claude.sh | 6 +- scripts/launch-copilot.sh | 6 +- scripts/start-services-robust.js | 234 ++++++++++++++++++------------- start-services.sh | 2 +- 5 files changed, 155 insertions(+), 100 deletions(-) diff --git a/bin/coding b/bin/coding index c408af3b2..79bafc302 100755 --- a/bin/coding +++ b/bin/coding @@ -9,6 +9,7 @@ set -e AGENT="" FORCE_AGENT="" ARGS=() +SERVICE_ARGS=() VERBOSE=false CONFIG_FILE="" PROJECT_DIR="" @@ -105,6 +106,10 @@ while [[ $# -gt 0 ]]; do --lsl-validate) exec node "$SCRIPT_DIR/../tests/integration/full-system-validation.test.js" ;; + --no-vkb|--no-constraints|--no-transcript|--no-logging|--no-health) + SERVICE_ARGS+=("$1") + shift + ;; --help|-h) show_help exit 0 @@ -177,6 +182,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 diff --git a/scripts/launch-claude.sh b/scripts/launch-claude.sh index 6bb5039ba..806f5b60a 100755 --- a/scripts/launch-claude.sh +++ b/scripts/launch-claude.sh @@ -58,6 +58,9 @@ verify_monitoring_systems() { } +# Reconstruct SERVICE_ARGS array from env var +SERVICE_ARGS=($SERVICE_ARGS_STR) + # Use target project directory if specified, otherwise use coding repo if [ -n "$CODING_PROJECT_DIR" ]; then TARGET_PROJECT_DIR="$CODING_PROJECT_DIR" @@ -136,7 +139,8 @@ if ! command -v node &> /dev/null; then fi # Start services using the simple startup script (from coding repo) -if ! "$CODING_REPO/start-services.sh"; then +# Forward any service-related arguments +if ! "$CODING_REPO/start-services.sh" "${SERVICE_ARGS[@]}"; then log "Error: Failed to start services" exit 1 fi diff --git a/scripts/launch-copilot.sh b/scripts/launch-copilot.sh index 32a470082..282b649f4 100755 --- a/scripts/launch-copilot.sh +++ b/scripts/launch-copilot.sh @@ -111,6 +111,9 @@ start_http_adapter() { fi } +# Reconstruct SERVICE_ARGS array from env var +SERVICE_ARGS=($SERVICE_ARGS_STR) + # Use target project directory if specified, otherwise use coding repo if [ -n "$CODING_PROJECT_DIR" ]; then TARGET_PROJECT_DIR="$CODING_PROJECT_DIR" @@ -148,7 +151,8 @@ if ! command -v node &> /dev/null; then fi # Start services using the simple startup script (from coding repo) -if ! "$CODING_REPO/start-services.sh"; then +# Forward any service-related arguments +if ! "$CODING_REPO/start-services.sh" "${SERVICE_ARGS[@]}"; then log "Error: Failed to start services" exit 1 fi diff --git a/scripts/start-services-robust.js b/scripts/start-services-robust.js index 37db526e1..3263f4a7e 100755 --- a/scripts/start-services-robust.js +++ b/scripts/start-services-robust.js @@ -40,6 +40,26 @@ const CODING_DIR = path.resolve(SCRIPT_DIR, '..'); const execAsync = promisify(exec); const psm = new ProcessStateManager(); +// Parse CLI arguments for service control +const args = process.argv.slice(2); +const SERVICE_FLAGS = { + skipVkb: args.includes('--no-vkb'), + skipConstraints: args.includes('--no-constraints'), + skipTranscript: args.includes('--no-transcript'), + skipLogging: args.includes('--no-logging'), + skipHealth: args.includes('--no-health') +}; + +if (Object.values(SERVICE_FLAGS).some(Boolean)) { + console.log('šŸ”§ Service Configuration:'); + if (SERVICE_FLAGS.skipVkb) console.log(' - VKB Server disabled (--no-vkb)'); + if (SERVICE_FLAGS.skipConstraints) console.log(' - Constraint Monitor disabled (--no-constraints)'); + if (SERVICE_FLAGS.skipTranscript) console.log(' - Transcript Monitor disabled (--no-transcript)'); + if (SERVICE_FLAGS.skipLogging) console.log(' - Live Logging disabled (--no-logging)'); + if (SERVICE_FLAGS.skipHealth) console.log(' - Health Monitoring disabled (--no-health)'); + console.log(''); +} + // Service configurations const SERVICE_CONFIGS = { transcriptMonitor: { @@ -504,46 +524,54 @@ async function startAllServices() { console.log('šŸ“‹ Starting REQUIRED services (Live Logging System)...'); console.log(''); - try { - const transcriptResult = await startServiceWithRetry( - SERVICE_CONFIGS.transcriptMonitor.name, - SERVICE_CONFIGS.transcriptMonitor.startFn, - SERVICE_CONFIGS.transcriptMonitor.healthCheckFn, - { - required: SERVICE_CONFIGS.transcriptMonitor.required, - maxRetries: SERVICE_CONFIGS.transcriptMonitor.maxRetries, - timeout: SERVICE_CONFIGS.transcriptMonitor.timeout - } - ); - results.successful.push(transcriptResult); - await registerWithPSM(transcriptResult, 'scripts/enhanced-transcript-monitor.js'); - } catch (error) { - results.failed.push({ - serviceName: SERVICE_CONFIGS.transcriptMonitor.name, - error: error.message, - required: true - }); + if (!SERVICE_FLAGS.skipTranscript) { + try { + const transcriptResult = await startServiceWithRetry( + SERVICE_CONFIGS.transcriptMonitor.name, + SERVICE_CONFIGS.transcriptMonitor.startFn, + SERVICE_CONFIGS.transcriptMonitor.healthCheckFn, + { + required: SERVICE_CONFIGS.transcriptMonitor.required, + maxRetries: SERVICE_CONFIGS.transcriptMonitor.maxRetries, + timeout: SERVICE_CONFIGS.transcriptMonitor.timeout + } + ); + results.successful.push(transcriptResult); + await registerWithPSM(transcriptResult, 'scripts/enhanced-transcript-monitor.js'); + } catch (error) { + results.failed.push({ + serviceName: SERVICE_CONFIGS.transcriptMonitor.name, + error: error.message, + required: true + }); + } + } else { + console.log('ā­ļø Skipping Transcript Monitor (--no-transcript)'); } - try { - const coordinatorResult = await startServiceWithRetry( - SERVICE_CONFIGS.liveLoggingCoordinator.name, - SERVICE_CONFIGS.liveLoggingCoordinator.startFn, - SERVICE_CONFIGS.liveLoggingCoordinator.healthCheckFn, - { - required: SERVICE_CONFIGS.liveLoggingCoordinator.required, - maxRetries: SERVICE_CONFIGS.liveLoggingCoordinator.maxRetries, - timeout: SERVICE_CONFIGS.liveLoggingCoordinator.timeout - } - ); - results.successful.push(coordinatorResult); - await registerWithPSM(coordinatorResult, 'scripts/live-logging-coordinator.js'); - } catch (error) { - results.failed.push({ - serviceName: SERVICE_CONFIGS.liveLoggingCoordinator.name, - error: error.message, - required: true - }); + if (!SERVICE_FLAGS.skipLogging) { + try { + const coordinatorResult = await startServiceWithRetry( + SERVICE_CONFIGS.liveLoggingCoordinator.name, + SERVICE_CONFIGS.liveLoggingCoordinator.startFn, + SERVICE_CONFIGS.liveLoggingCoordinator.healthCheckFn, + { + required: SERVICE_CONFIGS.liveLoggingCoordinator.required, + maxRetries: SERVICE_CONFIGS.liveLoggingCoordinator.maxRetries, + timeout: SERVICE_CONFIGS.liveLoggingCoordinator.timeout + } + ); + results.successful.push(coordinatorResult); + await registerWithPSM(coordinatorResult, 'scripts/live-logging-coordinator.js'); + } catch (error) { + results.failed.push({ + serviceName: SERVICE_CONFIGS.liveLoggingCoordinator.name, + error: error.message, + required: true + }); + } + } else { + console.log('ā­ļø Skipping Live Logging Coordinator (--no-logging)'); } console.log(''); @@ -552,85 +580,97 @@ async function startAllServices() { console.log('šŸ”µ Starting OPTIONAL services (graceful degradation enabled)...'); console.log(''); - const vkbResult = await startServiceWithRetry( - SERVICE_CONFIGS.vkbServer.name, - SERVICE_CONFIGS.vkbServer.startFn, - SERVICE_CONFIGS.vkbServer.healthCheckFn, - { - required: SERVICE_CONFIGS.vkbServer.required, - maxRetries: SERVICE_CONFIGS.vkbServer.maxRetries, - timeout: SERVICE_CONFIGS.vkbServer.timeout - } - ); + if (!SERVICE_FLAGS.skipVkb) { + const vkbResult = await startServiceWithRetry( + SERVICE_CONFIGS.vkbServer.name, + SERVICE_CONFIGS.vkbServer.startFn, + SERVICE_CONFIGS.vkbServer.healthCheckFn, + { + required: SERVICE_CONFIGS.vkbServer.required, + maxRetries: SERVICE_CONFIGS.vkbServer.maxRetries, + timeout: SERVICE_CONFIGS.vkbServer.timeout + } + ); - if (vkbResult.status === 'success') { - results.successful.push(vkbResult); - await registerWithPSM(vkbResult, 'lib/vkb-server/cli.js'); + if (vkbResult.status === 'success') { + results.successful.push(vkbResult); + await registerWithPSM(vkbResult, 'lib/vkb-server/cli.js'); + } else { + results.degraded.push(vkbResult); + } } else { - results.degraded.push(vkbResult); + console.log('ā­ļø Skipping VKB Server (--no-vkb)'); } console.log(''); // 3. OPTIONAL: Constraint Monitor - const constraintResult = await startServiceWithRetry( - SERVICE_CONFIGS.constraintMonitor.name, - SERVICE_CONFIGS.constraintMonitor.startFn, - SERVICE_CONFIGS.constraintMonitor.healthCheckFn, - { - required: SERVICE_CONFIGS.constraintMonitor.required, - maxRetries: SERVICE_CONFIGS.constraintMonitor.maxRetries, - timeout: SERVICE_CONFIGS.constraintMonitor.timeout - } - ); + if (!SERVICE_FLAGS.skipConstraints) { + const constraintResult = await startServiceWithRetry( + SERVICE_CONFIGS.constraintMonitor.name, + SERVICE_CONFIGS.constraintMonitor.startFn, + SERVICE_CONFIGS.constraintMonitor.healthCheckFn, + { + required: SERVICE_CONFIGS.constraintMonitor.required, + maxRetries: SERVICE_CONFIGS.constraintMonitor.maxRetries, + timeout: SERVICE_CONFIGS.constraintMonitor.timeout + } + ); - if (constraintResult.status === 'success') { - results.successful.push(constraintResult); - // No PSM registration for Docker-based service + if (constraintResult.status === 'success') { + results.successful.push(constraintResult); + // No PSM registration for Docker-based service + } else { + results.degraded.push(constraintResult); + } } else { - results.degraded.push(constraintResult); + console.log('ā­ļø Skipping Constraint Monitor (--no-constraints)'); } console.log(''); // 4. OPTIONAL: Health Verifier - const healthVerifierResult = await startServiceWithRetry( - SERVICE_CONFIGS.healthVerifier.name, - SERVICE_CONFIGS.healthVerifier.startFn, - SERVICE_CONFIGS.healthVerifier.healthCheckFn, - { - required: SERVICE_CONFIGS.healthVerifier.required, - maxRetries: SERVICE_CONFIGS.healthVerifier.maxRetries, - timeout: SERVICE_CONFIGS.healthVerifier.timeout + if (!SERVICE_FLAGS.skipHealth) { + const healthVerifierResult = await startServiceWithRetry( + SERVICE_CONFIGS.healthVerifier.name, + SERVICE_CONFIGS.healthVerifier.startFn, + SERVICE_CONFIGS.healthVerifier.healthCheckFn, + { + required: SERVICE_CONFIGS.healthVerifier.required, + maxRetries: SERVICE_CONFIGS.healthVerifier.maxRetries, + timeout: SERVICE_CONFIGS.healthVerifier.timeout + } + ); + + if (healthVerifierResult.status === 'success') { + results.successful.push(healthVerifierResult); + await registerWithPSM(healthVerifierResult, 'scripts/health-verifier.js'); + } else { + results.degraded.push(healthVerifierResult); } - ); - if (healthVerifierResult.status === 'success') { - results.successful.push(healthVerifierResult); - await registerWithPSM(healthVerifierResult, 'scripts/health-verifier.js'); - } else { - results.degraded.push(healthVerifierResult); - } + console.log(''); - console.log(''); + // 5. OPTIONAL: StatusLine Health Monitor + const statuslineHealthResult = await startServiceWithRetry( + SERVICE_CONFIGS.statuslineHealthMonitor.name, + SERVICE_CONFIGS.statuslineHealthMonitor.startFn, + SERVICE_CONFIGS.statuslineHealthMonitor.healthCheckFn, + { + required: SERVICE_CONFIGS.statuslineHealthMonitor.required, + maxRetries: SERVICE_CONFIGS.statuslineHealthMonitor.maxRetries, + timeout: SERVICE_CONFIGS.statuslineHealthMonitor.timeout + } + ); - // 5. OPTIONAL: StatusLine Health Monitor - const statuslineHealthResult = await startServiceWithRetry( - SERVICE_CONFIGS.statuslineHealthMonitor.name, - SERVICE_CONFIGS.statuslineHealthMonitor.startFn, - SERVICE_CONFIGS.statuslineHealthMonitor.healthCheckFn, - { - required: SERVICE_CONFIGS.statuslineHealthMonitor.required, - maxRetries: SERVICE_CONFIGS.statuslineHealthMonitor.maxRetries, - timeout: SERVICE_CONFIGS.statuslineHealthMonitor.timeout + if (statuslineHealthResult.status === 'success') { + results.successful.push(statuslineHealthResult); + await registerWithPSM(statuslineHealthResult, 'scripts/statusline-health-monitor.js'); + } else { + results.degraded.push(statuslineHealthResult); } - ); - - if (statuslineHealthResult.status === 'success') { - results.successful.push(statuslineHealthResult); - await registerWithPSM(statuslineHealthResult, 'scripts/statusline-health-monitor.js'); } else { - results.degraded.push(statuslineHealthResult); + console.log('ā­ļø Skipping Health Monitoring (--no-health)'); } console.log(''); diff --git a/start-services.sh b/start-services.sh index a01d1b065..e3262d223 100755 --- a/start-services.sh +++ b/start-services.sh @@ -18,7 +18,7 @@ if [ "$ROBUST_MODE" = "true" ]; then echo "" # Use the Node.js-based robust service starter - exec node "$SCRIPT_DIR/scripts/start-services-robust.js" + exec node "$SCRIPT_DIR/scripts/start-services-robust.js" "$@" fi # LEGACY MODE (kept for backward compatibility, disable with ROBUST_MODE=false) From 90f9f135e0affc2e7e09f1c5904b25f6fbdc42e8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 29 Nov 2025 23:09:58 +0000 Subject: [PATCH 2/5] feat: add Board of Directors consensus mechanism - Implements a 'Board of Directors' workflow with 5 distinct AI personas (Pragmatist, Architect, Security Officer, Performance Zealot, User Advocate). - Adds `bin/coding board` command to trigger the consensus process. - Implements `BoardMeeting` class for orchestration (Proposal -> Anonymization -> Voting -> Tally). - Adds `LLMClient` for lightweight API interaction (Anthropic/OpenAI). - Adds unit tests for the voting logic. --- .eslintrc.cjs | 1 + bin/coding | 4 + lib/consensus/board-meeting.js | 146 ++++++++++++++++++++++++++++++++ lib/consensus/directors.js | 49 +++++++++++ lib/consensus/llm-client.js | 78 +++++++++++++++++ scripts/run-board-meeting.js | 80 +++++++++++++++++ test/setup.js | 1 + tests/unit/BoardMeeting.test.js | 76 +++++++++++++++++ 8 files changed, 435 insertions(+) create mode 100644 .eslintrc.cjs create mode 100644 lib/consensus/board-meeting.js create mode 100644 lib/consensus/directors.js create mode 100644 lib/consensus/llm-client.js create mode 100755 scripts/run-board-meeting.js create mode 100644 test/setup.js create mode 100644 tests/unit/BoardMeeting.test.js diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 000000000..1d4ff7b8c --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1 @@ +module.exports = { extends: "eslint:recommended", env: { node: true, es6: true }, parserOptions: { ecmaVersion: 2022, sourceType: "module" } }; diff --git a/bin/coding b/bin/coding index 79bafc302..5566462b6 100755 --- a/bin/coding +++ b/bin/coding @@ -106,6 +106,10 @@ 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 diff --git a/lib/consensus/board-meeting.js b/lib/consensus/board-meeting.js new file mode 100644 index 000000000..2c2b47379 --- /dev/null +++ b/lib/consensus/board-meeting.js @@ -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; diff --git a/lib/consensus/directors.js b/lib/consensus/directors.js new file mode 100644 index 000000000..e170e461c --- /dev/null +++ b/lib/consensus/directors.js @@ -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; diff --git a/lib/consensus/llm-client.js b/lib/consensus/llm-client.js new file mode 100644 index 000000000..129c79fe2 --- /dev/null +++ b/lib/consensus/llm-client.js @@ -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; diff --git a/scripts/run-board-meeting.js b/scripts/run-board-meeting.js new file mode 100755 index 000000000..a40c3de89 --- /dev/null +++ b/scripts/run-board-meeting.js @@ -0,0 +1,80 @@ +#!/usr/bin/env node + +import BoardMeeting from '../lib/consensus/board-meeting.js'; +import readline from 'readline'; + +async function main() { + const args = process.argv.slice(2); + let topic = args.join(' '); + + if (!topic) { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + + topic = await new Promise(resolve => { + rl.question('Enter the topic for the Board Meeting: ', (answer) => { + rl.close(); + resolve(answer); + }); + }); + } + + if (!topic) { + console.error("Error: Topic is required."); + process.exit(1); + } + + // Check for API keys + if (!process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) { + console.error("Error: ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable is required."); + process.exit(1); + } + + const meeting = new BoardMeeting(); + + try { + const result = await meeting.conductMeeting(topic); + + console.log("\n" + "=".repeat(50)); + console.log("šŸ MEETING ADJOURNED šŸ"); + console.log("=".repeat(50)); + + if (result.winner) { + console.log(`\nšŸ† WINNER: Proposal ${result.winner.id} (by ${result.winner.originalDirector})`); + console.log(`\nšŸ“„ THE WINNING PROPOSAL:\n${result.winner.content}`); + } else { + console.log("\nšŸ† WINNER: None (No votes cast or tie with no votes)"); + } + + console.log("\n" + "-".repeat(50)); + console.log("šŸ“Š VOTE TALLY"); + console.log("-".repeat(50)); + + // Sort scores + const sortedScores = Object.entries(result.scores).sort((a, b) => b[1] - a[1]); + + sortedScores.forEach(([id, score]) => { + const p = result.proposals.find(prop => prop.id === id); + console.log(`Proposal ${id} (${p.originalDirector}): ${score} votes`); + }); + + console.log("\n" + "-".repeat(50)); + console.log("šŸ—³ļø VOTING RECORDS"); + console.log("-".repeat(50)); + + result.votes.forEach(vote => { + if (vote) { + console.log(`${vote.voter} voted for ${vote.choice}`); + console.log(`Reason: ${vote.reason}\n`); + } + }); + + } catch (error) { + console.error("Board meeting failed:", error); + process.exit(1); + } +} + +main(); diff --git a/test/setup.js b/test/setup.js new file mode 100644 index 000000000..f36f7d1c6 --- /dev/null +++ b/test/setup.js @@ -0,0 +1 @@ +console.log('Test setup loaded'); diff --git a/tests/unit/BoardMeeting.test.js b/tests/unit/BoardMeeting.test.js new file mode 100644 index 000000000..3a720fec4 --- /dev/null +++ b/tests/unit/BoardMeeting.test.js @@ -0,0 +1,76 @@ +import { jest } from '@jest/globals'; +import BoardMeeting from '../../lib/consensus/board-meeting.js'; +import LLMClient from '../../lib/consensus/llm-client.js'; + +// Mock LLMClient +jest.mock('../../lib/consensus/llm-client.js'); + +describe('BoardMeeting', () => { + let meeting; + let mockLLM; + + beforeEach(() => { + // Setup mock implementation + mockLLM = { + complete: jest.fn() + }; + + // In ESM mocking with Jest, we might need to handle the mock differently + // if LLMClient is the default export. + // However, since we are mocking the module, we assume the constructor calls will rely on the mocked class. + + // For this specific test, we can just spy on the methods or ensure the class is mocked correctly. + // Given the error "mockClear is not a function", it seems LLMClient isn't being treated as a Jest mock function automatically in this ESM context. + + // Workaround: Mock the instance method on the prototype if strict mocking fails + // But better: Use the mocked module instance. + }); + + test('generateProposals should call LLM for each director', async () => { + // Manually injecting mock into the meeting instance for this test + // to bypass module mocking complexity in ESM/Jest for now. + meeting = new BoardMeeting(); + meeting.llm = mockLLM; + mockLLM.complete.mockResolvedValue('A proposal'); + + const proposals = await meeting.generateProposals('Topic'); + + expect(proposals.length).toBe(5); + expect(mockLLM.complete).toHaveBeenCalledTimes(5); + expect(proposals[0].content).toBe('A proposal'); + }); + + test('anonymizeProposals should assign IDs', () => { + meeting = new BoardMeeting(); + const proposals = [ + { director: 'Dir 1', content: 'Content 1' }, + { director: 'Dir 2', content: 'Content 2' } + ]; + + const result = meeting.anonymizeProposals(proposals); + + expect(result[0].id).toBe('A'); + expect(result[1].id).toBe('B'); + expect(result[0].originalDirector).toBe('Dir 1'); + }); + + test('tallyVotes should determine the winner', () => { + meeting = new BoardMeeting(); + const anonymizedProposals = [ + { id: 'A', originalDirector: 'Dir 1', content: 'Content 1' }, + { id: 'B', originalDirector: 'Dir 2', content: 'Content 2' } + ]; + + const votes = [ + { voter: 'Voter 1', choice: 'A', reason: 'Good' }, + { voter: 'Voter 2', choice: 'A', reason: 'Better' }, + { voter: 'Voter 3', choice: 'B', reason: 'Okay' } + ]; + + const result = meeting.tallyVotes(votes, anonymizedProposals); + + expect(result.winner.id).toBe('A'); + expect(result.scores['A']).toBe(2); + expect(result.scores['B']).toBe(1); + }); +}); From 33f7c98d85dea1ee0efaee2f41f65d00942ce5dd Mon Sep 17 00:00:00 2001 From: David Raehles Date: Mon, 1 Dec 2025 15:23:44 +0100 Subject: [PATCH 3/5] chore(installer): switch submodules to HTTPS and use Docker CLI plugin; update installer run artifacts --- .activate | 6 +- .gitmodules | 6 +- .lsl/config.json | 4 +- enhanced-lsl-deployment-report.md | 4 +- integrations/browser-access/package-lock.json | 3 + scripts/cleanup-aliases.sh | 2 - scripts/start-services-robust.js | 4 +- uninstall.sh.backup-20251201-123841 | 279 ++++++++++++++++++ 8 files changed, 294 insertions(+), 14 deletions(-) create mode 100755 uninstall.sh.backup-20251201-123841 diff --git a/.activate b/.activate index 9b6dc774c..ef2fe336a 100755 --- a/.activate +++ b/.activate @@ -1,9 +1,9 @@ #!/bin/bash # Activate Agent-Agnostic Coding Tools environment -export CODING_REPO="/Users/q284340/Agentic/coding" -export PATH="/Users/q284340/Agentic/coding/bin:$PATH" +export CODING_REPO="/home/q494415/workspace/agentic-coding-framework" +export PATH="/home/q494415/workspace/agentic-coding-framework/bin:$PATH" echo "āœ… Agent-Agnostic Coding Tools environment activated!" -echo "Commands 'ukb', 'vkb', and 'coding' are now available." +echo "Commands 'vkb' and 'coding' are now available." echo "" echo "Usage:" echo " coding # Use best available agent" diff --git a/.gitmodules b/.gitmodules index e59d23cd2..ebb938d8d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/.lsl/config.json b/.lsl/config.json index 621792c65..1ab6c3fe8 100644 --- a/.lsl/config.json +++ b/.lsl/config.json @@ -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", diff --git a/enhanced-lsl-deployment-report.md b/enhanced-lsl-deployment-report.md index f6fcdd750..4c034bb66 100644 --- a/enhanced-lsl-deployment-report.md +++ b/enhanced-lsl-deployment-report.md @@ -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 diff --git a/integrations/browser-access/package-lock.json b/integrations/browser-access/package-lock.json index deb4f6f29..79dbe2908 100644 --- a/integrations/browser-access/package-lock.json +++ b/integrations/browser-access/package-lock.json @@ -418,6 +418,7 @@ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", "license": "Apache-2.0", + "peer": true, "dependencies": { "playwright": "1.52.0" }, @@ -994,6 +995,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", @@ -2616,6 +2618,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.46.tgz", "integrity": "sha512-IqRxcHEIjqLd4LNS/zKffB3Jzg3NwqJxQQ0Ns7pdrvgGkwQsEBdEQcOHaBVqvvZArShRzI39+aMST3FBGmTrLQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/scripts/cleanup-aliases.sh b/scripts/cleanup-aliases.sh index a398354e6..21ba5be9c 100755 --- a/scripts/cleanup-aliases.sh +++ b/scripts/cleanup-aliases.sh @@ -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 diff --git a/scripts/start-services-robust.js b/scripts/start-services-robust.js index a02ebaedd..b0cecc40a 100755 --- a/scripts/start-services-robust.js +++ b/scripts/start-services-robust.js @@ -208,7 +208,7 @@ const SERVICE_CONFIGS = { } try { - await execAsync('docker-compose up -d', { + await execAsync('docker compose up -d', { cwd: constraintDir, timeout: 60000 }); @@ -219,7 +219,7 @@ const SERVICE_CONFIGS = { console.log('[ConstraintMonitor] Docker containers started successfully'); console.log('[ConstraintMonitor] Web services (API + Dashboard) managed by Global Service Coordinator'); - return { + return { service: 'constraint-monitor-docker', mode: 'docker-compose', containers: ['redis', 'qdrant'] diff --git a/uninstall.sh.backup-20251201-123841 b/uninstall.sh.backup-20251201-123841 new file mode 100755 index 000000000..d0c3162e7 --- /dev/null +++ b/uninstall.sh.backup-20251201-123841 @@ -0,0 +1,279 @@ +#!/bin/bash +# Coding Tools System - Uninstall Script +# Removes installations but preserves data + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +CODING_REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +echo -e "${YELLOW}šŸ—‘ļø Coding Tools System - Uninstaller${NC}" +echo -e "${YELLOW}=========================================${NC}" +echo "" +echo -e "${RED}āš ļø WARNING: This will remove installed components${NC}" +echo -e "${GREEN}āœ… Your knowledge data (.data/knowledge-graph/ and .data/knowledge-export/) will be preserved${NC}" +echo "" +read -p "Continue with uninstall? (y/N) " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Uninstall cancelled." + exit 0 +fi + +echo -e "\n${BLUE}šŸ”§ Removing shell configuration...${NC}" +# Remove from common shell configs +for rc_file in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.bash_profile"; do + if [[ -f "$rc_file" ]]; then + # Remove old Claude Knowledge Management System entries + sed -i '/# Claude Knowledge Management System/,+3d' "$rc_file" 2>/dev/null || true + # Remove new Coding Tools entries + sed -i '/# Coding Tools - Start/,/# Coding Tools - End/d' "$rc_file" 2>/dev/null || true + # Remove any CODING_TOOLS_PATH or CODING_REPO entries + sed -i '/CODING_TOOLS_PATH/d' "$rc_file" 2>/dev/null || true + sed -i '/CODING_REPO/d' "$rc_file" 2>/dev/null || true + # Remove team configuration + sed -i '/# Coding Tools - Team Configuration/,+1d' "$rc_file" 2>/dev/null || true + sed -i '/CODING_TEAM/d' "$rc_file" 2>/dev/null || true + # Remove any PATH additions for coding tools + sed -i '/knowledge-management.*coding/d' "$rc_file" 2>/dev/null || true + echo " Cleaned $rc_file" + fi +done + +echo -e "\n${BLUE}šŸ—‘ļø Removing installed components...${NC}" +# Remove bin directory +if [[ -d "$CODING_REPO/bin" ]]; then + rm -rf "$CODING_REPO/bin" + echo " Removed bin directory" +fi + +# Clean memory-visualizer (git submodule - preserve source) +if [[ -d "$CODING_REPO/integrations/memory-visualizer" ]]; then + echo " Cleaning memory-visualizer (git submodule)..." + rm -rf "$CODING_REPO/integrations/memory-visualizer/node_modules" + rm -rf "$CODING_REPO/integrations/memory-visualizer/dist" + echo " Removed build artifacts (source code preserved)" +fi + +# Clean mcp-server-browserbase (git submodule - preserve source) +if [[ -d "$CODING_REPO/integrations/mcp-server-browserbase" ]]; then + echo " Cleaning mcp-server-browserbase (git submodule)..." + rm -rf "$CODING_REPO/integrations/mcp-server-browserbase/node_modules" + rm -rf "$CODING_REPO/integrations/mcp-server-browserbase/dist" + echo " Removed build artifacts (source code preserved)" +fi + +# Clean semantic analysis MCP server (git submodule - preserve source) +if [[ -d "$CODING_REPO/integrations/mcp-server-semantic-analysis" ]]; then + echo " Cleaning semantic analysis MCP server (git submodule)..." + + # Remove node_modules + if [[ -d "$CODING_REPO/integrations/mcp-server-semantic-analysis/node_modules" ]]; then + rm -rf "$CODING_REPO/integrations/mcp-server-semantic-analysis/node_modules" + echo " Removed Node.js dependencies" + fi + + # Remove built dist directory + if [[ -d "$CODING_REPO/integrations/mcp-server-semantic-analysis/dist" ]]; then + rm -rf "$CODING_REPO/integrations/mcp-server-semantic-analysis/dist" + echo " Removed built TypeScript files" + fi + + # Remove logs directory + if [[ -d "$CODING_REPO/integrations/mcp-server-semantic-analysis/logs" ]]; then + rm -rf "$CODING_REPO/integrations/mcp-server-semantic-analysis/logs" + echo " Removed semantic analysis logs" + fi + + echo " Git submodule source code preserved" +fi + +# Clean Serena MCP server (git submodule - preserve source) +if [[ -d "$CODING_REPO/integrations/serena" ]]; then + echo " Cleaning Serena MCP server (git submodule)..." + + # Remove .venv directory (uv virtual environment) + if [[ -d "$CODING_REPO/integrations/serena/.venv" ]]; then + rm -rf "$CODING_REPO/integrations/serena/.venv" + echo " Removed Python virtual environment" + fi + + # Remove __pycache__ directories + find "$CODING_REPO/integrations/serena" -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true + echo " Removed Python cache files" + + # Remove .pyc files + find "$CODING_REPO/integrations/serena" -name "*.pyc" -type f -exec rm -f {} + 2>/dev/null || true + + # Remove uv.lock file + if [[ -f "$CODING_REPO/integrations/serena/uv.lock" ]]; then + rm -f "$CODING_REPO/integrations/serena/uv.lock" + echo " Removed uv lock file" + fi + + echo " Git submodule source code preserved" +fi + +# Clean up node_modules in MCP servers (non-submodules) +for dir in "integrations/browser-access"; do + if [[ -d "$CODING_REPO/$dir/node_modules" ]]; then + rm -rf "$CODING_REPO/$dir/node_modules" + echo " Removed $dir/node_modules" + fi + if [[ -d "$CODING_REPO/$dir/dist" ]]; then + rm -rf "$CODING_REPO/$dir/dist" + echo " Removed $dir/dist" + fi +done + +# Note: memory-visualizer and mcp-server-semantic-analysis are git submodules +# and have already been cleaned above + +# Remove .coding-tools directory +if [[ -d "$HOME/.coding-tools" ]]; then + rm -rf "$HOME/.coding-tools" + echo " Removed ~/.coding-tools" +fi + +# Remove logs +rm -f "$CODING_REPO/install.log" 2>/dev/null || true +# ukb removed - no temp logs to clean +rm -f /tmp/vkb-server.* 2>/dev/null || true + +# Remove MCP configuration files +echo -e "\n${BLUE}šŸ”§ Removing MCP configuration files...${NC}" +rm -f "$CODING_REPO/claude-code-mcp-processed.json" 2>/dev/null || true + +# Remove user-level MCP configuration (optional - ask user) +echo "" +read -p "Remove user-level MCP configuration? This affects all projects using Claude Code. (y/N) " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + USER_MCP_CONFIG="$HOME/.config/claude-code-mcp.json" + if [[ -f "$USER_MCP_CONFIG" ]]; then + rm -f "$USER_MCP_CONFIG" + echo " Removed user-level MCP configuration" + fi + + # Remove from Claude app directory + if [[ "$OSTYPE" == "darwin"* ]]; then + CLAUDE_CONFIG_DIR="$HOME/Library/Application Support/Claude" + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + CLAUDE_CONFIG_DIR="$HOME/.config/Claude" + elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then + CLAUDE_CONFIG_DIR="${APPDATA:-$HOME/AppData/Roaming}/Claude" + fi + + if [[ -n "$CLAUDE_CONFIG_DIR" ]] && [[ -f "$CLAUDE_CONFIG_DIR/claude-code-mcp.json" ]]; then + rm -f "$CLAUDE_CONFIG_DIR/claude-code-mcp.json" + echo " Removed Claude app MCP configuration" + fi +else + echo " Keeping user-level MCP configuration" +fi + +# Remove constraint monitor and LSL hooks +echo -e "\n${BLUE}šŸ”— Removing Hooks (Constraints + LSL)...${NC}" +SETTINGS_FILE="$HOME/.claude/settings.json" + +if [[ ! -f "$SETTINGS_FILE" ]]; then + echo " No settings file found - hooks already removed" +else + # Check if jq is available + if ! command -v jq >/dev/null 2>&1; then + echo -e "${YELLOW} āš ļø jq not found - cannot automatically remove hooks${NC}" + echo " Please manually edit: $SETTINGS_FILE" + echo " Remove PreToolUse hooks containing 'pre-tool-hook-wrapper.js'" + echo " Remove PostToolUse hooks containing 'tool-interaction-hook-wrapper.js'" + else + # Backup settings file + BACKUP_FILE="${SETTINGS_FILE}.backup.$(date +%Y%m%d_%H%M%S)" + cp "$SETTINGS_FILE" "$BACKUP_FILE" + echo " Backed up settings to: $BACKUP_FILE" + + # Remove both PreToolUse and PostToolUse hooks + TEMP_FILE=$(mktemp) + jq 'if .hooks.PreToolUse then + .hooks.PreToolUse = [ + .hooks.PreToolUse[] | + select(.hooks[]?.command | contains("pre-tool-hook-wrapper.js") | not) + ] + else . end | + if .hooks.PreToolUse == [] then + del(.hooks.PreToolUse) + else . end | + if .hooks.PostToolUse then + .hooks.PostToolUse = [ + .hooks.PostToolUse[] | + select(.hooks[]?.command | contains("tool-interaction-hook-wrapper.js") | not) + ] + else . end | + if .hooks.PostToolUse == [] then + del(.hooks.PostToolUse) + else . end' "$SETTINGS_FILE" > "$TEMP_FILE" + + # Validate and apply + if jq empty "$TEMP_FILE" 2>/dev/null; then + mv "$TEMP_FILE" "$SETTINGS_FILE" + echo " āœ… Removed PreToolUse and PostToolUse hooks from settings" + else + rm -f "$TEMP_FILE" + echo -e "${RED} āŒ Failed to update settings - JSON validation failed${NC}" + echo " Original settings preserved in: $BACKUP_FILE" + fi + fi +fi + +echo -e "\n${BLUE}šŸ—‘ļø Removing knowledge databases...${NC}" +# Remove .data directory with database files (optional - ask user) +if [[ -d "$CODING_REPO/.data" ]]; then + echo "" + read -p "Remove .data directory (contains SQLite knowledge database)? This will delete all learning history. (y/N) " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf "$CODING_REPO/.data" + echo " Removed .data directory" + else + echo -e "${GREEN} Kept .data directory with knowledge database${NC}" + fi +fi + +# Inform about Qdrant collections +echo -e "\n${YELLOW}ā„¹ļø Note about Qdrant collections:${NC}" +echo " If you were using Qdrant for vector search, you may want to remove collections:" +echo " docker exec qdrant-container /bin/sh -c \"rm -rf /qdrant/storage/collections/knowledge_*\"" +echo " Or stop the Qdrant container:" +echo " docker stop qdrant-container" + +echo -e "\n${GREEN}āœ… Uninstall completed!${NC}" +echo -e "${GREEN}šŸ“Š Your knowledge data preservation status:${NC}" + +# Check for GraphDB and knowledge exports +if [[ -d "$CODING_REPO/.data/knowledge-graph" ]]; then + echo " $CODING_REPO/.data/knowledge-graph/ - PRESERVED (GraphDB)" +fi + +if [[ -d "$CODING_REPO/.data/knowledge-export" ]]; then + EXPORT_FILES=$(find "$CODING_REPO/.data/knowledge-export" -name "*.json" 2>/dev/null || true) + if [[ -n "$EXPORT_FILES" ]]; then + echo -e "${GREEN}šŸ“Š Knowledge export files preserved:${NC}" + echo "$EXPORT_FILES" | while read -r file; do + [[ -n "$file" ]] && echo " $(basename "$file")" + done + fi +fi + +if [[ -d "$CODING_REPO/.data" ]]; then + echo -e "${GREEN}šŸ“Š Knowledge database preserved:${NC}" + echo " $CODING_REPO/.data/knowledge.db (SQLite database with learning history)" +fi + +echo "" +echo "To reinstall, run: ./install.sh" +echo "Your team configuration will need to be set up again during installation." \ No newline at end of file From b21be9eeafef9dff21007933388d657cec40b768 Mon Sep 17 00:00:00 2001 From: David Raehles Date: Mon, 1 Dec 2025 15:48:43 +0100 Subject: [PATCH 4/5] chore: remove backup file from index (keep local copy) --- uninstall.sh.backup-20251201-123841 | 279 ---------------------------- 1 file changed, 279 deletions(-) delete mode 100755 uninstall.sh.backup-20251201-123841 diff --git a/uninstall.sh.backup-20251201-123841 b/uninstall.sh.backup-20251201-123841 deleted file mode 100755 index d0c3162e7..000000000 --- a/uninstall.sh.backup-20251201-123841 +++ /dev/null @@ -1,279 +0,0 @@ -#!/bin/bash -# Coding Tools System - Uninstall Script -# Removes installations but preserves data - -set -euo pipefail - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -CODING_REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -echo -e "${YELLOW}šŸ—‘ļø Coding Tools System - Uninstaller${NC}" -echo -e "${YELLOW}=========================================${NC}" -echo "" -echo -e "${RED}āš ļø WARNING: This will remove installed components${NC}" -echo -e "${GREEN}āœ… Your knowledge data (.data/knowledge-graph/ and .data/knowledge-export/) will be preserved${NC}" -echo "" -read -p "Continue with uninstall? (y/N) " -n 1 -r -echo -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "Uninstall cancelled." - exit 0 -fi - -echo -e "\n${BLUE}šŸ”§ Removing shell configuration...${NC}" -# Remove from common shell configs -for rc_file in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.bash_profile"; do - if [[ -f "$rc_file" ]]; then - # Remove old Claude Knowledge Management System entries - sed -i '/# Claude Knowledge Management System/,+3d' "$rc_file" 2>/dev/null || true - # Remove new Coding Tools entries - sed -i '/# Coding Tools - Start/,/# Coding Tools - End/d' "$rc_file" 2>/dev/null || true - # Remove any CODING_TOOLS_PATH or CODING_REPO entries - sed -i '/CODING_TOOLS_PATH/d' "$rc_file" 2>/dev/null || true - sed -i '/CODING_REPO/d' "$rc_file" 2>/dev/null || true - # Remove team configuration - sed -i '/# Coding Tools - Team Configuration/,+1d' "$rc_file" 2>/dev/null || true - sed -i '/CODING_TEAM/d' "$rc_file" 2>/dev/null || true - # Remove any PATH additions for coding tools - sed -i '/knowledge-management.*coding/d' "$rc_file" 2>/dev/null || true - echo " Cleaned $rc_file" - fi -done - -echo -e "\n${BLUE}šŸ—‘ļø Removing installed components...${NC}" -# Remove bin directory -if [[ -d "$CODING_REPO/bin" ]]; then - rm -rf "$CODING_REPO/bin" - echo " Removed bin directory" -fi - -# Clean memory-visualizer (git submodule - preserve source) -if [[ -d "$CODING_REPO/integrations/memory-visualizer" ]]; then - echo " Cleaning memory-visualizer (git submodule)..." - rm -rf "$CODING_REPO/integrations/memory-visualizer/node_modules" - rm -rf "$CODING_REPO/integrations/memory-visualizer/dist" - echo " Removed build artifacts (source code preserved)" -fi - -# Clean mcp-server-browserbase (git submodule - preserve source) -if [[ -d "$CODING_REPO/integrations/mcp-server-browserbase" ]]; then - echo " Cleaning mcp-server-browserbase (git submodule)..." - rm -rf "$CODING_REPO/integrations/mcp-server-browserbase/node_modules" - rm -rf "$CODING_REPO/integrations/mcp-server-browserbase/dist" - echo " Removed build artifacts (source code preserved)" -fi - -# Clean semantic analysis MCP server (git submodule - preserve source) -if [[ -d "$CODING_REPO/integrations/mcp-server-semantic-analysis" ]]; then - echo " Cleaning semantic analysis MCP server (git submodule)..." - - # Remove node_modules - if [[ -d "$CODING_REPO/integrations/mcp-server-semantic-analysis/node_modules" ]]; then - rm -rf "$CODING_REPO/integrations/mcp-server-semantic-analysis/node_modules" - echo " Removed Node.js dependencies" - fi - - # Remove built dist directory - if [[ -d "$CODING_REPO/integrations/mcp-server-semantic-analysis/dist" ]]; then - rm -rf "$CODING_REPO/integrations/mcp-server-semantic-analysis/dist" - echo " Removed built TypeScript files" - fi - - # Remove logs directory - if [[ -d "$CODING_REPO/integrations/mcp-server-semantic-analysis/logs" ]]; then - rm -rf "$CODING_REPO/integrations/mcp-server-semantic-analysis/logs" - echo " Removed semantic analysis logs" - fi - - echo " Git submodule source code preserved" -fi - -# Clean Serena MCP server (git submodule - preserve source) -if [[ -d "$CODING_REPO/integrations/serena" ]]; then - echo " Cleaning Serena MCP server (git submodule)..." - - # Remove .venv directory (uv virtual environment) - if [[ -d "$CODING_REPO/integrations/serena/.venv" ]]; then - rm -rf "$CODING_REPO/integrations/serena/.venv" - echo " Removed Python virtual environment" - fi - - # Remove __pycache__ directories - find "$CODING_REPO/integrations/serena" -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true - echo " Removed Python cache files" - - # Remove .pyc files - find "$CODING_REPO/integrations/serena" -name "*.pyc" -type f -exec rm -f {} + 2>/dev/null || true - - # Remove uv.lock file - if [[ -f "$CODING_REPO/integrations/serena/uv.lock" ]]; then - rm -f "$CODING_REPO/integrations/serena/uv.lock" - echo " Removed uv lock file" - fi - - echo " Git submodule source code preserved" -fi - -# Clean up node_modules in MCP servers (non-submodules) -for dir in "integrations/browser-access"; do - if [[ -d "$CODING_REPO/$dir/node_modules" ]]; then - rm -rf "$CODING_REPO/$dir/node_modules" - echo " Removed $dir/node_modules" - fi - if [[ -d "$CODING_REPO/$dir/dist" ]]; then - rm -rf "$CODING_REPO/$dir/dist" - echo " Removed $dir/dist" - fi -done - -# Note: memory-visualizer and mcp-server-semantic-analysis are git submodules -# and have already been cleaned above - -# Remove .coding-tools directory -if [[ -d "$HOME/.coding-tools" ]]; then - rm -rf "$HOME/.coding-tools" - echo " Removed ~/.coding-tools" -fi - -# Remove logs -rm -f "$CODING_REPO/install.log" 2>/dev/null || true -# ukb removed - no temp logs to clean -rm -f /tmp/vkb-server.* 2>/dev/null || true - -# Remove MCP configuration files -echo -e "\n${BLUE}šŸ”§ Removing MCP configuration files...${NC}" -rm -f "$CODING_REPO/claude-code-mcp-processed.json" 2>/dev/null || true - -# Remove user-level MCP configuration (optional - ask user) -echo "" -read -p "Remove user-level MCP configuration? This affects all projects using Claude Code. (y/N) " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - USER_MCP_CONFIG="$HOME/.config/claude-code-mcp.json" - if [[ -f "$USER_MCP_CONFIG" ]]; then - rm -f "$USER_MCP_CONFIG" - echo " Removed user-level MCP configuration" - fi - - # Remove from Claude app directory - if [[ "$OSTYPE" == "darwin"* ]]; then - CLAUDE_CONFIG_DIR="$HOME/Library/Application Support/Claude" - elif [[ "$OSTYPE" == "linux-gnu"* ]]; then - CLAUDE_CONFIG_DIR="$HOME/.config/Claude" - elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then - CLAUDE_CONFIG_DIR="${APPDATA:-$HOME/AppData/Roaming}/Claude" - fi - - if [[ -n "$CLAUDE_CONFIG_DIR" ]] && [[ -f "$CLAUDE_CONFIG_DIR/claude-code-mcp.json" ]]; then - rm -f "$CLAUDE_CONFIG_DIR/claude-code-mcp.json" - echo " Removed Claude app MCP configuration" - fi -else - echo " Keeping user-level MCP configuration" -fi - -# Remove constraint monitor and LSL hooks -echo -e "\n${BLUE}šŸ”— Removing Hooks (Constraints + LSL)...${NC}" -SETTINGS_FILE="$HOME/.claude/settings.json" - -if [[ ! -f "$SETTINGS_FILE" ]]; then - echo " No settings file found - hooks already removed" -else - # Check if jq is available - if ! command -v jq >/dev/null 2>&1; then - echo -e "${YELLOW} āš ļø jq not found - cannot automatically remove hooks${NC}" - echo " Please manually edit: $SETTINGS_FILE" - echo " Remove PreToolUse hooks containing 'pre-tool-hook-wrapper.js'" - echo " Remove PostToolUse hooks containing 'tool-interaction-hook-wrapper.js'" - else - # Backup settings file - BACKUP_FILE="${SETTINGS_FILE}.backup.$(date +%Y%m%d_%H%M%S)" - cp "$SETTINGS_FILE" "$BACKUP_FILE" - echo " Backed up settings to: $BACKUP_FILE" - - # Remove both PreToolUse and PostToolUse hooks - TEMP_FILE=$(mktemp) - jq 'if .hooks.PreToolUse then - .hooks.PreToolUse = [ - .hooks.PreToolUse[] | - select(.hooks[]?.command | contains("pre-tool-hook-wrapper.js") | not) - ] - else . end | - if .hooks.PreToolUse == [] then - del(.hooks.PreToolUse) - else . end | - if .hooks.PostToolUse then - .hooks.PostToolUse = [ - .hooks.PostToolUse[] | - select(.hooks[]?.command | contains("tool-interaction-hook-wrapper.js") | not) - ] - else . end | - if .hooks.PostToolUse == [] then - del(.hooks.PostToolUse) - else . end' "$SETTINGS_FILE" > "$TEMP_FILE" - - # Validate and apply - if jq empty "$TEMP_FILE" 2>/dev/null; then - mv "$TEMP_FILE" "$SETTINGS_FILE" - echo " āœ… Removed PreToolUse and PostToolUse hooks from settings" - else - rm -f "$TEMP_FILE" - echo -e "${RED} āŒ Failed to update settings - JSON validation failed${NC}" - echo " Original settings preserved in: $BACKUP_FILE" - fi - fi -fi - -echo -e "\n${BLUE}šŸ—‘ļø Removing knowledge databases...${NC}" -# Remove .data directory with database files (optional - ask user) -if [[ -d "$CODING_REPO/.data" ]]; then - echo "" - read -p "Remove .data directory (contains SQLite knowledge database)? This will delete all learning history. (y/N) " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - rm -rf "$CODING_REPO/.data" - echo " Removed .data directory" - else - echo -e "${GREEN} Kept .data directory with knowledge database${NC}" - fi -fi - -# Inform about Qdrant collections -echo -e "\n${YELLOW}ā„¹ļø Note about Qdrant collections:${NC}" -echo " If you were using Qdrant for vector search, you may want to remove collections:" -echo " docker exec qdrant-container /bin/sh -c \"rm -rf /qdrant/storage/collections/knowledge_*\"" -echo " Or stop the Qdrant container:" -echo " docker stop qdrant-container" - -echo -e "\n${GREEN}āœ… Uninstall completed!${NC}" -echo -e "${GREEN}šŸ“Š Your knowledge data preservation status:${NC}" - -# Check for GraphDB and knowledge exports -if [[ -d "$CODING_REPO/.data/knowledge-graph" ]]; then - echo " $CODING_REPO/.data/knowledge-graph/ - PRESERVED (GraphDB)" -fi - -if [[ -d "$CODING_REPO/.data/knowledge-export" ]]; then - EXPORT_FILES=$(find "$CODING_REPO/.data/knowledge-export" -name "*.json" 2>/dev/null || true) - if [[ -n "$EXPORT_FILES" ]]; then - echo -e "${GREEN}šŸ“Š Knowledge export files preserved:${NC}" - echo "$EXPORT_FILES" | while read -r file; do - [[ -n "$file" ]] && echo " $(basename "$file")" - done - fi -fi - -if [[ -d "$CODING_REPO/.data" ]]; then - echo -e "${GREEN}šŸ“Š Knowledge database preserved:${NC}" - echo " $CODING_REPO/.data/knowledge.db (SQLite database with learning history)" -fi - -echo "" -echo "To reinstall, run: ./install.sh" -echo "Your team configuration will need to be set up again during installation." \ No newline at end of file From c89f94100af7f1c2bd0317eb7fab267bb9ffb303 Mon Sep 17 00:00:00 2001 From: David Raehles Date: Mon, 1 Dec 2025 16:07:27 +0100 Subject: [PATCH 5/5] chore: remove .activate from index (keep local) --- .activate | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100755 .activate diff --git a/.activate b/.activate deleted file mode 100755 index ef2fe336a..000000000 --- a/.activate +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -# Activate Agent-Agnostic Coding Tools environment -export CODING_REPO="/home/q494415/workspace/agentic-coding-framework" -export PATH="/home/q494415/workspace/agentic-coding-framework/bin:$PATH" -echo "āœ… Agent-Agnostic Coding Tools environment activated!" -echo "Commands 'vkb' and 'coding' are now available." -echo "" -echo "Usage:" -echo " coding # Use best available agent" -echo " coding --copilot # Force CoPilot" -echo " coding --claude # Force Claude Code"