akasa 0.1.1__tar.gz

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.
akasa-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: akasa
3
+ Version: 0.1.1
4
+ Summary: Agnostic Volume Router and Event Bus Substrate.
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: Flask>=3.0.0
8
+ Requires-Dist: cryptography>=41.0.0
9
+
10
+ # 🌌 Akasa: Application Kernel & Volume Router
11
+
12
+ **Akasa** (Sanskrit for *Ether / Substrate / Space*) is a local-first, event-sourced Python micro-kernel.
13
+
14
+ Extracted from the [inSetu Developer OS](https://github.com/Callosemic/insetu), Akasa acts as the foundational substrate for multi-tenant, offline-first Python applications. It is strictly domain-agnostic: it knows nothing about your application's business logic, acting purely as a high-performance routing and synchronization engine.
15
+
16
+ ## ✨ Core Mechanics
17
+
18
+ 1. **The Volume Router (VFS):** An asynchronous, non-blocking Virtual File System. It abstracts physical disk I/O behind a strict Mount Table, allowing host applications to mount sandboxed repositories and virtual domains to unified URIs (e.g., `vfs://` or `ctx://`).
19
+ 2. **Stateless Multi-Tenancy:** All databases, caches, and file resolutions are scoped to an active `workspace_id`, allowing a single daemon process to serve multiple isolated tenant environments safely.
20
+ 3. **The Typed Event Bus:** A synchronous/asynchronous `HookRegistry` enforcing strict authorization boundaries for inter-module communication.
21
+ 4. **The Metronome (Worker Engine):** A background SQLite-backed job ledger (`jobs` and `immediate_jobs`) providing distributed, dependency-driven task execution and UI telemetry without blocking the main event loop.
22
+ 5. **SQLite WAL Connection Pooling:** Thread-local, auto-evicting database connection pooling explicitly optimized for Write-Ahead Logging concurrency.
23
+
24
+ ## 🏗️ Architecture Mandate
25
+
26
+ Akasa adheres to the **Blind Substrate Mandate**.
27
+ * **Zero Domain Logic:** Akasa does not parse target repositories, compile RAG contexts, or understand Git diffs. It only provides the tools to store and route them.
28
+ * **Inversion of Control:** All application-specific behavior is injected into Akasa by the host application via `@hooks.on()` subscriptions, Driver registrations, and Volume mounts.
29
+
30
+ ## 🚀 Installation
31
+
32
+ Akasa is designed to be installed as a foundational dependency for your host application.
33
+
34
+ ```bash
35
+ pip install akasa
36
+
37
+ ```
akasa-0.1.1/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # 🌌 Akasa: Application Kernel & Volume Router
2
+
3
+ **Akasa** (Sanskrit for *Ether / Substrate / Space*) is a local-first, event-sourced Python micro-kernel.
4
+
5
+ Extracted from the [inSetu Developer OS](https://github.com/Callosemic/insetu), Akasa acts as the foundational substrate for multi-tenant, offline-first Python applications. It is strictly domain-agnostic: it knows nothing about your application's business logic, acting purely as a high-performance routing and synchronization engine.
6
+
7
+ ## ✨ Core Mechanics
8
+
9
+ 1. **The Volume Router (VFS):** An asynchronous, non-blocking Virtual File System. It abstracts physical disk I/O behind a strict Mount Table, allowing host applications to mount sandboxed repositories and virtual domains to unified URIs (e.g., `vfs://` or `ctx://`).
10
+ 2. **Stateless Multi-Tenancy:** All databases, caches, and file resolutions are scoped to an active `workspace_id`, allowing a single daemon process to serve multiple isolated tenant environments safely.
11
+ 3. **The Typed Event Bus:** A synchronous/asynchronous `HookRegistry` enforcing strict authorization boundaries for inter-module communication.
12
+ 4. **The Metronome (Worker Engine):** A background SQLite-backed job ledger (`jobs` and `immediate_jobs`) providing distributed, dependency-driven task execution and UI telemetry without blocking the main event loop.
13
+ 5. **SQLite WAL Connection Pooling:** Thread-local, auto-evicting database connection pooling explicitly optimized for Write-Ahead Logging concurrency.
14
+
15
+ ## 🏗️ Architecture Mandate
16
+
17
+ Akasa adheres to the **Blind Substrate Mandate**.
18
+ * **Zero Domain Logic:** Akasa does not parse target repositories, compile RAG contexts, or understand Git diffs. It only provides the tools to store and route them.
19
+ * **Inversion of Control:** All application-specific behavior is injected into Akasa by the host application via `@hooks.on()` subscriptions, Driver registrations, and Volume mounts.
20
+
21
+ ## 🚀 Installation
22
+
23
+ Akasa is designed to be installed as a foundational dependency for your host application.
24
+
25
+ ```bash
26
+ pip install akasa
27
+
28
+ ```
@@ -0,0 +1,151 @@
1
+ import os
2
+ import json
3
+ import socket
4
+ import secrets
5
+ from flask import Blueprint, request, jsonify
6
+ from akasa.utils import load_config, save_json_config, get_workspace_physics
7
+ from akasa.extension import AkasaExtension
8
+ auth_bp = Blueprint('auth', __name__)
9
+ def get_master_key():
10
+ import os
11
+ import shutil
12
+ from akasa.utils import _cwd
13
+ from pathlib import Path
14
+
15
+ control_dir_name = os.environ.get("AKASA_CONTROL_DIR", ".akasa")
16
+ global_key_path = Path.home().joinpath(control_dir_name, "master_key.txt")
17
+ local_key_path = Path(_cwd).joinpath(control_dir_name, "master_key.txt")
18
+
19
+ # Safe Migration: If a legacy local key exists...
20
+ if local_key_path.exists() and os.path.getsize(local_key_path) > 0:
21
+ # If no global key exists yet, elevate this local key to be the global key
22
+ if not global_key_path.exists():
23
+ global_key_path.parent.mkdir(parents=True, exist_ok=True)
24
+ shutil.move(local_key_path.as_posix(), global_key_path.as_posix())
25
+ return global_key_path.read_bytes()
26
+ else:
27
+ # A global key already exists. This local key is different.
28
+ # We MUST keep using the local one here so we don't brick this specific workspace's secrets.
29
+ return local_key_path.read_bytes()
30
+ # Standard Global Key Generation/Loading
31
+ if not global_key_path.exists() or os.path.getsize(global_key_path) == 0:
32
+ from cryptography.fernet import Fernet
33
+ from akasa.vfs import execute_vfs_save
34
+ key = Fernet.generate_key()
35
+ execute_vfs_save("default", global_key_path.as_posix(), key.decode('utf-8'), data={"is_absolute_artifact": True, "ignore_ledger": True})
36
+ return key
37
+
38
+ return global_key_path.read_bytes()
39
+
40
+ def encrypt_secret(val: str) -> str:
41
+ if not val: return val
42
+ from cryptography.fernet import Fernet
43
+ f = Fernet(get_master_key())
44
+ return "v1:" + f.encrypt(val.encode('utf-8')).decode('utf-8')
45
+
46
+ def decrypt_secret(val: str) -> str:
47
+ if not val or not val.startswith("v1:"):
48
+ return val
49
+ from cryptography.fernet import Fernet
50
+ f = Fernet(get_master_key())
51
+ try:
52
+ return f.decrypt(val[3:].encode('utf-8')).decode('utf-8')
53
+ except Exception:
54
+ return ""
55
+ security_bp = AkasaExtension(
56
+ 'security', __name__, title="Security & Encryption",
57
+ description="Local encryption key management.",
58
+ core=True,
59
+ settings_schema=lambda ws: [{
60
+ "id": "master_fernet_key",
61
+ "label": "Master Encryption Key (Fernet)",
62
+ "type": "text",
63
+ "scope": "daemon",
64
+ "secure": False,
65
+ "default": get_master_key().decode('utf-8'),
66
+ "description": "This global key encrypts your secrets.json. It is stored securely in your user home directory. If you move this workspace to another machine, you must copy this key to the new machine."
67
+ }]
68
+ )
69
+ @security_bp.route('settings', methods=['POST'])
70
+ def update_security_settings(ctx):
71
+ data = ctx.req.json or {}
72
+ new_key = data.get("master_fernet_key")
73
+ if new_key:
74
+ import os
75
+ from pathlib import Path
76
+ from akasa.utils import _cwd
77
+ control_dir_name = os.environ.get("AKASA_CONTROL_DIR", ".akasa")
78
+ global_key_path = Path.home().joinpath(control_dir_name, "master_key.txt")
79
+ local_key_path = Path(_cwd).joinpath(control_dir_name, "master_key.txt")
80
+ # If a local legacy key exists, update that one to avoid breaking state, otherwise update global
81
+ target_path = local_key_path if local_key_path.exists() else global_key_path
82
+ from akasa.vfs import execute_vfs_save
83
+ execute_vfs_save(ctx.workspace_id, target_path.as_posix(), new_key, data={"is_absolute_artifact": True, "ignore_ledger": True})
84
+
85
+ return {"status": "success", "requires_refresh": False}
86
+ # Generate a cryptographically sound scrolling runtime session token
87
+ # Anchor to the environment so it survives os.execv() and Werkzeug hot-reloads
88
+ BOOT_TOKEN = os.environ.get("AKASA_BOOT_TOKEN")
89
+ if not BOOT_TOKEN:
90
+ BOOT_TOKEN = secrets.token_hex(16)
91
+ os.environ["AKASA_BOOT_TOKEN"] = BOOT_TOKEN
92
+ @auth_bp.route('/auth/bootstrap', methods=['POST'])
93
+ def bootstrap():
94
+ """Unauthenticated token exchange gate supporting absolute dynamic fallback routing."""
95
+ data = request.json or {}
96
+
97
+ # Extract real IP if behind Tailscale Serve or a Reverse Proxy
98
+ client_ip = request.headers.get('X-Forwarded-For', request.remote_addr).split(',')[0].strip()
99
+ # --- ROUTE A: LOCALHOST BYPASS ---
100
+ # If the user is physically on the machine, auto-authenticate
101
+ if client_ip == '127.0.0.1':
102
+ # Check for cross-origin browser requests (Localhost Drive-By CSRF prevention)
103
+ origin = request.headers.get('Origin', '')
104
+ referer = request.headers.get('Referer', '')
105
+
106
+ import urllib.parse
107
+ def is_allowed(url_str):
108
+ try:
109
+ hostname = urllib.parse.urlparse(url_str).hostname or ""
110
+ return hostname in ['127.0.0.1', 'localhost'] or hostname.endswith('.ts.net')
111
+ except Exception:
112
+ return False
113
+
114
+ if origin and not is_allowed(origin):
115
+ return jsonify({"error": "Forbidden: Cross-origin request blocked"}), 403
116
+ if referer and not is_allowed(referer):
117
+ return jsonify({"error": "Forbidden: Cross-origin request blocked"}), 403
118
+
119
+ return jsonify({
120
+ "status": "authenticated",
121
+ "token": BOOT_TOKEN,
122
+ "method": "localhost"
123
+ })
124
+
125
+ cfg = load_config()
126
+ # --- ROUTE B: INVERSION OF CONTROL (Zero-Knowledge Identity Protocols) ---
127
+ from akasa.hooks import hooks
128
+ for res in hooks.emit('execute_identity_handshake', request=request, client_ip=client_ip, config=cfg):
129
+ if res and isinstance(res, dict) and res.get("status") == "authenticated":
130
+ return jsonify({
131
+ "status": "authenticated",
132
+ "token": BOOT_TOKEN,
133
+ "method": res.get("method", "hook"),
134
+ "user": res.get("user")
135
+ })
136
+
137
+ # --- ROUTE C: PERSISTENT CONFIG TOKEN CHECK ---
138
+ client_token = data.get("token")
139
+ system_token = cfg.get("auth_token")
140
+
141
+ if system_token and client_token == system_token:
142
+ return jsonify({
143
+ "status": "authenticated",
144
+ "token": BOOT_TOKEN,
145
+ "method": "static_config"
146
+ })
147
+
148
+ return jsonify({
149
+ "status": "challenge",
150
+ "message": "Authentication required."
151
+ }), 401
@@ -0,0 +1,139 @@
1
+ from pathlib import Path
2
+ import os
3
+ import sqlite3
4
+ import threading
5
+ from akasa.utils import get_workspace_physics
6
+ from akasa.hooks import hooks
7
+
8
+ # Thread-local storage guarantees safe connection pooling across the ASGI / Worker matrix
9
+ _local = threading.local()
10
+
11
+ _REGISTERED_SCHEMAS = {}
12
+
13
+ def register_schema(ext_name, schema_dict):
14
+ """Registers a declarative SQLite schema for automatic workspace migration."""
15
+ _REGISTERED_SCHEMAS[ext_name] = schema_dict
16
+
17
+ def apply_declarative_schema(db_name, schema_dict, workspace_id=None):
18
+ """Generates CREATE TABLE and executes ALTER TABLE ADD COLUMN migrations via diffing."""
19
+ conn = get_connection(db_name, workspace_id)
20
+ for table_name, columns in schema_dict.items():
21
+ # 1. Generate CREATE TABLE
22
+ col_defs = ", ".join([f"{col} {dtype}" for col, dtype in columns.items()])
23
+ conn.execute(f"CREATE TABLE IF NOT EXISTS {table_name} ({col_defs})")
24
+
25
+ # 2. Diff columns and ALTER TABLE
26
+ cursor = conn.execute(f"PRAGMA table_info({table_name})")
27
+ existing_cols = {row['name'] for row in cursor.fetchall()}
28
+
29
+ for col, dtype in columns.items():
30
+ if col not in existing_cols:
31
+ try:
32
+ conn.execute(f"ALTER TABLE {table_name} ADD COLUMN {col} {dtype}")
33
+ except Exception as e:
34
+ print(f"⚠️ Auto-migration failed for {table_name}.{col}: {e}")
35
+ conn.commit()
36
+ # Register core worker database schema for tracking all file deltas contextually
37
+ register_schema('workers', {
38
+ 'vfs_event_log': {
39
+ 'filepath': 'TEXT PRIMARY KEY',
40
+ 'mutation_type': 'TEXT',
41
+ 'timestamp': 'REAL'
42
+ }
43
+ })
44
+ @hooks.on('system_boot', priority=90)
45
+ def init_declarative_schemas(**kwargs):
46
+ """Automatically provisions schemas and boots workspaces across all tenants."""
47
+ from akasa.utils import get_all_workspace_ids
48
+ for ws_id in get_all_workspace_ids():
49
+ for ext_name, schema in _REGISTERED_SCHEMAS.items():
50
+ apply_declarative_schema(ext_name, schema, ws_id)
51
+ hooks.emit('workspace_boot', workspace_id=ws_id)
52
+
53
+ @hooks.on('workspace_shutdown')
54
+ def close_workspace_connections(workspace_id=None, **kwargs):
55
+ """Evicts and closes thread-local SQLite connections for an unmounting tenant workspace."""
56
+ if not workspace_id or not hasattr(_local, 'connections'):
57
+ return
58
+ keys_to_close = [k for k in _local.connections.keys() if k[0] == workspace_id]
59
+ for key in keys_to_close:
60
+ try:
61
+ _local.connections[key].close()
62
+ except Exception:
63
+ pass
64
+ del _local.connections[key]
65
+ def get_connection(db_name, workspace_id=None):
66
+ """
67
+ Returns a thread-local SQLite connection.
68
+ Keys connection by (workspace_id, db_name) to support stateless multi-tenancy.
69
+ Strictly enforces WAL mode and busy timeouts to prevent concurrent database locks.
70
+ """
71
+ if not hasattr(_local, 'connections'):
72
+ _local.connections = {}
73
+ if not workspace_id:
74
+ from akasa.utils import sniff_tenant_id
75
+ workspace_id = sniff_tenant_id()
76
+
77
+ # Key the connection by tenant
78
+ cache_key = (workspace_id, db_name)
79
+
80
+ # True LRU: Pop and re-insert to move the accessed key to the end of the dictionary
81
+ if cache_key in _local.connections:
82
+ conn = _local.connections.pop(cache_key)
83
+ _local.connections[cache_key] = conn
84
+ return conn
85
+
86
+ cfg_path, _ = get_workspace_physics(workspace_id)
87
+ db_dir = Path(cfg_path).parent.joinpath("ext", db_name, "db")
88
+ db_path = db_dir.joinpath(f"{db_name}.db").as_posix()
89
+
90
+ # Phase 3: LRU Eviction Policy (Max 5 Workspaces to prevent WAL lock exhaustion)
91
+ if len(_local.connections) >= 5:
92
+ oldest_key = list(_local.connections.keys())[0]
93
+ try:
94
+ _local.connections[oldest_key].close()
95
+ except Exception: pass
96
+ del _local.connections[oldest_key]
97
+ os.makedirs(db_dir, exist_ok=True)
98
+
99
+ def _connect():
100
+ conn = sqlite3.connect(db_path, check_same_thread=False)
101
+ conn.row_factory = sqlite3.Row
102
+ conn.execute("PRAGMA journal_mode=WAL;")
103
+ conn.execute("PRAGMA synchronous=NORMAL;")
104
+ conn.execute("PRAGMA busy_timeout=5000;")
105
+ conn.commit()
106
+ cursor = conn.execute("PRAGMA quick_check(1);")
107
+ res = cursor.fetchone()
108
+ if res and res[0] != "ok":
109
+ raise sqlite3.DatabaseError(f"Database disk image is malformed: {res[0]}")
110
+ return conn
111
+
112
+ try:
113
+ conn = _connect()
114
+ except sqlite3.DatabaseError as e:
115
+ if "malformed" in str(e).lower() or "corrupt" in str(e).lower():
116
+ print(f"⚠️ [Akasa DB] Malformed database detected at '{db_path}'. Healing database...")
117
+ try:
118
+ sqlite3.connect(db_path).close()
119
+ except Exception:
120
+ pass
121
+ import time, shutil
122
+ corrupt_path = f"{db_path}.corrupt_{int(time.time())}"
123
+ try:
124
+ if os.path.exists(db_path):
125
+ shutil.move(db_path, corrupt_path)
126
+ for ext in ["-wal", "-shm"]:
127
+ if os.path.exists(db_path + ext):
128
+ os.remove(db_path + ext)
129
+ except Exception as move_err:
130
+ print(f"⚠️ [Akasa DB] Failed to move corrupt db: {move_err}")
131
+
132
+ conn = _connect()
133
+ if db_name in _REGISTERED_SCHEMAS:
134
+ apply_declarative_schema(db_name, _REGISTERED_SCHEMAS[db_name], workspace_id)
135
+ else:
136
+ raise
137
+
138
+ _local.connections[cache_key] = conn
139
+ return conn
@@ -0,0 +1,31 @@
1
+ import threading
2
+ import queue
3
+ import json
4
+
5
+ class EventBus:
6
+ def __init__(self):
7
+ self.listeners = []
8
+ self.lock = threading.Lock()
9
+
10
+ def subscribe(self):
11
+ q = queue.Queue(maxsize=100)
12
+ with self.lock:
13
+ self.listeners.append(q)
14
+ return q
15
+
16
+ def unsubscribe(self, q):
17
+ with self.lock:
18
+ if q in self.listeners:
19
+ self.listeners.remove(q)
20
+
21
+ def emit_sse(self, event_type: str, payload: dict):
22
+ msg = f"event: {event_type}\ndata: {json.dumps(payload)}\n\n"
23
+ with self.lock:
24
+ for q in self.listeners:
25
+ try:
26
+ q.put_nowait(msg)
27
+ except queue.Full:
28
+ pass
29
+
30
+ # Global SSE Publisher
31
+ sse_bus = EventBus()