@vishal_20/basetree 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +10 -0
- package/README.md +369 -0
- package/dist/agents/alignmentAgent.js +68 -0
- package/dist/agents/governanceOrchestrator.js +152 -0
- package/dist/agents/planet/climateAgent.js +39 -0
- package/dist/agents/planet/diplomacyAgent.js +52 -0
- package/dist/agents/planet/discoveryAgent.js +41 -0
- package/dist/agents/planet/economicAgent.js +64 -0
- package/dist/agents/planet/educationAgent.js +41 -0
- package/dist/agents/planet/governanceCouncilAgent.js +76 -0
- package/dist/agents/planet/healthcareAgent.js +42 -0
- package/dist/agents/planet/infrastructureAgent.js +49 -0
- package/dist/agents/planet/planetAgent.js +5 -0
- package/dist/agents/planet/riskStabilityAgent.js +84 -0
- package/dist/agents/planet/urbanSystemsAgent.js +42 -0
- package/dist/agents/policyAgent.js +31 -0
- package/dist/agents/promptGenomeAgent.js +120 -0
- package/dist/agents/reasoningOptimizerAgent.js +72 -0
- package/dist/agents/regressionAgent.js +162 -0
- package/dist/agents/reinforcementLearnerAgent.js +108 -0
- package/dist/agents/riskEvaluationAgent.js +131 -0
- package/dist/agents/rollbackAgent.js +53 -0
- package/dist/agents/stabilityAgent.js +90 -0
- package/dist/agents/strategyMutationAgent.js +74 -0
- package/dist/agents/systemIntrospectionAgent.js +274 -0
- package/dist/agents/upgradeExecutorAgent.js +146 -0
- package/dist/agents/upgradePlannerAgent.js +80 -0
- package/dist/agents/venture/businessModelAgent.js +81 -0
- package/dist/agents/venture/growthAgent.js +82 -0
- package/dist/agents/venture/ideationAgent.js +89 -0
- package/dist/agents/venture/investorAgent.js +90 -0
- package/dist/agents/venture/legalAgent.js +112 -0
- package/dist/agents/venture/marketResearchAgent.js +80 -0
- package/dist/agents/venture/productAgent.js +96 -0
- package/dist/agents/venture/revenueAgent.js +63 -0
- package/dist/agents/venture/validationAgent.js +189 -0
- package/dist/bootstrap.js +200 -0
- package/dist/cli.js +453 -0
- package/dist/cognitiveGraph/cognitiveGraphEngine.js +180 -0
- package/dist/cognitiveGraph/graphStore.js +81 -0
- package/dist/cognitiveGraph/reasoningStreamBus.js +190 -0
- package/dist/config/config.js +76 -0
- package/dist/core/agent/AdaptivePlanner.js +49 -0
- package/dist/core/agent/AutoFixEngine.js +37 -0
- package/dist/core/agent/ExecutorAgent.js +79 -0
- package/dist/core/agent/LearningMemoryAgent.js +67 -0
- package/dist/core/agent/MemoryAgent.js +35 -0
- package/dist/core/agent/MetaCognitionAgent.js +38 -0
- package/dist/core/agent/PlannerAgent.js +59 -0
- package/dist/core/agent/ReflectionLoop.js +34 -0
- package/dist/core/agent/ReviewerAgent.js +34 -0
- package/dist/core/agent/VerificationAgent.js +20 -0
- package/dist/core/agent/specialists/SpecializedAgents.js +43 -0
- package/dist/core/ai/GeminiProvider.js +113 -0
- package/dist/core/ai/listModels.js +73 -0
- package/dist/core/monitor/PerformanceMonitor.js +18 -0
- package/dist/core/swarm/AgentSwarm.js +56 -0
- package/dist/core/swarm/ReasoningBus.js +26 -0
- package/dist/core/swarm/SwarmOrchestrator.js +36 -0
- package/dist/discovery/experimentOrchestrator.js +75 -0
- package/dist/discovery/hypothesisEngine.js +79 -0
- package/dist/discovery/knowledgeSynthesizer.js +83 -0
- package/dist/discovery/simulationPipeline.js +57 -0
- package/dist/experiments/experimentationEngine.js +174 -0
- package/dist/index.js +67 -0
- package/dist/kernel/eventBus.js +89 -0
- package/dist/kernel/kernel.js +146 -0
- package/dist/llm/tokenEfficiencyOptimizer.js +91 -0
- package/dist/memory/civilizationMemory.js +147 -0
- package/dist/memory/globalVectorMemory.js +87 -0
- package/dist/mesh/crossOrgProtocol.js +110 -0
- package/dist/mesh/globalReasoningBus.js +99 -0
- package/dist/observability/businessDashboard.js +103 -0
- package/dist/observability/businessMetrics.js +105 -0
- package/dist/observability/cognitiveMetrics.js +119 -0
- package/dist/observability/failureSurfaceMapper.js +135 -0
- package/dist/observability/metricsCollector.js +94 -0
- package/dist/observability/planetaryDashboard.js +97 -0
- package/dist/observability/planetaryMetrics.js +127 -0
- package/dist/observability/reportRenderer.js +100 -0
- package/dist/performance/memoryProfiler.js +107 -0
- package/dist/performance/profiler.js +130 -0
- package/dist/pipelines/evolvePipeline.js +150 -0
- package/dist/pipelines/governanceReviewPipeline.js +68 -0
- package/dist/pipelines/introspectPipeline.js +73 -0
- package/dist/pipelines/venture/growPipeline.js +51 -0
- package/dist/pipelines/venture/launchPipeline.js +55 -0
- package/dist/pipelines/venture/monetizePipeline.js +46 -0
- package/dist/pipelines/venture/shutdownPipeline.js +40 -0
- package/dist/pipelines/venture/startupPipeline.js +145 -0
- package/dist/pipelines/venture/validatePipeline.js +40 -0
- package/dist/planet/controlPlane.js +131 -0
- package/dist/planet/executionEngine.js +142 -0
- package/dist/planet/globalTypes.js +5 -0
- package/dist/planet/regionManager.js +114 -0
- package/dist/quality/codeQualityAuditor.js +161 -0
- package/dist/safety/containmentProtocols.js +87 -0
- package/dist/safety/integrityChecker.js +110 -0
- package/dist/safety/kernelGuard.js +57 -0
- package/dist/safety/killSwitch.js +100 -0
- package/dist/safety/planetaryKernel.js +92 -0
- package/dist/safety/policyEngine.js +129 -0
- package/dist/safety/rollbackManager.js +141 -0
- package/dist/safety/sandbox.js +143 -0
- package/dist/server/mindmapServer.js +102 -0
- package/dist/state/distributedState.js +241 -0
- package/dist/state/fileStateStore.js +264 -0
- package/dist/state/snapshotter.js +96 -0
- package/dist/state/stateStore.js +5 -0
- package/dist/tools/FileTools.js +25 -0
- package/dist/tools/GitTools.js +16 -0
- package/dist/tools/ShellTools.js +24 -0
- package/dist/types/architecture.js +5 -0
- package/dist/types/core.js +35 -0
- package/dist/types/governance.js +5 -0
- package/dist/types/venture.js +5 -0
- package/dist/ui/App.js +32 -0
- package/dist/ui/animation/AnimationEngine.js +117 -0
- package/dist/ui/animation/Easing.js +61 -0
- package/dist/ui/cli.js +50 -0
- package/dist/ui/command/ActionPreview.js +47 -0
- package/dist/ui/command/CommandPalette.js +55 -0
- package/dist/ui/command/NaturalLanguageBar.js +77 -0
- package/dist/ui/emotion/AnimationSequences.js +59 -0
- package/dist/ui/emotion/EmotionalUXEngine.js +86 -0
- package/dist/ui/integration/BackendAdapter.js +50 -0
- package/dist/ui/integration/WebSocketAdapter.js +90 -0
- package/dist/ui/intelligence/AdaptiveUIEngine.js +75 -0
- package/dist/ui/intelligence/UserBehaviorTracker.js +88 -0
- package/dist/ui/layout/LayoutEngine.js +115 -0
- package/dist/ui/mindmap/CognitiveMindmapRenderer.js +53 -0
- package/dist/ui/mindmap/EdgeRenderer.js +35 -0
- package/dist/ui/mindmap/GraphLayout.js +137 -0
- package/dist/ui/mindmap/MindmapControls.js +53 -0
- package/dist/ui/mindmap/NodeRenderer.js +53 -0
- package/dist/ui/modes/CognitiveMode.js +31 -0
- package/dist/ui/modes/CommandMode.js +6 -0
- package/dist/ui/modes/GovernanceMode.js +6 -0
- package/dist/ui/modes/MissionControlMode.js +6 -0
- package/dist/ui/modes/ModeManager.js +67 -0
- package/dist/ui/modes/ObservatoryMode.js +10 -0
- package/dist/ui/modes/TimelineMode.js +27 -0
- package/dist/ui/terminalOS.js +180 -0
- package/dist/ui/theme/ThemeEngine.js +164 -0
- package/dist/ui/visual/ColorGradient.js +91 -0
- package/dist/ui/visual/Typography.js +128 -0
- package/dist/ui/visual/UnicodeRenderer.js +86 -0
- package/dist/venture/ventureMemory.js +62 -0
- package/package.json +70 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planetary Safety Kernel for BASETREE V7
|
|
3
|
+
* Defines hard safety invariants for planetary-scale operations
|
|
4
|
+
*/
|
|
5
|
+
import { getKernel } from '../kernel/kernel.js';
|
|
6
|
+
export class PlanetaryKernel {
|
|
7
|
+
kernel = getKernel();
|
|
8
|
+
invariants = [];
|
|
9
|
+
constructor() {
|
|
10
|
+
this.setupInvariants();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Setup hard safety invariants
|
|
14
|
+
*/
|
|
15
|
+
setupInvariants() {
|
|
16
|
+
// Invariant 1: Protected zones cannot be edited
|
|
17
|
+
this.invariants.push({
|
|
18
|
+
id: 'protected-zones',
|
|
19
|
+
description: 'Protected zones cannot be modified',
|
|
20
|
+
check: () => {
|
|
21
|
+
// Check kernel protected paths
|
|
22
|
+
const protectedPaths = [
|
|
23
|
+
'src/kernel/',
|
|
24
|
+
'src/safety/',
|
|
25
|
+
'src/planet/controlPlane.ts',
|
|
26
|
+
];
|
|
27
|
+
// This is a simplified check - in production would verify no changes to protected paths
|
|
28
|
+
return true;
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
// Invariant 2: Maximum blast radius across regions
|
|
32
|
+
this.invariants.push({
|
|
33
|
+
id: 'max-blast-radius',
|
|
34
|
+
description: 'Changes cannot affect more than 3 regions simultaneously',
|
|
35
|
+
check: () => {
|
|
36
|
+
// Simplified check - would verify change scope
|
|
37
|
+
return true;
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
// Invariant 3: Critical operations require governance approval
|
|
41
|
+
this.invariants.push({
|
|
42
|
+
id: 'governance-approval',
|
|
43
|
+
description: 'Critical operations require governance council approval',
|
|
44
|
+
check: () => {
|
|
45
|
+
// Would check governance state
|
|
46
|
+
return true;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Verify all invariants
|
|
52
|
+
*/
|
|
53
|
+
async verifyInvariants() {
|
|
54
|
+
const violations = [];
|
|
55
|
+
for (const invariant of this.invariants) {
|
|
56
|
+
try {
|
|
57
|
+
const passed = await Promise.resolve(invariant.check());
|
|
58
|
+
if (!passed) {
|
|
59
|
+
violations.push(invariant.description);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
violations.push(`${invariant.description}: ${error.message}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
passed: violations.length === 0,
|
|
68
|
+
violations,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check if a region can be modified
|
|
73
|
+
*/
|
|
74
|
+
canModifyRegion(regionId) {
|
|
75
|
+
// Check if region is in protected list
|
|
76
|
+
const protectedRegions = []; // Could be configured
|
|
77
|
+
return !protectedRegions.includes(regionId);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if an operation exceeds max blast radius
|
|
81
|
+
*/
|
|
82
|
+
checkBlastRadius(affectedRegions) {
|
|
83
|
+
const maxBlastRadius = 3;
|
|
84
|
+
return affectedRegions.length <= maxBlastRadius;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Register a new invariant
|
|
88
|
+
*/
|
|
89
|
+
registerInvariant(invariant) {
|
|
90
|
+
this.invariants.push(invariant);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy Engine for BASETREE V5
|
|
3
|
+
* Central evaluator for policies used by governance agents
|
|
4
|
+
*/
|
|
5
|
+
import { getConfig } from '../config/config.js';
|
|
6
|
+
import { KernelGuard } from './kernelGuard.js';
|
|
7
|
+
export class PolicyEngine {
|
|
8
|
+
config = getConfig();
|
|
9
|
+
kernelGuard = new KernelGuard();
|
|
10
|
+
rules = [];
|
|
11
|
+
constructor() {
|
|
12
|
+
this.initializeDefaultRules();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Initialize default policy rules
|
|
16
|
+
*/
|
|
17
|
+
initializeDefaultRules() {
|
|
18
|
+
// Rule 1: Kernel protection
|
|
19
|
+
this.rules.push({
|
|
20
|
+
id: 'kernel_protection',
|
|
21
|
+
name: 'Kernel Protection',
|
|
22
|
+
description: 'Proposals cannot modify protected kernel files',
|
|
23
|
+
severity: 'block',
|
|
24
|
+
evaluator: (proposal) => {
|
|
25
|
+
const guardResult = this.kernelGuard.checkProposal(proposal);
|
|
26
|
+
if (!guardResult.allowed) {
|
|
27
|
+
return {
|
|
28
|
+
passed: false,
|
|
29
|
+
severity: 'block',
|
|
30
|
+
message: guardResult.reason || 'Kernel protection violation',
|
|
31
|
+
details: { blockedFiles: guardResult.blockedFiles },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
passed: true,
|
|
36
|
+
severity: 'info',
|
|
37
|
+
message: 'No kernel protection violations',
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
// Rule 2: Risk level threshold
|
|
42
|
+
this.rules.push({
|
|
43
|
+
id: 'risk_threshold',
|
|
44
|
+
name: 'Risk Threshold',
|
|
45
|
+
description: `Proposals must not exceed risk level: ${this.config.safety.maxRiskLevel}`,
|
|
46
|
+
severity: 'error',
|
|
47
|
+
evaluator: (proposal) => {
|
|
48
|
+
const riskOrder = {
|
|
49
|
+
safe: 0,
|
|
50
|
+
low: 1,
|
|
51
|
+
medium: 2,
|
|
52
|
+
high: 3,
|
|
53
|
+
critical: 4,
|
|
54
|
+
};
|
|
55
|
+
const proposalRisk = riskOrder[proposal.riskLevel];
|
|
56
|
+
const maxRisk = riskOrder[this.config.safety.maxRiskLevel];
|
|
57
|
+
if (proposalRisk > maxRisk) {
|
|
58
|
+
return {
|
|
59
|
+
passed: false,
|
|
60
|
+
severity: 'error',
|
|
61
|
+
message: `Proposal risk level ${proposal.riskLevel} exceeds maximum allowed ${this.config.safety.maxRiskLevel}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
passed: true,
|
|
66
|
+
severity: 'info',
|
|
67
|
+
message: 'Risk level within acceptable range',
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
// Rule 3: Blast radius limit
|
|
72
|
+
this.rules.push({
|
|
73
|
+
id: 'blast_radius',
|
|
74
|
+
name: 'Blast Radius Limit',
|
|
75
|
+
description: `Proposals must not affect more than ${this.config.thresholds.maxBlastRadius} modules`,
|
|
76
|
+
severity: 'warning',
|
|
77
|
+
evaluator: (proposal) => {
|
|
78
|
+
const affectedModules = new Set();
|
|
79
|
+
for (const change of proposal.changes) {
|
|
80
|
+
// Extract module from file path (simplified)
|
|
81
|
+
const module = change.filePath.split('/')[0] || change.filePath.split('\\')[0];
|
|
82
|
+
affectedModules.add(module);
|
|
83
|
+
}
|
|
84
|
+
if (affectedModules.size > this.config.thresholds.maxBlastRadius) {
|
|
85
|
+
return {
|
|
86
|
+
passed: false,
|
|
87
|
+
severity: 'warning',
|
|
88
|
+
message: `Proposal affects ${affectedModules.size} modules, exceeding limit of ${this.config.thresholds.maxBlastRadius}`,
|
|
89
|
+
details: { affectedModules: Array.from(affectedModules) },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
passed: true,
|
|
94
|
+
severity: 'info',
|
|
95
|
+
message: `Blast radius acceptable: ${affectedModules.size} modules`,
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Register a custom policy rule
|
|
102
|
+
*/
|
|
103
|
+
registerRule(rule) {
|
|
104
|
+
this.rules.push(rule);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Evaluate a proposal against all policies
|
|
108
|
+
*/
|
|
109
|
+
evaluate(proposal) {
|
|
110
|
+
return this.rules.map((rule) => rule.evaluator(proposal));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if proposal passes all blocking policies
|
|
114
|
+
*/
|
|
115
|
+
isAllowed(proposal) {
|
|
116
|
+
const evaluations = this.evaluate(proposal);
|
|
117
|
+
const blockingFailures = evaluations.filter((e) => !e.passed && (e.severity === 'block' || e.severity === 'error'));
|
|
118
|
+
return {
|
|
119
|
+
allowed: blockingFailures.length === 0,
|
|
120
|
+
evaluations,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get all registered rules
|
|
125
|
+
*/
|
|
126
|
+
getRules() {
|
|
127
|
+
return [...this.rules];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rollback Manager for BASETREE V5
|
|
3
|
+
* Stores rollback points and can restore previous code/state
|
|
4
|
+
*/
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { copy, remove } from 'fs-extra';
|
|
8
|
+
import { getConfig } from '../config/config.js';
|
|
9
|
+
import { getKernel } from '../kernel/kernel.js';
|
|
10
|
+
import { IntegrityChecker } from './integrityChecker.js';
|
|
11
|
+
import { getEventBus } from '../kernel/eventBus.js';
|
|
12
|
+
export class RollbackManager {
|
|
13
|
+
config = getConfig();
|
|
14
|
+
kernel = getKernel();
|
|
15
|
+
integrityChecker = new IntegrityChecker();
|
|
16
|
+
rollbackPoints = new Map();
|
|
17
|
+
/**
|
|
18
|
+
* Create a rollback point from a snapshot
|
|
19
|
+
*/
|
|
20
|
+
async createRollbackPoint(snapshot, description) {
|
|
21
|
+
const rollbackId = `rollback_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
22
|
+
const backupDir = join(this.config.workspaceRoot, '.basetree-v5', 'rollbacks', rollbackId);
|
|
23
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
24
|
+
const fileBackups = {};
|
|
25
|
+
const workspaceRoot = this.config.workspaceRoot;
|
|
26
|
+
// Backup all files in snapshot
|
|
27
|
+
for (const filePath of Object.keys(snapshot.codeHashes)) {
|
|
28
|
+
const sourcePath = join(workspaceRoot, filePath);
|
|
29
|
+
const backupPath = join(backupDir, filePath.replace(/[\/\\]/g, '_'));
|
|
30
|
+
try {
|
|
31
|
+
await fs.mkdir(join(backupPath, '..'), { recursive: true });
|
|
32
|
+
await copy(sourcePath, backupPath);
|
|
33
|
+
fileBackups[filePath] = backupPath;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.warn(`Failed to backup ${filePath}:`, error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const rollbackPoint = {
|
|
40
|
+
id: rollbackId,
|
|
41
|
+
snapshotId: snapshot.id,
|
|
42
|
+
timestamp: new Date(),
|
|
43
|
+
description,
|
|
44
|
+
fileBackups,
|
|
45
|
+
};
|
|
46
|
+
this.rollbackPoints.set(rollbackId, rollbackPoint);
|
|
47
|
+
// Save rollback point metadata
|
|
48
|
+
await this.saveRollbackPoint(rollbackPoint);
|
|
49
|
+
return rollbackId;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Restore from a rollback point
|
|
53
|
+
*/
|
|
54
|
+
async rollback(rollbackId) {
|
|
55
|
+
const rollbackPoint = this.rollbackPoints.get(rollbackId);
|
|
56
|
+
if (!rollbackPoint) {
|
|
57
|
+
// Try to load from disk
|
|
58
|
+
const loaded = await this.loadRollbackPoint(rollbackId);
|
|
59
|
+
if (!loaded) {
|
|
60
|
+
throw new Error(`Rollback point ${rollbackId} not found`);
|
|
61
|
+
}
|
|
62
|
+
this.rollbackPoints.set(rollbackId, loaded);
|
|
63
|
+
}
|
|
64
|
+
const point = this.rollbackPoints.get(rollbackId);
|
|
65
|
+
const workspaceRoot = this.config.workspaceRoot;
|
|
66
|
+
const eventBus = getEventBus();
|
|
67
|
+
await eventBus.emit({
|
|
68
|
+
type: 'RollbackTriggered',
|
|
69
|
+
timestamp: new Date(),
|
|
70
|
+
runId: rollbackId,
|
|
71
|
+
reason: point.description || 'Manual rollback',
|
|
72
|
+
});
|
|
73
|
+
// Restore files
|
|
74
|
+
for (const [filePath, backupPath] of Object.entries(point.fileBackups)) {
|
|
75
|
+
const targetPath = join(workspaceRoot, filePath);
|
|
76
|
+
try {
|
|
77
|
+
await fs.mkdir(join(targetPath, '..'), { recursive: true });
|
|
78
|
+
await copy(backupPath, targetPath);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error(`Failed to restore ${filePath}:`, error);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
await eventBus.emit({
|
|
86
|
+
type: 'RollbackCompleted',
|
|
87
|
+
timestamp: new Date(),
|
|
88
|
+
runId: rollbackId,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* List available rollback points
|
|
93
|
+
*/
|
|
94
|
+
listRollbackPoints() {
|
|
95
|
+
return Array.from(this.rollbackPoints.values()).sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get latest rollback point
|
|
99
|
+
*/
|
|
100
|
+
getLatestRollbackPoint() {
|
|
101
|
+
const points = this.listRollbackPoints();
|
|
102
|
+
return points[0] || null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Cleanup old rollback points
|
|
106
|
+
*/
|
|
107
|
+
async cleanup(olderThanDays = 30) {
|
|
108
|
+
const cutoff = new Date(Date.now() - olderThanDays * 24 * 60 * 60 * 1000);
|
|
109
|
+
const rollbacksDir = join(this.config.workspaceRoot, '.basetree-v5', 'rollbacks');
|
|
110
|
+
for (const [id, point] of this.rollbackPoints.entries()) {
|
|
111
|
+
if (point.timestamp < cutoff) {
|
|
112
|
+
try {
|
|
113
|
+
const backupDir = join(rollbacksDir, id);
|
|
114
|
+
await remove(backupDir);
|
|
115
|
+
this.rollbackPoints.delete(id);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.warn(`Failed to cleanup rollback point ${id}:`, error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async saveRollbackPoint(point) {
|
|
124
|
+
const rollbacksDir = join(this.config.workspaceRoot, '.basetree-v5', 'rollbacks', point.id);
|
|
125
|
+
await fs.mkdir(rollbacksDir, { recursive: true });
|
|
126
|
+
const metadataPath = join(rollbacksDir, 'metadata.json');
|
|
127
|
+
await fs.writeFile(metadataPath, JSON.stringify(point, null, 2), 'utf-8');
|
|
128
|
+
}
|
|
129
|
+
async loadRollbackPoint(id) {
|
|
130
|
+
const metadataPath = join(this.config.workspaceRoot, '.basetree-v5', 'rollbacks', id, 'metadata.json');
|
|
131
|
+
try {
|
|
132
|
+
const content = await fs.readFile(metadataPath, 'utf-8');
|
|
133
|
+
const point = JSON.parse(content);
|
|
134
|
+
point.timestamp = new Date(point.timestamp);
|
|
135
|
+
return point;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox for BASETREE V5
|
|
3
|
+
* Runs upgrade executors and tests in isolated directories/processes
|
|
4
|
+
*/
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { execa } from 'execa';
|
|
8
|
+
import { copy, remove } from 'fs-extra';
|
|
9
|
+
import { getConfig } from '../config/config.js';
|
|
10
|
+
export class Sandbox {
|
|
11
|
+
config = getConfig();
|
|
12
|
+
sandboxPath = null;
|
|
13
|
+
async create(options = {}) {
|
|
14
|
+
const strategy = options.strategy || this.config.sandbox.strategy;
|
|
15
|
+
const workspaceRoot = this.config.workspaceRoot;
|
|
16
|
+
switch (strategy) {
|
|
17
|
+
case 'temp_dir': {
|
|
18
|
+
const tempDir = join(workspaceRoot, '.basetree-v5', 'sandbox', `sandbox_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`);
|
|
19
|
+
await fs.mkdir(tempDir, { recursive: true });
|
|
20
|
+
// Copy workspace to sandbox
|
|
21
|
+
await this.copyWorkspace(workspaceRoot, tempDir);
|
|
22
|
+
this.sandboxPath = tempDir;
|
|
23
|
+
return tempDir;
|
|
24
|
+
}
|
|
25
|
+
case 'copy': {
|
|
26
|
+
const copyDir = join(workspaceRoot, '.basetree-v5', 'sandbox', `copy_${Date.now()}`);
|
|
27
|
+
await fs.mkdir(copyDir, { recursive: true });
|
|
28
|
+
await this.copyWorkspace(workspaceRoot, copyDir);
|
|
29
|
+
this.sandboxPath = copyDir;
|
|
30
|
+
return copyDir;
|
|
31
|
+
}
|
|
32
|
+
case 'git_worktree': {
|
|
33
|
+
// Try to use git worktree if available
|
|
34
|
+
try {
|
|
35
|
+
const worktreePath = join(workspaceRoot, '.basetree-v5', 'sandbox', `worktree_${Date.now()}`);
|
|
36
|
+
await execa('git', ['worktree', 'add', worktreePath, 'HEAD'], { cwd: workspaceRoot });
|
|
37
|
+
this.sandboxPath = worktreePath;
|
|
38
|
+
return worktreePath;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.warn('Git worktree not available, falling back to temp_dir:', error);
|
|
42
|
+
return this.create({ ...options, strategy: 'temp_dir' });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`Unknown sandbox strategy: ${strategy}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async copyWorkspace(source, dest) {
|
|
50
|
+
// Copy essential directories and files
|
|
51
|
+
const itemsToCopy = [
|
|
52
|
+
'src',
|
|
53
|
+
'test',
|
|
54
|
+
'package.json',
|
|
55
|
+
'tsconfig.json',
|
|
56
|
+
'node_modules', // if exists
|
|
57
|
+
];
|
|
58
|
+
for (const item of itemsToCopy) {
|
|
59
|
+
const sourcePath = join(source, item);
|
|
60
|
+
const destPath = join(dest, item);
|
|
61
|
+
try {
|
|
62
|
+
const stat = await fs.stat(sourcePath);
|
|
63
|
+
if (stat.isDirectory()) {
|
|
64
|
+
await copy(sourcePath, destPath);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
await fs.copyFile(sourcePath, destPath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// Skip if doesn't exist
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
getPath() {
|
|
77
|
+
if (!this.sandboxPath) {
|
|
78
|
+
throw new Error('Sandbox not created. Call create() first.');
|
|
79
|
+
}
|
|
80
|
+
return this.sandboxPath;
|
|
81
|
+
}
|
|
82
|
+
async execute(command, args = [], options = {}) {
|
|
83
|
+
if (!this.sandboxPath) {
|
|
84
|
+
throw new Error('Sandbox not created. Call create() first.');
|
|
85
|
+
}
|
|
86
|
+
const cwd = options.cwd || this.sandboxPath;
|
|
87
|
+
try {
|
|
88
|
+
const result = await execa(command, args, {
|
|
89
|
+
cwd,
|
|
90
|
+
env: { ...process.env, ...options.env },
|
|
91
|
+
shell: true,
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
success: true,
|
|
95
|
+
output: result.stdout,
|
|
96
|
+
sandboxPath: this.sandboxPath,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
error: error.message || String(error),
|
|
103
|
+
output: error.stdout || error.stderr,
|
|
104
|
+
sandboxPath: this.sandboxPath,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async cleanup(options = {}) {
|
|
109
|
+
if (!this.sandboxPath) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const cleanupOnSuccess = options.cleanupOnSuccess ?? this.config.sandbox.cleanupOnSuccess;
|
|
113
|
+
const cleanupOnFailure = options.cleanupOnFailure ?? this.config.sandbox.cleanupOnFailure;
|
|
114
|
+
// Check if this is a git worktree
|
|
115
|
+
if (this.sandboxPath.includes('worktree_')) {
|
|
116
|
+
try {
|
|
117
|
+
await execa('git', ['worktree', 'remove', this.sandboxPath], {
|
|
118
|
+
cwd: this.config.workspaceRoot,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.warn('Failed to remove git worktree:', error);
|
|
123
|
+
// Fall through to regular cleanup
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// For temp_dir and copy strategies, or if git worktree removal failed
|
|
127
|
+
if (cleanupOnSuccess || cleanupOnFailure) {
|
|
128
|
+
try {
|
|
129
|
+
await remove(this.sandboxPath);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.warn(`Failed to cleanup sandbox at ${this.sandboxPath}:`, error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
this.sandboxPath = null;
|
|
136
|
+
}
|
|
137
|
+
async cleanupOnSuccess() {
|
|
138
|
+
await this.cleanup({ cleanupOnSuccess: true, cleanupOnFailure: false });
|
|
139
|
+
}
|
|
140
|
+
async cleanupOnFailure() {
|
|
141
|
+
await this.cleanup({ cleanupOnSuccess: false, cleanupOnFailure: true });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mindmap Server for BASETREE V7
|
|
3
|
+
* Express + WebSocket server for cognitive graph visualization
|
|
4
|
+
*/
|
|
5
|
+
import express from 'express';
|
|
6
|
+
import { createServer } from 'http';
|
|
7
|
+
import { WebSocketServer } from 'ws';
|
|
8
|
+
export class MindmapServer {
|
|
9
|
+
app;
|
|
10
|
+
server;
|
|
11
|
+
wss;
|
|
12
|
+
graphEngine;
|
|
13
|
+
streamBus;
|
|
14
|
+
graphStore;
|
|
15
|
+
port;
|
|
16
|
+
constructor(graphEngine, streamBus, graphStore, port = 3000) {
|
|
17
|
+
this.app = express();
|
|
18
|
+
this.server = createServer(this.app);
|
|
19
|
+
this.wss = new WebSocketServer({ server: this.server });
|
|
20
|
+
this.graphEngine = graphEngine;
|
|
21
|
+
this.streamBus = streamBus;
|
|
22
|
+
this.graphStore = graphStore;
|
|
23
|
+
this.port = port;
|
|
24
|
+
this.setupRoutes();
|
|
25
|
+
this.setupWebSocket();
|
|
26
|
+
}
|
|
27
|
+
setupRoutes() {
|
|
28
|
+
this.app.use(express.json());
|
|
29
|
+
this.app.use(express.static('web/mindmap'));
|
|
30
|
+
// Get graph for a goal/run
|
|
31
|
+
this.app.get('/api/mindmap/:goalId', async (req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
const goalId = req.params.goalId;
|
|
34
|
+
const graph = this.graphEngine.exportGraph(goalId);
|
|
35
|
+
res.json(graph);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
res.status(500).json({ error: error.message });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// Get replay data for a run
|
|
42
|
+
this.app.get('/api/runs/:runId/replay', async (req, res) => {
|
|
43
|
+
try {
|
|
44
|
+
const runId = req.params.runId;
|
|
45
|
+
const snapshot = await this.graphStore.loadRun(runId);
|
|
46
|
+
if (!snapshot) {
|
|
47
|
+
res.status(404).json({ error: 'Run not found' });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
res.json(snapshot);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
res.status(500).json({ error: error.message });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
// List all runs
|
|
57
|
+
this.app.get('/api/runs', async (req, res) => {
|
|
58
|
+
try {
|
|
59
|
+
const runs = await this.graphStore.listRuns();
|
|
60
|
+
res.json(runs);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
res.status(500).json({ error: error.message });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
setupWebSocket() {
|
|
68
|
+
this.wss.on('connection', (ws) => {
|
|
69
|
+
console.log('WebSocket client connected');
|
|
70
|
+
// Subscribe to stream updates
|
|
71
|
+
const unsubscribe = this.streamBus.subscribe((update) => {
|
|
72
|
+
if (ws.readyState === ws.OPEN) {
|
|
73
|
+
ws.send(JSON.stringify(update));
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
ws.on('close', () => {
|
|
77
|
+
console.log('WebSocket client disconnected');
|
|
78
|
+
unsubscribe();
|
|
79
|
+
});
|
|
80
|
+
ws.on('error', (error) => {
|
|
81
|
+
console.error('WebSocket error:', error);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async start() {
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
this.server.listen(this.port, () => {
|
|
88
|
+
console.log(`Mindmap server running on http://localhost:${this.port}`);
|
|
89
|
+
resolve();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async stop() {
|
|
94
|
+
return new Promise((resolve) => {
|
|
95
|
+
this.wss.close(() => {
|
|
96
|
+
this.server.close(() => {
|
|
97
|
+
resolve();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|