diff --git a/@eaDir/get_logs.py@SynoEAStream b/@eaDir/get_logs.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/get_logs.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/list_images.py@SynoEAStream b/@eaDir/list_images.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/list_images.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/list_stacks.py@SynoEAStream b/@eaDir/list_stacks.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/list_stacks.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/patch_container.py@SynoEAStream b/@eaDir/patch_container.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/patch_container.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/rebuild_check.py@SynoEAStream b/@eaDir/rebuild_check.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/rebuild_check.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/rebuild_via_portainer.py@SynoEAStream b/@eaDir/rebuild_via_portainer.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/rebuild_via_portainer.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/restart_container.py@SynoEAStream b/@eaDir/restart_container.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/restart_container.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/run_git.py@SynoEAStream b/@eaDir/run_git.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/run_git.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/update_stack.py@SynoEAStream b/@eaDir/update_stack.py@SynoEAStream deleted file mode 100644 index 1ca6728..0000000 Binary files a/@eaDir/update_stack.py@SynoEAStream and /dev/null differ diff --git a/@eaDir/get_alpine_logs.py@SynoEAStream b/@eaDir/walkthrough.1.md@SynoEAStream similarity index 100% rename from @eaDir/get_alpine_logs.py@SynoEAStream rename to @eaDir/walkthrough.1.md@SynoEAStream diff --git a/build.log b/build.log deleted file mode 100644 index 54ac94e..0000000 --- a/build.log +++ /dev/null @@ -1,154 +0,0 @@ -time="2026-06-24T22:08:44Z" level=warning msg="/workspace/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion" -time="2026-06-24T22:08:44Z" level=warning msg="Docker Compose requires buildx plugin to be installed" - Image workspace-context-hub Building - Image workspace-context-hub Building -Sending build context to Docker daemon 524.4kB Sending build context to Docker daemon 1.049MB Sending build context to Docker daemon 1.573MB Sending build context to Docker daemon 1.736MB -Step 1/11 : FROM python:3.11-slim - ---> a8a3e0a84b0d -Step 2/11 : WORKDIR /app - ---> Using cache - ---> af6f13d9fd7f -Step 3/11 : ENV PYTHONDONTWRITEBYTECODE=1 - ---> Using cache - ---> 57fad6d4b376 -Step 4/11 : ENV PYTHONUNBUFFERED=1 - ---> Using cache - ---> 4b030cb01fd7 -Step 5/11 : COPY requirements.txt . - ---> Using cache - ---> 8b61f7ebf9c8 -Step 6/11 : RUN pip install --no-cache-dir -r requirements.txt - ---> Running in b7f8db2149b9 -Collecting fastapi>=0.109.2 (from -r requirements.txt (line 1)) - Downloading fastapi-0.138.0-py3-none-any.whl.metadata (27 kB) -Collecting uvicorn>=0.27.0 (from -r requirements.txt (line 2)) - Downloading uvicorn-0.49.0-py3-none-any.whl.metadata (6.7 kB) -Collecting aiosqlite>=0.19.0 (from -r requirements.txt (line 3)) - Downloading aiosqlite-0.22.1-py3-none-any.whl.metadata (4.3 kB) -Collecting PyJWT>=2.8.0 (from -r requirements.txt (line 4)) - Downloading pyjwt-2.13.0-py3-none-any.whl.metadata (3.4 kB) -Collecting jinja2>=3.1.3 (from -r requirements.txt (line 5)) - Downloading jinja2-3.1.6-py3-none-any.whl.metadata (2.9 kB) -Collecting python-multipart>=0.0.9 (from -r requirements.txt (line 6)) - Downloading python_multipart-0.0.32-py3-none-any.whl.metadata (2.1 kB) -Collecting mcp>=1.2.0 (from -r requirements.txt (line 7)) - Downloading mcp-1.28.0-py3-none-any.whl.metadata (9.4 kB) -Collecting python-dotenv>=1.0.1 (from -r requirements.txt (line 8)) - Downloading python_dotenv-1.2.2-py3-none-any.whl.metadata (27 kB) -Collecting starlette>=0.46.0 (from fastapi>=0.109.2->-r requirements.txt (line 1)) - Downloading starlette-1.3.1-py3-none-any.whl.metadata (6.4 kB) -Collecting pydantic>=2.9.0 (from fastapi>=0.109.2->-r requirements.txt (line 1)) - Downloading pydantic-2.13.4-py3-none-any.whl.metadata (109 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 109.4/109.4 kB 1.0 MB/s eta 0:00:00 -Collecting typing-extensions>=4.8.0 (from fastapi>=0.109.2->-r requirements.txt (line 1)) - Downloading typing_extensions-4.15.0-py3-none-any.whl.metadata (3.3 kB) -Collecting typing-inspection>=0.4.2 (from fastapi>=0.109.2->-r requirements.txt (line 1)) - Downloading typing_inspection-0.4.2-py3-none-any.whl.metadata (2.6 kB) -Collecting annotated-doc>=0.0.2 (from fastapi>=0.109.2->-r requirements.txt (line 1)) - Downloading annotated_doc-0.0.4-py3-none-any.whl.metadata (6.6 kB) -Collecting click>=7.0 (from uvicorn>=0.27.0->-r requirements.txt (line 2)) - Downloading click-8.4.2-py3-none-any.whl.metadata (2.6 kB) -Collecting h11>=0.8 (from uvicorn>=0.27.0->-r requirements.txt (line 2)) - Downloading h11-0.16.0-py3-none-any.whl.metadata (8.3 kB) -Collecting MarkupSafe>=2.0 (from jinja2>=3.1.3->-r requirements.txt (line 5)) - Downloading markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (2.7 kB) -Collecting anyio>=4.5 (from mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading anyio-4.14.1-py3-none-any.whl.metadata (4.6 kB) -Collecting httpx-sse>=0.4 (from mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading httpx_sse-0.4.3-py3-none-any.whl.metadata (9.7 kB) -Collecting httpx<1.0.0,>=0.27.1 (from mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading httpx-0.28.1-py3-none-any.whl.metadata (7.1 kB) -Collecting jsonschema>=4.20.0 (from mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading jsonschema-4.26.0-py3-none-any.whl.metadata (7.6 kB) -Collecting pydantic-settings>=2.5.2 (from mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading pydantic_settings-2.14.2-py3-none-any.whl.metadata (3.4 kB) -Collecting sse-starlette>=1.6.1 (from mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading sse_starlette-3.4.5-py3-none-any.whl.metadata (15 kB) -Collecting idna>=2.8 (from anyio>=4.5->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading idna-3.18-py3-none-any.whl.metadata (6.1 kB) -Collecting certifi (from httpx<1.0.0,>=0.27.1->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading certifi-2026.6.17-py3-none-any.whl.metadata (2.5 kB) -Collecting httpcore==1.* (from httpx<1.0.0,>=0.27.1->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading httpcore-1.0.9-py3-none-any.whl.metadata (21 kB) -Collecting attrs>=22.2.0 (from jsonschema>=4.20.0->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading attrs-26.1.0-py3-none-any.whl.metadata (8.8 kB) -Collecting jsonschema-specifications>=2023.03.6 (from jsonschema>=4.20.0->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl.metadata (2.9 kB) -Collecting referencing>=0.28.4 (from jsonschema>=4.20.0->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading referencing-0.37.0-py3-none-any.whl.metadata (2.8 kB) -Collecting rpds-py>=0.25.0 (from jsonschema>=4.20.0->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading rpds_py-2026.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.1 kB) -Collecting annotated-types>=0.6.0 (from pydantic>=2.9.0->fastapi>=0.109.2->-r requirements.txt (line 1)) - Downloading annotated_types-0.7.0-py3-none-any.whl.metadata (15 kB) -Collecting pydantic-core==2.46.4 (from pydantic>=2.9.0->fastapi>=0.109.2->-r requirements.txt (line 1)) - Downloading pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB) -Collecting cryptography>=3.4.0 (from pyjwt[crypto]>=2.10.1->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading cryptography-49.0.0-cp311-abi3-manylinux_2_34_x86_64.whl.metadata (4.3 kB) -Collecting cffi>=2.0.0 (from cryptography>=3.4.0->pyjwt[crypto]>=2.10.1->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (2.6 kB) -Collecting pycparser (from cffi>=2.0.0->cryptography>=3.4.0->pyjwt[crypto]>=2.10.1->mcp>=1.2.0->-r requirements.txt (line 7)) - Downloading pycparser-3.0-py3-none-any.whl.metadata (8.2 kB) -Downloading fastapi-0.138.0-py3-none-any.whl (126 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 126.8/126.8 kB 1.2 MB/s eta 0:00:00 -Downloading uvicorn-0.49.0-py3-none-any.whl (71 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 71.4/71.4 kB 1.4 MB/s eta 0:00:00 -Downloading aiosqlite-0.22.1-py3-none-any.whl (17 kB) -Downloading pyjwt-2.13.0-py3-none-any.whl (31 kB) -Downloading jinja2-3.1.6-py3-none-any.whl (134 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 134.9/134.9 kB 1.5 MB/s eta 0:00:00 -Downloading python_multipart-0.0.32-py3-none-any.whl (30 kB) -Downloading mcp-1.28.0-py3-none-any.whl (221 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 222.0/222.0 kB 1.7 MB/s eta 0:00:00 -Downloading python_dotenv-1.2.2-py3-none-any.whl (22 kB) -Downloading annotated_doc-0.0.4-py3-none-any.whl (5.3 kB) -Downloading anyio-4.14.1-py3-none-any.whl (124 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 124.9/124.9 kB 610.4 kB/s eta 0:00:00 -Downloading click-8.4.2-py3-none-any.whl (119 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 119.2/119.2 kB 234.8 kB/s eta 0:00:00 -Downloading h11-0.16.0-py3-none-any.whl (37 kB) -Downloading httpx-0.28.1-py3-none-any.whl (73 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 73.5/73.5 kB 240.6 kB/s eta 0:00:00 -Downloading httpcore-1.0.9-py3-none-any.whl (78 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 78.8/78.8 kB 437.1 kB/s eta 0:00:00 -Downloading httpx_sse-0.4.3-py3-none-any.whl (9.0 kB) -Downloading jsonschema-4.26.0-py3-none-any.whl (90 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 90.6/90.6 kB 578.4 kB/s eta 0:00:00 -Downloading markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB) -Downloading pydantic-2.13.4-py3-none-any.whl (472 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 472.3/472.3 kB 949.9 kB/s eta 0:00:00 -Downloading pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.1/2.1 MB 625.1 kB/s eta 0:00:00 -Downloading pydantic_settings-2.14.2-py3-none-any.whl (61 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.7/61.7 kB 113.8 MB/s eta 0:00:00 -Downloading sse_starlette-3.4.5-py3-none-any.whl (16 kB) -Downloading starlette-1.3.1-py3-none-any.whl (73 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 73.6/73.6 kB 1.8 MB/s eta 0:00:00 -Downloading typing_extensions-4.15.0-py3-none-any.whl (44 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 44.6/44.6 kB 1.3 MB/s eta 0:00:00 -Downloading typing_inspection-0.4.2-py3-none-any.whl (14 kB) -Downloading annotated_types-0.7.0-py3-none-any.whl (13 kB) -Downloading attrs-26.1.0-py3-none-any.whl (67 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 67.5/67.5 kB 874.8 kB/s eta 0:00:00 -Downloading cryptography-49.0.0-cp311-abi3-manylinux_2_34_x86_64.whl (4.7 MB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.7/4.7 MB 546.3 kB/s eta 0:00:00 -Downloading idna-3.18-py3-none-any.whl (65 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 65.5/65.5 kB 1.8 MB/s eta 0:00:00 -Downloading jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB) -Downloading referencing-0.37.0-py3-none-any.whl (26 kB) -Downloading rpds_py-2026.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (378 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 378.0/378.0 kB 2.1 MB/s eta 0:00:00 -Downloading certifi-2026.6.17-py3-none-any.whl (133 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.3/133.3 kB 2.6 MB/s eta 0:00:00 -Downloading cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (215 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 215.6/215.6 kB 2.5 MB/s eta 0:00:00 -Downloading pycparser-3.0-py3-none-any.whl (48 kB) - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 48.2/48.2 kB 4.1 MB/s eta 0:00:00 -Installing collected packages: typing-extensions, rpds-py, python-multipart, python-dotenv, PyJWT, pycparser, MarkupSafe, idna, httpx-sse, h11, click, certifi, attrs, annotated-types, annotated-doc, aiosqlite, uvicorn, typing-inspection, referencing, pydantic-core, jinja2, httpcore, cffi, anyio, starlette, pydantic, jsonschema-specifications, httpx, cryptography, sse-starlette, pydantic-settings, jsonschema, fastapi, mcp -Successfully installed MarkupSafe-3.0.3 PyJWT-2.13.0 aiosqlite-0.22.1 annotated-doc-0.0.4 annotated-types-0.7.0 anyio-4.14.1 attrs-26.1.0 certifi-2026.6.17 cffi-2.0.0 click-8.4.2 cryptography-49.0.0 fastapi-0.138.0 h11-0.16.0 httpcore-1.0.9 httpx-0.28.1 httpx-sse-0.4.3 idna-3.18 jinja2-3.1.6 jsonschema-4.26.0 jsonschema-specifications-2025.9.1 mcp-1.28.0 pycparser-3.0 pydantic-2.13.4 pydantic-core-2.46.4 pydantic-settings-2.14.2 python-dotenv-1.2.2 python-multipart-0.0.32 referencing-0.37.0 rpds-py-2026.5.1 sse-starlette-3.4.5 starlette-1.3.1 typing-extensions-4.15.0 typing-inspection-0.4.2 uvicorn-0.49.0 -WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv - -[notice] A new release of pip is available: 24.0 -> 26.1.2 -[notice] To update, run: pip install --upgrade pip -Removing intermediate container b7f8db2149b9 - ---> da7499cf1bc4 -Step 7/11 : COPY . . diff --git a/data/context_hub.db b/data/context_hub.db index 1bd3cfd..46ce0d8 100644 Binary files a/data/context_hub.db and b/data/context_hub.db differ diff --git a/docker-compose.yml b/docker-compose.yml index 2e145c6..dc190eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,9 @@ services: - "3093:8000" volumes: - ./data:/app/data + - ./templates:/app/templates + - ./static:/app/static + - ./app:/app/app env_file: - .env networks: diff --git a/get_alpine_logs.py b/get_alpine_logs.py deleted file mode 100644 index 06d1f83..0000000 --- a/get_alpine_logs.py +++ /dev/null @@ -1,26 +0,0 @@ -import urllib.request -import json -import urllib.parse - -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -token = json.loads(urllib.request.urlopen(req).read().decode())['jwt'] - -req = urllib.request.Request(f"{base_url}/endpoints", headers={'Authorization': f'Bearer {token}'}) -endpoint_id = json.loads(urllib.request.urlopen(req).read().decode())[0]['Id'] - -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/json?all=1", headers={'Authorization': f'Bearer {token}'}) -containers = json.loads(urllib.request.urlopen(req).read().decode()) - -container_id = None -for c in containers: - if c['Image'] == 'python:3.12-alpine': - container_id = c['Id'] - break - -if container_id: - params = urllib.parse.urlencode({"stdout": 1, "stderr": 1, "tail": 50}) - req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/{container_id}/logs?{params}", headers={'Authorization': f'Bearer {token}'}) - logs = urllib.request.urlopen(req).read() - print(logs) diff --git a/get_logs.py b/get_logs.py deleted file mode 100644 index 17a9263..0000000 --- a/get_logs.py +++ /dev/null @@ -1,28 +0,0 @@ -import urllib.request -import json -import urllib.parse - -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -token = json.loads(urllib.request.urlopen(req).read().decode())['jwt'] - -req = urllib.request.Request(f"{base_url}/endpoints", headers={'Authorization': f'Bearer {token}'}) -endpoint_id = json.loads(urllib.request.urlopen(req).read().decode())[0]['Id'] - -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/json?all=1", headers={'Authorization': f'Bearer {token}'}) -containers = json.loads(urllib.request.urlopen(req).read().decode()) - -container_id = None -for c in containers: - if "/context-hub" in c.get('Names', []): - container_id = c['Id'] - break - -if container_id: - # Get logs - params = urllib.parse.urlencode({"stdout": 1, "stderr": 1, "tail": 50}) - req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/{container_id}/logs?{params}", headers={'Authorization': f'Bearer {token}'}) - logs = urllib.request.urlopen(req).read() - # Docker logs from API have headers, we just print as is, it might have garbage bytes but we can read it. - print(logs) diff --git a/list_images.py b/list_images.py deleted file mode 100644 index 57d8988..0000000 --- a/list_images.py +++ /dev/null @@ -1,13 +0,0 @@ -import urllib.request -import json -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -token = json.loads(urllib.request.urlopen(req).read().decode())['jwt'] - -req = urllib.request.Request(f"{base_url}/endpoints", headers={'Authorization': f'Bearer {token}'}) -endpoint_id = json.loads(urllib.request.urlopen(req).read().decode())[0]['Id'] - -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/images/json", headers={'Authorization': f'Bearer {token}'}) -images = json.loads(urllib.request.urlopen(req).read().decode()) -print([img.get('RepoTags', [''])[0] for img in images if img.get('RepoTags')]) diff --git a/list_stacks.py b/list_stacks.py deleted file mode 100644 index 6e2376f..0000000 --- a/list_stacks.py +++ /dev/null @@ -1,10 +0,0 @@ -import urllib.request -import json -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -token = json.loads(urllib.request.urlopen(req).read().decode())['jwt'] - -req = urllib.request.Request(f"{base_url}/stacks", headers={'Authorization': f'Bearer {token}'}) -stacks = json.loads(urllib.request.urlopen(req).read().decode()) -print([s['Name'] for s in stacks]) diff --git a/patch_container.py b/patch_container.py deleted file mode 100644 index 02a3a37..0000000 --- a/patch_container.py +++ /dev/null @@ -1,48 +0,0 @@ -import urllib.request -import json -import urllib.parse -import time - -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -token = json.loads(urllib.request.urlopen(req).read().decode())['jwt'] - -req = urllib.request.Request(f"{base_url}/endpoints", headers={'Authorization': f'Bearer {token}'}) -endpoint_id = json.loads(urllib.request.urlopen(req).read().decode())[0]['Id'] - -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/json?all=1", headers={'Authorization': f'Bearer {token}'}) -containers = json.loads(urllib.request.urlopen(req).read().decode()) - -container_id = None -for c in containers: - if "/context-hub" in c.get('Names', []): - container_id = c['Id'] - break - -if not container_id: - print("context-hub container not found") - exit(1) - -# Create exec instance -exec_data = { - "AttachStdin": False, - "AttachStdout": True, - "AttachStderr": True, - "Tty": False, - "Cmd": ["cp", "/app/data/admin.py", "/app/app/routes/admin.py"] -} -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/{container_id}/exec", method="POST", data=json.dumps(exec_data).encode('utf-8'), headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}) -exec_res = json.loads(urllib.request.urlopen(req).read().decode()) -exec_id = exec_res['Id'] - -# Start exec instance -start_data = {"Detach": False, "Tty": False} -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/exec/{exec_id}/start", method="POST", data=json.dumps(start_data).encode('utf-8'), headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}) -out = urllib.request.urlopen(req).read() -print("Exec output:", out) - -# Restart container -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/{container_id}/restart", method="POST", headers={'Authorization': f'Bearer {token}'}) -urllib.request.urlopen(req) -print("Restarted container.") diff --git a/rebuild_check.py b/rebuild_check.py deleted file mode 100644 index fedb9f1..0000000 --- a/rebuild_check.py +++ /dev/null @@ -1,32 +0,0 @@ -import urllib.request -import json -import time - -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -token = json.loads(urllib.request.urlopen(req).read().decode())['jwt'] - -req = urllib.request.Request(f"{base_url}/endpoints", headers={'Authorization': f'Bearer {token}'}) -endpoints = json.loads(urllib.request.urlopen(req).read().decode()) -endpoint_id = endpoints[0]['Id'] - -create_data = { - "Image": "python:3.12-alpine", - "Cmd": ["sh", "-c", "apk add --no-cache docker-cli docker-cli-compose && cd /workspace && docker compose up --build > /workspace/build.log 2>&1"], - "HostConfig": { - "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "/volume1/docker/context-hub:/workspace" - ] - } -} -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/create", method="POST", data=json.dumps(create_data).encode('utf-8'), headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}) -try: - response = urllib.request.urlopen(req) - container_id = json.loads(response.read().decode())['Id'] -except Exception as e: - exit(1) - -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/{container_id}/start", method="POST", headers={'Authorization': f'Bearer {token}'}) -urllib.request.urlopen(req) diff --git a/rebuild_via_portainer.py b/rebuild_via_portainer.py deleted file mode 100644 index cb0e9b7..0000000 --- a/rebuild_via_portainer.py +++ /dev/null @@ -1,44 +0,0 @@ -import urllib.request -import json -import time - -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -token = json.loads(urllib.request.urlopen(req).read().decode())['jwt'] - -req = urllib.request.Request(f"{base_url}/endpoints", headers={'Authorization': f'Bearer {token}'}) -endpoints = json.loads(urllib.request.urlopen(req).read().decode()) -endpoint_id = endpoints[0]['Id'] - -create_data = { - "Image": "python:3.12-alpine", - "Cmd": ["sh", "-c", "apk add --no-cache docker-cli docker-cli-compose && cd /workspace && docker compose up -d --build"], - "HostConfig": { - "Binds": [ - "/var/run/docker.sock:/var/run/docker.sock", - "/volume1/docker/context-hub:/workspace" - ] - } -} -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/create", method="POST", data=json.dumps(create_data).encode('utf-8'), headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}) -try: - response = urllib.request.urlopen(req) - container_id = json.loads(response.read().decode())['Id'] - print("Created container:", container_id) -except Exception as e: - print("Create failed:", e.read().decode() if hasattr(e, 'read') else str(e)) - exit(1) - -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/{container_id}/start", method="POST", headers={'Authorization': f'Bearer {token}'}) -urllib.request.urlopen(req) -print("Started container.") - -time.sleep(15) - -# Optional: check if context-hub is running -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/json?all=1", headers={'Authorization': f'Bearer {token}'}) -containers = json.loads(urllib.request.urlopen(req).read().decode()) -for c in containers: - if "/context-hub" in c.get('Names', []): - print("context-hub status:", c['State']) diff --git a/restart_container.py b/restart_container.py deleted file mode 100644 index 7b49770..0000000 --- a/restart_container.py +++ /dev/null @@ -1,48 +0,0 @@ -import urllib.request -import json - -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -try: - with urllib.request.urlopen(req) as response: - token = json.loads(response.read().decode())['jwt'] - print("Got token") -except Exception as e: - print("Auth failed:", e) - exit(1) - -req = urllib.request.Request(f"{base_url}/endpoints", headers={'Authorization': f'Bearer {token}'}) -try: - with urllib.request.urlopen(req) as response: - endpoints = json.loads(response.read().decode()) - endpoint_id = endpoints[0]['Id'] - print("Endpoint ID:", endpoint_id) -except Exception as e: - print("Endpoints failed:", e) - exit(1) - -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/json?all=1", headers={'Authorization': f'Bearer {token}'}) -try: - with urllib.request.urlopen(req) as response: - containers = json.loads(response.read().decode()) - container_id = None - for c in containers: - if "/context-hub" in c.get('Names', []): - container_id = c['Id'] - break - print("Container ID:", container_id) -except Exception as e: - print("Containers failed:", e) - exit(1) - -if container_id: - req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/{container_id}/restart", method="POST", headers={'Authorization': f'Bearer {token}'}) - try: - with urllib.request.urlopen(req) as response: - print("Restarted:", response.status) - except Exception as e: - print("Restart failed:", e) - exit(1) -else: - print("Container not found") diff --git a/run_git.py b/run_git.py deleted file mode 100644 index 80996dd..0000000 --- a/run_git.py +++ /dev/null @@ -1,31 +0,0 @@ -import urllib.request -import json - -base_url = "http://192.168.100.33:9000/api" -data = json.dumps({"Username":"bestof","Password":"2L2u519wportainer"}).encode('utf-8') -req = urllib.request.Request(f"{base_url}/auth", data=data, headers={'Content-Type': 'application/json'}) -token = json.loads(urllib.request.urlopen(req).read().decode())['jwt'] - -req = urllib.request.Request(f"{base_url}/endpoints", headers={'Authorization': f'Bearer {token}'}) -endpoint_id = json.loads(urllib.request.urlopen(req).read().decode())[0]['Id'] - -create_data = { - "Image": "python:3.12-alpine", - "Cmd": ["sh", "-c", "apk add --no-cache git && cd /workspace && git config --global user.email 'antigravity@gemini.com' && git config --global user.name 'Antigravity' && rm -rf .git && git init && git add . && git commit -m 'deploy: fix TemplateResponse signature' && git branch -M main && git remote add origin http://bolbol:2L2u519wgitea@172.17.0.1:3232/bolbol/context-hub.git && git push -u origin main -f > /workspace/git.log 2>&1"], - "HostConfig": { - "Binds": [ - "/volume1/docker/context-hub:/workspace" - ] - } -} -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/create", method="POST", data=json.dumps(create_data).encode('utf-8'), headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}) -try: - response = urllib.request.urlopen(req) - container_id = json.loads(response.read().decode())['Id'] -except Exception as e: - print("Failed create") - exit(1) - -req = urllib.request.Request(f"{base_url}/endpoints/{endpoint_id}/docker/containers/{container_id}/start", method="POST", headers={'Authorization': f'Bearer {token}'}) -urllib.request.urlopen(req) -print("Git container started") diff --git a/static/style.css b/static/style.css index ae74f4e..bf45461 100644 --- a/static/style.css +++ b/static/style.css @@ -1,19 +1,122 @@ -/* Minimal overrides, mostly handled by Tailwind */ -body { - background-color: #111827; /* gray-900 */ - color: #f3f4f6; /* gray-100 */ +/* context-hub — global styles */ + +/* Scrollbar */ +::-webkit-scrollbar { width: 6px; height: 6px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: rgba(212,160,26,0.3); border-radius: 3px; } +::-webkit-scrollbar-thumb:hover { background: rgba(212,160,26,0.6); } + +/* Login page glass card */ +.login-card { + background: var(--bg-glass); + backdrop-filter: blur(24px) saturate(180%); + -webkit-backdrop-filter: blur(24px) saturate(180%); + border: 1px solid var(--border); + border-radius: 1.25rem; + box-shadow: var(--shadow-card), var(--inset-light); } -::-webkit-scrollbar { - width: 8px; - height: 8px; + +/* Inputs */ +input[type=text], input[type=password] { + background: rgba(0,0,0,0.2) !important; + border: 1px solid var(--border) !important; + color: var(--text-primary) !important; + border-radius: 0.5rem; + transition: all 0.2s; } -::-webkit-scrollbar-track { - background: #1f2937; +[data-theme="light"] input[type=text], +[data-theme="light"] input[type=password] { + background: rgba(255,255,255,0.8) !important; } -::-webkit-scrollbar-thumb { - background: #4b5563; - border-radius: 4px; +input:focus { border-color: rgba(212,160,26,0.5) !important; outline: none; box-shadow: 0 0 0 3px rgba(212,160,26,0.1) !important; } + +/* Gold accent button */ +.btn-gold { + background: linear-gradient(135deg, #d4a01a, #f0b429); + color: #0a0e1a; + font-weight: 700; + border: none; + border-radius: 0.5rem; + padding: 0.65rem 1.5rem; + cursor: pointer; + transition: all 0.2s; + box-shadow: 0 4px 16px rgba(212,160,26,0.3); } -::-webkit-scrollbar-thumb:hover { - background: #6b7280; +.btn-gold:hover { transform: translateY(-1px); box-shadow: 0 8px 24px rgba(212,160,26,0.4); } + +/* Accordion */ +.accordion-content { transition: max-height 0.3s ease, opacity 0.3s ease; overflow: hidden; } + +/* Tags */ +.tag { + font-size: 0.65rem; + font-weight: 700; + padding: 0.15rem 0.55rem; + border-radius: 999px; + text-transform: uppercase; + letter-spacing: 0.05em; + display: inline-flex; + align-items: center; + white-space: nowrap; +} + +/* Glow pulse for kill-switch */ +@keyframes glow-pulse { + 0%, 100% { box-shadow: 0 0 20px rgba(239,68,68,0.15); } + 50% { box-shadow: 0 0 40px rgba(239,68,68,0.35); } +} +.glow-red { animation: glow-pulse 3s ease-in-out infinite; } + +/* Gold shimmer */ +@keyframes shimmer { + 0% { background-position: -200% center; } + 100% { background-position: 200% center; } +} +.gold-shimmer { + background: linear-gradient(90deg, #d4a01a, #f0b429, #d4a01a); + background-size: 200% auto; + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: shimmer 3s linear infinite; +} + +/* Mesh background reinforcement */ +body::before { + content: ''; + position: fixed; + inset: 0; + background: var(--bg-mesh); + z-index: -1; + pointer-events: none; +} + +/* ── HF LIGHT MODE OVERRIDES ── */ +html:not(.dark) { color-scheme: light; } +html:not(.dark) .text-gray-100 { color: #0f172a !important; } +html:not(.dark) .text-gray-300 { color: #374151 !important; } +html:not(.dark) .text-gray-400 { color: #6b7280 !important; } +html:not(.dark) .text-gray-500 { color: #9ca3af !important; } +html:not(.dark) .bg-gray-900 { background: #f8fafc !important; } +html:not(.dark) .bg-gray-800 { background: #f1f5f9 !important; } +html:not(.dark) .bg-gray-700 { background: #e2e8f0 !important; } +html:not(.dark) .border-gray-700{ border-color: #e2e8f0 !important; } +html:not(.dark) .border-gray-600{ border-color: #e2e8f0 !important; } + +/* Progress bars HF style */ +html:not(.dark) .bg-black\/40 { background: #f1f5f9 !important; } +html:not(.dark) .border-red-900\/30 { border-color: #fecaca !important; } + +/* Input HF style */ +html:not(.dark) input[type=text], +html:not(.dark) input[type=password], +html:not(.dark) input[type=number] { + background: #ffffff !important; + border: 1px solid #d1d5db !important; + color: #111827 !important; + box-shadow: 0 1px 2px rgba(0,0,0,0.04) !important; +} +html:not(.dark) input:focus { + border-color: #d4a01a !important; + box-shadow: 0 0 0 3px rgba(212,160,26,0.12) !important; } diff --git a/templates/audit.html b/templates/audit.html index 04dc448..6cd471f 100644 --- a/templates/audit.html +++ b/templates/audit.html @@ -4,26 +4,26 @@

Audit Logs

-

History of API and MCP accesses by agents.

+

History of API and MCP accesses by agents.

- ← Back to Dashboard + ← Back to Dashboard
-
+
- - - - + + + + {% for log in logs %} - +
TimeAgentScope / ActionIP AddressTimeAgentScope / ActionIP Address
{{ log.timestamp }}{{ log.timestamp }} {{ log.agent_name }} {% if 'FORBIDDEN' in log.scope %} diff --git a/templates/base.html b/templates/base.html index c4590de..ba3f7c6 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,44 +1,204 @@ - + {% block title %}context-hub | Nyora Infrastructure{% endblock %} + + + + + - - + + + < HF-style ticker (mode clair uniquement) --> + + {% if request.url.path != "/login" %} -