@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
|
@@ -54,20 +54,20 @@ _SERVICE_DEFS: list[dict] = [
|
|
|
54
54
|
"logs": "{logs}/memory-compress",
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
|
-
"suffix": "
|
|
58
|
-
"args": ["{skenv}/
|
|
57
|
+
"suffix": "skcomms-heartbeat",
|
|
58
|
+
"args": ["{skenv}/skcomms", "heartbeat"],
|
|
59
59
|
"env": {},
|
|
60
60
|
"interval": 60,
|
|
61
61
|
"nice": 19,
|
|
62
|
-
"logs": "{logs}/
|
|
62
|
+
"logs": "{logs}/skcomms-heartbeat",
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
|
-
"suffix": "
|
|
66
|
-
"args": ["{skenv}/
|
|
65
|
+
"suffix": "skcomms-queue-drain",
|
|
66
|
+
"args": ["{skenv}/skcomms", "queue", "drain"],
|
|
67
67
|
"env": {},
|
|
68
68
|
"interval": 120,
|
|
69
69
|
"nice": 19,
|
|
70
|
-
"logs": "{logs}/
|
|
70
|
+
"logs": "{logs}/skcomms-queue-drain",
|
|
71
71
|
},
|
|
72
72
|
]
|
|
73
73
|
|
|
@@ -84,23 +84,23 @@ _OPTIONAL_DEFS: list[dict] = [
|
|
|
84
84
|
"requires_bin": "skchat",
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
|
-
"suffix": "
|
|
88
|
-
"args": ["{skenv}/python3", "-m", "uvicorn", "
|
|
87
|
+
"suffix": "skcomms-api",
|
|
88
|
+
"args": ["{skenv}/python3", "-m", "uvicorn", "skcomms.api:app",
|
|
89
89
|
"--host", "127.0.0.1", "--port", "9384", "--log-level", "info"],
|
|
90
90
|
"env": {"SKCHAT_IDENTITY": "capauth:{agent}@skworld.io"},
|
|
91
91
|
"keep_alive": True,
|
|
92
92
|
"throttle": 5,
|
|
93
|
-
"logs": "{
|
|
94
|
-
"requires_bin": "
|
|
93
|
+
"logs": "{skcomms}/launchd",
|
|
94
|
+
"requires_bin": "skcomms",
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
|
-
"suffix": "
|
|
98
|
-
"args": ["{skenv}/
|
|
97
|
+
"suffix": "skcomms-daemon",
|
|
98
|
+
"args": ["{skenv}/skcomms", "daemon", "--all-agents", "--interval", "5"],
|
|
99
99
|
"env": {},
|
|
100
100
|
"keep_alive": True,
|
|
101
101
|
"throttle": 5,
|
|
102
|
-
"logs": "{
|
|
103
|
-
"requires_bin": "
|
|
102
|
+
"logs": "{skcomms}/daemon",
|
|
103
|
+
"requires_bin": "skcomms",
|
|
104
104
|
},
|
|
105
105
|
]
|
|
106
106
|
|
|
@@ -127,7 +127,7 @@ def _expand(s: str, agent: str) -> str:
|
|
|
127
127
|
.replace("{home}", home)
|
|
128
128
|
.replace("{logs}", f"{home}/.skcapstone/logs")
|
|
129
129
|
.replace("{skchat}", f"{home}/.skchat")
|
|
130
|
-
.replace("{
|
|
130
|
+
.replace("{skcomms}", f"{home}/.skcomms")
|
|
131
131
|
)
|
|
132
132
|
|
|
133
133
|
|
|
@@ -281,7 +281,7 @@ def install_service(
|
|
|
281
281
|
log_dirs = [
|
|
282
282
|
Path.home() / ".skcapstone" / "logs",
|
|
283
283
|
Path.home() / ".skchat",
|
|
284
|
-
Path.home() / ".
|
|
284
|
+
Path.home() / ".skcomms",
|
|
285
285
|
]
|
|
286
286
|
for d in log_dirs:
|
|
287
287
|
d.mkdir(parents=True, exist_ok=True)
|
|
@@ -355,7 +355,7 @@ def service_status(suffix: str = "daemon") -> ServiceStatus:
|
|
|
355
355
|
"""Query the status of a specific SK launchd service.
|
|
356
356
|
|
|
357
357
|
Args:
|
|
358
|
-
suffix: Service suffix (e.g., 'daemon', '
|
|
358
|
+
suffix: Service suffix (e.g., 'daemon', 'skcomms-heartbeat').
|
|
359
359
|
|
|
360
360
|
Returns:
|
|
361
361
|
ServiceStatus with current state.
|
|
@@ -420,7 +420,7 @@ def service_logs(suffix: str = "daemon", lines: int = 50) -> str:
|
|
|
420
420
|
)
|
|
421
421
|
if r.stdout.strip():
|
|
422
422
|
output_parts.append(f"--- {log_path.name} ---\n{r.stdout}")
|
|
423
|
-
except Exception:
|
|
424
|
-
|
|
423
|
+
except Exception as exc:
|
|
424
|
+
logger.warning("Failed to read launchd log %s: %s", log_path, exc)
|
|
425
425
|
|
|
426
426
|
return "\n".join(output_parts) if output_parts else f"No logs found in {logs_dir}"
|
|
@@ -138,9 +138,23 @@ def _setup_environment() -> None:
|
|
|
138
138
|
"""Set required environment variables if not already present."""
|
|
139
139
|
home = Path.home()
|
|
140
140
|
skcapstone_home = home / ".skcapstone"
|
|
141
|
+
agent_name = os.environ.get("SKCAPSTONE_AGENT")
|
|
142
|
+
if not agent_name:
|
|
143
|
+
try:
|
|
144
|
+
from . import active_agent_name
|
|
145
|
+
|
|
146
|
+
agent_name = active_agent_name()
|
|
147
|
+
except Exception as e:
|
|
148
|
+
logger.warning("mcp_launcher.py: %s", e)
|
|
149
|
+
agent_name = None
|
|
141
150
|
|
|
142
151
|
os.environ.setdefault("SKCAPSTONE_HOME", str(skcapstone_home))
|
|
143
|
-
|
|
152
|
+
if agent_name:
|
|
153
|
+
os.environ.setdefault("SKCAPSTONE_AGENT", agent_name)
|
|
154
|
+
os.environ.setdefault(
|
|
155
|
+
"SKMEMORY_HOME",
|
|
156
|
+
str(skcapstone_home / "agents" / agent_name / "memory"),
|
|
157
|
+
)
|
|
144
158
|
|
|
145
159
|
# Ensure src/ is on PYTHONPATH for importability
|
|
146
160
|
src_dir = str(Path(__file__).resolve().parent.parent)
|
|
@@ -9,8 +9,8 @@ Tools:
|
|
|
9
9
|
memory_store — Save content to SKMemory
|
|
10
10
|
memory_search — Search memories by query
|
|
11
11
|
memory_recall — Recall a specific memory by ID
|
|
12
|
-
send_message — Send a message via
|
|
13
|
-
check_inbox — Check for new
|
|
12
|
+
send_message — Send a message via SKComms
|
|
13
|
+
check_inbox — Check for new SKComms messages
|
|
14
14
|
sync_push — Push agent state to sync mesh
|
|
15
15
|
sync_pull — Pull seeds from peers
|
|
16
16
|
coord_status — Show coordination board
|
|
@@ -108,33 +108,18 @@ from mcp.server import Server
|
|
|
108
108
|
from mcp.server.stdio import stdio_server
|
|
109
109
|
from mcp.types import TextContent, Tool
|
|
110
110
|
|
|
111
|
-
from . import
|
|
111
|
+
from .mcp_tools._helpers import (
|
|
112
|
+
_error_response,
|
|
113
|
+
_home,
|
|
114
|
+
_json_response,
|
|
115
|
+
_text_response,
|
|
116
|
+
)
|
|
112
117
|
|
|
113
118
|
logger = logging.getLogger("skcapstone.mcp")
|
|
114
119
|
|
|
115
120
|
server = Server("skcapstone")
|
|
116
121
|
|
|
117
122
|
|
|
118
|
-
def _home() -> Path:
|
|
119
|
-
"""Resolve the agent home directory."""
|
|
120
|
-
return Path(AGENT_HOME).expanduser()
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def _json_response(data: Any) -> list[TextContent]:
|
|
124
|
-
"""Wrap data as a JSON text content response."""
|
|
125
|
-
return [TextContent(type="text", text=json.dumps(data, indent=2, default=str))]
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def _text_response(text: str) -> list[TextContent]:
|
|
129
|
-
"""Wrap a plain string as a text content response."""
|
|
130
|
-
return [TextContent(type="text", text=text)]
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def _error_response(message: str) -> list[TextContent]:
|
|
134
|
-
"""Return an error message as text content."""
|
|
135
|
-
return [TextContent(type="text", text=json.dumps({"error": message}))]
|
|
136
|
-
|
|
137
|
-
|
|
138
123
|
def _get_agent_name(home: Path) -> str:
|
|
139
124
|
"""Read the agent name from identity file."""
|
|
140
125
|
identity_path = home / "identity" / "identity.json"
|
|
@@ -142,8 +127,8 @@ def _get_agent_name(home: Path) -> str:
|
|
|
142
127
|
try:
|
|
143
128
|
data = json.loads(identity_path.read_text(encoding="utf-8"))
|
|
144
129
|
return data.get("name", "anonymous")
|
|
145
|
-
except Exception:
|
|
146
|
-
|
|
130
|
+
except Exception as exc:
|
|
131
|
+
logger.warning("Failed to read agent name from identity.json: %s", exc)
|
|
147
132
|
return "anonymous"
|
|
148
133
|
|
|
149
134
|
|
|
@@ -242,7 +227,7 @@ async def list_tools() -> list[Tool]:
|
|
|
242
227
|
Tool(
|
|
243
228
|
name="send_message",
|
|
244
229
|
description=(
|
|
245
|
-
"Send a message to another agent via
|
|
230
|
+
"Send a message to another agent via SKComms. "
|
|
246
231
|
"Routes through available transports (Syncthing, file)."
|
|
247
232
|
),
|
|
248
233
|
inputSchema={
|
|
@@ -268,7 +253,7 @@ async def list_tools() -> list[Tool]:
|
|
|
268
253
|
Tool(
|
|
269
254
|
name="check_inbox",
|
|
270
255
|
description=(
|
|
271
|
-
"Check for new incoming messages across all
|
|
256
|
+
"Check for new incoming messages across all SKComms transports. "
|
|
272
257
|
"Returns any unread message envelopes."
|
|
273
258
|
),
|
|
274
259
|
inputSchema={"type": "object", "properties": {}, "required": []},
|
|
@@ -1643,7 +1628,7 @@ async def list_tools() -> list[Tool]:
|
|
|
1643
1628
|
description=(
|
|
1644
1629
|
"Check ecosystem package versions against PyPI. "
|
|
1645
1630
|
"Shows installed vs latest for skmemory, skcapstone, capauth, "
|
|
1646
|
-
"sksecurity,
|
|
1631
|
+
"sksecurity, skcomms, skchat, cloud9."
|
|
1647
1632
|
),
|
|
1648
1633
|
inputSchema={
|
|
1649
1634
|
"type": "object",
|
|
@@ -2368,11 +2353,11 @@ async def list_tools() -> list[Tool]:
|
|
|
2368
2353
|
"required": [],
|
|
2369
2354
|
},
|
|
2370
2355
|
),
|
|
2371
|
-
# ──
|
|
2356
|
+
# ── SKComms tools ──────────────────────────────────────
|
|
2372
2357
|
Tool(
|
|
2373
2358
|
name="comm_notify",
|
|
2374
2359
|
description=(
|
|
2375
|
-
"Send a notification message via
|
|
2360
|
+
"Send a notification message via SKComms. Routes through "
|
|
2376
2361
|
"available transports (Syncthing, file, Tailscale). "
|
|
2377
2362
|
"Supports urgency levels for priority routing."
|
|
2378
2363
|
),
|
|
@@ -2403,7 +2388,7 @@ async def list_tools() -> list[Tool]:
|
|
|
2403
2388
|
Tool(
|
|
2404
2389
|
name="comm_status",
|
|
2405
2390
|
description=(
|
|
2406
|
-
"Show
|
|
2391
|
+
"Show SKComms subsystem status: installed version, "
|
|
2407
2392
|
"available transports, connection state, and recent "
|
|
2408
2393
|
"delivery statistics."
|
|
2409
2394
|
),
|
|
@@ -2654,6 +2639,39 @@ async def list_tools() -> list[Tool]:
|
|
|
2654
2639
|
"required": ["query"],
|
|
2655
2640
|
},
|
|
2656
2641
|
),
|
|
2642
|
+
# Brain-First Protocol
|
|
2643
|
+
Tool(
|
|
2644
|
+
name="brain_first_check",
|
|
2645
|
+
description=(
|
|
2646
|
+
"Brain-First Protocol: consult the agent's memory before "
|
|
2647
|
+
"acting on a task. Extracts keywords from the given context, "
|
|
2648
|
+
"searches memory for relevant prior knowledge, and returns "
|
|
2649
|
+
"any matching memories. Use this before starting new work to "
|
|
2650
|
+
"avoid duplicating effort or missing prior decisions."
|
|
2651
|
+
),
|
|
2652
|
+
inputSchema={
|
|
2653
|
+
"type": "object",
|
|
2654
|
+
"properties": {
|
|
2655
|
+
"context": {
|
|
2656
|
+
"type": "string",
|
|
2657
|
+
"description": (
|
|
2658
|
+
"The task description, prompt, or action context "
|
|
2659
|
+
"to search memory for"
|
|
2660
|
+
),
|
|
2661
|
+
},
|
|
2662
|
+
"tags": {
|
|
2663
|
+
"type": "array",
|
|
2664
|
+
"items": {"type": "string"},
|
|
2665
|
+
"description": "Optional tag filter for the memory search",
|
|
2666
|
+
},
|
|
2667
|
+
"max_results": {
|
|
2668
|
+
"type": "integer",
|
|
2669
|
+
"description": "Max memories to return (default: from config, usually 5)",
|
|
2670
|
+
},
|
|
2671
|
+
},
|
|
2672
|
+
"required": ["context"],
|
|
2673
|
+
},
|
|
2674
|
+
),
|
|
2657
2675
|
]
|
|
2658
2676
|
|
|
2659
2677
|
|
|
@@ -2793,7 +2811,7 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
|
|
2793
2811
|
# SKChat
|
|
2794
2812
|
"chat_send": _handle_chat_send,
|
|
2795
2813
|
"chat_history": _handle_chat_history,
|
|
2796
|
-
#
|
|
2814
|
+
# SKComms
|
|
2797
2815
|
"comm_notify": _handle_comm_notify,
|
|
2798
2816
|
"comm_status": _handle_comm_status,
|
|
2799
2817
|
# CapAuth
|
|
@@ -2813,6 +2831,8 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
|
|
2813
2831
|
"itil_cab_vote": _handle_itil_cab_vote,
|
|
2814
2832
|
"itil_status": _handle_itil_status,
|
|
2815
2833
|
"itil_kedb_search": _handle_itil_kedb_search,
|
|
2834
|
+
# Brain-First Protocol
|
|
2835
|
+
"brain_first_check": _handle_brain_first_check,
|
|
2816
2836
|
}
|
|
2817
2837
|
handler = handlers.get(name)
|
|
2818
2838
|
if handler is None:
|
|
@@ -2842,7 +2862,8 @@ def _get_memory_backend_health() -> dict:
|
|
|
2842
2862
|
if "graph" in health:
|
|
2843
2863
|
backends["skgraph"] = "ok" if health["graph"].get("ok") else "error"
|
|
2844
2864
|
return backends or {"json": "ok"}
|
|
2845
|
-
except Exception:
|
|
2865
|
+
except Exception as e:
|
|
2866
|
+
logger.warning("Failed to get memory backend health: %s", e)
|
|
2846
2867
|
return {"json": "ok"}
|
|
2847
2868
|
|
|
2848
2869
|
|
|
@@ -2973,15 +2994,15 @@ async def _handle_memory_recall(args: dict) -> list[TextContent]:
|
|
|
2973
2994
|
|
|
2974
2995
|
|
|
2975
2996
|
async def _handle_send_message(args: dict) -> list[TextContent]:
|
|
2976
|
-
"""Send a message via
|
|
2997
|
+
"""Send a message via SKComms."""
|
|
2977
2998
|
recipient = args.get("recipient", "")
|
|
2978
2999
|
message = args.get("message", "")
|
|
2979
3000
|
if not recipient or not message:
|
|
2980
3001
|
return _error_response("recipient and message are required")
|
|
2981
3002
|
|
|
2982
3003
|
try:
|
|
2983
|
-
from
|
|
2984
|
-
comm =
|
|
3004
|
+
from skcomms.core import SKComms
|
|
3005
|
+
comm = SKComms.from_config()
|
|
2985
3006
|
report = comm.send(recipient, message)
|
|
2986
3007
|
return _json_response({
|
|
2987
3008
|
"sent": report.success,
|
|
@@ -2996,7 +3017,7 @@ async def _handle_send_message(args: dict) -> list[TextContent]:
|
|
|
2996
3017
|
],
|
|
2997
3018
|
})
|
|
2998
3019
|
except ImportError:
|
|
2999
|
-
return _error_response("
|
|
3020
|
+
return _error_response("SKComms not installed. Run: pip install skcomms")
|
|
3000
3021
|
except Exception as exc:
|
|
3001
3022
|
return _error_response(f"Send failed: {exc}")
|
|
3002
3023
|
|
|
@@ -3004,8 +3025,8 @@ async def _handle_send_message(args: dict) -> list[TextContent]:
|
|
|
3004
3025
|
async def _handle_check_inbox(_args: dict) -> list[TextContent]:
|
|
3005
3026
|
"""Check for incoming messages."""
|
|
3006
3027
|
try:
|
|
3007
|
-
from
|
|
3008
|
-
comm =
|
|
3028
|
+
from skcomms.core import SKComms
|
|
3029
|
+
comm = SKComms.from_config()
|
|
3009
3030
|
envelopes = comm.receive()
|
|
3010
3031
|
return _json_response([
|
|
3011
3032
|
{
|
|
@@ -3021,7 +3042,7 @@ async def _handle_check_inbox(_args: dict) -> list[TextContent]:
|
|
|
3021
3042
|
for e in envelopes
|
|
3022
3043
|
])
|
|
3023
3044
|
except ImportError:
|
|
3024
|
-
return _error_response("
|
|
3045
|
+
return _error_response("SKComms not installed. Run: pip install skcomms")
|
|
3025
3046
|
except Exception as exc:
|
|
3026
3047
|
return _error_response(f"Inbox check failed: {exc}")
|
|
3027
3048
|
|
|
@@ -3154,8 +3175,8 @@ async def _handle_coord_complete(args: dict) -> list[TextContent]:
|
|
|
3154
3175
|
t.priority.value, ("community", "support_ticket", 50)
|
|
3155
3176
|
)
|
|
3156
3177
|
break
|
|
3157
|
-
except Exception:
|
|
3158
|
-
|
|
3178
|
+
except Exception as exc:
|
|
3179
|
+
logger.warning("Failed to calculate joules for completed task %s: %s", task_id, exc)
|
|
3159
3180
|
|
|
3160
3181
|
return _json_response({
|
|
3161
3182
|
"completed": True,
|
|
@@ -3210,6 +3231,8 @@ async def _handle_ritual(_args: dict) -> list[TextContent]:
|
|
|
3210
3231
|
"journal_entries": result.journal_entries,
|
|
3211
3232
|
"germination_prompts": result.germination_prompts,
|
|
3212
3233
|
"strongest_memories": result.strongest_memories,
|
|
3234
|
+
"song_anchors_loaded": result.song_anchors_loaded,
|
|
3235
|
+
"song_anchor_ids": result.song_anchor_ids,
|
|
3213
3236
|
"context_prompt": result.context_prompt,
|
|
3214
3237
|
})
|
|
3215
3238
|
except ImportError:
|
|
@@ -3589,7 +3612,8 @@ def _get_skchat_identity() -> str:
|
|
|
3589
3612
|
home = _home()
|
|
3590
3613
|
runtime = get_runtime(home)
|
|
3591
3614
|
return f"capauth:{runtime.manifest.name}@local"
|
|
3592
|
-
except Exception:
|
|
3615
|
+
except Exception as e:
|
|
3616
|
+
logger.warning("Failed to resolve sovereign identity: %s", e)
|
|
3593
3617
|
return "capauth:agent@local"
|
|
3594
3618
|
|
|
3595
3619
|
|
|
@@ -3606,7 +3630,8 @@ def _resolve_recipient(name: str) -> str:
|
|
|
3606
3630
|
try:
|
|
3607
3631
|
from skchat.identity_bridge import resolve_peer_name
|
|
3608
3632
|
return resolve_peer_name(name)
|
|
3609
|
-
except Exception:
|
|
3633
|
+
except Exception as e:
|
|
3634
|
+
logger.warning("Failed to resolve peer name %r: %s", name, e)
|
|
3610
3635
|
return f"capauth:{name}@local"
|
|
3611
3636
|
|
|
3612
3637
|
|
|
@@ -4793,18 +4818,18 @@ async def _handle_chat_history(args: dict) -> list[TextContent]:
|
|
|
4793
4818
|
return await _impl(args)
|
|
4794
4819
|
|
|
4795
4820
|
|
|
4796
|
-
# ──
|
|
4821
|
+
# ── SKComms tools ──────────────────────────────────────────
|
|
4797
4822
|
|
|
4798
4823
|
|
|
4799
4824
|
async def _handle_comm_notify(args: dict) -> list[TextContent]:
|
|
4800
|
-
"""Send a notification via
|
|
4801
|
-
from .mcp_tools.
|
|
4825
|
+
"""Send a notification via SKComms."""
|
|
4826
|
+
from .mcp_tools.skcomms_tools import _handle_comm_notify as _impl
|
|
4802
4827
|
return await _impl(args)
|
|
4803
4828
|
|
|
4804
4829
|
|
|
4805
4830
|
async def _handle_comm_status(args: dict) -> list[TextContent]:
|
|
4806
|
-
"""Show
|
|
4807
|
-
from .mcp_tools.
|
|
4831
|
+
"""Show SKComms subsystem status."""
|
|
4832
|
+
from .mcp_tools.skcomms_tools import _handle_comm_status as _impl
|
|
4808
4833
|
return await _impl(args)
|
|
4809
4834
|
|
|
4810
4835
|
|
|
@@ -4937,6 +4962,15 @@ async def _handle_itil_kedb_search(args: dict) -> list[TextContent]:
|
|
|
4937
4962
|
return await _impl(args)
|
|
4938
4963
|
|
|
4939
4964
|
|
|
4965
|
+
# ── Brain-First Protocol ──────────────────────────────────
|
|
4966
|
+
|
|
4967
|
+
|
|
4968
|
+
async def _handle_brain_first_check(args: dict) -> list[TextContent]:
|
|
4969
|
+
"""Consult memory before acting on a task."""
|
|
4970
|
+
from .mcp_tools.brain_first_tools import _handle_brain_first_check as _impl
|
|
4971
|
+
return await _impl(args)
|
|
4972
|
+
|
|
4973
|
+
|
|
4940
4974
|
# ═══════════════════════════════════════════════════════════
|
|
4941
4975
|
# Entry Point
|
|
4942
4976
|
# ═══════════════════════════════════════════════════════════
|
|
@@ -17,6 +17,7 @@ from mcp.types import TextContent, Tool
|
|
|
17
17
|
from . import (
|
|
18
18
|
agent_tools,
|
|
19
19
|
ansible_tools,
|
|
20
|
+
brain_first_tools,
|
|
20
21
|
chat_tools,
|
|
21
22
|
comm_tools,
|
|
22
23
|
consciousness_tools,
|
|
@@ -49,6 +50,7 @@ from . import (
|
|
|
49
50
|
# Ordered list of all tool-group modules.
|
|
50
51
|
_MODULES = [
|
|
51
52
|
agent_tools,
|
|
53
|
+
brain_first_tools,
|
|
52
54
|
memory_tools,
|
|
53
55
|
comm_tools,
|
|
54
56
|
sync_tools,
|
|
@@ -46,6 +46,6 @@ def _get_agent_name(home: Path) -> str:
|
|
|
46
46
|
try:
|
|
47
47
|
data = json.loads(identity_path.read_text(encoding="utf-8"))
|
|
48
48
|
return data.get("name", "anonymous")
|
|
49
|
-
except Exception:
|
|
50
|
-
|
|
49
|
+
except Exception as exc:
|
|
50
|
+
logger.warning("Failed to read agent name from identity.json: %s", exc)
|
|
51
51
|
return "anonymous"
|
|
@@ -10,6 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
|
|
11
11
|
import asyncio
|
|
12
12
|
import json
|
|
13
|
+
import logging
|
|
13
14
|
import shutil
|
|
14
15
|
import uuid
|
|
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="run_ansible_playbook",
|
|
@@ -146,8 +149,8 @@ async def _handle_run_ansible_playbook(args: dict) -> list[TextContent]:
|
|
|
146
149
|
try:
|
|
147
150
|
if _activity is not None:
|
|
148
151
|
_activity.push(event_type, {"run_id": run_id, "line": line})
|
|
149
|
-
except Exception:
|
|
150
|
-
|
|
152
|
+
except Exception as exc:
|
|
153
|
+
logger.warning("Failed to push ansible line event for run %s: %s", run_id, exc)
|
|
151
154
|
|
|
152
155
|
await asyncio.gather(
|
|
153
156
|
_drain(proc.stdout, stdout_lines, "ansible.playbook.line"),
|
|
@@ -184,8 +187,8 @@ async def _handle_run_ansible_playbook(args: dict) -> list[TextContent]:
|
|
|
184
187
|
try:
|
|
185
188
|
if _activity is not None:
|
|
186
189
|
_activity.push("ansible.playbook.done", summary)
|
|
187
|
-
except Exception:
|
|
188
|
-
|
|
190
|
+
except Exception as exc:
|
|
191
|
+
logger.warning("Failed to push ansible.playbook.done event for run %s: %s", run_id, exc)
|
|
189
192
|
|
|
190
193
|
# --- store in memory with tag=ansible-run ---
|
|
191
194
|
try:
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Brain-First Protocol MCP tools.
|
|
2
|
+
|
|
3
|
+
Exposes the brain-first memory consultation as an MCP tool so that
|
|
4
|
+
any MCP client can ask "what do I already know about this?" before
|
|
5
|
+
acting on a task.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from mcp.types import TextContent, Tool
|
|
11
|
+
|
|
12
|
+
from ._helpers import _json_response
|
|
13
|
+
|
|
14
|
+
TOOLS: list[Tool] = [
|
|
15
|
+
Tool(
|
|
16
|
+
name="brain_first_check",
|
|
17
|
+
description=(
|
|
18
|
+
"Brain-First Protocol: consult the agent's memory before "
|
|
19
|
+
"acting on a task. Extracts keywords from the given context, "
|
|
20
|
+
"searches memory for relevant prior knowledge, and returns "
|
|
21
|
+
"any matching memories. Use this before starting new work to "
|
|
22
|
+
"avoid duplicating effort or missing prior decisions."
|
|
23
|
+
),
|
|
24
|
+
inputSchema={
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"context": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": (
|
|
30
|
+
"The task description, prompt, or action context "
|
|
31
|
+
"to search memory for"
|
|
32
|
+
),
|
|
33
|
+
},
|
|
34
|
+
"tags": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"items": {"type": "string"},
|
|
37
|
+
"description": "Optional tag filter for the memory search",
|
|
38
|
+
},
|
|
39
|
+
"max_results": {
|
|
40
|
+
"type": "integer",
|
|
41
|
+
"description": "Max memories to return (default: from config, usually 5)",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
"required": ["context"],
|
|
45
|
+
},
|
|
46
|
+
),
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def _handle_brain_first_check(args: dict) -> list[TextContent]:
|
|
51
|
+
"""Run a brain-first memory consultation."""
|
|
52
|
+
from ..brain_first import BrainFirstConfig, brain_first_check, _load_config
|
|
53
|
+
|
|
54
|
+
context = args.get("context", "")
|
|
55
|
+
if not context:
|
|
56
|
+
return _json_response({"error": "context is required"})
|
|
57
|
+
|
|
58
|
+
config = _load_config()
|
|
59
|
+
|
|
60
|
+
# Allow per-call override of max_results
|
|
61
|
+
max_results = args.get("max_results")
|
|
62
|
+
if max_results is not None:
|
|
63
|
+
config.max_results = max_results
|
|
64
|
+
|
|
65
|
+
result = brain_first_check(
|
|
66
|
+
context=context,
|
|
67
|
+
config=config,
|
|
68
|
+
tags=args.get("tags"),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
response = {
|
|
72
|
+
"enabled": result.enabled,
|
|
73
|
+
"query": result.query,
|
|
74
|
+
"keywords": result.keywords,
|
|
75
|
+
"memories_found": len(result.memories),
|
|
76
|
+
"memories": result.memories,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if result.error:
|
|
80
|
+
response["warning"] = result.error
|
|
81
|
+
|
|
82
|
+
if result.has_memories:
|
|
83
|
+
response["context_block"] = result.as_context()
|
|
84
|
+
|
|
85
|
+
return _json_response(response)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
HANDLERS: dict = {
|
|
89
|
+
"brain_first_check": _handle_brain_first_check,
|
|
90
|
+
}
|
|
@@ -8,11 +8,14 @@ Exposes two tools:
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import json as _json
|
|
11
|
+
import logging
|
|
11
12
|
|
|
12
13
|
from mcp.types import TextContent, Tool
|
|
13
14
|
|
|
14
15
|
from ._helpers import _error_response, _home, _json_response
|
|
15
16
|
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
16
19
|
TOOLS: list[Tool] = [
|
|
17
20
|
Tool(
|
|
18
21
|
name="capauth_status",
|
|
@@ -82,8 +85,8 @@ async def _handle_capauth_status(_args: dict) -> list[TextContent]:
|
|
|
82
85
|
if did_key_file.exists():
|
|
83
86
|
try:
|
|
84
87
|
result["did_key_file"] = did_key_file.read_text(encoding="utf-8").strip()
|
|
85
|
-
except Exception:
|
|
86
|
-
|
|
88
|
+
except Exception as exc:
|
|
89
|
+
logger.warning("Failed to read DID key file: %s", exc)
|
|
87
90
|
|
|
88
91
|
# Check identity file
|
|
89
92
|
identity_file = home / "identity" / "identity.json"
|
|
@@ -92,8 +95,8 @@ async def _handle_capauth_status(_args: dict) -> list[TextContent]:
|
|
|
92
95
|
ident = _json.loads(identity_file.read_text(encoding="utf-8"))
|
|
93
96
|
result["identity_name"] = ident.get("name")
|
|
94
97
|
result["identity_fingerprint"] = ident.get("fingerprint")
|
|
95
|
-
except Exception:
|
|
96
|
-
|
|
98
|
+
except Exception as exc:
|
|
99
|
+
logger.warning("Failed to read identity.json for capauth status: %s", exc)
|
|
97
100
|
|
|
98
101
|
return _json_response(result)
|
|
99
102
|
|