@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
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
Sync pipeline engine — comms path alignment for Syncthing ↔ consciousness loop.
|
|
3
3
|
|
|
4
4
|
Verifies that the inbox/outbox directories used by the consciousness loop
|
|
5
|
-
inotify watcher and the
|
|
5
|
+
inotify watcher and the SKComms Syncthing transport are aligned under the
|
|
6
6
|
Syncthing-synced comms root, and reports pipeline health.
|
|
7
7
|
|
|
8
8
|
Pipeline:
|
|
9
9
|
Syncthing → {shared_root}/sync/comms/inbox/{peer}/*.skc.json
|
|
10
10
|
↓ inotify (ConsciousnessLoop._INBOX_DIR = "sync/comms/inbox")
|
|
11
11
|
ConsciousnessLoop.process_envelope()
|
|
12
|
-
↓
|
|
12
|
+
↓ skcomms.send() — must route to SyncthingTransport with
|
|
13
13
|
comms_root = {shared_root}/sync/comms
|
|
14
14
|
SyncthingTransport → {shared_root}/sync/comms/outbox/{peer}/*.skc.json
|
|
15
15
|
↓ Syncthing propagates to peer
|
|
@@ -17,11 +17,11 @@ Pipeline:
|
|
|
17
17
|
|
|
18
18
|
Path alignment requirement
|
|
19
19
|
--------------------------
|
|
20
|
-
The
|
|
20
|
+
The SKComms Syncthing transport must be configured with::
|
|
21
21
|
|
|
22
22
|
comms_root: ~/.skcapstone/sync/comms
|
|
23
23
|
|
|
24
|
-
in ~/.
|
|
24
|
+
in ~/.skcomms/config.yml so its outbox and inbox paths match the paths the
|
|
25
25
|
consciousness loop watches via inotify. This module provides
|
|
26
26
|
:func:`verify_pipeline_paths` to detect mismatches and
|
|
27
27
|
:func:`get_sync_pipeline_status` for the daemon health loop.
|
|
@@ -128,19 +128,19 @@ def ensure_comms_dirs(shared_root: Path) -> None:
|
|
|
128
128
|
# ---------------------------------------------------------------------------
|
|
129
129
|
|
|
130
130
|
|
|
131
|
-
def verify_pipeline_paths(shared_root: Path,
|
|
131
|
+
def verify_pipeline_paths(shared_root: Path, skcomms=None) -> dict:
|
|
132
132
|
"""Verify inbox/outbox path alignment for the full sync pipeline.
|
|
133
133
|
|
|
134
134
|
Checks:
|
|
135
135
|
|
|
136
136
|
1. The consciousness loop's watched inbox dir exists.
|
|
137
137
|
2. The outbox dir exists so responses can be written and synced.
|
|
138
|
-
3. (Optional) The active
|
|
138
|
+
3. (Optional) The active SKComms Syncthing transport's ``comms_root``
|
|
139
139
|
matches ``{shared_root}/sync/comms``.
|
|
140
140
|
|
|
141
141
|
Args:
|
|
142
142
|
shared_root: The agent SHARED_ROOT.
|
|
143
|
-
|
|
143
|
+
skcomms: Optional :class:`SKComms` instance to inspect transport config.
|
|
144
144
|
|
|
145
145
|
Returns:
|
|
146
146
|
Dict with keys:
|
|
@@ -148,7 +148,7 @@ def verify_pipeline_paths(shared_root: Path, skcomm=None) -> dict:
|
|
|
148
148
|
- ``inbox_ok`` (bool) — inbox dir exists.
|
|
149
149
|
- ``outbox_ok`` (bool) — outbox dir exists.
|
|
150
150
|
- ``transport_aligned`` (bool | None) — transport comms_root matches
|
|
151
|
-
(None if
|
|
151
|
+
(None if skcomms not provided or check failed).
|
|
152
152
|
- ``inbox_path`` (str) — absolute inbox path.
|
|
153
153
|
- ``outbox_path`` (str) — absolute outbox path.
|
|
154
154
|
- ``expected_comms_root`` (str) — the expected comms root.
|
|
@@ -168,9 +168,9 @@ def verify_pipeline_paths(shared_root: Path, skcomm=None) -> dict:
|
|
|
168
168
|
issues.append(f"Outbox dir missing: {outbox}")
|
|
169
169
|
|
|
170
170
|
transport_aligned: Optional[bool] = None
|
|
171
|
-
if
|
|
171
|
+
if skcomms is not None:
|
|
172
172
|
try:
|
|
173
|
-
transport_aligned = _check_transport_alignment(
|
|
173
|
+
transport_aligned = _check_transport_alignment(skcomms, expected_root, issues)
|
|
174
174
|
except Exception as exc:
|
|
175
175
|
logger.debug("Transport alignment check failed: %s", exc)
|
|
176
176
|
issues.append(f"Transport alignment check error: {exc}")
|
|
@@ -186,11 +186,11 @@ def verify_pipeline_paths(shared_root: Path, skcomm=None) -> dict:
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
|
|
189
|
-
def _check_transport_alignment(
|
|
190
|
-
"""Walk
|
|
189
|
+
def _check_transport_alignment(skcomms, expected_root: Path, issues: list[str]) -> bool:
|
|
190
|
+
"""Walk SKComms router transports and check the Syncthing transport's root.
|
|
191
191
|
|
|
192
192
|
Args:
|
|
193
|
-
|
|
193
|
+
skcomms: SKComms instance (has ``router`` or ``_router`` attribute).
|
|
194
194
|
expected_root: The expected comms root path.
|
|
195
195
|
issues: Mutable list; problem strings are appended here.
|
|
196
196
|
|
|
@@ -198,7 +198,7 @@ def _check_transport_alignment(skcomm, expected_root: Path, issues: list[str]) -
|
|
|
198
198
|
``True`` if aligned (or no Syncthing transport registered),
|
|
199
199
|
``False`` on mismatch.
|
|
200
200
|
"""
|
|
201
|
-
router = getattr(
|
|
201
|
+
router = getattr(skcomms, "router", None) or getattr(skcomms, "_router", None)
|
|
202
202
|
if router is None:
|
|
203
203
|
return True # can't check — assume ok
|
|
204
204
|
|
|
@@ -214,7 +214,7 @@ def _check_transport_alignment(skcomm, expected_root: Path, issues: list[str]) -
|
|
|
214
214
|
issues.append(
|
|
215
215
|
f"SyncthingTransport comms_root mismatch — "
|
|
216
216
|
f"expected {expected_root}, got {actual_root}. "
|
|
217
|
-
f"Set comms_root: {expected_root} in ~/.
|
|
217
|
+
f"Set comms_root: {expected_root} in ~/.skcomms/config.yml"
|
|
218
218
|
)
|
|
219
219
|
aligned = False
|
|
220
220
|
return aligned
|
|
@@ -574,8 +574,8 @@ class SyncWatcher:
|
|
|
574
574
|
try:
|
|
575
575
|
self._observer.stop()
|
|
576
576
|
self._observer.join(timeout=5)
|
|
577
|
-
except Exception:
|
|
578
|
-
|
|
577
|
+
except Exception as exc:
|
|
578
|
+
logger.warning("Error stopping SyncWatcher observer: %s", exc)
|
|
579
579
|
self._observer = None
|
|
580
580
|
logger.info("SyncWatcher stopped.")
|
|
581
581
|
|
|
@@ -35,10 +35,10 @@ def _require_linux() -> None:
|
|
|
35
35
|
|
|
36
36
|
SERVICE_NAME = "skcapstone.service"
|
|
37
37
|
SOCKET_NAME = "skcapstone-api.socket"
|
|
38
|
-
HEARTBEAT_SERVICE = "
|
|
39
|
-
HEARTBEAT_TIMER = "
|
|
40
|
-
QUEUE_DRAIN_SERVICE = "
|
|
41
|
-
QUEUE_DRAIN_TIMER = "
|
|
38
|
+
HEARTBEAT_SERVICE = "skcomms-heartbeat.service"
|
|
39
|
+
HEARTBEAT_TIMER = "skcomms-heartbeat.timer"
|
|
40
|
+
QUEUE_DRAIN_SERVICE = "skcomms-queue-drain.service"
|
|
41
|
+
QUEUE_DRAIN_TIMER = "skcomms-queue-drain.timer"
|
|
42
42
|
|
|
43
43
|
ALL_UNITS = [
|
|
44
44
|
SERVICE_NAME,
|
|
@@ -53,7 +53,7 @@ TIMER_UNITS = [HEARTBEAT_TIMER, QUEUE_DRAIN_TIMER]
|
|
|
53
53
|
|
|
54
54
|
SYSTEMD_USER_DIR = Path.home() / ".config" / "systemd" / "user"
|
|
55
55
|
|
|
56
|
-
BUNDLED_DIR = Path(__file__).parent
|
|
56
|
+
BUNDLED_DIR = Path(__file__).parent / "data" / "systemd"
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
@dataclass
|
|
@@ -121,24 +121,32 @@ def systemd_available() -> bool:
|
|
|
121
121
|
|
|
122
122
|
|
|
123
123
|
def install_service(
|
|
124
|
+
agent_name: Optional[str] = None,
|
|
124
125
|
unit_dir: Optional[Path] = None,
|
|
125
126
|
source_dir: Optional[Path] = None,
|
|
126
127
|
enable: bool = True,
|
|
127
128
|
start: bool = True,
|
|
128
129
|
) -> dict:
|
|
129
|
-
"""Install the skcapstone systemd user service.
|
|
130
|
+
"""Install the skcapstone systemd user service for an agent.
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
When *agent_name* is provided, installs the template unit
|
|
133
|
+
``skcapstone@.service`` and enables ``skcapstone@<agent>.service``.
|
|
134
|
+
This supports multiple agents running as independent services on
|
|
135
|
+
the same machine.
|
|
136
|
+
|
|
137
|
+
When *agent_name* is None, falls back to the single-agent
|
|
138
|
+
``skcapstone.service`` unit for backwards compatibility.
|
|
133
139
|
|
|
134
140
|
Args:
|
|
141
|
+
agent_name: Agent name (e.g. "jarvis"). Uses template unit.
|
|
135
142
|
unit_dir: Target directory for unit files.
|
|
136
143
|
source_dir: Directory containing the .service/.socket files.
|
|
137
144
|
enable: Whether to enable the service at login.
|
|
138
145
|
start: Whether to start the service immediately.
|
|
139
146
|
|
|
140
147
|
Returns:
|
|
141
|
-
dict: Result with 'installed', 'enabled', 'started' bools
|
|
148
|
+
dict: Result with 'installed', 'enabled', 'started' bools
|
|
149
|
+
and 'service_name' for the installed unit.
|
|
142
150
|
"""
|
|
143
151
|
_require_linux()
|
|
144
152
|
target = unit_dir or SYSTEMD_USER_DIR
|
|
@@ -146,15 +154,41 @@ def install_service(
|
|
|
146
154
|
|
|
147
155
|
target.mkdir(parents=True, exist_ok=True)
|
|
148
156
|
|
|
149
|
-
result = {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
result = {
|
|
158
|
+
"installed": False,
|
|
159
|
+
"enabled": False,
|
|
160
|
+
"started": False,
|
|
161
|
+
"timers_enabled": False,
|
|
162
|
+
"service_name": "",
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# Determine which unit to use
|
|
166
|
+
if agent_name:
|
|
167
|
+
# Multi-agent: use template unit skcapstone@.service
|
|
168
|
+
template_name = "skcapstone@.service"
|
|
169
|
+
instance_name = f"skcapstone@{agent_name}.service"
|
|
170
|
+
template_src = source / template_name
|
|
171
|
+
if not template_src.exists():
|
|
172
|
+
logger.error("Template unit not found: %s", template_src)
|
|
173
|
+
return result
|
|
174
|
+
shutil.copy2(template_src, target / template_name)
|
|
175
|
+
service_unit = instance_name
|
|
176
|
+
result["service_name"] = instance_name
|
|
177
|
+
else:
|
|
178
|
+
# Single-agent fallback
|
|
179
|
+
service_src = source / SERVICE_NAME
|
|
180
|
+
if not service_src.exists():
|
|
181
|
+
logger.error("Service unit not found: %s", service_src)
|
|
182
|
+
return result
|
|
183
|
+
shutil.copy2(service_src, target / SERVICE_NAME)
|
|
184
|
+
service_unit = SERVICE_NAME
|
|
185
|
+
result["service_name"] = SERVICE_NAME
|
|
186
|
+
|
|
187
|
+
# Copy ancillary units (socket, timers, etc.)
|
|
188
|
+
copied = 1 # already copied the main unit
|
|
157
189
|
for unit_name in ALL_UNITS:
|
|
190
|
+
if unit_name == SERVICE_NAME:
|
|
191
|
+
continue # already handled above
|
|
158
192
|
src = source / unit_name
|
|
159
193
|
if src.exists():
|
|
160
194
|
shutil.copy2(src, target / unit_name)
|
|
@@ -162,10 +196,10 @@ def install_service(
|
|
|
162
196
|
|
|
163
197
|
_systemctl("daemon-reload")
|
|
164
198
|
result["installed"] = True
|
|
165
|
-
logger.info("Installed %d unit file(s) to %s", copied, target)
|
|
199
|
+
logger.info("Installed %d unit file(s) to %s (service: %s)", copied, target, service_unit)
|
|
166
200
|
|
|
167
201
|
if enable:
|
|
168
|
-
r = _systemctl("enable",
|
|
202
|
+
r = _systemctl("enable", service_unit)
|
|
169
203
|
result["enabled"] = r.returncode == 0
|
|
170
204
|
|
|
171
205
|
timers_ok = True
|
|
@@ -177,7 +211,7 @@ def install_service(
|
|
|
177
211
|
result["timers_enabled"] = timers_ok
|
|
178
212
|
|
|
179
213
|
if start:
|
|
180
|
-
r = _systemctl("start",
|
|
214
|
+
r = _systemctl("start", service_unit)
|
|
181
215
|
result["started"] = r.returncode == 0
|
|
182
216
|
|
|
183
217
|
for timer in TIMER_UNITS:
|
|
@@ -336,7 +370,7 @@ WatchdogSec=120
|
|
|
336
370
|
NoNewPrivileges=true
|
|
337
371
|
ProtectSystem=strict
|
|
338
372
|
ProtectHome=read-only
|
|
339
|
-
ReadWritePaths=%h/.skcapstone %h/.capauth %h/.cloud9 %h/.
|
|
373
|
+
ReadWritePaths=%h/.skcapstone %h/.capauth %h/.cloud9 %h/.skcomms %h/.skchat
|
|
340
374
|
PrivateTmp=true
|
|
341
375
|
ProtectKernelTunables=true
|
|
342
376
|
ProtectControlGroups=true
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Team Communications —
|
|
2
|
+
Team Communications — SKComms/SKChat wiring for deployed agent teams.
|
|
3
3
|
|
|
4
|
-
Bootstraps a local file-based
|
|
4
|
+
Bootstraps a local file-based SKComms channel for each deployed team so that
|
|
5
5
|
agents can message each other without external infrastructure. Each agent gets
|
|
6
6
|
its own inbox directory; messages are plain JSON envelopes written atomically
|
|
7
7
|
to the recipient's inbox folder.
|
|
@@ -34,7 +34,7 @@ logger = logging.getLogger(__name__)
|
|
|
34
34
|
# Sentinel value: the queen/manager role name used to discover the broadcast sender
|
|
35
35
|
_QUEEN_ROLES = frozenset({"manager", "queen"})
|
|
36
36
|
|
|
37
|
-
# File suffix used by the
|
|
37
|
+
# File suffix used by the SKComms file transport
|
|
38
38
|
_ENVELOPE_SUFFIX = ".skc.json"
|
|
39
39
|
|
|
40
40
|
|
|
@@ -105,9 +105,9 @@ def _build_envelope(
|
|
|
105
105
|
content: str,
|
|
106
106
|
thread_id: Optional[str] = None,
|
|
107
107
|
) -> dict:
|
|
108
|
-
"""Build a minimal
|
|
108
|
+
"""Build a minimal SKComms-compatible envelope dict.
|
|
109
109
|
|
|
110
|
-
Uses the same schema as
|
|
110
|
+
Uses the same schema as skcomms.models.MessageEnvelope so downstream
|
|
111
111
|
consumers can deserialize with MessageEnvelope.from_bytes().
|
|
112
112
|
|
|
113
113
|
Args:
|
|
@@ -121,7 +121,7 @@ def _build_envelope(
|
|
|
121
121
|
"""
|
|
122
122
|
now = datetime.now(timezone.utc).isoformat()
|
|
123
123
|
return {
|
|
124
|
-
"
|
|
124
|
+
"skcomms_version": "1.0.0",
|
|
125
125
|
"envelope_id": str(uuid.uuid4()),
|
|
126
126
|
"sender": sender,
|
|
127
127
|
"recipient": recipient,
|
|
@@ -276,7 +276,7 @@ def send_to_teammate(
|
|
|
276
276
|
) -> str:
|
|
277
277
|
"""Send a message from one agent to another within the same team.
|
|
278
278
|
|
|
279
|
-
Writes a
|
|
279
|
+
Writes a SKComms-compatible envelope JSON file to the recipient's inbox
|
|
280
280
|
directory. Optionally logs the activity to the coordination board.
|
|
281
281
|
|
|
282
282
|
Args:
|
|
@@ -392,7 +392,7 @@ def receive_messages(
|
|
|
392
392
|
board: Optional Board instance for activity logging.
|
|
393
393
|
|
|
394
394
|
Returns:
|
|
395
|
-
List[dict]: Raw envelope dicts (
|
|
395
|
+
List[dict]: Raw envelope dicts (skcomms MessageEnvelope schema).
|
|
396
396
|
"""
|
|
397
397
|
envelopes = _drain_inbox(agent_name, channel)
|
|
398
398
|
|
|
@@ -472,7 +472,7 @@ class TeamEngine:
|
|
|
472
472
|
deployment: TeamDeployment,
|
|
473
473
|
blueprint: BlueprintManifest,
|
|
474
474
|
) -> TeamChannel:
|
|
475
|
-
"""Bootstrap
|
|
475
|
+
"""Bootstrap SKComms file channel for all agents in a deployment.
|
|
476
476
|
|
|
477
477
|
Identifies the queen agent from the blueprint's coordination config
|
|
478
478
|
(falling back to any agent with role=manager) and provisions per-agent
|
|
@@ -7,7 +7,7 @@ terminal — no CI server, no IDE, no special tooling.
|
|
|
7
7
|
|
|
8
8
|
Usage:
|
|
9
9
|
skcapstone test # run all packages
|
|
10
|
-
skcapstone test --package
|
|
10
|
+
skcapstone test --package skcomms # run one package
|
|
11
11
|
skcapstone test --fast # stop on first failure
|
|
12
12
|
skcapstone test --json-out # machine-readable results
|
|
13
13
|
"""
|
|
@@ -26,10 +26,10 @@ from typing import Optional
|
|
|
26
26
|
ECOSYSTEM_PACKAGES = [
|
|
27
27
|
{"name": "skcapstone", "path": "skcapstone", "tests": "skcapstone/tests"},
|
|
28
28
|
{"name": "capauth", "path": "capauth", "tests": "capauth/tests"},
|
|
29
|
-
{"name": "
|
|
29
|
+
{"name": "skcomms", "path": "skcomms", "tests": "skcomms/tests"},
|
|
30
30
|
{"name": "skchat", "path": "skchat", "tests": "skchat/tests"},
|
|
31
31
|
{"name": "skmemory", "path": "skmemory", "tests": "skmemory/tests"},
|
|
32
|
-
{"name": "cloud9
|
|
32
|
+
{"name": "cloud9", "path": "cloud9", "tests": "cloud9/tests"},
|
|
33
33
|
]
|
|
34
34
|
|
|
35
35
|
|
|
@@ -117,6 +117,8 @@ def build_trust_graph(home: Path) -> TrustGraph:
|
|
|
117
117
|
|
|
118
118
|
def _add_self_node(home: Path, graph: TrustGraph) -> None:
|
|
119
119
|
"""Add the local agent as the central node."""
|
|
120
|
+
manifest_data: dict[str, Any] = {}
|
|
121
|
+
|
|
120
122
|
identity_file = home / "identity" / "identity.json"
|
|
121
123
|
if identity_file.exists():
|
|
122
124
|
try:
|
|
@@ -130,20 +132,53 @@ def _add_self_node(home: Path, graph: TrustGraph) -> None:
|
|
|
130
132
|
fingerprint=data.get("fingerprint"),
|
|
131
133
|
metadata={"capauth_managed": data.get("capauth_managed", False)},
|
|
132
134
|
))
|
|
133
|
-
return
|
|
134
135
|
except (json.JSONDecodeError, OSError):
|
|
135
136
|
pass
|
|
136
137
|
|
|
137
138
|
manifest = home / "manifest.json"
|
|
138
139
|
if manifest.exists():
|
|
139
140
|
try:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
manifest_data = json.loads(manifest.read_text(encoding="utf-8"))
|
|
142
|
+
if not graph.nodes:
|
|
143
|
+
name = manifest_data.get("name", "self")
|
|
144
|
+
graph.agent_name = name
|
|
145
|
+
graph.add_node(TrustNode(id=name, label=name, node_type="agent"))
|
|
144
146
|
except (json.JSONDecodeError, OSError):
|
|
145
147
|
pass
|
|
146
148
|
|
|
149
|
+
_add_operator_edge(manifest_data, graph)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _add_operator_edge(manifest_data: dict[str, Any], graph: TrustGraph) -> None:
|
|
153
|
+
"""Add an explicit human-operator relationship from manifest metadata."""
|
|
154
|
+
operator = manifest_data.get("operator")
|
|
155
|
+
if not isinstance(operator, dict):
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
name = str(operator.get("name", "")).strip()
|
|
159
|
+
if not name or not graph.agent_name:
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
node_id = str(operator.get("fingerprint", "")).strip() or f"operator:{name}"
|
|
163
|
+
graph.add_node(TrustNode(
|
|
164
|
+
id=node_id,
|
|
165
|
+
label=name,
|
|
166
|
+
node_type="peer",
|
|
167
|
+
fingerprint=str(operator.get("fingerprint", "")).strip() or None,
|
|
168
|
+
metadata={
|
|
169
|
+
"relationship": operator.get("relationship", "human-operator"),
|
|
170
|
+
"entity_type": operator.get("entity_type", "human"),
|
|
171
|
+
"source": operator.get("source", "manifest"),
|
|
172
|
+
},
|
|
173
|
+
))
|
|
174
|
+
graph.add_edge(TrustEdge(
|
|
175
|
+
source=graph.agent_name,
|
|
176
|
+
target=node_id,
|
|
177
|
+
edge_type="operator",
|
|
178
|
+
label=operator.get("relationship", "human-operator"),
|
|
179
|
+
strength=1.0,
|
|
180
|
+
))
|
|
181
|
+
|
|
147
182
|
|
|
148
183
|
def _add_token_edges(home: Path, graph: TrustGraph) -> None:
|
|
149
184
|
"""Add edges from capability token issuance (issuer trusts subject)."""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Unified Search — full-text search across all agent data stores.
|
|
3
3
|
|
|
4
|
-
Searches memories, conversations, and
|
|
4
|
+
Searches memories, conversations, and SKComms messages in one query.
|
|
5
5
|
Results are ranked by a combined relevance + recency score.
|
|
6
6
|
|
|
7
7
|
Data stores searched:
|
|
@@ -15,6 +15,7 @@ from __future__ import annotations
|
|
|
15
15
|
|
|
16
16
|
import json
|
|
17
17
|
import logging
|
|
18
|
+
import os
|
|
18
19
|
import re
|
|
19
20
|
from dataclasses import dataclass, field
|
|
20
21
|
from datetime import datetime, timezone
|
|
@@ -140,8 +141,16 @@ def _search_memories(
|
|
|
140
141
|
List of SearchResult objects from the memory store.
|
|
141
142
|
"""
|
|
142
143
|
results: list[SearchResult] = []
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
from . import active_agent_name
|
|
145
|
+
|
|
146
|
+
agent_name = os.environ.get("SKCAPSTONE_AGENT") or active_agent_name()
|
|
147
|
+
if home.parent.name == "agents":
|
|
148
|
+
# home is already an agent-specific dir (e.g. ~/.skcapstone/agents/lumina)
|
|
149
|
+
mem_dir = home / "memory"
|
|
150
|
+
elif agent_name:
|
|
151
|
+
mem_dir = home / "agents" / agent_name / "memory"
|
|
152
|
+
else:
|
|
153
|
+
mem_dir = home / "memory"
|
|
145
154
|
if not mem_dir.exists():
|
|
146
155
|
return results
|
|
147
156
|
|
|
@@ -252,7 +261,7 @@ def _search_messages(
|
|
|
252
261
|
home: Path,
|
|
253
262
|
pattern: re.Pattern,
|
|
254
263
|
) -> list[SearchResult]:
|
|
255
|
-
"""Search archived
|
|
264
|
+
"""Search archived SKComms envelope files (.skc.json).
|
|
256
265
|
|
|
257
266
|
Handles both the legacy schema (payload.text) and the newer
|
|
258
267
|
schema (payload.content).
|
|
@@ -262,7 +271,7 @@ def _search_messages(
|
|
|
262
271
|
pattern: Compiled search pattern.
|
|
263
272
|
|
|
264
273
|
Returns:
|
|
265
|
-
List of SearchResult objects from
|
|
274
|
+
List of SearchResult objects from SKComms messages.
|
|
266
275
|
"""
|
|
267
276
|
results: list[SearchResult] = []
|
|
268
277
|
|
|
@@ -387,7 +396,7 @@ def search(
|
|
|
387
396
|
"""Search across all agent data stores.
|
|
388
397
|
|
|
389
398
|
Performs full-text regex matching against memories, conversations,
|
|
390
|
-
|
|
399
|
+
SKComms messages, and journal entries. Results are ranked by a
|
|
391
400
|
combined relevance × recency score, highest first.
|
|
392
401
|
|
|
393
402
|
Args:
|
|
@@ -35,6 +35,9 @@ from rich.table import Table
|
|
|
35
35
|
|
|
36
36
|
from . import AGENT_HOME
|
|
37
37
|
|
|
38
|
+
import logging
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
38
41
|
console = Console()
|
|
39
42
|
|
|
40
43
|
|
|
@@ -236,7 +239,8 @@ def _transfer_to_device(
|
|
|
236
239
|
d for name, d in registry.get("devices", {}).items()
|
|
237
240
|
if name != hostname and d.get("is_datastore")
|
|
238
241
|
]
|
|
239
|
-
except Exception:
|
|
242
|
+
except Exception as e:
|
|
243
|
+
logger.warning("uninstall_wizard.py: %s", e)
|
|
240
244
|
other_devices = []
|
|
241
245
|
|
|
242
246
|
if not other_devices:
|
|
@@ -310,6 +314,7 @@ def _deregister_from_vault_registry(home_path: Path) -> None:
|
|
|
310
314
|
except ImportError:
|
|
311
315
|
console.print("[dim]skref not installed — skipping[/]")
|
|
312
316
|
except Exception as exc:
|
|
317
|
+
logger.warning("uninstall_wizard.py: %s", exc)
|
|
313
318
|
console.print(f"[yellow]{exc}[/]")
|
|
314
319
|
|
|
315
320
|
|
|
@@ -331,6 +336,7 @@ def _teardown_tailscale() -> None:
|
|
|
331
336
|
except ImportError:
|
|
332
337
|
console.print("[dim]skref not installed — skipping[/]")
|
|
333
338
|
except Exception as exc:
|
|
339
|
+
logger.warning("uninstall_wizard.py: %s", exc)
|
|
334
340
|
console.print(f"[yellow]{exc}[/]")
|
|
335
341
|
|
|
336
342
|
|
|
@@ -369,6 +375,7 @@ def _remove_syncthing_folder(home_path: Path) -> None:
|
|
|
369
375
|
|
|
370
376
|
console.print("[dim]no matching folder found[/]")
|
|
371
377
|
except Exception as exc:
|
|
378
|
+
logger.warning("uninstall_wizard.py: %s", exc)
|
|
372
379
|
console.print(f"[dim]could not reach Syncthing API: {exc}[/]")
|
|
373
380
|
console.print(
|
|
374
381
|
" [dim]You may need to remove the shared folder manually\n"
|
|
@@ -450,8 +457,8 @@ def _uninstall_packages() -> None:
|
|
|
450
457
|
|
|
451
458
|
console.print(" Uninstalling packages...", end=" ")
|
|
452
459
|
packages = [
|
|
453
|
-
"skcapstone", "capauth", "skmemory", "
|
|
454
|
-
"cloud9
|
|
460
|
+
"skcapstone", "capauth", "skmemory", "skcomms",
|
|
461
|
+
"cloud9", "skref", "skchat",
|
|
455
462
|
]
|
|
456
463
|
try:
|
|
457
464
|
result = subprocess.run(
|
|
@@ -529,6 +536,7 @@ def _export_backup(home_path: Path) -> Optional[Path]:
|
|
|
529
536
|
)
|
|
530
537
|
return archive_path
|
|
531
538
|
except Exception as exc:
|
|
539
|
+
logger.warning("uninstall_wizard.py: %s", exc)
|
|
532
540
|
console.print(f"[red]failed: {exc}[/]")
|
|
533
541
|
return None
|
|
534
542
|
|
|
@@ -9,20 +9,22 @@ standalone ``skcapstone version-check`` CLI command.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import json
|
|
12
|
+
import logging
|
|
12
13
|
import urllib.request
|
|
13
14
|
import urllib.error
|
|
14
15
|
from dataclasses import dataclass, field
|
|
15
16
|
from typing import Optional
|
|
16
17
|
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
17
19
|
|
|
18
20
|
ECOSYSTEM_PACKAGES = [
|
|
19
21
|
"skmemory",
|
|
20
22
|
"skcapstone",
|
|
21
23
|
"capauth",
|
|
22
24
|
"sksecurity",
|
|
23
|
-
"
|
|
25
|
+
"skcomms",
|
|
24
26
|
"skchat",
|
|
25
|
-
"cloud9
|
|
27
|
+
"cloud9",
|
|
26
28
|
]
|
|
27
29
|
|
|
28
30
|
|
|
@@ -82,7 +84,8 @@ def _get_installed_version(package_name: str) -> Optional[str]:
|
|
|
82
84
|
from importlib.metadata import version
|
|
83
85
|
|
|
84
86
|
return version(package_name)
|
|
85
|
-
except Exception:
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.debug("version_check.py metadata lookup failed: %s", e)
|
|
86
89
|
# Try import-based fallback for packages with dashes
|
|
87
90
|
try:
|
|
88
91
|
mod_name = package_name.replace("-", "_")
|
|
@@ -90,7 +93,8 @@ def _get_installed_version(package_name: str) -> Optional[str]:
|
|
|
90
93
|
|
|
91
94
|
mod = importlib.import_module(mod_name)
|
|
92
95
|
return getattr(mod, "__version__", None)
|
|
93
|
-
except Exception:
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.debug("version_check.py import fallback failed: %s", e)
|
|
94
98
|
return None
|
|
95
99
|
|
|
96
100
|
|
|
@@ -287,7 +287,8 @@ def _calibrate_from_memories(home: Path, cal: AnchorCalibration) -> None:
|
|
|
287
287
|
|
|
288
288
|
try:
|
|
289
289
|
memories = list_memories(home, limit=50)
|
|
290
|
-
except Exception:
|
|
290
|
+
except Exception as e:
|
|
291
|
+
logger.warning("warmth_anchor.py: %s", e)
|
|
291
292
|
return
|
|
292
293
|
|
|
293
294
|
if not memories:
|
|
@@ -314,7 +315,8 @@ def _calibrate_from_coordination(home: Path, cal: AnchorCalibration) -> None:
|
|
|
314
315
|
board = Board(home)
|
|
315
316
|
views = board.get_task_views()
|
|
316
317
|
agents = board.load_agents()
|
|
317
|
-
except Exception:
|
|
318
|
+
except Exception as e:
|
|
319
|
+
logger.warning("warmth_anchor.py: %s", e)
|
|
318
320
|
return
|
|
319
321
|
|
|
320
322
|
done = sum(1 for v in views if v.status.value == "done")
|
package/src/skcapstone/whoami.py
CHANGED
|
@@ -48,7 +48,7 @@ class IdentityCard(BaseModel):
|
|
|
48
48
|
trust_status: Current trust state (active, degraded, missing).
|
|
49
49
|
consciousness: Agent consciousness level.
|
|
50
50
|
memory_count: How many memories the agent holds.
|
|
51
|
-
contact_uris: Ways to reach this agent (
|
|
51
|
+
contact_uris: Ways to reach this agent (skcomms, email, nostr, etc.).
|
|
52
52
|
hostname: Machine the card was generated on.
|
|
53
53
|
created_at: When this card was generated.
|
|
54
54
|
"""
|
|
@@ -246,10 +246,10 @@ def _load_capabilities(home: Path, card: IdentityCard) -> None:
|
|
|
246
246
|
logger.debug("capauth not installed — skipping capauth:identity capability")
|
|
247
247
|
|
|
248
248
|
try:
|
|
249
|
-
import
|
|
250
|
-
caps.append("
|
|
249
|
+
import skcomms # noqa: F401
|
|
250
|
+
caps.append("skcomms:messaging")
|
|
251
251
|
except ImportError:
|
|
252
|
-
logger.debug("
|
|
252
|
+
logger.debug("skcomms not installed — skipping skcomms:messaging capability")
|
|
253
253
|
|
|
254
254
|
try:
|
|
255
255
|
import skchat # noqa: F401
|
|
@@ -16,20 +16,18 @@ MemoryMax=4G
|
|
|
16
16
|
# Keep Ollama models warm for 5 minutes between requests
|
|
17
17
|
Environment=PYTHONUNBUFFERED=1
|
|
18
18
|
Environment=OLLAMA_KEEP_ALIVE=5m
|
|
19
|
+
Environment=SKAGENT=lumina
|
|
19
20
|
Environment=SKCAPSTONE_AGENT=lumina
|
|
21
|
+
Environment=SKMEMORY_AGENT=lumina
|
|
20
22
|
# Journal logging
|
|
21
23
|
StandardOutput=journal
|
|
22
24
|
StandardError=journal
|
|
23
25
|
SyslogIdentifier=skcapstone
|
|
24
26
|
|
|
25
|
-
# Security hardening
|
|
27
|
+
# Security hardening (relaxed — ProtectHome=read-only breaks if any
|
|
28
|
+
# ReadWritePaths dir is missing on the host)
|
|
26
29
|
NoNewPrivileges=true
|
|
27
|
-
ProtectSystem=strict
|
|
28
|
-
ProtectHome=read-only
|
|
29
|
-
ReadWritePaths=%h/.skcapstone %h/.skenv %h/.capauth %h/.cloud9 %h/.skcomm %h/.skchat
|
|
30
30
|
PrivateTmp=true
|
|
31
|
-
ProtectKernelTunables=true
|
|
32
|
-
ProtectControlGroups=true
|
|
33
31
|
|
|
34
32
|
[Install]
|
|
35
33
|
WantedBy=default.target
|