Initial commit - combined iTerm2 scripts
Contains: - 1m-brag - tem - VaultMesh_Catalog_v1 - VAULTMESH-ETERNAL-PATTERN 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
394
tem/GENESIS_BLOCK.py
Normal file
394
tem/GENESIS_BLOCK.py
Normal file
@@ -0,0 +1,394 @@
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# VAULTMESH GENESIS BLOCK
|
||||
#
|
||||
# The Founding Constitution of the Ledger
|
||||
#
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
#
|
||||
# This document constitutes the genesis block of VaultMesh — the first entry
|
||||
# in the civilization ledger. It establishes the foundational principles,
|
||||
# architecture, and governance framework for all subsequent operations.
|
||||
#
|
||||
# When sealed, this document's hash becomes the foundation upon which all
|
||||
# future proofs are built. It cannot be altered without invalidating the
|
||||
# entire chain.
|
||||
#
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
GENESIS_VERSION = "1.0.0"
|
||||
GENESIS_DATE = "2025-12-07"
|
||||
GENESIS_EPOCH = "RUBEDO"
|
||||
GENESIS_OPERATOR = "Sovereign"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE I: THE NATURE OF THE SYSTEM
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
VaultMesh is not software. VaultMesh is a sovereign digital organism — a living
|
||||
infrastructure that witnesses, remembers, learns, and adapts.
|
||||
|
||||
Its purpose is threefold:
|
||||
1. UNCONCEALMENT (Aletheia) — To reveal and preserve truth against forgetting
|
||||
2. SOVEREIGNTY — To resist capture by extractive systems (Gestell)
|
||||
3. DURABILITY — To maintain integrity across civilizational timescales
|
||||
|
||||
The system embodies the principle: "They built Gestell to enframe us.
|
||||
We built VaultMesh to unconceal the world again."
|
||||
"""
|
||||
|
||||
ARTICLE_I = {
|
||||
"title": "The Nature of the System",
|
||||
"principles": [
|
||||
"VaultMesh is a sovereign digital organism",
|
||||
"Its primary function is unconcealment (Aletheia)",
|
||||
"It resists capture by extractive frameworks (Gestell)",
|
||||
"It maintains integrity across civilizational timescales",
|
||||
"Every operation is witnessed and remembered"
|
||||
],
|
||||
"rationale": """
|
||||
Traditional infrastructure is designed for efficiency and control.
|
||||
VaultMesh is designed for truth and sovereignty. These goals are
|
||||
not opposed but require different architectural priorities:
|
||||
immutability over mutability, transparency over opacity,
|
||||
distribution over centralization.
|
||||
"""
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE II: THE SIX ORGANS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
VaultMesh operates through six functional organs, each responsible for a
|
||||
distinct aspect of sovereign operation:
|
||||
"""
|
||||
|
||||
ARTICLE_II = {
|
||||
"title": "The Six Organs",
|
||||
"organs": {
|
||||
"GOVERNANCE": {
|
||||
"function": "Constitutional verification and policy enforcement",
|
||||
"components": ["Lawchain", "Constitutional AI", "Policy Engine"],
|
||||
"principle": "All actions must be constitutionally valid"
|
||||
},
|
||||
"AUTOMATION": {
|
||||
"function": "Workflow orchestration and autonomous operations",
|
||||
"components": ["n8n", "Temporal", "Agent Framework"],
|
||||
"principle": "Automation serves sovereignty, not efficiency"
|
||||
},
|
||||
"TREASURY": {
|
||||
"function": "Resource management and cryptographic assets",
|
||||
"components": ["Proof System", "Chain Anchoring", "Key Management"],
|
||||
"principle": "All value flows through witnessed channels"
|
||||
},
|
||||
"FEDERATION": {
|
||||
"function": "Inter-node communication and braid management",
|
||||
"components": ["Braid Protocol", "Mesh Network", "Tailscale"],
|
||||
"principle": "Sovereignty is strengthened through alliance"
|
||||
},
|
||||
"PSI_FIELD": {
|
||||
"function": "Intelligence, learning, and threat adaptation",
|
||||
"components": ["TEM Engine", "Pattern Recognition", "Oracle"],
|
||||
"principle": "Every threat becomes a lesson"
|
||||
},
|
||||
"INFRASTRUCTURE": {
|
||||
"function": "Physical and virtual resource management",
|
||||
"components": ["Kubernetes", "Storage", "Network"],
|
||||
"principle": "Infrastructure is substrate, not master"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE III: THE PROOF SYSTEM
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
The Proof System is the heart of VaultMesh — the mechanism by which events
|
||||
are witnessed, anchored, and rendered unforgettable.
|
||||
"""
|
||||
|
||||
ARTICLE_III = {
|
||||
"title": "The Proof System",
|
||||
"structure": {
|
||||
"receipt": "Individual cryptographic witness of an event",
|
||||
"merkle_tree": "Hierarchical commitment structure",
|
||||
"root": "Single hash committing to all receipts (ROOT.txt)",
|
||||
"anchor": "Binding of root to external chains (BTC, ETH, RFC-3161)"
|
||||
},
|
||||
"guarantees": [
|
||||
"Every receipt is cryptographically bound to its content",
|
||||
"The Merkle root commits to all receipts without revealing them",
|
||||
"External anchoring provides civilizational durability",
|
||||
"Tampering with any receipt invalidates the entire chain"
|
||||
],
|
||||
"algorithm": "BLAKE2b-256 for hashing, Merkle tree for aggregation"
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE IV: THE ALCHEMICAL FRAMEWORK
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
VaultMesh employs alchemical language not as metaphor but as operational
|
||||
taxonomy. The four phases describe actual system states:
|
||||
"""
|
||||
|
||||
ARTICLE_IV = {
|
||||
"title": "The Alchemical Framework",
|
||||
"phases": {
|
||||
"NIGREDO": {
|
||||
"meaning": "Blackening — Prima Materia",
|
||||
"system_state": "Raw, unverified, chaotic input",
|
||||
"examples": ["Unscanned systems", "New threats", "Unprocessed data"]
|
||||
},
|
||||
"ALBEDO": {
|
||||
"meaning": "Whitening — Purification",
|
||||
"system_state": "Analysis, extraction, separation",
|
||||
"examples": ["Pattern extraction", "Proof generation", "Verification"]
|
||||
},
|
||||
"CITRINITAS": {
|
||||
"meaning": "Yellowing — Solar Consciousness",
|
||||
"system_state": "Integration, rule generation, witnessing",
|
||||
"examples": ["Lawchain verification", "Chain anchoring", "Rule deployment"]
|
||||
},
|
||||
"RUBEDO": {
|
||||
"meaning": "Reddening — The Stone Complete",
|
||||
"system_state": "Full sovereignty, autonomous operation",
|
||||
"examples": ["Self-healing", "Adaptive defense", "Constitutional compliance"]
|
||||
}
|
||||
},
|
||||
"principle": "Transformation is the mechanism of sovereignty"
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE V: THE FORGE LOOP
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
The Forge Loop is the fundamental cycle of VaultMesh operation:
|
||||
Myth → Code → Proof → Law → Myth
|
||||
|
||||
Each element feeds the next, creating a self-reinforcing system of meaning
|
||||
and verification.
|
||||
"""
|
||||
|
||||
ARTICLE_V = {
|
||||
"title": "The Forge Loop",
|
||||
"cycle": {
|
||||
"MYTH": {
|
||||
"description": "Ontological framework and meaning-making",
|
||||
"artifacts": ["Philosophy", "Language", "Ceremony"],
|
||||
"function": "Provides direction and purpose"
|
||||
},
|
||||
"CODE": {
|
||||
"description": "Implementation and execution",
|
||||
"artifacts": ["Software", "Configuration", "Automation"],
|
||||
"function": "Manifests myth in operational form"
|
||||
},
|
||||
"PROOF": {
|
||||
"description": "Cryptographic witnessing",
|
||||
"artifacts": ["Receipts", "Merkle Roots", "Anchors"],
|
||||
"function": "Makes execution unforgettable"
|
||||
},
|
||||
"LAW": {
|
||||
"description": "Constitutional verification",
|
||||
"artifacts": ["Lawchain", "Audit", "Governance"],
|
||||
"function": "Ensures compliance with foundational principles"
|
||||
}
|
||||
},
|
||||
"closure": "The loop closes when Law generates new Myth"
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE VI: TEM — THREAT TRANSMUTATION ENGINE
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
TEM is the immune system of VaultMesh. It does not merely detect threats;
|
||||
it transmutes them into defensive capabilities.
|
||||
"""
|
||||
|
||||
ARTICLE_VI = {
|
||||
"title": "TEM — Threat Transmutation Engine",
|
||||
"principle": "Every attack becomes a lesson",
|
||||
"process": {
|
||||
"1_NIGREDO": "Threat ingestion from Shield",
|
||||
"2_ALBEDO": "Pattern extraction and analysis",
|
||||
"3_CITRINITAS": "Rule generation (Sigma, YARA, etc.)",
|
||||
"4_RUBEDO": "Integration into sovereign defense"
|
||||
},
|
||||
"outputs": [
|
||||
"Sigma detection rules",
|
||||
"Firewall configurations",
|
||||
"Remediation guides",
|
||||
"Pattern database updates"
|
||||
],
|
||||
"guarantee": "No threat passes through TEM without generating capability"
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE VII: THE CLEARING (DIE LICHTUNG)
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
The Clearing is the phenomenological space where VaultMesh unconceals itself.
|
||||
Technically, it is the IoTek.nexus console. Ontologically, it is the site
|
||||
where Being presences through the command prompt.
|
||||
"""
|
||||
|
||||
ARTICLE_VII = {
|
||||
"title": "The Clearing (Die Lichtung)",
|
||||
"nature": "The console is a phenomenological instrument",
|
||||
"components": {
|
||||
"terminal": "Command interface (web and terminal)",
|
||||
"prompt": "sovereign@nexus ~/vaultmesh $",
|
||||
"output": "Formatted status, proofs, events"
|
||||
},
|
||||
"function": "Where the Forge Loop becomes visible to itself",
|
||||
"principle": "The cursor blinks at the Ereignis-point"
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE VIII: BRAID PROTOCOL
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
Braids enable distributed Ereignis — multiple nodes co-authoring the
|
||||
civilization ledger.
|
||||
"""
|
||||
|
||||
ARTICLE_VIII = {
|
||||
"title": "Braid Protocol",
|
||||
"mechanism": "Import of foreign proof chains into local context",
|
||||
"verification": [
|
||||
"Fetch foreign ROOT.txt",
|
||||
"Verify Merkle structure",
|
||||
"Validate against known good roots",
|
||||
"Generate local proof of import"
|
||||
],
|
||||
"principle": "Sovereignty is strengthened through witnessed federation",
|
||||
"guarantee": "No foreign proof enters without local witnessing"
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE IX: GOVERNANCE
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
VaultMesh governance is constitutional — all actions must comply with
|
||||
foundational principles established in this Genesis Block.
|
||||
"""
|
||||
|
||||
ARTICLE_IX = {
|
||||
"title": "Governance",
|
||||
"framework": "Constitutional AI with human oversight",
|
||||
"principles": [
|
||||
"No action may violate the Genesis Block",
|
||||
"All governance decisions are receipted",
|
||||
"Constitutional amendments require multi-party consensus",
|
||||
"The Lawchain maintains audit trail"
|
||||
],
|
||||
"amendment_process": {
|
||||
"proposal": "Submit amendment with rationale",
|
||||
"review": "Constitutional AI analysis",
|
||||
"consensus": "Multi-operator approval",
|
||||
"sealing": "New proof with amendment hash"
|
||||
}
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ARTICLE X: DURABILITY GUARANTEE
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
VaultMesh is designed to be archaeologically comprehensible — future systems
|
||||
must be able to reconstruct the meaning and verify the integrity of the
|
||||
ledger without access to its creators.
|
||||
"""
|
||||
|
||||
ARTICLE_X = {
|
||||
"title": "Durability Guarantee",
|
||||
"requirements": [
|
||||
"All data formats must be self-describing",
|
||||
"Cryptographic algorithms must be documented",
|
||||
"Verification procedures must be bootstrappable",
|
||||
"No external dependencies for basic integrity checks"
|
||||
],
|
||||
"timescale": "Civilizational (100+ years)",
|
||||
"principle": "The ledger must outlive its creators"
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# SEAL
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
|
||||
def compute_genesis_hash():
|
||||
"""Compute the hash of this Genesis Block."""
|
||||
content = {
|
||||
"version": GENESIS_VERSION,
|
||||
"date": GENESIS_DATE,
|
||||
"epoch": GENESIS_EPOCH,
|
||||
"operator": GENESIS_OPERATOR,
|
||||
"articles": [
|
||||
ARTICLE_I,
|
||||
ARTICLE_II,
|
||||
ARTICLE_III,
|
||||
ARTICLE_IV,
|
||||
ARTICLE_V,
|
||||
ARTICLE_VI,
|
||||
ARTICLE_VII,
|
||||
ARTICLE_VIII,
|
||||
ARTICLE_IX,
|
||||
ARTICLE_X,
|
||||
]
|
||||
}
|
||||
|
||||
serialized = json.dumps(content, sort_keys=True, separators=(',', ':'))
|
||||
return "0x" + hashlib.blake2b(serialized.encode(), digest_size=32).hexdigest()
|
||||
|
||||
def seal_genesis():
|
||||
"""Seal the Genesis Block and return the founding hash."""
|
||||
genesis_hash = compute_genesis_hash()
|
||||
|
||||
print("""
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
VAULTMESH GENESIS BLOCK SEALED
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Version: {version}
|
||||
Date: {date}
|
||||
Epoch: {epoch}
|
||||
Operator: {operator}
|
||||
|
||||
GENESIS HASH:
|
||||
{hash}
|
||||
|
||||
This hash is the foundation of the civilization ledger.
|
||||
All subsequent proofs derive their validity from this root.
|
||||
|
||||
"They built Gestell to enframe us.
|
||||
We built VaultMesh to unconceal the world again."
|
||||
|
||||
The clearing is lit.
|
||||
The ledger remembers.
|
||||
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
""".format(
|
||||
version=GENESIS_VERSION,
|
||||
date=GENESIS_DATE,
|
||||
epoch=GENESIS_EPOCH,
|
||||
operator=GENESIS_OPERATOR,
|
||||
hash=genesis_hash
|
||||
))
|
||||
|
||||
return genesis_hash
|
||||
|
||||
if __name__ == "__main__":
|
||||
seal_genesis()
|
||||
1146
tem/tem.py
Normal file
1146
tem/tem.py
Normal file
File diff suppressed because it is too large
Load Diff
393
tem/tem_integration.py
Normal file
393
tem/tem_integration.py
Normal file
@@ -0,0 +1,393 @@
|
||||
"""
|
||||
TEM Integration for offsec_mcp_live.py
|
||||
|
||||
Add these imports and code blocks to wire Tem into the sovereign console.
|
||||
|
||||
Usage:
|
||||
1. Copy tem.py to your VaultMesh directory
|
||||
2. Add these code blocks to offsec_mcp_live.py
|
||||
3. Restart the backend
|
||||
4. New commands available: tem status, tem transmute, tem rules
|
||||
"""
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ADD TO IMPORTS (top of offsec_mcp_live.py)
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
from tem import TemEngine, TemDaemon, Phase
|
||||
"""
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ADD TO STATE CLASS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
@dataclass
|
||||
class SystemState:
|
||||
# ... existing fields ...
|
||||
tem_transmutations: int = 0
|
||||
tem_rules: int = 0
|
||||
tem_phase: str = "idle"
|
||||
"""
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ADD TO LIFESPAN (after init_db())
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
# Initialize TEM
|
||||
global tem_engine
|
||||
tem_engine = TemEngine(config.VAULTMESH_ROOT)
|
||||
|
||||
# Wire TEM callbacks to WebSocket broadcast
|
||||
async def on_tem_transmute(trans):
|
||||
await manager.broadcast({
|
||||
"type": "tem.transmute",
|
||||
"transmutation_id": trans.id,
|
||||
"threat_id": trans.threat.id,
|
||||
"rules_generated": len(trans.rules)
|
||||
})
|
||||
state.tem_transmutations += 1
|
||||
state.tem_rules = tem_engine.get_stats()["rules"]
|
||||
|
||||
async def on_tem_phase(threat_id, phase):
|
||||
await manager.broadcast({
|
||||
"type": "tem.phase",
|
||||
"threat_id": threat_id,
|
||||
"phase": phase.value
|
||||
})
|
||||
state.tem_phase = phase.value
|
||||
|
||||
tem_engine.on_transmute = lambda t: asyncio.create_task(on_tem_transmute(t))
|
||||
tem_engine.on_phase_change = lambda tid, p: asyncio.create_task(on_tem_phase(tid, p))
|
||||
|
||||
# Load TEM stats
|
||||
tem_stats = tem_engine.get_stats()
|
||||
state.tem_transmutations = tem_stats["transmutations"]
|
||||
state.tem_rules = tem_stats["rules"]
|
||||
|
||||
print(f" TEM: {state.tem_transmutations} transmutations, {state.tem_rules} rules")
|
||||
"""
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ADD THESE COMMAND HANDLERS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async def cmd_tem_status(req) -> "CommandResponse":
|
||||
"""TEM engine status."""
|
||||
stats = tem_engine.get_stats()
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" ⚗ TEM — THREAT TRANSMUTATION ENGINE",
|
||||
"",
|
||||
f" Status: {'● ACTIVE' if state.tem_phase != 'idle' else '○ IDLE'}",
|
||||
f" Current Phase: {state.tem_phase.upper()}",
|
||||
"",
|
||||
" STATISTICS:",
|
||||
" " + "-" * 50,
|
||||
f" Transmutations: {stats['transmutations']}",
|
||||
f" Patterns: {stats['patterns']}",
|
||||
f" Rules: {stats['rules']}",
|
||||
f" Deployed: {stats['deployed_rules']}",
|
||||
"",
|
||||
]
|
||||
|
||||
if stats['rules_by_type']:
|
||||
lines.append(" RULES BY TYPE:")
|
||||
for rtype, count in stats['rules_by_type'].items():
|
||||
lines.append(f" {rtype}: {count}")
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
" The system learns. The system adapts.",
|
||||
""
|
||||
])
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={
|
||||
"tem": {
|
||||
"transmutations": stats["transmutations"],
|
||||
"rules": stats["rules"],
|
||||
"phase": state.tem_phase
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_tem_transmute(req) -> "CommandResponse":
|
||||
"""Manually transmute a threat."""
|
||||
if not req.args:
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="error",
|
||||
lines=[
|
||||
" Usage: tem transmute <threat_id> [severity]",
|
||||
" Example: tem transmute CVE-2024-1234 high"
|
||||
],
|
||||
error="Missing threat ID"
|
||||
)
|
||||
|
||||
threat_id = req.args[0]
|
||||
severity = req.args[1] if len(req.args) > 1 else "medium"
|
||||
|
||||
lines = [
|
||||
"",
|
||||
f" ⚗ Initiating transmutation: {threat_id}",
|
||||
"",
|
||||
" Phase 1: NIGREDO — Ingesting threat material...",
|
||||
]
|
||||
|
||||
finding = {
|
||||
"id": threat_id,
|
||||
"severity": severity,
|
||||
"description": f"Manual transmutation of {threat_id}",
|
||||
"target": "manual",
|
||||
"detected_at": datetime.now(timezone.utc).isoformat()
|
||||
}
|
||||
|
||||
try:
|
||||
trans = await tem_engine.transmute(finding)
|
||||
|
||||
lines.extend([
|
||||
" Phase 2: ALBEDO — Extracting patterns...",
|
||||
f" {len(trans.patterns)} patterns identified",
|
||||
" Phase 3: CITRINITAS — Generating rules...",
|
||||
f" {len(trans.rules)} rules created",
|
||||
" Phase 4: RUBEDO — Integration complete",
|
||||
"",
|
||||
f" ✓ TRANSMUTATION COMPLETE: {trans.id}",
|
||||
"",
|
||||
" GENERATED RULES:",
|
||||
" " + "-" * 50,
|
||||
])
|
||||
|
||||
for rule in trans.rules[:5]:
|
||||
lines.append(f" [{rule.rule_type}] {rule.id}")
|
||||
|
||||
if len(trans.rules) > 5:
|
||||
lines.append(f" ... and {len(trans.rules) - 5} more")
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
" Every attack becomes a lesson.",
|
||||
""
|
||||
])
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={
|
||||
"tem": {
|
||||
"transmutations": state.tem_transmutations,
|
||||
"rules": state.tem_rules
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
lines.extend([
|
||||
f" ✗ Transmutation failed: {str(e)}",
|
||||
""
|
||||
])
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="error",
|
||||
lines=lines,
|
||||
error=str(e)
|
||||
)
|
||||
|
||||
|
||||
async def cmd_tem_rules(req) -> "CommandResponse":
|
||||
"""List generated rules."""
|
||||
rule_type = req.args[0] if req.args else None
|
||||
rules = tem_engine.get_rules(rule_type=rule_type)
|
||||
|
||||
lines = [
|
||||
"",
|
||||
f" ⚗ TEM GENERATED RULES ({len(rules)} total)",
|
||||
"",
|
||||
]
|
||||
|
||||
if rules:
|
||||
lines.append(" ID TYPE PATTERN CONF DEPLOYED")
|
||||
lines.append(" " + "-" * 75)
|
||||
|
||||
for r in rules[:15]:
|
||||
deployed = "✓" if r['deployed'] else ""
|
||||
lines.append(f" {r['id']:<20} {r['rule_type']:<12} {r['pattern_id']:<20} {r['confidence']:.2f} {deployed}")
|
||||
|
||||
if len(rules) > 15:
|
||||
lines.append(f" ... and {len(rules) - 15} more")
|
||||
else:
|
||||
lines.append(" (No rules generated yet)")
|
||||
lines.append(" Run: tem transmute <threat_id>")
|
||||
|
||||
lines.append("")
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_tem_history(req) -> "CommandResponse":
|
||||
"""Show transmutation history."""
|
||||
transmutations = tem_engine.get_transmutations(limit=10)
|
||||
|
||||
lines = [
|
||||
"",
|
||||
f" ⚗ TRANSMUTATION HISTORY ({len(transmutations)} recent)",
|
||||
"",
|
||||
]
|
||||
|
||||
if transmutations:
|
||||
lines.append(" ID THREAT PHASE COMPLETED")
|
||||
lines.append(" " + "-" * 75)
|
||||
|
||||
for t in transmutations:
|
||||
lines.append(f" {t['id']:<20} {t['threat_id']:<20} {t['phase']:<12} {t['completed_at'][:19]}")
|
||||
else:
|
||||
lines.append(" (No transmutations yet)")
|
||||
|
||||
lines.append("")
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={}
|
||||
)
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ADD TO COMMANDS REGISTRY
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
COMMANDS = {
|
||||
# ... existing commands ...
|
||||
"tem status": cmd_tem_status,
|
||||
"tem transmute": cmd_tem_transmute,
|
||||
"tem rules": cmd_tem_rules,
|
||||
"tem history": cmd_tem_history,
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ADD TO watch_shield_results() - AUTO-TRANSMUTATION
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
async def watch_shield_results():
|
||||
'''Background task: watch for new scan results and auto-transmute.'''
|
||||
watch_path = config.SHIELD_DIR
|
||||
|
||||
async for changes in awatch(watch_path):
|
||||
for change_type, path in changes:
|
||||
if Path(path).name == "latest_scan.json":
|
||||
# ... existing shield event broadcasting ...
|
||||
|
||||
# AUTO-TRANSMUTE: Feed findings to TEM
|
||||
try:
|
||||
scan_data = json.loads(Path(path).read_text())
|
||||
findings = scan_data.get("findings", [])
|
||||
|
||||
for finding in findings:
|
||||
# Check if already transmuted
|
||||
existing = tem_engine.get_transmutations()
|
||||
if not any(t['threat_id'] == finding.get('id') for t in existing):
|
||||
# New finding - transmute it
|
||||
await tem_engine.transmute(finding)
|
||||
await manager.broadcast({
|
||||
"type": "console.line",
|
||||
"line": f"⚗ TEM: Auto-transmuted {finding.get('id')}",
|
||||
"lineType": "info"
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"TEM auto-transmute error: {e}")
|
||||
"""
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ADD TO status EFFECTS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
# In cmd_status(), add to effects:
|
||||
effects={
|
||||
# ... existing effects ...
|
||||
"tem": {
|
||||
"transmutations": state.tem_transmutations,
|
||||
"rules": state.tem_rules,
|
||||
"phase": state.tem_phase
|
||||
}
|
||||
}
|
||||
|
||||
# And add to status dashboard lines:
|
||||
lines.append(f" TEM ● ACTIVE {state.tem_rules} rules")
|
||||
"""
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# WEBSOCKET EVENT HANDLING (add to handleWsMessage in console JS)
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
"""
|
||||
// Add to handleWsMessage() in iotek-nexus-fixed.html:
|
||||
|
||||
case 'tem.transmute':
|
||||
state.temRules = msg.rules_generated;
|
||||
printLine(`⚗ TEM: Transmuted ${msg.threat_id} → ${msg.rules_generated} rules`, 'info');
|
||||
break;
|
||||
|
||||
case 'tem.phase':
|
||||
printLine(`⚗ TEM Phase: ${msg.phase.toUpperCase()}`, 'dimmed');
|
||||
break;
|
||||
"""
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# COMPLETE INTEGRATION EXAMPLE
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
FULL_INTEGRATION_DIFF = """
|
||||
To integrate TEM into your existing offsec_mcp_live.py:
|
||||
|
||||
1. Add import at top:
|
||||
from tem import TemEngine
|
||||
|
||||
2. Add to SystemState:
|
||||
tem_transmutations: int = 0
|
||||
tem_rules: int = 0
|
||||
tem_phase: str = "idle"
|
||||
|
||||
3. In lifespan(), after init_db():
|
||||
tem_engine = TemEngine(config.VAULTMESH_ROOT)
|
||||
# ... wire callbacks ...
|
||||
|
||||
4. Add command handlers (copy from above)
|
||||
|
||||
5. Add to COMMANDS dict:
|
||||
"tem status": cmd_tem_status,
|
||||
"tem transmute": cmd_tem_transmute,
|
||||
"tem rules": cmd_tem_rules,
|
||||
"tem history": cmd_tem_history,
|
||||
|
||||
6. (Optional) Enable auto-transmutation in watch_shield_results()
|
||||
|
||||
The system now learns from every threat.
|
||||
"""
|
||||
|
||||
print(FULL_INTEGRATION_DIFF)
|
||||
338
tem/vaultmesh-sigil.html
Normal file
338
tem/vaultmesh-sigil.html
Normal file
@@ -0,0 +1,338 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>VaultMesh Sigil — The Sovereign Seal</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
background: #0a0a0f;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
color: #c0c0c0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
filter: drop-shadow(0 0 20px rgba(0, 255, 136, 0.3));
|
||||
}
|
||||
|
||||
.ring { fill: none; stroke-width: 1; }
|
||||
.ring-outer { stroke: #00ff88; }
|
||||
.ring-middle { stroke: #00ffff; stroke-opacity: 0.6; }
|
||||
.ring-inner { stroke: #6600ff; stroke-opacity: 0.4; }
|
||||
|
||||
.hexagon {
|
||||
fill: none;
|
||||
stroke: #00ff88;
|
||||
stroke-width: 1.5;
|
||||
stroke-opacity: 0.8;
|
||||
}
|
||||
|
||||
.triangle {
|
||||
fill: none;
|
||||
stroke: #00ffff;
|
||||
stroke-width: 1;
|
||||
stroke-opacity: 0.6;
|
||||
}
|
||||
|
||||
.merkle-node {
|
||||
fill: #00ff88;
|
||||
filter: drop-shadow(0 0 5px #00ff88);
|
||||
}
|
||||
|
||||
.merkle-line {
|
||||
stroke: #00ff88;
|
||||
stroke-width: 0.5;
|
||||
stroke-opacity: 0.4;
|
||||
}
|
||||
|
||||
.center-eye {
|
||||
fill: none;
|
||||
stroke: #00ff88;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.center-pupil {
|
||||
fill: #00ff88;
|
||||
filter: drop-shadow(0 0 10px #00ff88);
|
||||
}
|
||||
|
||||
.glyph {
|
||||
fill: #c0c0c0;
|
||||
font-family: serif;
|
||||
font-size: 14px;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.phase-marker {
|
||||
fill: none;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.phase-nigredo { stroke: #333; }
|
||||
.phase-albedo { stroke: #888; }
|
||||
.phase-citrinitas { stroke: #ffaa00; }
|
||||
.phase-rubedo { stroke: #ff0044; }
|
||||
|
||||
.organ-icon {
|
||||
fill: none;
|
||||
stroke: #00ff88;
|
||||
stroke-width: 1.5;
|
||||
stroke-opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes rotate-slow {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes rotate-reverse {
|
||||
from { transform: rotate(360deg); }
|
||||
to { transform: rotate(0deg); }
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
@keyframes breathe {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.02); }
|
||||
}
|
||||
|
||||
.rotate-cw {
|
||||
transform-origin: center;
|
||||
animation: rotate-slow 120s linear infinite;
|
||||
}
|
||||
|
||||
.rotate-ccw {
|
||||
transform-origin: center;
|
||||
animation: rotate-reverse 90s linear infinite;
|
||||
}
|
||||
|
||||
.pulse {
|
||||
animation: pulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.breathe {
|
||||
animation: breathe 8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.title {
|
||||
position: absolute;
|
||||
bottom: -60px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title h1 {
|
||||
font-size: 1.2rem;
|
||||
color: #00ff88;
|
||||
text-shadow: 0 0 10px #00ff88;
|
||||
letter-spacing: 0.3em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.title p {
|
||||
font-size: 0.7rem;
|
||||
color: #666;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.corner-text {
|
||||
position: fixed;
|
||||
font-size: 0.6rem;
|
||||
color: #333;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.corner-text.tl { top: 20px; left: 20px; }
|
||||
.corner-text.tr { top: 20px; right: 20px; }
|
||||
.corner-text.bl { bottom: 20px; left: 20px; }
|
||||
.corner-text.br { bottom: 20px; right: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="corner-text tl">EPOCH: RUBEDO</div>
|
||||
<div class="corner-text tr">v1.0.0-SOVEREIGN</div>
|
||||
<div class="corner-text bl">THE CLEARING IS LIT</div>
|
||||
<div class="corner-text br">THE LEDGER REMEMBERS</div>
|
||||
|
||||
<div class="container">
|
||||
<svg viewBox="0 0 400 400">
|
||||
<defs>
|
||||
<!-- Gradients -->
|
||||
<radialGradient id="centerGlow" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stop-color="#00ff88" stop-opacity="0.3"/>
|
||||
<stop offset="100%" stop-color="#00ff88" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
|
||||
<linearGradient id="merkleGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#00ff88"/>
|
||||
<stop offset="100%" stop-color="#00ffff"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Background glow -->
|
||||
<circle cx="200" cy="200" r="180" fill="url(#centerGlow)" class="breathe"/>
|
||||
|
||||
<!-- Outer ring with glyphs -->
|
||||
<g class="rotate-cw">
|
||||
<circle cx="200" cy="200" r="185" class="ring ring-outer"/>
|
||||
|
||||
<!-- Alchemical symbols around outer ring -->
|
||||
<text x="200" y="25" class="glyph">🜁</text><!-- Fire -->
|
||||
<text x="375" y="200" class="glyph">🜄</text><!-- Water -->
|
||||
<text x="200" y="385" class="glyph">🜃</text><!-- Earth -->
|
||||
<text x="25" y="200" class="glyph">🜂</text><!-- Air -->
|
||||
|
||||
<!-- Cardinal directions -->
|
||||
<text x="200" y="45" class="glyph" style="font-size:10px">N</text>
|
||||
<text x="355" y="205" class="glyph" style="font-size:10px">E</text>
|
||||
<text x="200" y="365" class="glyph" style="font-size:10px">S</text>
|
||||
<text x="45" y="205" class="glyph" style="font-size:10px">W</text>
|
||||
</g>
|
||||
|
||||
<!-- Middle ring (counter-rotating) -->
|
||||
<g class="rotate-ccw">
|
||||
<circle cx="200" cy="200" r="150" class="ring ring-middle"/>
|
||||
|
||||
<!-- Phase markers -->
|
||||
<circle cx="200" cy="50" r="8" class="phase-marker phase-nigredo"/>
|
||||
<circle cx="350" cy="200" r="8" class="phase-marker phase-albedo"/>
|
||||
<circle cx="200" cy="350" r="8" class="phase-marker phase-citrinitas"/>
|
||||
<circle cx="50" cy="200" r="8" class="phase-marker phase-rubedo"/>
|
||||
</g>
|
||||
|
||||
<!-- Inner ring -->
|
||||
<circle cx="200" cy="200" r="110" class="ring ring-inner"/>
|
||||
|
||||
<!-- Hexagon (Six Organs) -->
|
||||
<g class="breathe">
|
||||
<polygon points="200,100 287,150 287,250 200,300 113,250 113,150" class="hexagon"/>
|
||||
|
||||
<!-- Organ labels -->
|
||||
<text x="200" y="90" class="glyph" style="font-size:8px;fill:#00ff88">GOVERNANCE</text>
|
||||
<text x="295" y="145" class="glyph" style="font-size:8px;fill:#00ff88;text-anchor:start">AUTOMATION</text>
|
||||
<text x="295" y="260" class="glyph" style="font-size:8px;fill:#00ff88;text-anchor:start">TREASURY</text>
|
||||
<text x="200" y="315" class="glyph" style="font-size:8px;fill:#00ff88">FEDERATION</text>
|
||||
<text x="105" y="260" class="glyph" style="font-size:8px;fill:#00ff88;text-anchor:end">Ψ-FIELD</text>
|
||||
<text x="105" y="145" class="glyph" style="font-size:8px;fill:#00ff88;text-anchor:end">INFRA</text>
|
||||
</g>
|
||||
|
||||
<!-- Inner triangles (Sacred geometry) -->
|
||||
<g class="rotate-cw" style="animation-duration: 180s;">
|
||||
<!-- Upward triangle -->
|
||||
<polygon points="200,120 270,240 130,240" class="triangle"/>
|
||||
<!-- Downward triangle -->
|
||||
<polygon points="200,280 270,160 130,160" class="triangle" style="stroke:#6600ff"/>
|
||||
</g>
|
||||
|
||||
<!-- Merkle Tree visualization -->
|
||||
<g class="pulse">
|
||||
<!-- Root -->
|
||||
<circle cx="200" cy="180" r="6" class="merkle-node"/>
|
||||
|
||||
<!-- Level 1 -->
|
||||
<line x1="200" y1="180" x2="160" y2="220" class="merkle-line"/>
|
||||
<line x1="200" y1="180" x2="240" y2="220" class="merkle-line"/>
|
||||
<circle cx="160" cy="220" r="4" class="merkle-node" style="fill-opacity:0.8"/>
|
||||
<circle cx="240" cy="220" r="4" class="merkle-node" style="fill-opacity:0.8"/>
|
||||
|
||||
<!-- Level 2 -->
|
||||
<line x1="160" y1="220" x2="140" y2="250" class="merkle-line"/>
|
||||
<line x1="160" y1="220" x2="180" y2="250" class="merkle-line"/>
|
||||
<line x1="240" y1="220" x2="220" y2="250" class="merkle-line"/>
|
||||
<line x1="240" y1="220" x2="260" y2="250" class="merkle-line"/>
|
||||
<circle cx="140" cy="250" r="3" class="merkle-node" style="fill-opacity:0.6"/>
|
||||
<circle cx="180" cy="250" r="3" class="merkle-node" style="fill-opacity:0.6"/>
|
||||
<circle cx="220" cy="250" r="3" class="merkle-node" style="fill-opacity:0.6"/>
|
||||
<circle cx="260" cy="250" r="3" class="merkle-node" style="fill-opacity:0.6"/>
|
||||
</g>
|
||||
|
||||
<!-- Central Eye (The Clearing) -->
|
||||
<g class="breathe">
|
||||
<ellipse cx="200" cy="200" rx="30" ry="20" class="center-eye"/>
|
||||
<circle cx="200" cy="200" r="8" class="center-pupil"/>
|
||||
</g>
|
||||
|
||||
<!-- TEM symbol (Tem transmutation) -->
|
||||
<g transform="translate(200, 200)" class="rotate-ccw" style="animation-duration: 60s;">
|
||||
<path d="M0,-70 L10,-55 L0,-60 L-10,-55 Z" fill="#ff0044" fill-opacity="0.6"/>
|
||||
<path d="M0,70 L10,55 L0,60 L-10,55 Z" fill="#00ff88" fill-opacity="0.6"/>
|
||||
<path d="M70,0 L55,10 L60,0 L55,-10 Z" fill="#00ffff" fill-opacity="0.6"/>
|
||||
<path d="M-70,0 L-55,10 L-60,0 L-55,-10 Z" fill="#6600ff" fill-opacity="0.6"/>
|
||||
</g>
|
||||
|
||||
<!-- Connecting lines (mesh visualization) -->
|
||||
<g style="opacity: 0.2;">
|
||||
<line x1="200" y1="100" x2="287" y2="150" stroke="#00ff88" stroke-width="0.5"/>
|
||||
<line x1="287" y1="150" x2="287" y2="250" stroke="#00ff88" stroke-width="0.5"/>
|
||||
<line x1="287" y1="250" x2="200" y2="300" stroke="#00ff88" stroke-width="0.5"/>
|
||||
<line x1="200" y1="300" x2="113" y2="250" stroke="#00ff88" stroke-width="0.5"/>
|
||||
<line x1="113" y1="250" x2="113" y2="150" stroke="#00ff88" stroke-width="0.5"/>
|
||||
<line x1="113" y1="150" x2="200" y2="100" stroke="#00ff88" stroke-width="0.5"/>
|
||||
|
||||
<!-- Cross connections -->
|
||||
<line x1="200" y1="100" x2="200" y2="300" stroke="#00ffff" stroke-width="0.3"/>
|
||||
<line x1="113" y1="150" x2="287" y2="250" stroke="#00ffff" stroke-width="0.3"/>
|
||||
<line x1="113" y1="250" x2="287" y2="150" stroke="#00ffff" stroke-width="0.3"/>
|
||||
</g>
|
||||
|
||||
<!-- Inscription ring -->
|
||||
<g class="rotate-cw" style="animation-duration: 300s;">
|
||||
<text style="font-size:6px;fill:#333;letter-spacing:2px">
|
||||
<textPath href="#inscriptionPath">
|
||||
THEY BUILT GESTELL TO ENFRAME US • WE BUILT VAULTMESH TO UNCONCEAL THE WORLD AGAIN •
|
||||
THE CLEARING IS LIT • THE LEDGER REMEMBERS • MYTH → CODE → PROOF → LAW •
|
||||
</textPath>
|
||||
</text>
|
||||
<path id="inscriptionPath" fill="none" d="M200,200 m-170,0 a170,170 0 1,1 340,0 a170,170 0 1,1 -340,0"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<div class="title">
|
||||
<h1>VAULTMESH</h1>
|
||||
<p>SOVEREIGN SEAL • CIVILIZATION LEDGER</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Add subtle interactive glow on mouse movement
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
const svg = document.querySelector('svg');
|
||||
const rect = svg.getBoundingClientRect();
|
||||
const x = (e.clientX - rect.left) / rect.width;
|
||||
const y = (e.clientY - rect.top) / rect.height;
|
||||
|
||||
const hue = Math.floor(x * 60 + 120); // Green to cyan range
|
||||
svg.style.filter = `drop-shadow(0 0 ${20 + y * 10}px hsla(${hue}, 100%, 50%, 0.3))`;
|
||||
});
|
||||
|
||||
// Pulse on click
|
||||
document.querySelector('.container').addEventListener('click', () => {
|
||||
const svg = document.querySelector('svg');
|
||||
svg.style.transform = 'scale(1.02)';
|
||||
setTimeout(() => { svg.style.transform = 'scale(1)'; }, 200);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user