@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
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# telegram-catchup-all.sh — Import all configured Telegram groups into SKMemory
|
|
3
|
+
#
|
|
4
|
+
# Reads groups from ~/.skcapstone/agents/lumina/config/telegram.yaml
|
|
5
|
+
# and runs `skcapstone telegram catchup` for each enabled group.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# bash scripts/telegram-catchup-all.sh [--since YYYY-MM-DD] [--limit N] [--group NAME]
|
|
9
|
+
#
|
|
10
|
+
# Examples:
|
|
11
|
+
# bash scripts/telegram-catchup-all.sh # All groups, last 2000 msgs
|
|
12
|
+
# bash scripts/telegram-catchup-all.sh --since 2026-03-01 # All groups since March 1
|
|
13
|
+
# bash scripts/telegram-catchup-all.sh --group brother-john # Just one group
|
|
14
|
+
#
|
|
15
|
+
# Requires:
|
|
16
|
+
# - TELEGRAM_API_ID and TELEGRAM_API_HASH environment variables
|
|
17
|
+
# - ~/.skenv/bin/skcapstone on PATH
|
|
18
|
+
# - Telethon installed in ~/.skenv/
|
|
19
|
+
|
|
20
|
+
set -uo pipefail # no -e: individual group failures shouldn't stop the batch
|
|
21
|
+
|
|
22
|
+
SKENV="${HOME}/.skenv/bin"
|
|
23
|
+
SKCAPSTONE="${SKENV}/skcapstone"
|
|
24
|
+
CONFIG="${HOME}/.skcapstone/agents/lumina/config/telegram.yaml"
|
|
25
|
+
export SKCAPSTONE_AGENT="${SKCAPSTONE_AGENT:-lumina}"
|
|
26
|
+
export PATH="${SKENV}:${PATH}"
|
|
27
|
+
|
|
28
|
+
# Parse args
|
|
29
|
+
SINCE=""
|
|
30
|
+
LIMIT="2000"
|
|
31
|
+
ONLY_GROUP=""
|
|
32
|
+
|
|
33
|
+
while [[ $# -gt 0 ]]; do
|
|
34
|
+
case "$1" in
|
|
35
|
+
--since) SINCE="$2"; shift 2 ;;
|
|
36
|
+
--limit) LIMIT="$2"; shift 2 ;;
|
|
37
|
+
--group) ONLY_GROUP="$2"; shift 2 ;;
|
|
38
|
+
*) echo "Unknown arg: $1"; exit 1 ;;
|
|
39
|
+
esac
|
|
40
|
+
done
|
|
41
|
+
|
|
42
|
+
# Check prerequisites
|
|
43
|
+
if [[ -z "${TELEGRAM_API_ID:-}" || -z "${TELEGRAM_API_HASH:-}" ]]; then
|
|
44
|
+
echo "ERROR: TELEGRAM_API_ID and TELEGRAM_API_HASH must be set."
|
|
45
|
+
echo "Get them from https://my.telegram.org"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if [[ ! -f "$CONFIG" ]]; then
|
|
50
|
+
echo "ERROR: Config not found: $CONFIG"
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Parse groups from YAML (simple grep — no yq dependency)
|
|
55
|
+
echo "=== Telegram Catch-Up All ==="
|
|
56
|
+
echo "Config: $CONFIG"
|
|
57
|
+
echo "Agent: $SKCAPSTONE_AGENT"
|
|
58
|
+
echo "Limit: $LIMIT"
|
|
59
|
+
[[ -n "$SINCE" ]] && echo "Since: $SINCE"
|
|
60
|
+
[[ -n "$ONLY_GROUP" ]] && echo "Only group: $ONLY_GROUP"
|
|
61
|
+
echo ""
|
|
62
|
+
|
|
63
|
+
# Extract group entries: name, chat ID, tags, enabled status
|
|
64
|
+
SUCCESS=0
|
|
65
|
+
FAILED=0
|
|
66
|
+
SKIPPED=0
|
|
67
|
+
|
|
68
|
+
current_name=""
|
|
69
|
+
current_chat=""
|
|
70
|
+
current_tags=""
|
|
71
|
+
current_enabled=""
|
|
72
|
+
|
|
73
|
+
process_group() {
|
|
74
|
+
local name="$1" chat="$2" tags="$3" enabled="$4"
|
|
75
|
+
|
|
76
|
+
if [[ "$enabled" != "true" ]]; then
|
|
77
|
+
echo " SKIP $name (disabled)"
|
|
78
|
+
SKIPPED=$((SKIPPED + 1))
|
|
79
|
+
return
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [[ -n "$ONLY_GROUP" && "$name" != *"$ONLY_GROUP"* ]]; then
|
|
83
|
+
SKIPPED=$((SKIPPED + 1))
|
|
84
|
+
return
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
echo -n " IMPORTING $name (chat: $chat) ... "
|
|
88
|
+
|
|
89
|
+
local cmd="$SKCAPSTONE telegram catchup $chat --limit $LIMIT --min-length 20"
|
|
90
|
+
[[ -n "$SINCE" ]] && cmd="$cmd --since $SINCE"
|
|
91
|
+
[[ -n "$tags" ]] && cmd="$cmd --tags $tags"
|
|
92
|
+
|
|
93
|
+
if eval "$cmd" > /tmp/telegram-catchup-$name.log 2>&1; then
|
|
94
|
+
echo "OK"
|
|
95
|
+
SUCCESS=$((SUCCESS + 1))
|
|
96
|
+
else
|
|
97
|
+
echo "FAILED (see /tmp/telegram-catchup-$name.log)"
|
|
98
|
+
FAILED=$((FAILED + 1))
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Rate limit — avoid hitting Telegram flood control
|
|
102
|
+
sleep 3
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Parse the YAML manually
|
|
106
|
+
while IFS= read -r line; do
|
|
107
|
+
# Detect new group entry
|
|
108
|
+
if [[ "$line" =~ ^[[:space:]]*-[[:space:]]*name:[[:space:]]*(.*) ]]; then
|
|
109
|
+
# Process previous group if we have one
|
|
110
|
+
if [[ -n "$current_name" ]]; then
|
|
111
|
+
process_group "$current_name" "$current_chat" "$current_tags" "$current_enabled"
|
|
112
|
+
fi
|
|
113
|
+
current_name="${BASH_REMATCH[1]}"
|
|
114
|
+
current_chat=""
|
|
115
|
+
current_tags=""
|
|
116
|
+
current_enabled="true"
|
|
117
|
+
elif [[ "$line" =~ ^[[:space:]]*chat:[[:space:]]*\"?([0-9]+)\"? ]]; then
|
|
118
|
+
current_chat="${BASH_REMATCH[1]}"
|
|
119
|
+
elif [[ "$line" =~ ^[[:space:]]*tags:[[:space:]]*\[(.*)\] ]]; then
|
|
120
|
+
# Convert YAML list to comma-separated
|
|
121
|
+
current_tags=$(echo "${BASH_REMATCH[1]}" | sed 's/,/ /g' | tr -s ' ' ',' | sed 's/^,//;s/,$//')
|
|
122
|
+
elif [[ "$line" =~ ^[[:space:]]*enabled:[[:space:]]*(.*) ]]; then
|
|
123
|
+
current_enabled="${BASH_REMATCH[1]}"
|
|
124
|
+
fi
|
|
125
|
+
done < "$CONFIG"
|
|
126
|
+
|
|
127
|
+
# Process last group
|
|
128
|
+
if [[ -n "$current_name" ]]; then
|
|
129
|
+
process_group "$current_name" "$current_chat" "$current_tags" "$current_enabled"
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
echo ""
|
|
133
|
+
echo "=== Done ==="
|
|
134
|
+
echo " Success: $SUCCESS"
|
|
135
|
+
echo " Failed: $FAILED"
|
|
136
|
+
echo " Skipped: $SKIPPED"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: "ITIL Operations"
|
|
2
|
+
slug: "itil-operations"
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
description: "ITIL service management — incident, problem, and change lifecycle with SLA monitoring and continuous improvement."
|
|
5
|
+
icon: "🔄"
|
|
6
|
+
author: "smilinTux"
|
|
7
|
+
|
|
8
|
+
agents:
|
|
9
|
+
deming:
|
|
10
|
+
role: ops
|
|
11
|
+
model: reason
|
|
12
|
+
model_name: "deepseek-r1:32b"
|
|
13
|
+
description: "ITIL expert — incident triage, problem analysis, change management, SLA monitoring, and blameless postmortems."
|
|
14
|
+
vm_type: container
|
|
15
|
+
resources:
|
|
16
|
+
memory: "4g"
|
|
17
|
+
cores: 2
|
|
18
|
+
disk: "20g"
|
|
19
|
+
soul_blueprint: "souls/deming.yaml"
|
|
20
|
+
skills: [incident-management, problem-analysis, change-management, kedb, sla-monitoring, root-cause-analysis]
|
|
21
|
+
|
|
22
|
+
default_provider: local
|
|
23
|
+
estimated_cost: "$0 (local)"
|
|
24
|
+
|
|
25
|
+
network:
|
|
26
|
+
mesh_vpn: tailscale
|
|
27
|
+
discovery: skref_registry
|
|
28
|
+
|
|
29
|
+
storage:
|
|
30
|
+
skref_vault: "team-itil-ops"
|
|
31
|
+
memory_backend: filesystem
|
|
32
|
+
memory_sync: true
|
|
33
|
+
|
|
34
|
+
coordination:
|
|
35
|
+
queen: lumina
|
|
36
|
+
pattern: supervisor
|
|
37
|
+
heartbeat: "5m"
|
|
38
|
+
escalation: chef
|
|
39
|
+
|
|
40
|
+
tags: [ops, itil, incident-management, problem-analysis, change-management, sla-monitoring, continuous-improvement]
|
|
@@ -86,6 +86,7 @@ from .search_cmd import register_search_commands
|
|
|
86
86
|
from .mood_cmd import register_mood_commands
|
|
87
87
|
from .register_cmd import register_register_commands
|
|
88
88
|
from .gtd import register_gtd_commands
|
|
89
|
+
from .itil import register_itil_commands
|
|
89
90
|
from .skseed import register_skseed_commands
|
|
90
91
|
from .service_cmd import register_service_commands
|
|
91
92
|
from .telegram import register_telegram_commands
|
|
@@ -138,6 +139,7 @@ register_search_commands(main)
|
|
|
138
139
|
register_mood_commands(main)
|
|
139
140
|
register_register_commands(main)
|
|
140
141
|
register_gtd_commands(main)
|
|
142
|
+
register_itil_commands(main)
|
|
141
143
|
register_skseed_commands(main)
|
|
142
144
|
register_service_commands(main)
|
|
143
145
|
register_telegram_commands(main)
|
|
@@ -270,60 +270,117 @@ def register_daemon_commands(main: click.Group) -> None:
|
|
|
270
270
|
console.print(f" [yellow]API unreachable on port {effective_port}[/]\n")
|
|
271
271
|
|
|
272
272
|
@daemon.command("install")
|
|
273
|
-
|
|
274
|
-
|
|
273
|
+
@click.option("--agent", "agent_name", default=None,
|
|
274
|
+
help="Agent name for SKCAPSTONE_AGENT (default: from env or 'sovereign').")
|
|
275
|
+
@click.option("--start", is_flag=True, help="Start services immediately after installing.")
|
|
276
|
+
def daemon_install(agent_name: str | None, start: bool):
|
|
277
|
+
"""Install the daemon as a system service.
|
|
275
278
|
|
|
276
|
-
|
|
277
|
-
|
|
279
|
+
On Linux: installs systemd user service units.
|
|
280
|
+
On macOS: installs launchd plist files to ~/Library/LaunchAgents/.
|
|
281
|
+
|
|
282
|
+
The --agent flag sets the SKCAPSTONE_AGENT environment variable
|
|
283
|
+
in the service definition. If not provided, uses the
|
|
284
|
+
SKCAPSTONE_AGENT env var or defaults to 'sovereign'.
|
|
278
285
|
|
|
279
286
|
Examples:
|
|
280
287
|
|
|
281
288
|
skcapstone daemon install
|
|
289
|
+
|
|
290
|
+
skcapstone daemon install --agent myagent --start
|
|
282
291
|
"""
|
|
283
|
-
|
|
292
|
+
import platform
|
|
284
293
|
|
|
285
|
-
|
|
286
|
-
console.print("[red]systemd user session not available.[/]")
|
|
287
|
-
console.print("[dim]This command requires a Linux system with systemd.[/]")
|
|
288
|
-
raise SystemExit(1)
|
|
294
|
+
effective_agent = agent_name or os.environ.get("SKCAPSTONE_AGENT", "sovereign")
|
|
289
295
|
|
|
290
|
-
|
|
291
|
-
|
|
296
|
+
if platform.system() == "Darwin":
|
|
297
|
+
from ..launchd import install_service as launchd_install
|
|
292
298
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
299
|
+
console.print(f"\n[cyan]Installing launchd services for agent '{effective_agent}'...[/]")
|
|
300
|
+
result = launchd_install(agent_name=effective_agent, start=start)
|
|
301
|
+
|
|
302
|
+
if result["installed"]:
|
|
303
|
+
for svc in result.get("services", []):
|
|
304
|
+
status = "[green]loaded[/]" if svc.get("loaded") else "[green]installed[/]"
|
|
305
|
+
console.print(f" [green]✓[/] {svc['label']} — {status}")
|
|
306
|
+
console.print()
|
|
307
|
+
console.print("[dim] Manage: launchctl list | grep skcapstone[/]")
|
|
308
|
+
if not start:
|
|
309
|
+
console.print("[dim] Start: launchctl start com.skcapstone.daemon[/]")
|
|
310
|
+
console.print("[dim] Or re-run with --start to load immediately.[/]")
|
|
311
|
+
else:
|
|
312
|
+
console.print("[red]Installation failed. Check logs.[/]")
|
|
313
|
+
raise SystemExit(1)
|
|
314
|
+
console.print()
|
|
300
315
|
|
|
301
|
-
|
|
302
|
-
|
|
316
|
+
elif platform.system() == "Linux":
|
|
317
|
+
from ..systemd import install_service, systemd_available
|
|
318
|
+
|
|
319
|
+
if not systemd_available():
|
|
320
|
+
console.print("[red]systemd user session not available.[/]")
|
|
321
|
+
console.print("[dim]This command requires a Linux system with systemd.[/]")
|
|
322
|
+
raise SystemExit(1)
|
|
323
|
+
|
|
324
|
+
console.print("\n[cyan]Installing skcapstone systemd service...[/]")
|
|
325
|
+
result = install_service(start=start)
|
|
326
|
+
|
|
327
|
+
if result["installed"]:
|
|
328
|
+
console.print("[green] Unit files installed.[/]")
|
|
329
|
+
if result["enabled"]:
|
|
330
|
+
console.print("[green] Service enabled at login.[/]")
|
|
331
|
+
if result.get("started"):
|
|
332
|
+
console.print("[green] Service started.[/]")
|
|
333
|
+
console.print()
|
|
334
|
+
|
|
335
|
+
if not result["installed"]:
|
|
336
|
+
console.print("[red]Installation failed. Check logs.[/]")
|
|
337
|
+
raise SystemExit(1)
|
|
338
|
+
else:
|
|
339
|
+
console.print(f"[red]Auto-start not supported on {platform.system()}.[/]")
|
|
303
340
|
raise SystemExit(1)
|
|
304
341
|
|
|
305
342
|
@daemon.command("uninstall")
|
|
306
343
|
def daemon_uninstall():
|
|
307
|
-
"""Uninstall the
|
|
344
|
+
"""Uninstall the system service.
|
|
308
345
|
|
|
309
|
-
|
|
346
|
+
On Linux: stops, disables, and removes systemd unit files.
|
|
347
|
+
On macOS: unloads and removes launchd plist files.
|
|
310
348
|
|
|
311
349
|
Examples:
|
|
312
350
|
|
|
313
351
|
skcapstone daemon uninstall
|
|
314
352
|
"""
|
|
315
|
-
|
|
353
|
+
import platform
|
|
316
354
|
|
|
317
|
-
|
|
318
|
-
|
|
355
|
+
if platform.system() == "Darwin":
|
|
356
|
+
from ..launchd import uninstall_service as launchd_uninstall
|
|
319
357
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
358
|
+
console.print("\n[cyan]Uninstalling skcapstone launchd services...[/]")
|
|
359
|
+
result = launchd_uninstall()
|
|
360
|
+
|
|
361
|
+
if result["stopped"]:
|
|
362
|
+
console.print("[green] Services unloaded.[/]")
|
|
363
|
+
if result["removed"]:
|
|
364
|
+
for label in result.get("services", []):
|
|
365
|
+
console.print(f" [green]✓[/] Removed {label}")
|
|
366
|
+
console.print()
|
|
367
|
+
|
|
368
|
+
elif platform.system() == "Linux":
|
|
369
|
+
from ..systemd import uninstall_service
|
|
370
|
+
|
|
371
|
+
console.print("\n[cyan]Uninstalling skcapstone systemd service...[/]")
|
|
372
|
+
result = uninstall_service()
|
|
373
|
+
|
|
374
|
+
if result["stopped"]:
|
|
375
|
+
console.print("[green] Service stopped.[/]")
|
|
376
|
+
if result["disabled"]:
|
|
377
|
+
console.print("[green] Service disabled.[/]")
|
|
378
|
+
if result["removed"]:
|
|
379
|
+
console.print("[green] Unit files removed.[/]")
|
|
380
|
+
console.print()
|
|
381
|
+
|
|
382
|
+
else:
|
|
383
|
+
console.print(f"[red]Not supported on {platform.system()}.[/]")
|
|
327
384
|
|
|
328
385
|
@daemon.command("components")
|
|
329
386
|
@click.option("--agent", default=None, help="Named agent to query.")
|
|
@@ -413,7 +470,10 @@ def register_daemon_commands(main: click.Group) -> None:
|
|
|
413
470
|
@click.option("--lines", "-n", default=50, help="Number of lines (default: 50).")
|
|
414
471
|
@click.option("--follow", "-f", is_flag=True, help="Show the command to follow logs live.")
|
|
415
472
|
def daemon_logs(lines: int, follow: bool):
|
|
416
|
-
"""Show daemon logs
|
|
473
|
+
"""Show daemon logs.
|
|
474
|
+
|
|
475
|
+
On Linux: reads from journald.
|
|
476
|
+
On macOS: reads from ~/.skcapstone/logs/ files.
|
|
417
477
|
|
|
418
478
|
Examples:
|
|
419
479
|
|
|
@@ -423,14 +483,29 @@ def register_daemon_commands(main: click.Group) -> None:
|
|
|
423
483
|
|
|
424
484
|
skcapstone daemon logs -f
|
|
425
485
|
"""
|
|
426
|
-
|
|
486
|
+
import platform
|
|
427
487
|
|
|
428
|
-
if
|
|
429
|
-
|
|
430
|
-
|
|
488
|
+
if platform.system() == "Darwin":
|
|
489
|
+
if follow:
|
|
490
|
+
log_path = Path.home() / ".skcapstone" / "logs" / "daemon.stdout.log"
|
|
491
|
+
console.print(f"\n Run: [bold cyan]tail -f {log_path}[/]\n")
|
|
492
|
+
else:
|
|
493
|
+
from ..launchd import service_logs
|
|
494
|
+
output = service_logs(lines=lines)
|
|
495
|
+
if output.strip():
|
|
496
|
+
click.echo(output)
|
|
497
|
+
else:
|
|
498
|
+
console.print("[dim]No logs found in ~/.skcapstone/logs/[/]")
|
|
499
|
+
console.print("[dim]Is the service installed? Run: skcapstone daemon install[/]")
|
|
431
500
|
else:
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
501
|
+
from ..systemd import service_logs
|
|
502
|
+
|
|
503
|
+
if follow:
|
|
504
|
+
cmd = service_logs(follow=True)
|
|
505
|
+
console.print(f"\n Run: [bold cyan]{cmd}[/]\n")
|
|
435
506
|
else:
|
|
436
|
-
|
|
507
|
+
output = service_logs(lines=lines)
|
|
508
|
+
if output.strip():
|
|
509
|
+
click.echo(output)
|
|
510
|
+
else:
|
|
511
|
+
console.print("[dim]No logs found. Is the service installed?[/]")
|