@smilintux/skcapstone 0.9.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.
Files changed (284) hide show
  1. package/.env.example +10 -4
  2. package/.github/workflows/ci.yml +2 -2
  3. package/.github/workflows/publish.yml +9 -2
  4. package/.openclaw-workspace.json +2 -2
  5. package/CLAUDE.md +37 -0
  6. package/MISSION.md +17 -2
  7. package/README.md +282 -3
  8. package/docker/Dockerfile +7 -7
  9. package/docker/compose-templates/dev-team.yml +12 -12
  10. package/docker/compose-templates/mini-team.yml +9 -9
  11. package/docker/compose-templates/ops-team.yml +10 -10
  12. package/docker/compose-templates/research-team.yml +10 -10
  13. package/docker/entrypoint.sh +4 -4
  14. package/docs/ADR-optional-integration-backbone.md +181 -0
  15. package/docs/ARCHITECTURE.md +186 -43
  16. package/docs/BOND_WITH_GROK.md +6 -6
  17. package/docs/CUSTOM_AGENT.md +278 -1
  18. package/docs/DREAMING.md +70 -0
  19. package/docs/GETTING_STARTED.md +10 -7
  20. package/docs/QUICKSTART.md +10 -6
  21. package/docs/SKJOULE_ARCHITECTURE.md +3 -3
  22. package/docs/SOUL_SWAPPER.md +5 -5
  23. package/docs/hammertime-audit.md +402 -0
  24. package/docs/sk-integration-HANDOFF.md +117 -0
  25. package/docs/skscheduler.md +155 -0
  26. package/docs/superpowers/examples/jobs.yaml +31 -0
  27. package/docs/superpowers/plans/2026-06-08-skscheduler.md +1265 -0
  28. package/docs/superpowers/specs/2026-06-08-skscheduler-design.md +186 -0
  29. package/examples/custom-bond-template.json +1 -1
  30. package/examples/grok-feb.json +1 -1
  31. package/examples/queen-ava-feb.json +1 -1
  32. package/launchd/com.skcapstone.daemon.plist +52 -0
  33. package/launchd/com.skcapstone.memory-compress.plist +45 -0
  34. package/launchd/com.skcapstone.skcomms-heartbeat.plist +33 -0
  35. package/launchd/com.skcapstone.skcomms-queue-drain.plist +34 -0
  36. package/launchd/install-launchd.sh +156 -0
  37. package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/src/index.ts +3 -2
  38. package/package.json +1 -1
  39. package/pyproject.toml +16 -10
  40. package/scripts/archive-sessions.sh +95 -0
  41. package/scripts/check-updates.py +4 -4
  42. package/scripts/install-bundle.sh +8 -8
  43. package/scripts/install.ps1 +12 -11
  44. package/scripts/install.sh +196 -11
  45. package/scripts/model-fallback-monitor.sh +102 -0
  46. package/scripts/notion-api.py +259 -0
  47. package/scripts/nvidia-proxy.mjs +908 -0
  48. package/scripts/proxy-monitor.sh +89 -0
  49. package/scripts/refresh-anthropic-token.sh +172 -0
  50. package/scripts/release.sh +98 -0
  51. package/scripts/session-to-memory.py +219 -0
  52. package/scripts/skgateway.mjs +856 -0
  53. package/scripts/telegram-catchup-all.sh +147 -0
  54. package/scripts/verify_install.sh +2 -2
  55. package/scripts/wargov-ufo-capture/README.md +43 -0
  56. package/scripts/wargov-ufo-capture/cdp_capture_release2.py +273 -0
  57. package/scripts/wargov-ufo-capture/cdp_capture_splc_doj.py +246 -0
  58. package/scripts/wargov-ufo-capture/cdp_finish.py +271 -0
  59. package/scripts/wargov-ufo-capture/cdp_probe.py +188 -0
  60. package/scripts/wargov-ufo-capture/cdp_splc_pressrelease.py +101 -0
  61. package/scripts/wargov-ufo-capture/parse_csv.py +95 -0
  62. package/scripts/wargov-ufo-capture/pull_dvids.sh +107 -0
  63. package/scripts/watch-anthropic-token.sh +212 -0
  64. package/scripts/windows/install-tasks.ps1 +7 -7
  65. package/scripts/windows/skcapstone-task.xml +1 -1
  66. package/src/skcapstone/__init__.py +45 -3
  67. package/src/skcapstone/_cli_monolith.py +20 -15
  68. package/src/skcapstone/activity.py +5 -1
  69. package/src/skcapstone/agent_card.py +3 -2
  70. package/src/skcapstone/api.py +41 -40
  71. package/src/skcapstone/auction.py +14 -11
  72. package/src/skcapstone/backup.py +2 -1
  73. package/src/skcapstone/blueprint_registry.py +4 -3
  74. package/src/skcapstone/blueprints/builtins/itil-operations.yaml +40 -0
  75. package/src/skcapstone/brain_first.py +238 -0
  76. package/src/skcapstone/changelog.py +1 -1
  77. package/src/skcapstone/chat.py +22 -17
  78. package/src/skcapstone/cli/__init__.py +9 -1
  79. package/src/skcapstone/cli/_common.py +1 -0
  80. package/src/skcapstone/cli/agents_spawner.py +5 -2
  81. package/src/skcapstone/cli/alerts.py +25 -4
  82. package/src/skcapstone/cli/bench.py +15 -15
  83. package/src/skcapstone/cli/chat.py +7 -4
  84. package/src/skcapstone/cli/consciousness.py +5 -2
  85. package/src/skcapstone/cli/context_cmd.py +18 -4
  86. package/src/skcapstone/cli/daemon.py +121 -42
  87. package/src/skcapstone/cli/gtd.py +26 -1
  88. package/src/skcapstone/cli/housekeeping.py +3 -3
  89. package/src/skcapstone/cli/identity_cmd.py +378 -0
  90. package/src/skcapstone/cli/joule_cmd.py +7 -3
  91. package/src/skcapstone/cli/memory.py +8 -6
  92. package/src/skcapstone/cli/peers_dir.py +1 -1
  93. package/src/skcapstone/cli/register_cmd.py +29 -3
  94. package/src/skcapstone/cli/scheduler_cmd.py +167 -0
  95. package/src/skcapstone/cli/session.py +25 -0
  96. package/src/skcapstone/cli/setup.py +96 -29
  97. package/src/skcapstone/cli/shell_cmd.py +53 -1
  98. package/src/skcapstone/cli/skills_cmd.py +2 -2
  99. package/src/skcapstone/cli/soul.py +8 -5
  100. package/src/skcapstone/cli/status.py +37 -11
  101. package/src/skcapstone/cli/telegram.py +21 -0
  102. package/src/skcapstone/cli/test_cmd.py +5 -5
  103. package/src/skcapstone/cli/test_connection.py +2 -2
  104. package/src/skcapstone/cli/upgrade_cmd.py +23 -14
  105. package/src/skcapstone/cli/version_cmd.py +1 -1
  106. package/src/skcapstone/cli/watch_cmd.py +9 -6
  107. package/src/skcapstone/cloud9_bridge.py +14 -14
  108. package/src/skcapstone/codex_setup.py +255 -0
  109. package/src/skcapstone/config_validator.py +7 -4
  110. package/src/skcapstone/consciousness_config.py +5 -1
  111. package/src/skcapstone/consciousness_loop.py +313 -273
  112. package/src/skcapstone/context_loader.py +121 -0
  113. package/src/skcapstone/coord_federation.py +2 -1
  114. package/src/skcapstone/coordination.py +23 -6
  115. package/src/skcapstone/crush_integration.py +2 -1
  116. package/src/skcapstone/daemon.py +151 -88
  117. package/src/skcapstone/dashboard.py +10 -10
  118. package/src/skcapstone/data/sk-agent-picker.sh +421 -0
  119. package/src/skcapstone/data/systemd/skcapstone-api.socket +9 -0
  120. package/src/skcapstone/data/systemd/skcapstone-memory-compress.service +18 -0
  121. package/src/skcapstone/data/systemd/skcapstone-memory-compress.timer +11 -0
  122. package/src/skcapstone/data/systemd/skcapstone.service +37 -0
  123. package/src/skcapstone/data/systemd/skcapstone@.service +50 -0
  124. package/src/skcapstone/data/systemd/skcomms-heartbeat.service +18 -0
  125. package/{systemd/skcomm-heartbeat.timer → src/skcapstone/data/systemd/skcomms-heartbeat.timer} +2 -2
  126. package/src/skcapstone/data/systemd/skcomms-queue-drain.service +17 -0
  127. package/{systemd/skcomm-queue-drain.timer → src/skcapstone/data/systemd/skcomms-queue-drain.timer} +2 -2
  128. package/src/skcapstone/defaults/claude/CLAUDE.md +67 -0
  129. package/src/skcapstone/defaults/claude/settings.json +74 -0
  130. package/src/skcapstone/defaults/lumina/config/claude-hooks.md +57 -0
  131. package/src/skcapstone/defaults/lumina/config/skgraph.yaml +55 -10
  132. package/src/skcapstone/defaults/lumina/config/skmemory.yaml +79 -13
  133. package/src/skcapstone/defaults/lumina/config/skvector.yaml +60 -9
  134. package/src/skcapstone/defaults/lumina/memory/long-term/18b9c0d1e2f3-cloud9-protocol.json +2 -2
  135. package/src/skcapstone/defaults/lumina/memory/long-term/a1b2c3d4e5f6-ecosystem-overview.json +2 -2
  136. package/src/skcapstone/defaults/lumina/memory/long-term/b2c3d4e5f6a7-five-pillars.json +9 -9
  137. package/src/skcapstone/defaults/lumina/memory/long-term/d4e5f6a7b8c9-site-directory.json +2 -2
  138. package/src/skcapstone/defaults/unhinged.json +13 -0
  139. package/src/skcapstone/discovery.py +43 -20
  140. package/src/skcapstone/doctor.py +941 -22
  141. package/src/skcapstone/dreaming.py +1183 -109
  142. package/src/skcapstone/emotion_tracker.py +2 -2
  143. package/src/skcapstone/export.py +4 -3
  144. package/src/skcapstone/fuse_mount.py +35 -25
  145. package/src/skcapstone/gui_installer.py +2 -2
  146. package/src/skcapstone/heartbeat.py +34 -30
  147. package/src/skcapstone/housekeeping.py +14 -14
  148. package/src/skcapstone/install_wizard.py +209 -7
  149. package/src/skcapstone/itil.py +13 -4
  150. package/src/skcapstone/kms_scheduler.py +10 -8
  151. package/src/skcapstone/launchd.py +426 -0
  152. package/src/skcapstone/mcp_launcher.py +15 -1
  153. package/src/skcapstone/mcp_server.py +341 -49
  154. package/src/skcapstone/mcp_tools/__init__.py +2 -0
  155. package/src/skcapstone/mcp_tools/_helpers.py +2 -2
  156. package/src/skcapstone/mcp_tools/ansible_tools.py +7 -4
  157. package/src/skcapstone/mcp_tools/brain_first_tools.py +90 -0
  158. package/src/skcapstone/mcp_tools/capauth_tools.py +7 -4
  159. package/src/skcapstone/mcp_tools/comm_tools.py +10 -10
  160. package/src/skcapstone/mcp_tools/coord_tools.py +8 -4
  161. package/src/skcapstone/mcp_tools/did_tools.py +11 -8
  162. package/src/skcapstone/mcp_tools/gtd_tools.py +4 -4
  163. package/src/skcapstone/mcp_tools/memory_tools.py +6 -2
  164. package/src/skcapstone/mcp_tools/notification_tools.py +22 -6
  165. package/src/skcapstone/mcp_tools/{skcomm_tools.py → skcomms_tools.py} +14 -14
  166. package/src/skcapstone/mcp_tools/soul_tools.py +8 -2
  167. package/src/skcapstone/mdns_discovery.py +2 -2
  168. package/src/skcapstone/memory_curator.py +1 -1
  169. package/src/skcapstone/memory_engine.py +10 -3
  170. package/src/skcapstone/metrics.py +30 -16
  171. package/src/skcapstone/migrate_memories.py +4 -3
  172. package/src/skcapstone/migrate_multi_agent.py +8 -7
  173. package/src/skcapstone/models.py +47 -5
  174. package/src/skcapstone/notifications.py +42 -18
  175. package/src/skcapstone/onboard.py +1000 -126
  176. package/src/skcapstone/operator_link.py +170 -0
  177. package/src/skcapstone/peer_directory.py +4 -4
  178. package/src/skcapstone/peers.py +19 -19
  179. package/src/skcapstone/pillars/__init__.py +7 -5
  180. package/src/skcapstone/pillars/consciousness.py +191 -0
  181. package/src/skcapstone/pillars/identity.py +51 -7
  182. package/src/skcapstone/pillars/memory.py +9 -3
  183. package/src/skcapstone/pillars/sync.py +2 -2
  184. package/src/skcapstone/preflight.py +3 -3
  185. package/src/skcapstone/providers/docker.py +28 -28
  186. package/src/skcapstone/register.py +6 -6
  187. package/src/skcapstone/registry_client.py +5 -4
  188. package/src/skcapstone/runtime.py +14 -3
  189. package/src/skcapstone/scheduled_tasks.py +254 -19
  190. package/src/skcapstone/scheduler_jobs.py +456 -0
  191. package/src/skcapstone/scheduler_runner.py +239 -0
  192. package/src/skcapstone/scheduler_state.py +162 -0
  193. package/src/skcapstone/sdk.py +310 -0
  194. package/src/skcapstone/service_health.py +279 -39
  195. package/src/skcapstone/session_briefing.py +108 -0
  196. package/src/skcapstone/session_capture.py +1 -1
  197. package/src/skcapstone/shell.py +7 -1
  198. package/src/skcapstone/soul.py +3 -1
  199. package/src/skcapstone/soul_switch.py +3 -1
  200. package/src/skcapstone/summary.py +6 -6
  201. package/src/skcapstone/sync_engine.py +15 -15
  202. package/src/skcapstone/sync_watcher.py +2 -2
  203. package/src/skcapstone/systemd.py +72 -21
  204. package/src/skcapstone/team_comms.py +8 -8
  205. package/src/skcapstone/team_engine.py +1 -1
  206. package/src/skcapstone/testrunner.py +3 -3
  207. package/src/skcapstone/trust_graph.py +40 -5
  208. package/src/skcapstone/unified_search.py +15 -6
  209. package/src/skcapstone/uninstall_wizard.py +11 -3
  210. package/src/skcapstone/version_check.py +8 -4
  211. package/src/skcapstone/warmth_anchor.py +4 -2
  212. package/src/skcapstone/whoami.py +4 -4
  213. package/systemd/skcapstone.service +4 -6
  214. package/systemd/skcapstone@.service +7 -8
  215. package/systemd/skcomms-heartbeat.service +21 -0
  216. package/systemd/skcomms-heartbeat.timer +12 -0
  217. package/systemd/skcomms-queue-drain.service +17 -0
  218. package/systemd/skcomms-queue-drain.timer +12 -0
  219. package/tests/conftest.py +39 -0
  220. package/tests/integration/test_consciousness_e2e.py +39 -39
  221. package/tests/test_agent_card.py +1 -1
  222. package/tests/test_agent_home_scaffold.py +34 -0
  223. package/tests/test_alerts_consumer_topics.py +27 -0
  224. package/tests/test_backup.py +2 -1
  225. package/tests/test_chat.py +6 -6
  226. package/tests/test_claude_md.py +2 -2
  227. package/tests/test_cli_skills.py +10 -10
  228. package/tests/test_cli_test_cmd.py +4 -4
  229. package/tests/test_cli_test_connection.py +1 -1
  230. package/tests/test_cloud9_bridge.py +6 -6
  231. package/tests/test_consciousness_e2e.py +1 -1
  232. package/tests/test_consciousness_loop.py +10 -10
  233. package/tests/test_coordination.py +25 -0
  234. package/tests/test_cross_package.py +21 -21
  235. package/tests/test_daemon.py +4 -4
  236. package/tests/test_daemon_shutdown.py +1 -1
  237. package/tests/test_docker_provider.py +29 -29
  238. package/tests/test_doctor.py +400 -0
  239. package/tests/test_doctor_skscheduler.py +50 -0
  240. package/tests/test_dreaming_engine.py +147 -0
  241. package/tests/test_dreaming_gtd_capture.py +35 -0
  242. package/tests/test_e2e_automated.py +8 -5
  243. package/tests/test_fuse_mount.py +10 -10
  244. package/tests/test_gtd_brief.py +46 -0
  245. package/tests/test_gtd_malformed_tolerance.py +31 -0
  246. package/tests/test_housekeeping.py +15 -15
  247. package/tests/test_identity_migrate.py +251 -0
  248. package/tests/test_integration_backbone.py +598 -0
  249. package/tests/test_itil_gtd_lifecycle.py +37 -0
  250. package/tests/test_jobs_dropins.py +84 -0
  251. package/tests/test_mcp_server.py +82 -37
  252. package/tests/test_models.py +48 -4
  253. package/tests/test_multi_agent.py +31 -29
  254. package/tests/test_notifications.py +122 -32
  255. package/tests/test_onboard.py +63 -75
  256. package/tests/test_operator_link.py +78 -0
  257. package/tests/test_peers.py +14 -14
  258. package/tests/test_pillars.py +98 -0
  259. package/tests/test_preflight.py +3 -3
  260. package/tests/test_runtime.py +21 -0
  261. package/tests/test_scheduled_tasks.py +11 -6
  262. package/tests/test_scheduler_cli.py +47 -0
  263. package/tests/test_scheduler_features.py +133 -0
  264. package/tests/test_scheduler_integration.py +87 -0
  265. package/tests/test_scheduler_jobs.py +155 -0
  266. package/tests/test_scheduler_runner.py +64 -0
  267. package/tests/test_scheduler_state.py +57 -0
  268. package/tests/test_sdk.py +70 -0
  269. package/tests/test_service_health_incidents.py +34 -0
  270. package/tests/test_service_registry.py +52 -0
  271. package/tests/test_session_briefing.py +130 -0
  272. package/tests/test_snapshots.py +4 -4
  273. package/tests/test_sync_pipeline.py +26 -26
  274. package/tests/test_team_comms.py +2 -2
  275. package/tests/test_testrunner.py +2 -2
  276. package/tests/test_trust_graph.py +18 -0
  277. package/tests/test_unified_search.py +2 -2
  278. package/tests/test_version_check.py +10 -0
  279. package/tests/test_version_cmd.py +8 -8
  280. package/tests/test_whoami.py +1 -1
  281. package/systemd/skcomm-heartbeat.service +0 -18
  282. package/systemd/skcomm-queue-drain.service +0 -17
  283. /package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/package.json +0 -0
  284. /package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/src/openclaw.plugin.json +0 -0
@@ -5,11 +5,11 @@ Pipeline under test:
5
5
  {shared_root}/sync/comms/inbox/{peer}/*.skc.json ← Syncthing writes here
6
6
  → inotify detects file (ConsciousnessLoop._run_inotify)
7
7
  → ConsciousnessLoop.process_envelope()
8
- skcomm.send(sender, response)
8
+ skcomms.send(sender, response)
9
9
  → {shared_root}/sync/comms/outbox/{peer}/*.skc.json ← Syncthing syncs this out
10
10
 
11
11
  Three test classes:
12
- TestInboxToOutboxFlow — mock LLM, drop inbox file, verify skcomm.send called
12
+ TestInboxToOutboxFlow — mock LLM, drop inbox file, verify skcomms.send called
13
13
  TestOutboxEnvelopeFormat — verify envelope spec compliance and path layout
14
14
  TestSyncStatusInHealth — verify health snapshot includes sync_pipeline key
15
15
  """
@@ -61,11 +61,11 @@ def agent_home(shared_root: Path) -> Path:
61
61
 
62
62
 
63
63
  @pytest.fixture
64
- def mock_skcomm() -> MagicMock:
65
- skcomm = MagicMock()
66
- skcomm.send.return_value = None
67
- skcomm.receive.return_value = []
68
- return skcomm
64
+ def mock_skcomms() -> MagicMock:
65
+ skcomms = MagicMock()
66
+ skcomms.send.return_value = None
67
+ skcomms.receive.return_value = []
68
+ return skcomms
69
69
 
70
70
 
71
71
  # ---------------------------------------------------------------------------
@@ -76,7 +76,7 @@ def mock_skcomm() -> MagicMock:
76
76
  class TestInboxToOutboxFlow:
77
77
  """Drop a file in the inbox and verify the consciousness loop responds."""
78
78
 
79
- def _make_loop(self, agent_home: Path, shared_root: Path, mock_skcomm):
79
+ def _make_loop(self, agent_home: Path, shared_root: Path, mock_skcomms):
80
80
  """Return a ConsciousnessLoop with a mocked LLM bridge."""
81
81
  from skcapstone.consciousness_loop import ConsciousnessConfig, ConsciousnessLoop
82
82
 
@@ -100,14 +100,14 @@ class TestInboxToOutboxFlow:
100
100
  shared_root=shared_root,
101
101
  )
102
102
 
103
- loop.set_skcomm(mock_skcomm)
103
+ loop.set_skcomms(mock_skcomms)
104
104
  return loop
105
105
 
106
106
  def test_inbox_to_outbox_flow(
107
- self, shared_root: Path, agent_home: Path, mock_skcomm: MagicMock
107
+ self, shared_root: Path, agent_home: Path, mock_skcomms: MagicMock
108
108
  ):
109
- """File dropped in inbox triggers process_envelope and skcomm.send."""
110
- loop = self._make_loop(agent_home, shared_root, mock_skcomm)
109
+ """File dropped in inbox triggers process_envelope and skcomms.send."""
110
+ loop = self._make_loop(agent_home, shared_root, mock_skcomms)
111
111
 
112
112
  peer = "alice"
113
113
  inbox_peer = get_inbox_dir(shared_root) / peer
@@ -130,15 +130,15 @@ class TestInboxToOutboxFlow:
130
130
  loop._on_inbox_file(inbox_file)
131
131
  loop._executor.shutdown(wait=True)
132
132
 
133
- assert mock_skcomm.send.called, "skcomm.send() must be called with the LLM response"
134
- recipient_arg = mock_skcomm.send.call_args[0][0]
133
+ assert mock_skcomms.send.called, "skcomms.send() must be called with the LLM response"
134
+ recipient_arg = mock_skcomms.send.call_args[0][0]
135
135
  assert recipient_arg == peer, "Response must be addressed to the original sender"
136
136
 
137
137
  def test_skipped_when_sender_missing(
138
- self, shared_root: Path, agent_home: Path, mock_skcomm: MagicMock
138
+ self, shared_root: Path, agent_home: Path, mock_skcomms: MagicMock
139
139
  ):
140
140
  """Envelopes without a sender field are silently dropped."""
141
- loop = self._make_loop(agent_home, shared_root, mock_skcomm)
141
+ loop = self._make_loop(agent_home, shared_root, mock_skcomms)
142
142
 
143
143
  inbox_peer = get_inbox_dir(shared_root) / "ghost"
144
144
  inbox_peer.mkdir(parents=True, exist_ok=True)
@@ -149,13 +149,13 @@ class TestInboxToOutboxFlow:
149
149
  loop._on_inbox_file(inbox_file)
150
150
  loop._executor.shutdown(wait=True)
151
151
 
152
- mock_skcomm.send.assert_not_called()
152
+ mock_skcomms.send.assert_not_called()
153
153
 
154
154
  def test_duplicate_envelope_not_reprocessed(
155
- self, shared_root: Path, agent_home: Path, mock_skcomm: MagicMock
155
+ self, shared_root: Path, agent_home: Path, mock_skcomms: MagicMock
156
156
  ):
157
157
  """The same envelope_id is never processed twice."""
158
- loop = self._make_loop(agent_home, shared_root, mock_skcomm)
158
+ loop = self._make_loop(agent_home, shared_root, mock_skcomms)
159
159
 
160
160
  peer = "bob"
161
161
  inbox_peer = get_inbox_dir(shared_root) / peer
@@ -173,7 +173,7 @@ class TestInboxToOutboxFlow:
173
173
  # First call
174
174
  loop._on_inbox_file(inbox_file)
175
175
  loop._executor.shutdown(wait=True)
176
- first_count = mock_skcomm.send.call_count
176
+ first_count = mock_skcomms.send.call_count
177
177
 
178
178
  # Recreate the loop's executor for a second submission attempt
179
179
  from concurrent.futures import ThreadPoolExecutor
@@ -184,7 +184,7 @@ class TestInboxToOutboxFlow:
184
184
  loop._executor.shutdown(wait=True)
185
185
 
186
186
  # Exactly the same number of sends — second call was deduped
187
- assert mock_skcomm.send.call_count == first_count
187
+ assert mock_skcomms.send.call_count == first_count
188
188
 
189
189
 
190
190
  # ---------------------------------------------------------------------------
@@ -193,7 +193,7 @@ class TestInboxToOutboxFlow:
193
193
 
194
194
 
195
195
  class TestOutboxEnvelopeFormat:
196
- """Verify that outbox envelopes comply with the SKComm envelope spec."""
196
+ """Verify that outbox envelopes comply with the SKComms envelope spec."""
197
197
 
198
198
  def test_required_fields_preserved(self, shared_root: Path):
199
199
  """write_outbox_envelope writes all envelope fields to the .skc.json."""
@@ -348,7 +348,7 @@ class TestSyncStatusInHealth:
348
348
 
349
349
  def test_verify_pipeline_detects_transport_misalignment(self, shared_root: Path):
350
350
  """verify_pipeline_paths flags a SyncthingTransport with a wrong comms_root."""
351
- # Build a mock SKComm with a Syncthing transport pointing to the wrong path
351
+ # Build a mock SKComms with a Syncthing transport pointing to the wrong path
352
352
  wrong_transport = MagicMock()
353
353
  wrong_transport.name = "syncthing"
354
354
  wrong_transport._root = Path("/tmp/wrong/path")
@@ -356,9 +356,9 @@ class TestSyncStatusInHealth:
356
356
  mock_router = MagicMock()
357
357
  mock_router.transports = [wrong_transport]
358
358
 
359
- mock_skcomm = MagicMock()
360
- mock_skcomm.router = mock_router
359
+ mock_skcomms = MagicMock()
360
+ mock_skcomms.router = mock_router
361
361
 
362
- result = verify_pipeline_paths(shared_root, skcomm=mock_skcomm)
362
+ result = verify_pipeline_paths(shared_root, skcomms=mock_skcomms)
363
363
  assert result["transport_aligned"] is False
364
364
  assert any("mismatch" in issue.lower() for issue in result["issues"])
@@ -301,9 +301,9 @@ class TestBuildEnvelope:
301
301
  """Tests for the internal _build_envelope helper."""
302
302
 
303
303
  def test_required_fields_present(self) -> None:
304
- """Envelope dict has all required SKComm fields."""
304
+ """Envelope dict has all required SKComms fields."""
305
305
  env = _build_envelope("agent-a", "agent-b", "hello")
306
- assert env["skcomm_version"] == "1.0.0"
306
+ assert env["skcomms_version"] == "1.0.0"
307
307
  assert env["sender"] == "agent-a"
308
308
  assert env["recipient"] == "agent-b"
309
309
  assert env["payload"]["content"] == "hello"
@@ -233,6 +233,6 @@ class TestRunAllTests:
233
233
 
234
234
  def test_filter_by_package_names(self, tmp_path: Path):
235
235
  """Only requested packages appear in the report."""
236
- report = run_all_tests(tmp_path, packages=["skcomm", "skchat"])
236
+ report = run_all_tests(tmp_path, packages=["skcomms", "skchat"])
237
237
  names = [r.name for r in report.results]
238
- assert names == ["skcomm", "skchat"]
238
+ assert names == ["skcomms", "skchat"]
@@ -121,6 +121,24 @@ class TestBuildGraph:
121
121
  sync_edges = [e for e in graph.edges if e.edge_type == "sync"]
122
122
  assert len(sync_edges) >= 1
123
123
 
124
+ def test_manifest_operator_creates_human_link(self, tmp_agent_home: Path):
125
+ """Manifest operator metadata appears as an explicit trust relationship."""
126
+ _init_agent(tmp_agent_home, "operator-graph")
127
+ manifest_path = tmp_agent_home / "manifest.json"
128
+ manifest = json.loads(manifest_path.read_text())
129
+ manifest["operator"] = {
130
+ "name": "Casey",
131
+ "fingerprint": "FP1234567890",
132
+ "relationship": "human-operator",
133
+ "entity_type": "human",
134
+ }
135
+ manifest_path.write_text(json.dumps(manifest), encoding="utf-8")
136
+
137
+ graph = build_trust_graph(tmp_agent_home)
138
+
139
+ assert any(n.label == "Casey" for n in graph.nodes)
140
+ assert any(e.edge_type == "operator" and e.label == "human-operator" for e in graph.edges)
141
+
124
142
 
125
143
  class TestFormatDot:
126
144
  """Tests for DOT format output."""
@@ -232,10 +232,10 @@ class TestSearchConversations:
232
232
  # ---------------------------------------------------------------------------
233
233
 
234
234
  class TestSearchMessages:
235
- """Tests for searching SKComm messages."""
235
+ """Tests for searching SKComms messages."""
236
236
 
237
237
  def test_finds_skc_message(self, agent_home: Path):
238
- """Search should find text inside an archived SKComm envelope."""
238
+ """Search should find text inside an archived SKComms envelope."""
239
239
  _write_message(agent_home, "env001", "jarvis", "lumina",
240
240
  "Queen Lumina — welcome to the coordination board!")
241
241
  results = search(agent_home, "coordination", sources=frozenset({"message"}))
@@ -0,0 +1,10 @@
1
+ """Tests for ecosystem package version checks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from skcapstone.version_check import _get_installed_version
6
+
7
+
8
+ def test_missing_package_returns_none_without_name_error():
9
+ """Missing package lookup should not raise when logging the fallback failure."""
10
+ assert _get_installed_version("definitely-not-an-sk-package") is None
@@ -181,7 +181,7 @@ class TestGatherVersionInfo:
181
181
  assert "daemon_pid" in info
182
182
 
183
183
  def test_optional_deps_has_four_packages(self, agent_home: Path):
184
- """optional_deps covers watchdog, skcomm, skchat, skseed."""
184
+ """optional_deps covers watchdog, skcomms, skchat, skseed."""
185
185
  from skcapstone.cli.version_cmd import gather_version_info
186
186
 
187
187
  with patch("urllib.request.urlopen", side_effect=OSError), \
@@ -189,7 +189,7 @@ class TestGatherVersionInfo:
189
189
  info = gather_version_info(agent_home)
190
190
 
191
191
  deps = info["optional_deps"]
192
- assert set(deps.keys()) == {"watchdog", "skcomm", "skchat", "skseed"}
192
+ assert set(deps.keys()) == {"watchdog", "skcomms", "skchat", "skseed"}
193
193
 
194
194
  def test_package_version_matches_module(self, agent_home: Path):
195
195
  """package_version matches skcapstone.__version__."""
@@ -214,7 +214,7 @@ class TestVersionCommand:
214
214
  def _run(self, args: list[str], agent_home: Path):
215
215
  from skcapstone.cli import main
216
216
 
217
- runner = CliRunner(mix_stderr=False)
217
+ runner = CliRunner()
218
218
  with patch("urllib.request.urlopen", side_effect=OSError), \
219
219
  patch("skcapstone.daemon.read_pid", return_value=None):
220
220
  return runner.invoke(
@@ -235,7 +235,7 @@ class TestVersionCommand:
235
235
  """Normal output lists all four optional dep names."""
236
236
  result = self._run([], agent_home)
237
237
  assert result.exit_code == 0
238
- for pkg in ("watchdog", "skcomm", "skchat", "skseed"):
238
+ for pkg in ("watchdog", "skcomms", "skchat", "skseed"):
239
239
  assert pkg in result.output
240
240
 
241
241
  def test_json_output_is_valid_and_complete(self, agent_home: Path):
@@ -253,7 +253,7 @@ class TestVersionCommand:
253
253
  """Shows running + PID when daemon is alive."""
254
254
  from skcapstone.cli import main
255
255
 
256
- runner = CliRunner(mix_stderr=False)
256
+ runner = CliRunner()
257
257
  with patch("urllib.request.urlopen", side_effect=OSError), \
258
258
  patch("skcapstone.daemon.read_pid", return_value=42001):
259
259
  result = runner.invoke(
@@ -276,7 +276,7 @@ class TestVersionCommand:
276
276
  mock_resp.__exit__ = MagicMock(return_value=False)
277
277
  mock_resp.read.return_value = payload
278
278
 
279
- runner = CliRunner(mix_stderr=False)
279
+ runner = CliRunner()
280
280
  with patch("urllib.request.urlopen", return_value=mock_resp), \
281
281
  patch("skcapstone.daemon.read_pid", return_value=None):
282
282
  result = runner.invoke(
@@ -299,7 +299,7 @@ class TestDoctorVerbose:
299
299
  def _run_doctor(self, args: list[str], agent_home: Path):
300
300
  from skcapstone.cli import main
301
301
 
302
- runner = CliRunner(mix_stderr=False)
302
+ runner = CliRunner()
303
303
  return runner.invoke(
304
304
  main,
305
305
  ["doctor", "--home", str(agent_home)] + args,
@@ -349,7 +349,7 @@ class TestDoctorVerbose:
349
349
  """--help output documents the --verbose flag."""
350
350
  from skcapstone.cli import main
351
351
 
352
- runner = CliRunner(mix_stderr=False)
352
+ runner = CliRunner()
353
353
  result = runner.invoke(main, ["doctor", "--help"])
354
354
  assert result.exit_code == 0
355
355
  assert "--verbose" in result.output
@@ -81,7 +81,7 @@ class TestIdentityCard:
81
81
  name="Opus",
82
82
  fingerprint="AABB1122",
83
83
  entity_type="ai",
84
- capabilities=["capauth:identity", "skcomm:messaging"],
84
+ capabilities=["capauth:identity", "skcomms:messaging"],
85
85
  contact_uris=["capauth:AABB1122"],
86
86
  )
87
87
  json_str = card.model_dump_json()
@@ -1,18 +0,0 @@
1
- [Unit]
2
- Description=SKComm Heartbeat Emission
3
- Documentation=https://github.com/smilinTux/skcomm
4
- After=network-online.target
5
-
6
- [Service]
7
- Type=oneshot
8
- ExecStart=skcomm heartbeat --no-emit
9
- ExecStart=skcomm heartbeat
10
- Nice=19
11
-
12
- NoNewPrivileges=true
13
- ProtectSystem=strict
14
- ProtectHome=read-only
15
- ReadWritePaths=%h/.skcapstone %h/.skcomm
16
- PrivateTmp=true
17
-
18
- Environment=PYTHONUNBUFFERED=1
@@ -1,17 +0,0 @@
1
- [Unit]
2
- Description=SKComm Queue Drain — retry undelivered messages
3
- Documentation=https://github.com/smilinTux/skcomm
4
- After=network-online.target
5
-
6
- [Service]
7
- Type=oneshot
8
- ExecStart=skcomm queue drain
9
- Nice=19
10
-
11
- NoNewPrivileges=true
12
- ProtectSystem=strict
13
- ProtectHome=read-only
14
- ReadWritePaths=%h/.skcapstone %h/.skcomm
15
- PrivateTmp=true
16
-
17
- Environment=PYTHONUNBUFFERED=1