@smilintux/skcapstone 0.4.6 → 0.4.7
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/.github/workflows/publish.yml +8 -1
- package/docs/CUSTOM_AGENT.md +184 -0
- package/docs/GETTING_STARTED.md +3 -0
- package/launchd/com.skcapstone.daemon.plist +52 -0
- package/launchd/com.skcapstone.memory-compress.plist +45 -0
- package/launchd/com.skcapstone.skcomm-heartbeat.plist +33 -0
- package/launchd/com.skcapstone.skcomm-queue-drain.plist +34 -0
- package/launchd/install-launchd.sh +156 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/archive-sessions.sh +88 -0
- package/scripts/install.sh +39 -8
- package/scripts/notion-api.py +259 -0
- package/scripts/nvidia-proxy.mjs +856 -0
- package/scripts/proxy-monitor.sh +89 -0
- package/scripts/skgateway.mjs +856 -0
- package/scripts/telegram-catchup-all.sh +136 -0
- package/src/skcapstone/__init__.py +1 -1
- package/src/skcapstone/blueprints/builtins/itil-operations.yaml +40 -0
- package/src/skcapstone/cli/__init__.py +2 -0
- package/src/skcapstone/cli/daemon.py +116 -41
- package/src/skcapstone/cli/itil.py +434 -0
- package/src/skcapstone/consciousness_config.py +27 -0
- package/src/skcapstone/coordination.py +1 -0
- package/src/skcapstone/daemon.py +19 -11
- package/src/skcapstone/dreaming.py +761 -0
- package/src/skcapstone/fuse_mount.py +21 -13
- package/src/skcapstone/heartbeat.py +33 -29
- package/src/skcapstone/itil.py +1104 -0
- package/src/skcapstone/launchd.py +426 -0
- package/src/skcapstone/mcp_server.py +258 -0
- package/src/skcapstone/mcp_tools/__init__.py +2 -0
- package/src/skcapstone/mcp_tools/gtd_tools.py +1 -1
- package/src/skcapstone/mcp_tools/itil_tools.py +657 -0
- package/src/skcapstone/onboard.py +130 -10
- package/src/skcapstone/scheduled_tasks.py +107 -0
- package/src/skcapstone/service_health.py +81 -2
- package/src/skcapstone/systemd.py +17 -0
|
@@ -31,6 +31,7 @@ import errno
|
|
|
31
31
|
import json
|
|
32
32
|
import logging
|
|
33
33
|
import os
|
|
34
|
+
import platform
|
|
34
35
|
import stat
|
|
35
36
|
import subprocess
|
|
36
37
|
import sys
|
|
@@ -1001,16 +1002,17 @@ class FUSEDaemon:
|
|
|
1001
1002
|
mount_str = str(self._mount_point)
|
|
1002
1003
|
|
|
1003
1004
|
# Linux: parse /proc/mounts
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1005
|
+
if platform.system() == "Linux":
|
|
1006
|
+
proc_mounts = Path("/proc/mounts")
|
|
1007
|
+
if proc_mounts.exists():
|
|
1008
|
+
try:
|
|
1009
|
+
for line in proc_mounts.read_text(encoding="utf-8").splitlines():
|
|
1010
|
+
parts = line.split()
|
|
1011
|
+
if len(parts) >= 2 and parts[1] == mount_str:
|
|
1012
|
+
return True
|
|
1013
|
+
except OSError as exc:
|
|
1014
|
+
logger.warning("Failed to read /proc/mounts: %s", exc)
|
|
1015
|
+
return False
|
|
1014
1016
|
|
|
1015
1017
|
# macOS / other: use mount command
|
|
1016
1018
|
try:
|
|
@@ -1113,8 +1115,13 @@ class FUSEDaemon:
|
|
|
1113
1115
|
|
|
1114
1116
|
mount_str = str(self._mount_point)
|
|
1115
1117
|
|
|
1116
|
-
# Linux
|
|
1117
|
-
|
|
1118
|
+
# On Linux try fusermount first, then umount; on macOS skip fusermount
|
|
1119
|
+
if platform.system() == "Linux":
|
|
1120
|
+
unmount_cmds = [["fusermount", "-u", mount_str], ["umount", mount_str]]
|
|
1121
|
+
else:
|
|
1122
|
+
unmount_cmds = [["umount", mount_str]]
|
|
1123
|
+
|
|
1124
|
+
for cmd in unmount_cmds:
|
|
1118
1125
|
try:
|
|
1119
1126
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
|
|
1120
1127
|
if result.returncode == 0:
|
|
@@ -1130,7 +1137,8 @@ class FUSEDaemon:
|
|
|
1130
1137
|
except (FileNotFoundError, subprocess.TimeoutExpired, OSError) as exc:
|
|
1131
1138
|
logger.debug("Unmount command %s failed: %s", cmd, exc)
|
|
1132
1139
|
|
|
1133
|
-
|
|
1140
|
+
hint = "fusermount -u" if platform.system() == "Linux" else "umount"
|
|
1141
|
+
logger.error("Could not unmount %s — try: %s %s", mount_str, hint, mount_str)
|
|
1134
1142
|
return False
|
|
1135
1143
|
|
|
1136
1144
|
def status(self) -> Dict[str, Any]:
|
|
@@ -398,27 +398,30 @@ class HeartbeatBeacon:
|
|
|
398
398
|
mem = psutil.virtual_memory()
|
|
399
399
|
mem_used_mb = (mem.total - mem.available) // (1024 * 1024)
|
|
400
400
|
except ImportError:
|
|
401
|
-
# Fallback: /proc on Linux
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
401
|
+
# Fallback: /proc on Linux only
|
|
402
|
+
if platform.system() == "Linux":
|
|
403
|
+
try:
|
|
404
|
+
loadavg = Path("/proc/loadavg")
|
|
405
|
+
if loadavg.exists():
|
|
406
|
+
parts = loadavg.read_text().split()
|
|
407
|
+
cpu_load = round(float(parts[0]), 2)
|
|
408
|
+
except Exception as exc:
|
|
409
|
+
logger.debug("CPU load fallback failed: %s", exc)
|
|
410
|
+
try:
|
|
411
|
+
meminfo = Path("/proc/meminfo")
|
|
412
|
+
if meminfo.exists():
|
|
413
|
+
info: dict[str, int] = {}
|
|
414
|
+
for line in meminfo.read_text().splitlines():
|
|
415
|
+
parts = line.split()
|
|
416
|
+
if len(parts) >= 2:
|
|
417
|
+
info[parts[0].rstrip(":")] = int(parts[1])
|
|
418
|
+
total_kb = info.get("MemTotal", 0)
|
|
419
|
+
avail_kb = info.get("MemAvailable", 0)
|
|
420
|
+
mem_used_mb = (total_kb - avail_kb) // 1024
|
|
421
|
+
except Exception as exc:
|
|
422
|
+
logger.debug("Memory fallback failed: %s", exc)
|
|
423
|
+
else:
|
|
424
|
+
logger.debug("psutil not available and not on Linux; skipping CPU/mem detection")
|
|
422
425
|
except Exception as exc:
|
|
423
426
|
logger.debug("CPU/mem detection failed: %s", exc)
|
|
424
427
|
|
|
@@ -439,14 +442,15 @@ class HeartbeatBeacon:
|
|
|
439
442
|
mem_total = mem.total // (1024 * 1024)
|
|
440
443
|
mem_avail = mem.available // (1024 * 1024)
|
|
441
444
|
except ImportError:
|
|
442
|
-
# Fallback: read from /proc/meminfo on Linux
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
445
|
+
# Fallback: read from /proc/meminfo on Linux only
|
|
446
|
+
if platform.system() == "Linux":
|
|
447
|
+
meminfo = Path("/proc/meminfo")
|
|
448
|
+
if meminfo.exists():
|
|
449
|
+
for line in meminfo.read_text().splitlines():
|
|
450
|
+
if line.startswith("MemTotal:"):
|
|
451
|
+
mem_total = int(line.split()[1]) // 1024
|
|
452
|
+
elif line.startswith("MemAvailable:"):
|
|
453
|
+
mem_avail = int(line.split()[1]) // 1024
|
|
450
454
|
|
|
451
455
|
gpu_available = False
|
|
452
456
|
gpu_name = ""
|