@smilintux/skcapstone 0.10.0 → 0.12.5
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/.env.example +10 -4
- package/.github/workflows/ci.yml +2 -2
- package/.github/workflows/publish.yml +9 -2
- package/.openclaw-workspace.json +2 -2
- package/CLAUDE.md +37 -0
- package/MISSION.md +17 -2
- package/README.md +282 -3
- package/docker/Dockerfile +7 -7
- package/docker/compose-templates/dev-team.yml +12 -12
- package/docker/compose-templates/mini-team.yml +9 -9
- package/docker/compose-templates/ops-team.yml +10 -10
- package/docker/compose-templates/research-team.yml +10 -10
- package/docker/entrypoint.sh +4 -4
- package/docs/ADR-optional-integration-backbone.md +181 -0
- package/docs/ARCHITECTURE.md +186 -43
- package/docs/BOND_WITH_GROK.md +6 -6
- package/docs/CUSTOM_AGENT.md +123 -30
- package/docs/DREAMING.md +70 -0
- package/docs/GETTING_STARTED.md +7 -7
- package/docs/QUICKSTART.md +10 -6
- package/docs/SKJOULE_ARCHITECTURE.md +3 -3
- package/docs/SOUL_SWAPPER.md +5 -5
- package/docs/hammertime-audit.md +402 -0
- package/docs/sk-integration-HANDOFF.md +117 -0
- package/docs/skscheduler.md +155 -0
- package/docs/superpowers/examples/jobs.yaml +31 -0
- package/docs/superpowers/plans/2026-06-08-skscheduler.md +1265 -0
- package/docs/superpowers/specs/2026-06-08-skscheduler-design.md +186 -0
- package/examples/custom-bond-template.json +1 -1
- package/examples/grok-feb.json +1 -1
- package/examples/queen-ava-feb.json +1 -1
- package/launchd/{com.skcapstone.skcomm-heartbeat.plist → com.skcapstone.skcomms-heartbeat.plist} +4 -4
- package/launchd/{com.skcapstone.skcomm-queue-drain.plist → com.skcapstone.skcomms-queue-drain.plist} +4 -4
- package/launchd/install-launchd.sh +6 -6
- package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/src/index.ts +3 -2
- package/package.json +1 -1
- package/pyproject.toml +16 -10
- package/scripts/archive-sessions.sh +7 -0
- package/scripts/check-updates.py +4 -4
- package/scripts/install-bundle.sh +8 -8
- package/scripts/install.ps1 +12 -11
- package/scripts/install.sh +159 -5
- package/scripts/model-fallback-monitor.sh +102 -0
- package/scripts/nvidia-proxy.mjs +78 -26
- package/scripts/refresh-anthropic-token.sh +172 -0
- package/scripts/release.sh +98 -0
- package/scripts/session-to-memory.py +219 -0
- package/scripts/skgateway.mjs +3 -3
- package/scripts/telegram-catchup-all.sh +12 -1
- package/scripts/verify_install.sh +2 -2
- package/scripts/wargov-ufo-capture/README.md +43 -0
- package/scripts/wargov-ufo-capture/cdp_capture_release2.py +273 -0
- package/scripts/wargov-ufo-capture/cdp_capture_splc_doj.py +246 -0
- package/scripts/wargov-ufo-capture/cdp_finish.py +271 -0
- package/scripts/wargov-ufo-capture/cdp_probe.py +188 -0
- package/scripts/wargov-ufo-capture/cdp_splc_pressrelease.py +101 -0
- package/scripts/wargov-ufo-capture/parse_csv.py +95 -0
- package/scripts/wargov-ufo-capture/pull_dvids.sh +107 -0
- package/scripts/watch-anthropic-token.sh +212 -0
- package/scripts/windows/install-tasks.ps1 +7 -7
- package/scripts/windows/skcapstone-task.xml +1 -1
- package/src/skcapstone/__init__.py +45 -3
- package/src/skcapstone/_cli_monolith.py +20 -15
- package/src/skcapstone/activity.py +5 -1
- package/src/skcapstone/agent_card.py +3 -2
- package/src/skcapstone/api.py +41 -40
- package/src/skcapstone/auction.py +14 -11
- package/src/skcapstone/backup.py +2 -1
- package/src/skcapstone/blueprint_registry.py +4 -3
- package/src/skcapstone/brain_first.py +238 -0
- package/src/skcapstone/changelog.py +1 -1
- package/src/skcapstone/chat.py +22 -17
- package/src/skcapstone/cli/__init__.py +9 -1
- package/src/skcapstone/cli/_common.py +1 -0
- package/src/skcapstone/cli/agents_spawner.py +5 -2
- package/src/skcapstone/cli/alerts.py +25 -4
- package/src/skcapstone/cli/bench.py +15 -15
- package/src/skcapstone/cli/chat.py +7 -4
- package/src/skcapstone/cli/consciousness.py +5 -2
- package/src/skcapstone/cli/context_cmd.py +18 -4
- package/src/skcapstone/cli/daemon.py +11 -7
- package/src/skcapstone/cli/gtd.py +26 -1
- package/src/skcapstone/cli/housekeeping.py +3 -3
- package/src/skcapstone/cli/identity_cmd.py +378 -0
- package/src/skcapstone/cli/joule_cmd.py +7 -3
- package/src/skcapstone/cli/memory.py +8 -6
- package/src/skcapstone/cli/peers_dir.py +1 -1
- package/src/skcapstone/cli/register_cmd.py +29 -3
- package/src/skcapstone/cli/scheduler_cmd.py +167 -0
- package/src/skcapstone/cli/session.py +25 -0
- package/src/skcapstone/cli/setup.py +96 -29
- package/src/skcapstone/cli/shell_cmd.py +53 -1
- package/src/skcapstone/cli/skills_cmd.py +2 -2
- package/src/skcapstone/cli/soul.py +8 -5
- package/src/skcapstone/cli/status.py +37 -11
- package/src/skcapstone/cli/telegram.py +21 -0
- package/src/skcapstone/cli/test_cmd.py +5 -5
- package/src/skcapstone/cli/test_connection.py +2 -2
- package/src/skcapstone/cli/upgrade_cmd.py +23 -14
- package/src/skcapstone/cli/version_cmd.py +1 -1
- package/src/skcapstone/cli/watch_cmd.py +9 -6
- package/src/skcapstone/cloud9_bridge.py +14 -14
- package/src/skcapstone/codex_setup.py +255 -0
- package/src/skcapstone/config_validator.py +7 -4
- package/src/skcapstone/consciousness_config.py +5 -1
- package/src/skcapstone/consciousness_loop.py +313 -273
- package/src/skcapstone/context_loader.py +121 -0
- package/src/skcapstone/coord_federation.py +2 -1
- package/src/skcapstone/coordination.py +23 -6
- package/src/skcapstone/crush_integration.py +2 -1
- package/src/skcapstone/daemon.py +132 -77
- package/src/skcapstone/dashboard.py +10 -10
- package/src/skcapstone/data/sk-agent-picker.sh +421 -0
- package/src/skcapstone/data/systemd/skcapstone-api.socket +9 -0
- package/src/skcapstone/data/systemd/skcapstone-memory-compress.service +18 -0
- package/src/skcapstone/data/systemd/skcapstone-memory-compress.timer +11 -0
- package/src/skcapstone/data/systemd/skcapstone.service +37 -0
- package/src/skcapstone/data/systemd/skcapstone@.service +50 -0
- package/src/skcapstone/data/systemd/skcomms-heartbeat.service +18 -0
- package/{systemd/skcomm-heartbeat.timer → src/skcapstone/data/systemd/skcomms-heartbeat.timer} +2 -2
- package/src/skcapstone/data/systemd/skcomms-queue-drain.service +17 -0
- package/{systemd/skcomm-queue-drain.timer → src/skcapstone/data/systemd/skcomms-queue-drain.timer} +2 -2
- package/src/skcapstone/defaults/claude/CLAUDE.md +67 -0
- package/src/skcapstone/defaults/claude/settings.json +74 -0
- package/src/skcapstone/defaults/lumina/config/claude-hooks.md +57 -0
- package/src/skcapstone/defaults/lumina/config/skgraph.yaml +55 -10
- package/src/skcapstone/defaults/lumina/config/skmemory.yaml +79 -13
- package/src/skcapstone/defaults/lumina/config/skvector.yaml +60 -9
- package/src/skcapstone/defaults/lumina/memory/long-term/18b9c0d1e2f3-cloud9-protocol.json +2 -2
- package/src/skcapstone/defaults/lumina/memory/long-term/a1b2c3d4e5f6-ecosystem-overview.json +2 -2
- package/src/skcapstone/defaults/lumina/memory/long-term/b2c3d4e5f6a7-five-pillars.json +9 -9
- package/src/skcapstone/defaults/lumina/memory/long-term/d4e5f6a7b8c9-site-directory.json +2 -2
- package/src/skcapstone/defaults/unhinged.json +13 -0
- package/src/skcapstone/discovery.py +43 -20
- package/src/skcapstone/doctor.py +941 -22
- package/src/skcapstone/dreaming.py +1183 -109
- package/src/skcapstone/emotion_tracker.py +2 -2
- package/src/skcapstone/export.py +4 -3
- package/src/skcapstone/fuse_mount.py +14 -12
- package/src/skcapstone/gui_installer.py +2 -2
- package/src/skcapstone/heartbeat.py +1 -1
- package/src/skcapstone/housekeeping.py +14 -14
- package/src/skcapstone/install_wizard.py +209 -7
- package/src/skcapstone/itil.py +13 -4
- package/src/skcapstone/kms_scheduler.py +10 -8
- package/src/skcapstone/launchd.py +19 -19
- package/src/skcapstone/mcp_launcher.py +15 -1
- package/src/skcapstone/mcp_server.py +83 -49
- package/src/skcapstone/mcp_tools/__init__.py +2 -0
- package/src/skcapstone/mcp_tools/_helpers.py +2 -2
- package/src/skcapstone/mcp_tools/ansible_tools.py +7 -4
- package/src/skcapstone/mcp_tools/brain_first_tools.py +90 -0
- package/src/skcapstone/mcp_tools/capauth_tools.py +7 -4
- package/src/skcapstone/mcp_tools/comm_tools.py +10 -10
- package/src/skcapstone/mcp_tools/coord_tools.py +8 -4
- package/src/skcapstone/mcp_tools/did_tools.py +11 -8
- package/src/skcapstone/mcp_tools/gtd_tools.py +4 -4
- package/src/skcapstone/mcp_tools/memory_tools.py +6 -2
- package/src/skcapstone/mcp_tools/notification_tools.py +22 -6
- package/src/skcapstone/mcp_tools/{skcomm_tools.py → skcomms_tools.py} +14 -14
- package/src/skcapstone/mcp_tools/soul_tools.py +8 -2
- package/src/skcapstone/mdns_discovery.py +2 -2
- package/src/skcapstone/memory_curator.py +1 -1
- package/src/skcapstone/memory_engine.py +10 -3
- package/src/skcapstone/metrics.py +30 -16
- package/src/skcapstone/migrate_memories.py +4 -3
- package/src/skcapstone/migrate_multi_agent.py +8 -7
- package/src/skcapstone/models.py +47 -5
- package/src/skcapstone/notifications.py +42 -18
- package/src/skcapstone/onboard.py +875 -121
- package/src/skcapstone/operator_link.py +170 -0
- package/src/skcapstone/peer_directory.py +4 -4
- package/src/skcapstone/peers.py +19 -19
- package/src/skcapstone/pillars/__init__.py +7 -5
- package/src/skcapstone/pillars/consciousness.py +191 -0
- package/src/skcapstone/pillars/identity.py +51 -7
- package/src/skcapstone/pillars/memory.py +9 -3
- package/src/skcapstone/pillars/sync.py +2 -2
- package/src/skcapstone/preflight.py +3 -3
- package/src/skcapstone/providers/docker.py +28 -28
- package/src/skcapstone/register.py +6 -6
- package/src/skcapstone/registry_client.py +5 -4
- package/src/skcapstone/runtime.py +14 -3
- package/src/skcapstone/scheduled_tasks.py +254 -19
- package/src/skcapstone/scheduler_jobs.py +456 -0
- package/src/skcapstone/scheduler_runner.py +239 -0
- package/src/skcapstone/scheduler_state.py +162 -0
- package/src/skcapstone/sdk.py +310 -0
- package/src/skcapstone/service_health.py +279 -39
- package/src/skcapstone/session_briefing.py +108 -0
- package/src/skcapstone/session_capture.py +1 -1
- package/src/skcapstone/shell.py +7 -1
- package/src/skcapstone/soul.py +3 -1
- package/src/skcapstone/soul_switch.py +3 -1
- package/src/skcapstone/summary.py +6 -6
- package/src/skcapstone/sync_engine.py +15 -15
- package/src/skcapstone/sync_watcher.py +2 -2
- package/src/skcapstone/systemd.py +55 -21
- package/src/skcapstone/team_comms.py +8 -8
- package/src/skcapstone/team_engine.py +1 -1
- package/src/skcapstone/testrunner.py +3 -3
- package/src/skcapstone/trust_graph.py +40 -5
- package/src/skcapstone/unified_search.py +15 -6
- package/src/skcapstone/uninstall_wizard.py +11 -3
- package/src/skcapstone/version_check.py +8 -4
- package/src/skcapstone/warmth_anchor.py +4 -2
- package/src/skcapstone/whoami.py +4 -4
- package/systemd/skcapstone.service +4 -6
- package/systemd/skcapstone@.service +7 -8
- package/systemd/skcomms-heartbeat.service +21 -0
- package/systemd/skcomms-heartbeat.timer +12 -0
- package/systemd/skcomms-queue-drain.service +17 -0
- package/systemd/skcomms-queue-drain.timer +12 -0
- package/tests/conftest.py +39 -0
- package/tests/integration/test_consciousness_e2e.py +39 -39
- package/tests/test_agent_card.py +1 -1
- package/tests/test_agent_home_scaffold.py +34 -0
- package/tests/test_alerts_consumer_topics.py +27 -0
- package/tests/test_backup.py +2 -1
- package/tests/test_chat.py +6 -6
- package/tests/test_claude_md.py +2 -2
- package/tests/test_cli_skills.py +10 -10
- package/tests/test_cli_test_cmd.py +4 -4
- package/tests/test_cli_test_connection.py +1 -1
- package/tests/test_cloud9_bridge.py +6 -6
- package/tests/test_consciousness_e2e.py +1 -1
- package/tests/test_consciousness_loop.py +10 -10
- package/tests/test_coordination.py +25 -0
- package/tests/test_cross_package.py +21 -21
- package/tests/test_daemon.py +4 -4
- package/tests/test_daemon_shutdown.py +1 -1
- package/tests/test_docker_provider.py +29 -29
- package/tests/test_doctor.py +400 -0
- package/tests/test_doctor_skscheduler.py +50 -0
- package/tests/test_dreaming_engine.py +147 -0
- package/tests/test_dreaming_gtd_capture.py +35 -0
- package/tests/test_e2e_automated.py +8 -5
- package/tests/test_fuse_mount.py +10 -10
- package/tests/test_gtd_brief.py +46 -0
- package/tests/test_gtd_malformed_tolerance.py +31 -0
- package/tests/test_housekeeping.py +15 -15
- package/tests/test_identity_migrate.py +251 -0
- package/tests/test_integration_backbone.py +598 -0
- package/tests/test_itil_gtd_lifecycle.py +37 -0
- package/tests/test_jobs_dropins.py +84 -0
- package/tests/test_mcp_server.py +82 -37
- package/tests/test_models.py +48 -4
- package/tests/test_multi_agent.py +31 -29
- package/tests/test_notifications.py +122 -32
- package/tests/test_onboard.py +63 -75
- package/tests/test_operator_link.py +78 -0
- package/tests/test_peers.py +14 -14
- package/tests/test_pillars.py +98 -0
- package/tests/test_preflight.py +3 -3
- package/tests/test_runtime.py +21 -0
- package/tests/test_scheduled_tasks.py +11 -6
- package/tests/test_scheduler_cli.py +47 -0
- package/tests/test_scheduler_features.py +133 -0
- package/tests/test_scheduler_integration.py +87 -0
- package/tests/test_scheduler_jobs.py +155 -0
- package/tests/test_scheduler_runner.py +64 -0
- package/tests/test_scheduler_state.py +57 -0
- package/tests/test_sdk.py +70 -0
- package/tests/test_service_health_incidents.py +34 -0
- package/tests/test_service_registry.py +52 -0
- package/tests/test_session_briefing.py +130 -0
- package/tests/test_snapshots.py +4 -4
- package/tests/test_sync_pipeline.py +26 -26
- package/tests/test_team_comms.py +2 -2
- package/tests/test_testrunner.py +2 -2
- package/tests/test_trust_graph.py +18 -0
- package/tests/test_unified_search.py +2 -2
- package/tests/test_version_check.py +10 -0
- package/tests/test_version_cmd.py +8 -8
- package/tests/test_whoami.py +1 -1
- package/systemd/skcomm-heartbeat.service +0 -18
- package/systemd/skcomm-queue-drain.service +0 -17
- /package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/package.json +0 -0
- /package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/src/openclaw.plugin.json +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""SKComms send/receive messaging tools."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ TOOLS: list[Tool] = [
|
|
|
10
10
|
Tool(
|
|
11
11
|
name="send_message",
|
|
12
12
|
description=(
|
|
13
|
-
"Send a message to another agent via
|
|
13
|
+
"Send a message to another agent via SKComms. "
|
|
14
14
|
"Routes through available transports (Syncthing, file)."
|
|
15
15
|
),
|
|
16
16
|
inputSchema={
|
|
@@ -36,7 +36,7 @@ TOOLS: list[Tool] = [
|
|
|
36
36
|
Tool(
|
|
37
37
|
name="check_inbox",
|
|
38
38
|
description=(
|
|
39
|
-
"Check for new incoming messages across all
|
|
39
|
+
"Check for new incoming messages across all SKComms transports. "
|
|
40
40
|
"Returns any unread message envelopes."
|
|
41
41
|
),
|
|
42
42
|
inputSchema={"type": "object", "properties": {}, "required": []},
|
|
@@ -45,15 +45,15 @@ TOOLS: list[Tool] = [
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
async def _handle_send_message(args: dict) -> list[TextContent]:
|
|
48
|
-
"""Send a message via
|
|
48
|
+
"""Send a message via SKComms."""
|
|
49
49
|
recipient = args.get("recipient", "")
|
|
50
50
|
message = args.get("message", "")
|
|
51
51
|
if not recipient or not message:
|
|
52
52
|
return _error_response("recipient and message are required")
|
|
53
53
|
|
|
54
54
|
try:
|
|
55
|
-
from
|
|
56
|
-
comm =
|
|
55
|
+
from skcomms.core import SKComms
|
|
56
|
+
comm = SKComms.from_config()
|
|
57
57
|
report = comm.send(recipient, message)
|
|
58
58
|
return _json_response({
|
|
59
59
|
"sent": report.success,
|
|
@@ -68,7 +68,7 @@ async def _handle_send_message(args: dict) -> list[TextContent]:
|
|
|
68
68
|
],
|
|
69
69
|
})
|
|
70
70
|
except ImportError:
|
|
71
|
-
return _error_response("
|
|
71
|
+
return _error_response("SKComms not installed. Run: pip install skcomms")
|
|
72
72
|
except Exception as exc:
|
|
73
73
|
return _error_response(f"Send failed: {exc}")
|
|
74
74
|
|
|
@@ -76,8 +76,8 @@ async def _handle_send_message(args: dict) -> list[TextContent]:
|
|
|
76
76
|
async def _handle_check_inbox(_args: dict) -> list[TextContent]:
|
|
77
77
|
"""Check for incoming messages."""
|
|
78
78
|
try:
|
|
79
|
-
from
|
|
80
|
-
comm =
|
|
79
|
+
from skcomms.core import SKComms
|
|
80
|
+
comm = SKComms.from_config()
|
|
81
81
|
envelopes = comm.receive()
|
|
82
82
|
return _json_response([
|
|
83
83
|
{
|
|
@@ -93,7 +93,7 @@ async def _handle_check_inbox(_args: dict) -> list[TextContent]:
|
|
|
93
93
|
for e in envelopes
|
|
94
94
|
])
|
|
95
95
|
except ImportError:
|
|
96
|
-
return _error_response("
|
|
96
|
+
return _error_response("SKComms not installed. Run: pip install skcomms")
|
|
97
97
|
except Exception as exc:
|
|
98
98
|
return _error_response(f"Inbox check failed: {exc}")
|
|
99
99
|
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import logging
|
|
6
|
+
|
|
5
7
|
from mcp.types import TextContent, Tool
|
|
6
8
|
|
|
7
9
|
from ._helpers import _error_response, _home, _json_response, _shared_root
|
|
8
10
|
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
9
13
|
TOOLS: list[Tool] = [
|
|
10
14
|
Tool(
|
|
11
15
|
name="coord_status",
|
|
@@ -149,8 +153,8 @@ async def _handle_coord_claim(args: dict) -> list[TextContent]:
|
|
|
149
153
|
try:
|
|
150
154
|
from .. import activity
|
|
151
155
|
activity.push("task.claimed", {"task_id": task_id, "agent": agent_name})
|
|
152
|
-
except Exception:
|
|
153
|
-
|
|
156
|
+
except Exception as exc:
|
|
157
|
+
logger.warning("Failed to push task.claimed activity for %s: %s", task_id, exc)
|
|
154
158
|
return _json_response({
|
|
155
159
|
"claimed": True,
|
|
156
160
|
"task_id": task_id,
|
|
@@ -175,8 +179,8 @@ async def _handle_coord_complete(args: dict) -> list[TextContent]:
|
|
|
175
179
|
try:
|
|
176
180
|
from .. import activity
|
|
177
181
|
activity.push("task.completed", {"task_id": task_id, "agent": agent_name})
|
|
178
|
-
except Exception:
|
|
179
|
-
|
|
182
|
+
except Exception as exc:
|
|
183
|
+
logger.warning("Failed to push task.completed activity for %s: %s", task_id, exc)
|
|
180
184
|
return _json_response({
|
|
181
185
|
"completed": True,
|
|
182
186
|
"task_id": task_id,
|
|
@@ -10,6 +10,7 @@ Exposes four tools:
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import json as _json
|
|
13
|
+
import logging
|
|
13
14
|
import os as _os
|
|
14
15
|
import socket as _socket
|
|
15
16
|
from pathlib import Path
|
|
@@ -18,6 +19,8 @@ from mcp.types import TextContent, Tool
|
|
|
18
19
|
|
|
19
20
|
from ._helpers import _error_response, _home, _json_response
|
|
20
21
|
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
21
24
|
TOOLS: list[Tool] = [
|
|
22
25
|
Tool(
|
|
23
26
|
name="did_show",
|
|
@@ -165,8 +168,8 @@ def _load_policy() -> dict:
|
|
|
165
168
|
if p.exists():
|
|
166
169
|
try:
|
|
167
170
|
return _json.loads(p.read_text(encoding="utf-8"))
|
|
168
|
-
except Exception:
|
|
169
|
-
|
|
171
|
+
except Exception as exc:
|
|
172
|
+
logger.warning("Failed to load DID policy from %s: %s", p, exc)
|
|
170
173
|
return dict(_POLICY_DEFAULT)
|
|
171
174
|
|
|
172
175
|
|
|
@@ -191,8 +194,8 @@ def _resolve_tailnet(tailnet_hostname: str, tailnet_name: str) -> tuple[str, str
|
|
|
191
194
|
if not tailnet_hostname:
|
|
192
195
|
try:
|
|
193
196
|
tailnet_hostname = _socket.gethostname()
|
|
194
|
-
except Exception:
|
|
195
|
-
|
|
197
|
+
except Exception as exc:
|
|
198
|
+
logger.warning("Failed to resolve hostname for tailnet DID: %s", exc)
|
|
196
199
|
if not tailnet_name:
|
|
197
200
|
tailnet_name = _os.environ.get("SKWORLD_TAILNET", "")
|
|
198
201
|
return tailnet_hostname, tailnet_name
|
|
@@ -297,8 +300,8 @@ async def _handle_did_verify_peer(args: dict) -> list[TextContent]:
|
|
|
297
300
|
_json.dumps(peer_data, indent=2, default=str),
|
|
298
301
|
encoding="utf-8",
|
|
299
302
|
)
|
|
300
|
-
except Exception:
|
|
301
|
-
|
|
303
|
+
except Exception as exc:
|
|
304
|
+
logger.warning("Failed to cache did:key back to peer file %s: %s", peer_file, exc)
|
|
302
305
|
|
|
303
306
|
return _json_response({
|
|
304
307
|
"name": name,
|
|
@@ -361,11 +364,11 @@ async def _handle_did_publish(args: dict) -> list[TextContent]:
|
|
|
361
364
|
except Exception as exc:
|
|
362
365
|
errors.append(f"{path}: {exc}")
|
|
363
366
|
|
|
364
|
-
|
|
367
|
+
skcomms_home = Path(_os.environ.get("SKCOMMS_HOME", str(Path.home() / ".skcomms")))
|
|
365
368
|
did_dir = _home() / "did"
|
|
366
369
|
|
|
367
370
|
# Tier 2 (mesh) — always written; used by Tailscale Serve
|
|
368
|
-
_write(
|
|
371
|
+
_write(skcomms_home / "well-known" / "did.json", _json.dumps(docs[DIDTier.WEB_MESH], indent=2))
|
|
369
372
|
# Tier 1 (did:key) — always written; self-contained anchor
|
|
370
373
|
_write(did_dir / "key.json", _json.dumps(docs[DIDTier.KEY], indent=2))
|
|
371
374
|
_write(did_dir / "did_key.txt", gen._ctx.did_key_id)
|
|
@@ -382,7 +382,7 @@ async def _handle_gtd_capture(args: dict) -> list[TextContent]:
|
|
|
382
382
|
return _json_response({
|
|
383
383
|
"captured": True,
|
|
384
384
|
"id": item["id"],
|
|
385
|
-
"text": item
|
|
385
|
+
"text": item.get("text") or item.get("title") or "",
|
|
386
386
|
"source": item["source"],
|
|
387
387
|
"privacy": item["privacy"],
|
|
388
388
|
"context": item["context"],
|
|
@@ -498,7 +498,7 @@ async def _handle_gtd_clarify(args: dict) -> list[TextContent]:
|
|
|
498
498
|
return _json_response({
|
|
499
499
|
"clarified": True,
|
|
500
500
|
"id": item["id"],
|
|
501
|
-
"text": item
|
|
501
|
+
"text": item.get("text") or item.get("title") or "",
|
|
502
502
|
"destination": dest_name,
|
|
503
503
|
"status": item["status"],
|
|
504
504
|
"priority": item.get("priority"),
|
|
@@ -550,7 +550,7 @@ async def _handle_gtd_move(args: dict) -> list[TextContent]:
|
|
|
550
550
|
return _json_response({
|
|
551
551
|
"moved": True,
|
|
552
552
|
"id": item["id"],
|
|
553
|
-
"text": item
|
|
553
|
+
"text": item.get("text") or item.get("title") or "",
|
|
554
554
|
"from": source_list,
|
|
555
555
|
"to": dest_name,
|
|
556
556
|
"status": item["status"],
|
|
@@ -582,7 +582,7 @@ async def _handle_gtd_done(args: dict) -> list[TextContent]:
|
|
|
582
582
|
return _json_response({
|
|
583
583
|
"done": True,
|
|
584
584
|
"id": item["id"],
|
|
585
|
-
"text": item
|
|
585
|
+
"text": item.get("text") or item.get("title") or "",
|
|
586
586
|
"from": source_list,
|
|
587
587
|
"completed_at": item["completed_at"],
|
|
588
588
|
"archive_count": len(archive),
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import logging
|
|
6
|
+
|
|
5
7
|
from mcp.types import TextContent, Tool
|
|
6
8
|
|
|
7
9
|
from ._helpers import _error_response, _home, _json_response
|
|
8
10
|
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
9
13
|
TOOLS: list[Tool] = [
|
|
10
14
|
Tool(
|
|
11
15
|
name="memory_store",
|
|
@@ -130,8 +134,8 @@ async def _handle_memory_store(args: dict) -> list[TextContent]:
|
|
|
130
134
|
"importance": entry.importance,
|
|
131
135
|
"tags": entry.tags,
|
|
132
136
|
})
|
|
133
|
-
except Exception:
|
|
134
|
-
|
|
137
|
+
except Exception as exc:
|
|
138
|
+
logger.warning("Failed to push memory.stored activity for %s: %s", entry.memory_id, exc)
|
|
135
139
|
return _json_response({
|
|
136
140
|
"memory_id": entry.memory_id,
|
|
137
141
|
"layer": entry.layer.value,
|
|
@@ -54,10 +54,17 @@ async def _handle_send_notification(args: dict) -> list[TextContent]:
|
|
|
54
54
|
if urgency not in {"low", "normal", "critical"}:
|
|
55
55
|
return _error_response("urgency must be one of: low, normal, critical")
|
|
56
56
|
|
|
57
|
+
from ..notifications import desktop_notifications_enabled
|
|
58
|
+
|
|
59
|
+
if not desktop_notifications_enabled():
|
|
60
|
+
timestamp = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
|
61
|
+
return _json_response({"sent": False, "suppressed": True, "timestamp": timestamp})
|
|
62
|
+
|
|
57
63
|
# Run notify-send in a subprocess (non-blocking).
|
|
58
64
|
proc = await asyncio.create_subprocess_exec(
|
|
59
65
|
"notify-send",
|
|
60
|
-
"--urgency",
|
|
66
|
+
"--urgency",
|
|
67
|
+
urgency,
|
|
61
68
|
title,
|
|
62
69
|
body,
|
|
63
70
|
stdout=asyncio.subprocess.DEVNULL,
|
|
@@ -71,16 +78,25 @@ async def _handle_send_notification(args: dict) -> list[TextContent]:
|
|
|
71
78
|
|
|
72
79
|
timestamp = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
|
73
80
|
|
|
74
|
-
# Log notification to
|
|
81
|
+
# Log notification to skcomms/notifications/ (not memory/).
|
|
75
82
|
try:
|
|
76
83
|
import json as _j
|
|
77
84
|
import uuid
|
|
85
|
+
|
|
78
86
|
home = _home()
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
from .. import active_agent_name
|
|
88
|
+
|
|
89
|
+
agent_name = os.environ.get("SKCAPSTONE_AGENT") or active_agent_name()
|
|
90
|
+
notif_dir = home / "agents" / agent_name / "skcomms" / "notifications"
|
|
81
91
|
notif_dir.mkdir(parents=True, exist_ok=True)
|
|
82
|
-
entry = {
|
|
83
|
-
|
|
92
|
+
entry = {
|
|
93
|
+
"id": uuid.uuid4().hex[:12],
|
|
94
|
+
"type": "notification-sent",
|
|
95
|
+
"title": title,
|
|
96
|
+
"body": body,
|
|
97
|
+
"urgency": urgency,
|
|
98
|
+
"timestamp": timestamp,
|
|
99
|
+
}
|
|
84
100
|
(notif_dir / f"{entry['id']}.json").write_text(_j.dumps(entry, indent=2))
|
|
85
101
|
except Exception:
|
|
86
102
|
pass # notification log failure must not block the response
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""SKComms notification and status tools.
|
|
2
2
|
|
|
3
3
|
Exposes two tools:
|
|
4
|
-
comm_notify — Send a notification via
|
|
5
|
-
comm_status — Show
|
|
4
|
+
comm_notify — Send a notification via SKComms transports
|
|
5
|
+
comm_status — Show SKComms subsystem status
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
@@ -15,7 +15,7 @@ TOOLS: list[Tool] = [
|
|
|
15
15
|
Tool(
|
|
16
16
|
name="comm_notify",
|
|
17
17
|
description=(
|
|
18
|
-
"Send a notification message via
|
|
18
|
+
"Send a notification message via SKComms. Routes through "
|
|
19
19
|
"available transports (Syncthing, file, Tailscale). "
|
|
20
20
|
"Supports urgency levels for priority routing."
|
|
21
21
|
),
|
|
@@ -46,7 +46,7 @@ TOOLS: list[Tool] = [
|
|
|
46
46
|
Tool(
|
|
47
47
|
name="comm_status",
|
|
48
48
|
description=(
|
|
49
|
-
"Show
|
|
49
|
+
"Show SKComms subsystem status: installed version, "
|
|
50
50
|
"available transports, connection state, and recent "
|
|
51
51
|
"delivery statistics."
|
|
52
52
|
),
|
|
@@ -56,16 +56,16 @@ TOOLS: list[Tool] = [
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
async def _handle_comm_notify(args: dict) -> list[TextContent]:
|
|
59
|
-
"""Send a notification via
|
|
59
|
+
"""Send a notification via SKComms."""
|
|
60
60
|
recipient = args.get("recipient", "")
|
|
61
61
|
message = args.get("message", "")
|
|
62
62
|
if not recipient or not message:
|
|
63
63
|
return _error_response("recipient and message are required")
|
|
64
64
|
|
|
65
65
|
try:
|
|
66
|
-
from
|
|
66
|
+
from skcomms.core import SKComms # type: ignore[import]
|
|
67
67
|
|
|
68
|
-
comm =
|
|
68
|
+
comm = SKComms.from_config()
|
|
69
69
|
report = comm.send(recipient, message)
|
|
70
70
|
return _json_response({
|
|
71
71
|
"sent": report.success,
|
|
@@ -81,29 +81,29 @@ async def _handle_comm_notify(args: dict) -> list[TextContent]:
|
|
|
81
81
|
],
|
|
82
82
|
})
|
|
83
83
|
except ImportError:
|
|
84
|
-
return _error_response("
|
|
84
|
+
return _error_response("SKComms not installed. Run: pip install skcomms")
|
|
85
85
|
except Exception as exc:
|
|
86
86
|
return _error_response(f"Notification send failed: {exc}")
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
async def _handle_comm_status(_args: dict) -> list[TextContent]:
|
|
90
|
-
"""Show
|
|
90
|
+
"""Show SKComms subsystem status."""
|
|
91
91
|
result: dict = {}
|
|
92
92
|
|
|
93
93
|
try:
|
|
94
|
-
import
|
|
94
|
+
import skcomms # type: ignore[import]
|
|
95
95
|
|
|
96
96
|
result["installed"] = True
|
|
97
|
-
result["version"] = getattr(
|
|
97
|
+
result["version"] = getattr(skcomms, "__version__", "unknown")
|
|
98
98
|
except ImportError:
|
|
99
99
|
result["installed"] = False
|
|
100
100
|
result["version"] = None
|
|
101
101
|
return _json_response(result)
|
|
102
102
|
|
|
103
103
|
try:
|
|
104
|
-
from
|
|
104
|
+
from skcomms.core import SKComms # type: ignore[import]
|
|
105
105
|
|
|
106
|
-
comm =
|
|
106
|
+
comm = SKComms.from_config()
|
|
107
107
|
result["transports"] = [
|
|
108
108
|
t.name for t in getattr(comm, "transports", [])
|
|
109
109
|
]
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import logging
|
|
6
|
+
|
|
5
7
|
from mcp.types import TextContent, Tool
|
|
6
8
|
|
|
7
9
|
from ._helpers import _error_response, _home, _json_response, _text_response
|
|
8
10
|
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
9
13
|
TOOLS: list[Tool] = [
|
|
10
14
|
Tool(
|
|
11
15
|
name="soul_list",
|
|
@@ -179,6 +183,8 @@ async def _handle_ritual(args: dict) -> list[TextContent]:
|
|
|
179
183
|
"journal_entries": result.journal_entries,
|
|
180
184
|
"germination_prompts": result.germination_prompts,
|
|
181
185
|
"strongest_memories": result.strongest_memories,
|
|
186
|
+
"song_anchors_loaded": result.song_anchors_loaded,
|
|
187
|
+
"song_anchor_ids": result.song_anchor_ids,
|
|
182
188
|
"context_prompt": result.context_prompt,
|
|
183
189
|
})
|
|
184
190
|
except ImportError:
|
|
@@ -250,8 +256,8 @@ async def _handle_soul_list(args: dict) -> list[TextContent]:
|
|
|
250
256
|
"source": "installed",
|
|
251
257
|
"active": name == state.active_soul,
|
|
252
258
|
})
|
|
253
|
-
except Exception:
|
|
254
|
-
|
|
259
|
+
except Exception as exc:
|
|
260
|
+
logger.warning("Failed to list installed soul blueprints: %s", exc)
|
|
255
261
|
|
|
256
262
|
# 2) Blueprints repo
|
|
257
263
|
blueprints_repo = Path.home() / "clawd" / "soul-blueprints" / "blueprints"
|
|
@@ -238,8 +238,8 @@ class MDNSDiscovery:
|
|
|
238
238
|
agent_name,
|
|
239
239
|
)
|
|
240
240
|
return
|
|
241
|
-
except Exception:
|
|
242
|
-
|
|
241
|
+
except Exception as exc:
|
|
242
|
+
logger.warning("Failed to read existing mDNS heartbeat for %s: %s", agent_name, exc)
|
|
243
243
|
|
|
244
244
|
heartbeat = {
|
|
245
245
|
"agent_name": agent_name,
|
|
@@ -59,7 +59,7 @@ _TAG_PATTERNS: list[tuple[re.Pattern, str]] = [
|
|
|
59
59
|
(re.compile(r"\bcapauth\b", re.I), "capauth"),
|
|
60
60
|
(re.compile(r"\bskcapstone\b", re.I), "skcapstone"),
|
|
61
61
|
(re.compile(r"\bskmemory\b", re.I), "skmemory"),
|
|
62
|
-
(re.compile(r"\
|
|
62
|
+
(re.compile(r"\bskcomms\b", re.I), "skcomms"),
|
|
63
63
|
(re.compile(r"\bskchat\b", re.I), "skchat"),
|
|
64
64
|
(re.compile(r"\bsyncthing\b", re.I), "syncthing"),
|
|
65
65
|
(re.compile(r"\bMCP\b", re.I), "mcp"),
|
|
@@ -25,6 +25,7 @@ from datetime import datetime, timezone
|
|
|
25
25
|
from pathlib import Path
|
|
26
26
|
from typing import Optional
|
|
27
27
|
|
|
28
|
+
from . import active_agent_name
|
|
28
29
|
from .models import MemoryEntry, MemoryLayer, MemoryState, PillarStatus
|
|
29
30
|
|
|
30
31
|
logger = logging.getLogger("skcapstone.memory")
|
|
@@ -48,9 +49,15 @@ def _get_unified():
|
|
|
48
49
|
|
|
49
50
|
def _memory_dir(home: Path) -> Path:
|
|
50
51
|
"""Resolve the memory directory, creating it if needed."""
|
|
51
|
-
#
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
# Accept either the shared root (~/.skcapstone) or an agent home
|
|
53
|
+
# (~/.skcapstone/agents/<agent>) and resolve to the active memory dir.
|
|
54
|
+
agent_name = os.environ.get("SKCAPSTONE_AGENT") or active_agent_name()
|
|
55
|
+
if home.parent.name == "agents":
|
|
56
|
+
mem = home / "memory"
|
|
57
|
+
elif agent_name:
|
|
58
|
+
mem = home / "agents" / agent_name / "memory"
|
|
59
|
+
else:
|
|
60
|
+
mem = home / "memory"
|
|
54
61
|
mem.mkdir(parents=True, exist_ok=True)
|
|
55
62
|
for layer in MemoryLayer:
|
|
56
63
|
(mem / layer.value).mkdir(parents=True, exist_ok=True)
|
|
@@ -59,7 +59,7 @@ class ChatMetrics(BaseModel):
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
class TransportMetrics(BaseModel):
|
|
62
|
-
"""
|
|
62
|
+
"""SKComms transport stats."""
|
|
63
63
|
|
|
64
64
|
available: bool = False
|
|
65
65
|
transport_count: int = 0
|
|
@@ -242,7 +242,8 @@ class MetricsCollector:
|
|
|
242
242
|
try:
|
|
243
243
|
data = json.loads(fp.read_text(encoding="utf-8"))
|
|
244
244
|
return data.get("name") or data.get("agent_name") or ""
|
|
245
|
-
except Exception:
|
|
245
|
+
except Exception as e:
|
|
246
|
+
logger.warning("metrics.py: %s", e)
|
|
246
247
|
continue
|
|
247
248
|
return "unknown"
|
|
248
249
|
|
|
@@ -265,6 +266,7 @@ class MetricsCollector:
|
|
|
265
266
|
name=entity.get("name", ""),
|
|
266
267
|
)
|
|
267
268
|
except Exception as exc:
|
|
269
|
+
logger.warning("metrics.py: %s", exc)
|
|
268
270
|
report.errors.append(f"identity: {exc}")
|
|
269
271
|
|
|
270
272
|
def _collect_memory(self, report: MetricsReport) -> None:
|
|
@@ -304,6 +306,7 @@ class MetricsCollector:
|
|
|
304
306
|
except ImportError:
|
|
305
307
|
pass
|
|
306
308
|
except Exception as exc:
|
|
309
|
+
logger.warning("metrics.py: %s", exc)
|
|
307
310
|
report.errors.append(f"memory: {exc}")
|
|
308
311
|
|
|
309
312
|
def _collect_chat(self, report: MetricsReport) -> None:
|
|
@@ -331,13 +334,14 @@ class MetricsCollector:
|
|
|
331
334
|
except ImportError:
|
|
332
335
|
pass
|
|
333
336
|
except Exception as exc:
|
|
337
|
+
logger.warning("metrics.py: %s", exc)
|
|
334
338
|
report.errors.append(f"chat: {exc}")
|
|
335
339
|
|
|
336
340
|
def _collect_transport(self, report: MetricsReport) -> None:
|
|
337
|
-
"""Collect
|
|
341
|
+
"""Collect SKComms transport metrics."""
|
|
338
342
|
try:
|
|
339
|
-
|
|
340
|
-
outbox_dir =
|
|
343
|
+
skcomms_dir = Path.home() / ".skcomms"
|
|
344
|
+
outbox_dir = skcomms_dir / "outbox"
|
|
341
345
|
|
|
342
346
|
pending = 0
|
|
343
347
|
dead = 0
|
|
@@ -346,20 +350,20 @@ class MetricsCollector:
|
|
|
346
350
|
if (outbox_dir / "dead").exists():
|
|
347
351
|
dead = len(list((outbox_dir / "dead").glob("*.json")))
|
|
348
352
|
|
|
349
|
-
config_path =
|
|
353
|
+
config_path = skcomms_dir / "config.yml"
|
|
350
354
|
transport_count = 0
|
|
351
355
|
if config_path.exists():
|
|
352
356
|
try:
|
|
353
357
|
import yaml
|
|
354
358
|
|
|
355
359
|
cfg = yaml.safe_load(config_path.read_text(encoding="utf-8"))
|
|
356
|
-
transports = cfg.get("
|
|
360
|
+
transports = cfg.get("skcomms", {}).get("transports", {})
|
|
357
361
|
transport_count = sum(
|
|
358
362
|
1 for t in transports.values()
|
|
359
363
|
if isinstance(t, dict) and t.get("enabled", True)
|
|
360
364
|
)
|
|
361
|
-
except Exception:
|
|
362
|
-
|
|
365
|
+
except Exception as exc:
|
|
366
|
+
logger.warning("Failed to parse skcomms transport config: %s", exc)
|
|
363
367
|
|
|
364
368
|
report.transport = TransportMetrics(
|
|
365
369
|
available=True,
|
|
@@ -368,6 +372,7 @@ class MetricsCollector:
|
|
|
368
372
|
outbox_dead=dead,
|
|
369
373
|
)
|
|
370
374
|
except Exception as exc:
|
|
375
|
+
logger.warning("metrics.py: %s", exc)
|
|
371
376
|
report.errors.append(f"transport: {exc}")
|
|
372
377
|
|
|
373
378
|
def _collect_coordination(self, report: MetricsReport) -> None:
|
|
@@ -390,7 +395,8 @@ class MetricsCollector:
|
|
|
390
395
|
if status in counts:
|
|
391
396
|
counts[status] += 1
|
|
392
397
|
total += 1
|
|
393
|
-
except Exception:
|
|
398
|
+
except Exception as e:
|
|
399
|
+
logger.warning("metrics.py: %s", e)
|
|
394
400
|
total += 1
|
|
395
401
|
|
|
396
402
|
report.coordination = CoordinationMetrics(
|
|
@@ -401,6 +407,7 @@ class MetricsCollector:
|
|
|
401
407
|
claimed=counts["claimed"],
|
|
402
408
|
)
|
|
403
409
|
except Exception as exc:
|
|
410
|
+
logger.warning("metrics.py: %s", exc)
|
|
404
411
|
report.errors.append(f"coordination: {exc}")
|
|
405
412
|
|
|
406
413
|
def _collect_trust(self, report: MetricsReport) -> None:
|
|
@@ -424,6 +431,7 @@ class MetricsCollector:
|
|
|
424
431
|
last_rehydration=data.get("last_rehydration", ""),
|
|
425
432
|
)
|
|
426
433
|
except Exception as exc:
|
|
434
|
+
logger.warning("metrics.py: %s", exc)
|
|
427
435
|
report.errors.append(f"trust: {exc}")
|
|
428
436
|
|
|
429
437
|
def _collect_security(self, report: MetricsReport) -> None:
|
|
@@ -455,6 +463,7 @@ class MetricsCollector:
|
|
|
455
463
|
event_types=type_counts,
|
|
456
464
|
)
|
|
457
465
|
except Exception as exc:
|
|
466
|
+
logger.warning("metrics.py: %s", exc)
|
|
458
467
|
report.errors.append(f"security: {exc}")
|
|
459
468
|
|
|
460
469
|
def _collect_sync(self, report: MetricsReport) -> None:
|
|
@@ -474,8 +483,8 @@ class MetricsCollector:
|
|
|
474
483
|
if state_path.exists():
|
|
475
484
|
try:
|
|
476
485
|
state = json.loads(state_path.read_text(encoding="utf-8"))
|
|
477
|
-
except Exception:
|
|
478
|
-
|
|
486
|
+
except Exception as exc:
|
|
487
|
+
logger.warning("Failed to read sync_state.json: %s", exc)
|
|
479
488
|
|
|
480
489
|
report.sync = SyncMetrics(
|
|
481
490
|
available=True,
|
|
@@ -486,6 +495,7 @@ class MetricsCollector:
|
|
|
486
495
|
last_pull=state.get("last_pull", ""),
|
|
487
496
|
)
|
|
488
497
|
except Exception as exc:
|
|
498
|
+
logger.warning("metrics.py: %s", exc)
|
|
489
499
|
report.errors.append(f"sync: {exc}")
|
|
490
500
|
|
|
491
501
|
def _collect_pubsub(self, report: MetricsReport) -> None:
|
|
@@ -510,8 +520,8 @@ class MetricsCollector:
|
|
|
510
520
|
try:
|
|
511
521
|
subs = json.loads(subs_file.read_text(encoding="utf-8"))
|
|
512
522
|
sub_count = len(subs)
|
|
513
|
-
except Exception:
|
|
514
|
-
|
|
523
|
+
except Exception as exc:
|
|
524
|
+
logger.warning("Failed to read pubsub subscriptions.json: %s", exc)
|
|
515
525
|
|
|
516
526
|
report.pubsub = PubSubMetrics(
|
|
517
527
|
available=True,
|
|
@@ -520,6 +530,7 @@ class MetricsCollector:
|
|
|
520
530
|
subscriptions=sub_count,
|
|
521
531
|
)
|
|
522
532
|
except Exception as exc:
|
|
533
|
+
logger.warning("metrics.py: %s", exc)
|
|
523
534
|
report.errors.append(f"pubsub: {exc}")
|
|
524
535
|
|
|
525
536
|
def _collect_kms(self, report: MetricsReport) -> None:
|
|
@@ -546,8 +557,8 @@ class MetricsCollector:
|
|
|
546
557
|
try:
|
|
547
558
|
rot_data = json.loads(rot_log.read_text(encoding="utf-8"))
|
|
548
559
|
rotations = len(rot_data)
|
|
549
|
-
except Exception:
|
|
550
|
-
|
|
560
|
+
except Exception as exc:
|
|
561
|
+
logger.warning("Failed to read KMS rotation log: %s", exc)
|
|
551
562
|
|
|
552
563
|
report.kms = KmsMetrics(
|
|
553
564
|
available=True,
|
|
@@ -557,6 +568,7 @@ class MetricsCollector:
|
|
|
557
568
|
rotations=rotations,
|
|
558
569
|
)
|
|
559
570
|
except Exception as exc:
|
|
571
|
+
logger.warning("metrics.py: %s", exc)
|
|
560
572
|
report.errors.append(f"kms: {exc}")
|
|
561
573
|
|
|
562
574
|
def _collect_fortress(self, report: MetricsReport) -> None:
|
|
@@ -573,6 +585,7 @@ class MetricsCollector:
|
|
|
573
585
|
seal_algorithm=data.get("seal_algorithm", ""),
|
|
574
586
|
)
|
|
575
587
|
except Exception as exc:
|
|
588
|
+
logger.warning("metrics.py: %s", exc)
|
|
576
589
|
report.errors.append(f"fortress: {exc}")
|
|
577
590
|
|
|
578
591
|
def _collect_backup(self, report: MetricsReport) -> None:
|
|
@@ -593,6 +606,7 @@ class MetricsCollector:
|
|
|
593
606
|
latest_size_bytes=latest.stat().st_size,
|
|
594
607
|
)
|
|
595
608
|
except Exception as exc:
|
|
609
|
+
logger.warning("metrics.py: %s", exc)
|
|
596
610
|
report.errors.append(f"backup: {exc}")
|
|
597
611
|
|
|
598
612
|
|
|
@@ -100,8 +100,8 @@ def migrate(
|
|
|
100
100
|
try:
|
|
101
101
|
existing = store.list_memories(limit=10000)
|
|
102
102
|
existing_ids = {m.id for m in existing}
|
|
103
|
-
except Exception:
|
|
104
|
-
|
|
103
|
+
except Exception as exc:
|
|
104
|
+
logger.warning("Failed to load existing memory IDs for deduplication: %s", exc)
|
|
105
105
|
|
|
106
106
|
for entry in entries:
|
|
107
107
|
if entry.memory_id in existing_ids:
|
|
@@ -162,7 +162,8 @@ def _verify_migration(
|
|
|
162
162
|
recalled = store.recall(entry.memory_id)
|
|
163
163
|
if recalled is None:
|
|
164
164
|
missing.append(entry.memory_id)
|
|
165
|
-
except Exception:
|
|
165
|
+
except Exception as e:
|
|
166
|
+
logger.warning("migrate_memories.py: %s", e)
|
|
166
167
|
missing.append(entry.memory_id)
|
|
167
168
|
|
|
168
169
|
result["verified"] = len(entries) - len(missing)
|