@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
package/src/skcapstone/chat.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Interactive agent-to-agent chat for the sovereign terminal.
|
|
3
3
|
|
|
4
4
|
Provides a real-time terminal chat experience between agents using
|
|
5
|
-
SKChat for message models and
|
|
5
|
+
SKChat for message models and SKComms for transport. Works from any
|
|
6
6
|
terminal on any platform — no IDE dependency.
|
|
7
7
|
|
|
8
8
|
Usage:
|
|
@@ -52,7 +52,7 @@ _TEXT_SUFFIXES = {
|
|
|
52
52
|
class AgentChat:
|
|
53
53
|
"""Interactive chat engine for sovereign agent communication.
|
|
54
54
|
|
|
55
|
-
Wraps SKChat models and
|
|
55
|
+
Wraps SKChat models and SKComms transport into a simple
|
|
56
56
|
send/receive/poll interface suitable for terminal use.
|
|
57
57
|
|
|
58
58
|
Args:
|
|
@@ -71,7 +71,7 @@ class AgentChat:
|
|
|
71
71
|
# ------------------------------------------------------------------
|
|
72
72
|
|
|
73
73
|
def _ensure_comm(self) -> bool:
|
|
74
|
-
"""Lazily initialize the
|
|
74
|
+
"""Lazily initialize the SKComms engine.
|
|
75
75
|
|
|
76
76
|
Returns:
|
|
77
77
|
bool: True if communication layer is available.
|
|
@@ -80,15 +80,15 @@ class AgentChat:
|
|
|
80
80
|
return True
|
|
81
81
|
|
|
82
82
|
try:
|
|
83
|
-
from
|
|
83
|
+
from skcomms.core import SKComms
|
|
84
84
|
|
|
85
|
-
self._comm =
|
|
85
|
+
self._comm = SKComms.from_config()
|
|
86
86
|
return len(self._comm.router.transports) > 0
|
|
87
87
|
except ImportError:
|
|
88
|
-
logger.info("
|
|
88
|
+
logger.info("skcomms not installed")
|
|
89
89
|
return False
|
|
90
90
|
except Exception as exc:
|
|
91
|
-
logger.info("
|
|
91
|
+
logger.info("SKComms init failed: %s", exc)
|
|
92
92
|
return False
|
|
93
93
|
|
|
94
94
|
def _ensure_history(self):
|
|
@@ -123,7 +123,7 @@ class AgentChat:
|
|
|
123
123
|
"""Send a message to a peer agent.
|
|
124
124
|
|
|
125
125
|
Stores locally in SKMemory-backed history and delivers via
|
|
126
|
-
|
|
126
|
+
SKComms if transports are available.
|
|
127
127
|
|
|
128
128
|
Args:
|
|
129
129
|
recipient: Peer agent name or CapAuth identity.
|
|
@@ -162,6 +162,7 @@ class AgentChat:
|
|
|
162
162
|
result["delivered"] = True
|
|
163
163
|
result["transport"] = getattr(report, "successful_transport", None)
|
|
164
164
|
except Exception as exc:
|
|
165
|
+
logger.warning("chat.py: %s", exc)
|
|
165
166
|
result["error"] = str(exc)
|
|
166
167
|
|
|
167
168
|
except ImportError as exc:
|
|
@@ -204,8 +205,8 @@ class AgentChat:
|
|
|
204
205
|
thread_id=msg_dict.get("thread_id"),
|
|
205
206
|
)
|
|
206
207
|
history.store_message(chat_msg)
|
|
207
|
-
except Exception:
|
|
208
|
-
|
|
208
|
+
except Exception as exc:
|
|
209
|
+
logger.warning("Failed to store received message in history: %s", exc)
|
|
209
210
|
except Exception as exc:
|
|
210
211
|
logger.warning("Receive error: %s", exc)
|
|
211
212
|
|
|
@@ -226,14 +227,16 @@ class AgentChat:
|
|
|
226
227
|
|
|
227
228
|
try:
|
|
228
229
|
return history.search_messages(self.identity, limit=limit)
|
|
229
|
-
except Exception:
|
|
230
|
+
except Exception as e:
|
|
231
|
+
logger.warning("chat.py: %s", e)
|
|
230
232
|
try:
|
|
231
233
|
memories = history._store.list_memories(
|
|
232
234
|
tags=["skchat:message"],
|
|
233
235
|
limit=limit,
|
|
234
236
|
)
|
|
235
237
|
return [history._memory_to_chat_dict(m) for m in memories]
|
|
236
|
-
except Exception:
|
|
238
|
+
except Exception as e:
|
|
239
|
+
logger.warning("chat.py: %s", e)
|
|
237
240
|
return []
|
|
238
241
|
|
|
239
242
|
def forward(
|
|
@@ -246,7 +249,7 @@ class AgentChat:
|
|
|
246
249
|
|
|
247
250
|
Wraps the original message in a forward envelope that records the
|
|
248
251
|
original sender and timestamp, then delivers it to target_peer via
|
|
249
|
-
|
|
252
|
+
SKComms and stores it locally in history.
|
|
250
253
|
|
|
251
254
|
Args:
|
|
252
255
|
original_msg: Original message dict (from inbox or receive).
|
|
@@ -298,6 +301,7 @@ class AgentChat:
|
|
|
298
301
|
history.store_message(fwd_msg)
|
|
299
302
|
result["stored"] = True
|
|
300
303
|
except Exception as exc:
|
|
304
|
+
logger.warning("chat.py: %s", exc)
|
|
301
305
|
result["error"] = str(exc)
|
|
302
306
|
|
|
303
307
|
if self._ensure_comm():
|
|
@@ -311,6 +315,7 @@ class AgentChat:
|
|
|
311
315
|
result["delivered"] = True
|
|
312
316
|
result["transport"] = getattr(report, "successful_transport", None)
|
|
313
317
|
except Exception as exc:
|
|
318
|
+
logger.warning("chat.py: %s", exc)
|
|
314
319
|
result["error"] = str(exc)
|
|
315
320
|
|
|
316
321
|
return result
|
|
@@ -410,8 +415,8 @@ class AgentChat:
|
|
|
410
415
|
state["last_recv_thread"] = recv_thread
|
|
411
416
|
display = _format_content(content)
|
|
412
417
|
print(f"\n \033[32m{sender}\033[0m \033[2m[{ts}]\033[0m {display}\n")
|
|
413
|
-
except Exception:
|
|
414
|
-
|
|
418
|
+
except Exception as exc:
|
|
419
|
+
logger.warning("Chat poll loop error: %s", exc)
|
|
415
420
|
|
|
416
421
|
# Print header
|
|
417
422
|
tr_label = "✓ connected" if transport_ok else "✗ local-only"
|
|
@@ -629,7 +634,7 @@ class AgentChat:
|
|
|
629
634
|
# ---------------------------------------------------------------------------
|
|
630
635
|
|
|
631
636
|
def _pack_chat_payload(msg) -> str:
|
|
632
|
-
"""Serialize a ChatMessage for
|
|
637
|
+
"""Serialize a ChatMessage for SKComms transport.
|
|
633
638
|
|
|
634
639
|
Args:
|
|
635
640
|
msg: ChatMessage instance.
|
|
@@ -649,7 +654,7 @@ def _pack_chat_payload(msg) -> str:
|
|
|
649
654
|
|
|
650
655
|
|
|
651
656
|
def _unpack_chat_payload(payload: str, sender: str, recipient: str) -> dict:
|
|
652
|
-
"""Deserialize a chat payload from
|
|
657
|
+
"""Deserialize a chat payload from SKComms.
|
|
653
658
|
|
|
654
659
|
Falls back to plain text if not structured JSON.
|
|
655
660
|
|
|
@@ -19,7 +19,7 @@ from .. import __version__
|
|
|
19
19
|
@click.group()
|
|
20
20
|
@click.version_option(version=__version__, prog_name="skcapstone")
|
|
21
21
|
@click.option(
|
|
22
|
-
"--agent", envvar="
|
|
22
|
+
"--agent", envvar="SKAGENT", default="",
|
|
23
23
|
help="Agent name — resolves home to {root}/agents/{name}/",
|
|
24
24
|
)
|
|
25
25
|
@click.pass_context
|
|
@@ -52,6 +52,7 @@ from .completions import register_completions_commands
|
|
|
52
52
|
from .peer import register_peer_commands
|
|
53
53
|
from .backup import register_backup_commands
|
|
54
54
|
from .chat import register_chat_commands
|
|
55
|
+
from .record_cmd import register_record_commands
|
|
55
56
|
from .anchor import register_anchor_commands
|
|
56
57
|
from .session import register_session_commands
|
|
57
58
|
from .context_cmd import register_context_commands
|
|
@@ -91,6 +92,9 @@ from .skseed import register_skseed_commands
|
|
|
91
92
|
from .service_cmd import register_service_commands
|
|
92
93
|
from .telegram import register_telegram_commands
|
|
93
94
|
from .joule_cmd import register_joule_commands
|
|
95
|
+
from .alerts import register_alerts_commands
|
|
96
|
+
from .scheduler_cmd import register_scheduler_commands
|
|
97
|
+
from .identity_cmd import register_identity_commands
|
|
94
98
|
|
|
95
99
|
register_setup_commands(main)
|
|
96
100
|
register_shell_commands(main)
|
|
@@ -106,6 +110,7 @@ register_completions_commands(main)
|
|
|
106
110
|
register_peer_commands(main)
|
|
107
111
|
register_backup_commands(main)
|
|
108
112
|
register_chat_commands(main)
|
|
113
|
+
register_record_commands(main)
|
|
109
114
|
register_anchor_commands(main)
|
|
110
115
|
register_session_commands(main)
|
|
111
116
|
register_context_commands(main)
|
|
@@ -144,3 +149,6 @@ register_skseed_commands(main)
|
|
|
144
149
|
register_service_commands(main)
|
|
145
150
|
register_telegram_commands(main)
|
|
146
151
|
register_joule_commands(main)
|
|
152
|
+
register_alerts_commands(main)
|
|
153
|
+
register_scheduler_commands(main)
|
|
154
|
+
register_identity_commands(main)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import logging
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
@@ -12,6 +13,8 @@ from ._common import AGENT_HOME, console
|
|
|
12
13
|
from rich.panel import Panel
|
|
13
14
|
from rich.table import Table
|
|
14
15
|
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
15
18
|
|
|
16
19
|
def _resolve_provider_backend(provider: Optional[str], home_path: Path):
|
|
17
20
|
"""Resolve provider string to backend object and ProviderType.
|
|
@@ -37,8 +40,8 @@ def _resolve_provider_backend(provider: Optional[str], home_path: Path):
|
|
|
37
40
|
prov_backend = DockerProvider()
|
|
38
41
|
elif prov_type == ProviderType.PROXMOX:
|
|
39
42
|
prov_backend = ProxmoxProvider()
|
|
40
|
-
except Exception:
|
|
41
|
-
|
|
43
|
+
except Exception as exc:
|
|
44
|
+
logger.warning("Failed to initialize provider backend for %s: %s", provider, exc)
|
|
42
45
|
return prov_backend, prov_type
|
|
43
46
|
|
|
44
47
|
|
|
@@ -25,15 +25,21 @@ except ImportError: # pragma: no cover
|
|
|
25
25
|
# Constants
|
|
26
26
|
# ---------------------------------------------------------------------------
|
|
27
27
|
|
|
28
|
-
#: Default topics the alerts command subscribes to.
|
|
28
|
+
#: Default topics the alerts command subscribes to. The trailing ``*.<sev>``
|
|
29
|
+
#: wildcards surface alerts published by any sk* service via ``sdk.alert()``,
|
|
30
|
+
#: which follows the ``<service>.<severity>`` topic convention (e.g.
|
|
31
|
+
#: ``skmemory.error``, ``sksecurity.critical``).
|
|
29
32
|
DEFAULT_TOPICS: tuple[str, ...] = (
|
|
30
33
|
"agent.critical",
|
|
31
34
|
"coord.task_failed",
|
|
32
35
|
"consciousness.error",
|
|
33
36
|
"pillar.degraded",
|
|
37
|
+
"*.critical",
|
|
38
|
+
"*.error",
|
|
39
|
+
"*.warn",
|
|
34
40
|
)
|
|
35
41
|
|
|
36
|
-
#: Rich markup styles per topic
|
|
42
|
+
#: Rich markup styles per exact topic name.
|
|
37
43
|
_TOPIC_STYLE: dict[str, str] = {
|
|
38
44
|
"agent.critical": "bold red",
|
|
39
45
|
"coord.task_failed": "red",
|
|
@@ -41,6 +47,15 @@ _TOPIC_STYLE: dict[str, str] = {
|
|
|
41
47
|
"pillar.degraded": "yellow",
|
|
42
48
|
}
|
|
43
49
|
|
|
50
|
+
#: Rich markup styles by severity suffix — used for ``<service>.<severity>``
|
|
51
|
+
#: consumer topics with no exact match in ``_TOPIC_STYLE``.
|
|
52
|
+
_SEVERITY_STYLE: dict[str, str] = {
|
|
53
|
+
"critical": "bold red",
|
|
54
|
+
"error": "red",
|
|
55
|
+
"warn": "yellow",
|
|
56
|
+
"info": "cyan",
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
#: Default polling interval in seconds.
|
|
45
60
|
DEFAULT_INTERVAL: float = 1.0
|
|
46
61
|
|
|
@@ -56,9 +71,15 @@ def _style_for_topic(topic: str) -> str:
|
|
|
56
71
|
topic: Full topic name (e.g. ``"agent.critical"``).
|
|
57
72
|
|
|
58
73
|
Returns:
|
|
59
|
-
Rich style string for the topic
|
|
74
|
+
Rich style string for the topic. Exact matches win; otherwise the
|
|
75
|
+
topic's ``<service>.<severity>`` suffix is used (e.g. ``skmemory.error``
|
|
76
|
+
→ the ``error`` style). Falls back to ``"dim"`` if unrecognised.
|
|
60
77
|
"""
|
|
61
|
-
|
|
78
|
+
exact = _TOPIC_STYLE.get(topic)
|
|
79
|
+
if exact:
|
|
80
|
+
return exact
|
|
81
|
+
suffix = topic.rsplit(".", 1)[-1]
|
|
82
|
+
return _SEVERITY_STYLE.get(suffix, "dim")
|
|
62
83
|
|
|
63
84
|
|
|
64
85
|
def _format_payload(payload: dict) -> str:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"""Benchmark
|
|
1
|
+
"""Benchmark SKComms transport throughput and latency.
|
|
2
2
|
|
|
3
3
|
Sends N messages of a configurable size through each available
|
|
4
|
-
|
|
4
|
+
SKComms transport. Reports p50/p95/p99 latency, throughput (msg/s),
|
|
5
5
|
and error rate.
|
|
6
6
|
|
|
7
7
|
The file transport is benchmarked via a local temp-dir loopback
|
|
@@ -25,14 +25,14 @@ from rich.table import Table
|
|
|
25
25
|
|
|
26
26
|
from ._common import console
|
|
27
27
|
|
|
28
|
-
# Mirrors
|
|
28
|
+
# Mirrors skcomms.core.BUILTIN_TRANSPORTS — kept local to avoid hard dep
|
|
29
29
|
_BUILTIN_TRANSPORTS: dict[str, str] = {
|
|
30
|
-
"file": "
|
|
31
|
-
"syncthing": "
|
|
32
|
-
"nostr": "
|
|
33
|
-
"websocket": "
|
|
34
|
-
"tailscale": "
|
|
35
|
-
"webrtc": "
|
|
30
|
+
"file": "skcomms.transports.file",
|
|
31
|
+
"syncthing": "skcomms.transports.syncthing",
|
|
32
|
+
"nostr": "skcomms.transports.nostr",
|
|
33
|
+
"websocket": "skcomms.transports.websocket",
|
|
34
|
+
"tailscale": "skcomms.transports.tailscale",
|
|
35
|
+
"webrtc": "skcomms.transports.webrtc",
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
|
|
@@ -70,9 +70,9 @@ def _bench_file_loopback(count: int, size: int) -> dict:
|
|
|
70
70
|
Result dict with status, mode, latency percentiles, throughput,
|
|
71
71
|
and error counts.
|
|
72
72
|
"""
|
|
73
|
-
tmp = tempfile.mkdtemp(prefix="
|
|
73
|
+
tmp = tempfile.mkdtemp(prefix="skcomms_bench_")
|
|
74
74
|
try:
|
|
75
|
-
mod = importlib.import_module("
|
|
75
|
+
mod = importlib.import_module("skcomms.transports.file")
|
|
76
76
|
factory = getattr(mod, "create_transport", None)
|
|
77
77
|
if factory is None:
|
|
78
78
|
return {"status": "error", "error": "no create_transport() in file transport"}
|
|
@@ -108,7 +108,7 @@ def _bench_file_loopback(count: int, size: int) -> dict:
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
except ImportError:
|
|
111
|
-
return {"status": "unavailable", "error": "
|
|
111
|
+
return {"status": "unavailable", "error": "skcomms not installed"}
|
|
112
112
|
except Exception as exc:
|
|
113
113
|
return {"status": "error", "error": str(exc)[:120]}
|
|
114
114
|
finally:
|
|
@@ -247,7 +247,7 @@ def run_bench(
|
|
|
247
247
|
def _render_table(results: list[dict], count: int, size: int, health_count: int) -> None:
|
|
248
248
|
"""Render benchmark results as a Rich table with a fastest-transport summary."""
|
|
249
249
|
table = Table(
|
|
250
|
-
title=f"
|
|
250
|
+
title=f"SKComms Transport Benchmark [{count} msgs × {size}B | health×{health_count}]",
|
|
251
251
|
show_header=True,
|
|
252
252
|
header_style="bold magenta",
|
|
253
253
|
)
|
|
@@ -333,7 +333,7 @@ def register_bench_commands(main: click.Group) -> None:
|
|
|
333
333
|
transports: tuple,
|
|
334
334
|
json_out: bool,
|
|
335
335
|
) -> None:
|
|
336
|
-
"""Benchmark
|
|
336
|
+
"""Benchmark SKComms transport throughput and latency.
|
|
337
337
|
|
|
338
338
|
Sends COUNT messages of SIZE bytes through each available transport
|
|
339
339
|
and reports p50/p95/p99 latency, throughput (msg/s), and error rate.
|
|
@@ -357,7 +357,7 @@ def register_bench_commands(main: click.Group) -> None:
|
|
|
357
357
|
if not json_out:
|
|
358
358
|
scope = ", ".join(selected) if selected else "all transports"
|
|
359
359
|
console.print(
|
|
360
|
-
f"[bold]
|
|
360
|
+
f"[bold]SKComms Transport Benchmark[/] "
|
|
361
361
|
f"scope={scope} count={count} size={size}B "
|
|
362
362
|
f"health-count={health_count}"
|
|
363
363
|
)
|
|
@@ -13,12 +13,15 @@ skcapstone chat summary <peer> LLM-powered conversation summary
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
import json
|
|
16
|
+
import logging
|
|
16
17
|
import sys
|
|
17
18
|
from pathlib import Path
|
|
18
19
|
from typing import Optional
|
|
19
20
|
|
|
20
21
|
import click
|
|
21
22
|
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
22
25
|
from ._common import AGENT_HOME, console, get_runtime
|
|
23
26
|
from ._validators import validate_agent_name
|
|
24
27
|
|
|
@@ -85,8 +88,8 @@ def _run_llm_chat(peer: str, home_path: Path, identity: str) -> None:
|
|
|
85
88
|
content = msg.get("content", "")[:100]
|
|
86
89
|
console.print(f" {label}: {content}")
|
|
87
90
|
console.print()
|
|
88
|
-
except Exception:
|
|
89
|
-
|
|
91
|
+
except Exception as exc:
|
|
92
|
+
logger.warning("Failed to load previous conversation history with %s: %s", peer, exc)
|
|
90
93
|
|
|
91
94
|
console.print(f"[bold]Chat with [cyan]{peer}[/][/] [dim]Ctrl+C or /quit to exit[/]\n")
|
|
92
95
|
|
|
@@ -194,7 +197,7 @@ def register_chat_commands(main: click.Group) -> None:
|
|
|
194
197
|
def chat_send(peer: str, message: str, home: str, thread: Optional[str], encrypt: bool):
|
|
195
198
|
"""Send a message to a peer agent.
|
|
196
199
|
|
|
197
|
-
Stores locally and delivers via
|
|
200
|
+
Stores locally and delivers via SKComms if transports
|
|
198
201
|
are configured.
|
|
199
202
|
|
|
200
203
|
\b
|
|
@@ -248,7 +251,7 @@ def register_chat_commands(main: click.Group) -> None:
|
|
|
248
251
|
"""Show recent messages.
|
|
249
252
|
|
|
250
253
|
Displays messages from local history. Use --poll to check
|
|
251
|
-
|
|
254
|
+
SKComms transports for new messages first. Use --decrypt to
|
|
252
255
|
automatically decrypt AES-256-GCM encrypted messages.
|
|
253
256
|
|
|
254
257
|
\b
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
+
import logging
|
|
6
7
|
import sys
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
|
|
@@ -10,6 +11,8 @@ import click
|
|
|
10
11
|
|
|
11
12
|
from ._common import AGENT_HOME, console
|
|
12
13
|
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
13
16
|
|
|
14
17
|
def register_consciousness_commands(main: click.Group) -> None:
|
|
15
18
|
"""Register the consciousness command group."""
|
|
@@ -233,8 +236,8 @@ def register_consciousness_commands(main: click.Group) -> None:
|
|
|
233
236
|
try:
|
|
234
237
|
file_data = json.loads(daily.read_text(encoding="utf-8"))
|
|
235
238
|
quality = file_data.get("quality_avg", {})
|
|
236
|
-
except Exception:
|
|
237
|
-
|
|
239
|
+
except Exception as exc:
|
|
240
|
+
logger.warning("Failed to read daily quality metrics from %s: %s", daily, exc)
|
|
238
241
|
|
|
239
242
|
if not quality or quality.get("count", 0) == 0:
|
|
240
243
|
if json_out:
|
|
@@ -6,7 +6,8 @@ from pathlib import Path
|
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
9
|
-
from ._common import AGENT_HOME, console
|
|
9
|
+
from ._common import AGENT_HOME, SKCAPSTONE_AGENT, console, resolve_agent_home
|
|
10
|
+
from ._validators import validate_file_path
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def register_context_commands(main: click.Group) -> None:
|
|
@@ -22,7 +23,11 @@ def register_context_commands(main: click.Group) -> None:
|
|
|
22
23
|
"""
|
|
23
24
|
|
|
24
25
|
@context.command("show")
|
|
25
|
-
@click.option(
|
|
26
|
+
@click.option(
|
|
27
|
+
"--home",
|
|
28
|
+
default=str(resolve_agent_home(SKCAPSTONE_AGENT)),
|
|
29
|
+
type=click.Path(),
|
|
30
|
+
)
|
|
26
31
|
@click.option(
|
|
27
32
|
"--format",
|
|
28
33
|
"fmt",
|
|
@@ -55,7 +60,11 @@ def register_context_commands(main: click.Group) -> None:
|
|
|
55
60
|
click.echo(FORMATTERS[fmt](ctx))
|
|
56
61
|
|
|
57
62
|
@context.command("generate")
|
|
58
|
-
@click.option(
|
|
63
|
+
@click.option(
|
|
64
|
+
"--home",
|
|
65
|
+
default=str(resolve_agent_home(SKCAPSTONE_AGENT)),
|
|
66
|
+
type=click.Path(),
|
|
67
|
+
)
|
|
59
68
|
@click.option("--memories", "-n", default=10, help="Max recent memories to include.")
|
|
60
69
|
@click.option(
|
|
61
70
|
"--target",
|
|
@@ -95,7 +104,11 @@ def register_context_commands(main: click.Group) -> None:
|
|
|
95
104
|
console.print()
|
|
96
105
|
|
|
97
106
|
@main.command("refresh-context")
|
|
98
|
-
@click.option(
|
|
107
|
+
@click.option(
|
|
108
|
+
"--home",
|
|
109
|
+
default=str(resolve_agent_home(SKCAPSTONE_AGENT)),
|
|
110
|
+
type=click.Path(),
|
|
111
|
+
)
|
|
99
112
|
@click.option("--memories", "-n", default=10, help="Max recent memories to embed.")
|
|
100
113
|
@click.option(
|
|
101
114
|
"--dest",
|
|
@@ -122,6 +135,7 @@ def register_context_commands(main: click.Group) -> None:
|
|
|
122
135
|
home_path = Path(home).expanduser()
|
|
123
136
|
|
|
124
137
|
if dest:
|
|
138
|
+
validate_file_path(dest)
|
|
125
139
|
target = Path(dest).expanduser().resolve()
|
|
126
140
|
if target.is_dir():
|
|
127
141
|
target = target / "CLAUDE.md"
|
|
@@ -140,7 +140,8 @@ def register_daemon_commands(main: click.Group) -> None:
|
|
|
140
140
|
effective_port = _resolve_agent_port(agent, port)
|
|
141
141
|
|
|
142
142
|
if agent:
|
|
143
|
-
# Propagate identity to child imports that read
|
|
143
|
+
# Propagate identity to child imports that read SKAGENT.
|
|
144
|
+
os.environ["SKAGENT"] = agent
|
|
144
145
|
os.environ["SKCAPSTONE_AGENT"] = agent
|
|
145
146
|
|
|
146
147
|
if not home_path.exists():
|
|
@@ -314,22 +315,25 @@ def register_daemon_commands(main: click.Group) -> None:
|
|
|
314
315
|
console.print()
|
|
315
316
|
|
|
316
317
|
elif platform.system() == "Linux":
|
|
317
|
-
from ..systemd import install_service, systemd_available
|
|
318
|
+
from ..systemd import install_service, systemd_available, SERVICE_NAME
|
|
318
319
|
|
|
319
320
|
if not systemd_available():
|
|
320
321
|
console.print("[red]systemd user session not available.[/]")
|
|
321
322
|
console.print("[dim]This command requires a Linux system with systemd.[/]")
|
|
322
323
|
raise SystemExit(1)
|
|
323
324
|
|
|
324
|
-
console.print("\n[cyan]Installing skcapstone systemd service...[/]")
|
|
325
|
-
result = install_service(start=start)
|
|
325
|
+
console.print(f"\n[cyan]Installing skcapstone systemd service for agent '{effective_agent}'...[/]")
|
|
326
|
+
result = install_service(agent_name=effective_agent, start=start)
|
|
327
|
+
svc_name = result.get("service_name", SERVICE_NAME)
|
|
326
328
|
|
|
327
329
|
if result["installed"]:
|
|
328
|
-
console.print("[green] Unit files installed.[/]")
|
|
330
|
+
console.print(f"[green] Unit files installed ({svc_name}).[/]")
|
|
329
331
|
if result["enabled"]:
|
|
330
|
-
console.print("[green] Service enabled at login.[/]")
|
|
332
|
+
console.print(f"[green] Service enabled at login.[/]")
|
|
331
333
|
if result.get("started"):
|
|
332
|
-
console.print("[green] Service started.[/]")
|
|
334
|
+
console.print(f"[green] Service started.[/]")
|
|
335
|
+
else:
|
|
336
|
+
console.print(f"[dim] Start: systemctl --user start {svc_name}[/]")
|
|
333
337
|
console.print()
|
|
334
338
|
|
|
335
339
|
if not result["installed"]:
|
|
@@ -108,10 +108,35 @@ def register_gtd_commands(main: click.Group) -> None:
|
|
|
108
108
|
console.print()
|
|
109
109
|
|
|
110
110
|
@gtd.command("status")
|
|
111
|
-
|
|
111
|
+
@click.option("--brief", is_flag=True,
|
|
112
|
+
help="One-line summary (for hooks / session start).")
|
|
113
|
+
def gtd_status(brief: bool):
|
|
112
114
|
"""Summary of all GTD lists."""
|
|
113
115
|
from ..mcp_tools.gtd_tools import _load_list, _GTD_LISTS
|
|
114
116
|
|
|
117
|
+
if brief:
|
|
118
|
+
from datetime import datetime, timezone
|
|
119
|
+
|
|
120
|
+
counts = {name: len(_load_list(name)) for name in _GTD_LISTS}
|
|
121
|
+
now = datetime.now(timezone.utc)
|
|
122
|
+
stale = 0
|
|
123
|
+
for p in _load_list("projects"):
|
|
124
|
+
ts = p.get("moved_at") or p.get("created_at")
|
|
125
|
+
try:
|
|
126
|
+
if ts and (now - datetime.fromisoformat(ts)).days >= 7:
|
|
127
|
+
stale += 1
|
|
128
|
+
except (ValueError, TypeError):
|
|
129
|
+
pass
|
|
130
|
+
stale_str = f" ({stale} stale)" if stale else ""
|
|
131
|
+
click.echo(
|
|
132
|
+
f"GTD: {counts.get('inbox', 0)} inbox · "
|
|
133
|
+
f"{counts.get('next-actions', 0)} next · "
|
|
134
|
+
f"{counts.get('projects', 0)} projects{stale_str} · "
|
|
135
|
+
f"{counts.get('waiting-for', 0)} waiting · "
|
|
136
|
+
f"{counts.get('someday-maybe', 0)} someday"
|
|
137
|
+
)
|
|
138
|
+
return
|
|
139
|
+
|
|
115
140
|
console.print()
|
|
116
141
|
total = 0
|
|
117
142
|
rows = []
|
|
@@ -14,9 +14,9 @@ def register_housekeeping_commands(main: click.Group) -> None:
|
|
|
14
14
|
|
|
15
15
|
@main.command("housekeeping")
|
|
16
16
|
@click.option("--home", default=AGENT_HOME, type=click.Path(), help="Agent home directory.")
|
|
17
|
-
@click.option("--
|
|
17
|
+
@click.option("--skcomms-home", default="~/.skcomms", type=click.Path(), help="SKComms home directory.")
|
|
18
18
|
@click.option("--dry-run", is_flag=True, help="Report what would be deleted without deleting.")
|
|
19
|
-
def housekeeping(home: str,
|
|
19
|
+
def housekeeping(home: str, skcomms_home: str, dry_run: bool):
|
|
20
20
|
"""Prune stale ACKs, delivered envelopes, and old seeds.
|
|
21
21
|
|
|
22
22
|
Reclaims disk space from files that accumulate in the agent
|
|
@@ -33,7 +33,7 @@ def register_housekeeping_commands(main: click.Group) -> None:
|
|
|
33
33
|
|
|
34
34
|
results = run_housekeeping(
|
|
35
35
|
skcapstone_home=Path(home).expanduser(),
|
|
36
|
-
|
|
36
|
+
skcomms_home=Path(skcomms_home).expanduser(),
|
|
37
37
|
dry_run=dry_run,
|
|
38
38
|
)
|
|
39
39
|
|