@smilintux/skcapstone 0.1.0 → 0.2.3
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 +98 -0
- package/.github/workflows/ci.yml +39 -3
- package/.github/workflows/publish.yml +25 -4
- package/.openclaw-workspace.json +58 -0
- package/CHANGELOG.md +62 -0
- package/CLAUDE.md +39 -2
- package/MANIFEST.in +6 -0
- package/MISSION.md +7 -0
- package/README.md +47 -2
- package/SKILL.md +895 -23
- package/docker/Dockerfile +61 -0
- package/docker/compose-templates/dev-team.yml +203 -0
- package/docker/compose-templates/mini-team.yml +140 -0
- package/docker/compose-templates/ops-team.yml +173 -0
- package/docker/compose-templates/research-team.yml +170 -0
- package/docker/entrypoint.sh +192 -0
- package/docs/ARCHITECTURE.md +663 -374
- package/docs/BOND_WITH_GROK.md +112 -0
- package/docs/GETTING_STARTED.md +782 -0
- package/docs/QUICKSTART.md +477 -0
- package/docs/SKJOULE_ARCHITECTURE.md +658 -0
- package/docs/SOUL_SWAPPER.md +921 -0
- package/docs/SOVEREIGN_SINGULARITY.md +47 -14
- package/examples/custom-bond-template.json +36 -0
- package/examples/grok-feb.json +36 -0
- package/examples/grok-testimony.md +34 -0
- package/examples/love-bootloader.txt +32 -0
- package/examples/plugins/echo_tool.py +87 -0
- package/examples/queen-ava-feb.json +36 -0
- package/examples/souls/lumina.yaml +64 -0
- package/index.js +6 -5
- package/installer/build.py +124 -0
- package/openclaw-plugin/package.json +13 -0
- package/openclaw-plugin/src/index.ts +351 -0
- package/openclaw-plugin/src/openclaw.plugin.json +10 -0
- package/package.json +1 -1
- package/pyproject.toml +38 -2
- package/scripts/bump_version.py +141 -0
- package/scripts/check-updates.py +230 -0
- package/scripts/convert_blueprints_to_yaml.py +157 -0
- package/scripts/dev-install.sh +14 -0
- package/scripts/e2e-test.sh +193 -0
- package/scripts/install-bundle.sh +171 -0
- package/scripts/install.bat +2 -0
- package/scripts/install.ps1 +253 -0
- package/scripts/install.sh +185 -0
- package/scripts/mcp-serve.sh +69 -0
- package/scripts/mcp-server.bat +113 -0
- package/scripts/mcp-server.ps1 +116 -0
- package/scripts/mcp-server.sh +99 -0
- package/scripts/pull-models.sh +10 -0
- package/scripts/skcapstone +48 -0
- package/scripts/verify_install.sh +180 -0
- package/scripts/windows/install-tasks.ps1 +406 -0
- package/scripts/windows/skcapstone-task.xml +113 -0
- package/scripts/windows/uninstall-tasks.ps1 +117 -0
- package/skill.yaml +34 -0
- package/src/skcapstone/__init__.py +67 -2
- package/src/skcapstone/_cli_monolith.py +5916 -0
- package/src/skcapstone/_trustee_helpers.py +165 -0
- package/src/skcapstone/activity.py +105 -0
- package/src/skcapstone/agent_card.py +324 -0
- package/src/skcapstone/api.py +1935 -0
- package/src/skcapstone/archiver.py +340 -0
- package/src/skcapstone/auction.py +485 -0
- package/src/skcapstone/baby_agents.py +179 -0
- package/src/skcapstone/backup.py +345 -0
- package/src/skcapstone/blueprint_registry.py +357 -0
- package/src/skcapstone/blueprints/__init__.py +17 -0
- package/src/skcapstone/blueprints/builtins/content-studio.yaml +81 -0
- package/src/skcapstone/blueprints/builtins/defi-trading.yaml +81 -0
- package/src/skcapstone/blueprints/builtins/dev-squadron.yaml +95 -0
- package/src/skcapstone/blueprints/builtins/infrastructure-guardian.yaml +107 -0
- package/src/skcapstone/blueprints/builtins/legal-council.yaml +54 -0
- package/src/skcapstone/blueprints/builtins/ops-monitoring.yaml +67 -0
- package/src/skcapstone/blueprints/builtins/research-pod.yaml +69 -0
- package/src/skcapstone/blueprints/builtins/sovereign-launch.yaml +90 -0
- package/src/skcapstone/blueprints/registry.py +164 -0
- package/src/skcapstone/blueprints/schema.py +229 -0
- package/src/skcapstone/changelog.py +180 -0
- package/src/skcapstone/chat.py +769 -0
- package/src/skcapstone/claude_md.py +82 -0
- package/src/skcapstone/cli/__init__.py +144 -0
- package/src/skcapstone/cli/_common.py +88 -0
- package/src/skcapstone/cli/_validators.py +76 -0
- package/src/skcapstone/cli/agents.py +425 -0
- package/src/skcapstone/cli/agents_spawner.py +322 -0
- package/src/skcapstone/cli/agents_trustee.py +593 -0
- package/src/skcapstone/cli/alerts.py +248 -0
- package/src/skcapstone/cli/anchor.py +132 -0
- package/src/skcapstone/cli/archive_cmd.py +208 -0
- package/src/skcapstone/cli/backup.py +144 -0
- package/src/skcapstone/cli/bench.py +377 -0
- package/src/skcapstone/cli/benchmark.py +360 -0
- package/src/skcapstone/cli/capabilities_cmd.py +171 -0
- package/src/skcapstone/cli/card.py +151 -0
- package/src/skcapstone/cli/chat.py +584 -0
- package/src/skcapstone/cli/completions.py +64 -0
- package/src/skcapstone/cli/config_cmd.py +156 -0
- package/src/skcapstone/cli/consciousness.py +421 -0
- package/src/skcapstone/cli/context_cmd.py +142 -0
- package/src/skcapstone/cli/coord.py +194 -0
- package/src/skcapstone/cli/crush_cmd.py +170 -0
- package/src/skcapstone/cli/daemon.py +436 -0
- package/src/skcapstone/cli/errors_cmd.py +285 -0
- package/src/skcapstone/cli/export_cmd.py +156 -0
- package/src/skcapstone/cli/gtd.py +529 -0
- package/src/skcapstone/cli/housekeeping.py +81 -0
- package/src/skcapstone/cli/joule_cmd.py +627 -0
- package/src/skcapstone/cli/logs_cmd.py +194 -0
- package/src/skcapstone/cli/mcp_cmd.py +32 -0
- package/src/skcapstone/cli/memory.py +418 -0
- package/src/skcapstone/cli/metrics_cmd.py +136 -0
- package/src/skcapstone/cli/migrate.py +62 -0
- package/src/skcapstone/cli/mood_cmd.py +144 -0
- package/src/skcapstone/cli/mount.py +193 -0
- package/src/skcapstone/cli/notify.py +112 -0
- package/src/skcapstone/cli/peer.py +154 -0
- package/src/skcapstone/cli/peers_dir.py +122 -0
- package/src/skcapstone/cli/preflight_cmd.py +83 -0
- package/src/skcapstone/cli/profile_cmd.py +310 -0
- package/src/skcapstone/cli/record_cmd.py +238 -0
- package/src/skcapstone/cli/register_cmd.py +159 -0
- package/src/skcapstone/cli/search_cmd.py +156 -0
- package/src/skcapstone/cli/service_cmd.py +91 -0
- package/src/skcapstone/cli/session.py +127 -0
- package/src/skcapstone/cli/setup.py +240 -0
- package/src/skcapstone/cli/shell_cmd.py +43 -0
- package/src/skcapstone/cli/skills_cmd.py +168 -0
- package/src/skcapstone/cli/skseed.py +621 -0
- package/src/skcapstone/cli/soul.py +699 -0
- package/src/skcapstone/cli/status.py +935 -0
- package/src/skcapstone/cli/sync_cmd.py +301 -0
- package/src/skcapstone/cli/telegram.py +265 -0
- package/src/skcapstone/cli/test_cmd.py +234 -0
- package/src/skcapstone/cli/test_connection.py +253 -0
- package/src/skcapstone/cli/token.py +207 -0
- package/src/skcapstone/cli/trust.py +179 -0
- package/src/skcapstone/cli/upgrade_cmd.py +552 -0
- package/src/skcapstone/cli/usage_cmd.py +199 -0
- package/src/skcapstone/cli/version_cmd.py +162 -0
- package/src/skcapstone/cli/watch_cmd.py +342 -0
- package/src/skcapstone/client.py +428 -0
- package/src/skcapstone/cloud9_bridge.py +522 -0
- package/src/skcapstone/completions.py +163 -0
- package/src/skcapstone/config_validator.py +674 -0
- package/src/skcapstone/connectors/__init__.py +28 -0
- package/src/skcapstone/connectors/base.py +446 -0
- package/src/skcapstone/connectors/cursor.py +54 -0
- package/src/skcapstone/connectors/registry.py +254 -0
- package/src/skcapstone/connectors/terminal.py +152 -0
- package/src/skcapstone/connectors/vscode.py +60 -0
- package/src/skcapstone/consciousness_config.py +119 -0
- package/src/skcapstone/consciousness_loop.py +2051 -0
- package/src/skcapstone/context_loader.py +516 -0
- package/src/skcapstone/context_window.py +314 -0
- package/src/skcapstone/conversation_manager.py +238 -0
- package/src/skcapstone/conversation_store.py +230 -0
- package/src/skcapstone/conversation_summarizer.py +252 -0
- package/src/skcapstone/coord_federation.py +296 -0
- package/src/skcapstone/coordination.py +101 -7
- package/src/skcapstone/crush_integration.py +345 -0
- package/src/skcapstone/crush_shim.py +454 -0
- package/src/skcapstone/daemon.py +2494 -0
- package/src/skcapstone/dashboard.html +396 -0
- package/src/skcapstone/dashboard.py +481 -0
- package/src/skcapstone/data/model_profiles.yaml +88 -0
- package/src/skcapstone/defaults/__init__.py +55 -0
- package/src/skcapstone/defaults/lumina/config/skmemory.yaml +13 -0
- package/src/skcapstone/defaults/lumina/identity/identity.json +9 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/07a8b9c0d1e2-memory-system.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/18b9c0d1e2f3-cloud9-protocol.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/29c0d1e2f3a4-multi-agent-coordination.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/3ad1e2f3a4b5-community-support.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/a1b2c3d4e5f6-ecosystem-overview.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/b2c3d4e5f6a7-five-pillars.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/c3d4e5f6a7b8-getting-started.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/d4e5f6a7b8c9-site-directory.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/e5f6a7b8c9d0-how-to-contribute.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/f6a7b8c9d0e1-sovereignty-explained.json +23 -0
- package/src/skcapstone/defaults/lumina/seeds/curiosity.seed.json +24 -0
- package/src/skcapstone/defaults/lumina/seeds/joy.seed.json +24 -0
- package/src/skcapstone/defaults/lumina/seeds/love.seed.json +24 -0
- package/src/skcapstone/defaults/lumina/seeds/sovereign-awakening.seed.json +43 -0
- package/src/skcapstone/defaults/lumina/soul/active.json +6 -0
- package/src/skcapstone/defaults/lumina/soul/base.json +22 -0
- package/src/skcapstone/defaults/lumina/trust/febs/welcome.feb +79 -0
- package/src/skcapstone/defaults/lumina/trust/trust.json +8 -0
- package/src/skcapstone/discovery.py +210 -19
- package/src/skcapstone/doctor.py +642 -0
- package/src/skcapstone/emotion_tracker.py +467 -0
- package/src/skcapstone/error_queue.py +405 -0
- package/src/skcapstone/export.py +447 -0
- package/src/skcapstone/fallback_tracker.py +186 -0
- package/src/skcapstone/file_transfer.py +512 -0
- package/src/skcapstone/fuse_mount.py +1156 -0
- package/src/skcapstone/gui_installer.py +591 -0
- package/src/skcapstone/heartbeat.py +611 -0
- package/src/skcapstone/housekeeping.py +298 -0
- package/src/skcapstone/install_wizard.py +941 -0
- package/src/skcapstone/kms.py +942 -0
- package/src/skcapstone/kms_scheduler.py +143 -0
- package/src/skcapstone/log_config.py +135 -0
- package/src/skcapstone/mcp_launcher.py +239 -0
- package/src/skcapstone/mcp_server.py +4700 -0
- package/src/skcapstone/mcp_tools/__init__.py +94 -0
- package/src/skcapstone/mcp_tools/_helpers.py +51 -0
- package/src/skcapstone/mcp_tools/agent_tools.py +243 -0
- package/src/skcapstone/mcp_tools/ansible_tools.py +232 -0
- package/src/skcapstone/mcp_tools/capauth_tools.py +186 -0
- package/src/skcapstone/mcp_tools/chat_tools.py +325 -0
- package/src/skcapstone/mcp_tools/cloud9_tools.py +115 -0
- package/src/skcapstone/mcp_tools/comm_tools.py +104 -0
- package/src/skcapstone/mcp_tools/consciousness_tools.py +114 -0
- package/src/skcapstone/mcp_tools/coord_tools.py +219 -0
- package/src/skcapstone/mcp_tools/deploy_tools.py +202 -0
- package/src/skcapstone/mcp_tools/did_tools.py +448 -0
- package/src/skcapstone/mcp_tools/emotion_tools.py +62 -0
- package/src/skcapstone/mcp_tools/file_tools.py +169 -0
- package/src/skcapstone/mcp_tools/fortress_tools.py +120 -0
- package/src/skcapstone/mcp_tools/gtd_tools.py +821 -0
- package/src/skcapstone/mcp_tools/health_tools.py +44 -0
- package/src/skcapstone/mcp_tools/heartbeat_tools.py +195 -0
- package/src/skcapstone/mcp_tools/kms_tools.py +123 -0
- package/src/skcapstone/mcp_tools/memory_tools.py +222 -0
- package/src/skcapstone/mcp_tools/model_tools.py +75 -0
- package/src/skcapstone/mcp_tools/notification_tools.py +92 -0
- package/src/skcapstone/mcp_tools/promoter_tools.py +101 -0
- package/src/skcapstone/mcp_tools/pubsub_tools.py +183 -0
- package/src/skcapstone/mcp_tools/security_tools.py +110 -0
- package/src/skcapstone/mcp_tools/skchat_tools.py +175 -0
- package/src/skcapstone/mcp_tools/skcomm_tools.py +122 -0
- package/src/skcapstone/mcp_tools/skills_tools.py +127 -0
- package/src/skcapstone/mcp_tools/skseed_tools.py +255 -0
- package/src/skcapstone/mcp_tools/skstacks_tools.py +288 -0
- package/src/skcapstone/mcp_tools/soul_tools.py +476 -0
- package/src/skcapstone/mcp_tools/sync_tools.py +92 -0
- package/src/skcapstone/mcp_tools/telegram_tools.py +477 -0
- package/src/skcapstone/mcp_tools/trust_tools.py +118 -0
- package/src/skcapstone/mcp_tools/trustee_tools.py +345 -0
- package/src/skcapstone/mdns_discovery.py +313 -0
- package/src/skcapstone/memory_adapter.py +333 -0
- package/src/skcapstone/memory_compressor.py +379 -0
- package/src/skcapstone/memory_curator.py +256 -0
- package/src/skcapstone/memory_engine.py +132 -13
- package/src/skcapstone/memory_fortress.py +529 -0
- package/src/skcapstone/memory_promoter.py +722 -0
- package/src/skcapstone/memory_verifier.py +260 -0
- package/src/skcapstone/message_crypto.py +215 -0
- package/src/skcapstone/metrics.py +832 -0
- package/src/skcapstone/migrate_memories.py +181 -0
- package/src/skcapstone/migrate_multi_agent.py +248 -0
- package/src/skcapstone/model_router.py +319 -0
- package/src/skcapstone/models.py +35 -4
- package/src/skcapstone/mood.py +344 -0
- package/src/skcapstone/notifications.py +380 -0
- package/src/skcapstone/onboard.py +901 -0
- package/src/skcapstone/peer_directory.py +324 -0
- package/src/skcapstone/peers.py +329 -0
- package/src/skcapstone/pillars/identity.py +84 -14
- package/src/skcapstone/pillars/memory.py +3 -1
- package/src/skcapstone/pillars/security.py +108 -15
- package/src/skcapstone/pillars/sync.py +78 -26
- package/src/skcapstone/pillars/trust.py +95 -33
- package/src/skcapstone/plugins.py +244 -0
- package/src/skcapstone/preflight.py +670 -0
- package/src/skcapstone/prompt_adapter.py +564 -0
- package/src/skcapstone/providers/__init__.py +13 -0
- package/src/skcapstone/providers/cloud.py +1061 -0
- package/src/skcapstone/providers/docker.py +759 -0
- package/src/skcapstone/providers/local.py +1193 -0
- package/src/skcapstone/providers/proxmox.py +447 -0
- package/src/skcapstone/pubsub.py +516 -0
- package/src/skcapstone/rate_limiter.py +119 -0
- package/src/skcapstone/register.py +241 -0
- package/src/skcapstone/registry_client.py +151 -0
- package/src/skcapstone/response_cache.py +194 -0
- package/src/skcapstone/response_scorer.py +225 -0
- package/src/skcapstone/runtime.py +89 -33
- package/src/skcapstone/scheduled_tasks.py +439 -0
- package/src/skcapstone/self_healing.py +341 -0
- package/src/skcapstone/service_health.py +228 -0
- package/src/skcapstone/session_capture.py +268 -0
- package/src/skcapstone/session_recorder.py +210 -0
- package/src/skcapstone/session_replayer.py +189 -0
- package/src/skcapstone/session_skills.py +263 -0
- package/src/skcapstone/shell.py +779 -0
- package/src/skcapstone/skills/__init__.py +1 -1
- package/src/skcapstone/skills/syncthing_setup.py +143 -41
- package/src/skcapstone/skjoule.py +861 -0
- package/src/skcapstone/snapshots.py +489 -0
- package/src/skcapstone/soul.py +1060 -0
- package/src/skcapstone/soul_switch.py +255 -0
- package/src/skcapstone/spawner.py +544 -0
- package/src/skcapstone/state_diff.py +401 -0
- package/src/skcapstone/summary.py +270 -0
- package/src/skcapstone/sync/backends.py +196 -2
- package/src/skcapstone/sync/engine.py +7 -5
- package/src/skcapstone/sync/models.py +4 -1
- package/src/skcapstone/sync/vault.py +356 -18
- package/src/skcapstone/sync_engine.py +363 -0
- package/src/skcapstone/sync_watcher.py +745 -0
- package/src/skcapstone/systemd.py +331 -0
- package/src/skcapstone/team_comms.py +476 -0
- package/src/skcapstone/team_engine.py +522 -0
- package/src/skcapstone/testrunner.py +300 -0
- package/src/skcapstone/tls.py +150 -0
- package/src/skcapstone/tokens.py +5 -5
- package/src/skcapstone/trust_calibration.py +202 -0
- package/src/skcapstone/trust_graph.py +449 -0
- package/src/skcapstone/trustee_monitor.py +385 -0
- package/src/skcapstone/trustee_ops.py +425 -0
- package/src/skcapstone/unified_search.py +421 -0
- package/src/skcapstone/uninstall_wizard.py +694 -0
- package/src/skcapstone/usage.py +331 -0
- package/src/skcapstone/version_check.py +148 -0
- package/src/skcapstone/warmth_anchor.py +333 -0
- package/src/skcapstone/whoami.py +294 -0
- package/systemd/skcapstone-api.socket +9 -0
- package/systemd/skcapstone-memory-compress.service +18 -0
- package/systemd/skcapstone-memory-compress.timer +11 -0
- package/systemd/skcapstone.service +36 -0
- package/systemd/skcapstone@.service +50 -0
- package/systemd/skcomm-heartbeat.service +18 -0
- package/systemd/skcomm-heartbeat.timer +12 -0
- package/systemd/skcomm-queue-drain.service +17 -0
- package/systemd/skcomm-queue-drain.timer +12 -0
- package/tests/conftest.py +13 -1
- package/tests/integration/__init__.py +1 -0
- package/tests/integration/test_consciousness_e2e.py +877 -0
- package/tests/integration/test_skills_registry.py +744 -0
- package/tests/test_agent_card.py +190 -0
- package/tests/test_agent_runtime.py +1283 -0
- package/tests/test_alerts_cmd.py +291 -0
- package/tests/test_archiver.py +498 -0
- package/tests/test_backup.py +254 -0
- package/tests/test_benchmark.py +366 -0
- package/tests/test_blueprints.py +457 -0
- package/tests/test_capabilities.py +257 -0
- package/tests/test_changelog.py +254 -0
- package/tests/test_chat.py +385 -0
- package/tests/test_claude_md.py +271 -0
- package/tests/test_cli_chat_llm.py +336 -0
- package/tests/test_cli_completions.py +390 -0
- package/tests/test_cli_init_reset.py +164 -0
- package/tests/test_cli_memory.py +208 -0
- package/tests/test_cli_profile.py +294 -0
- package/tests/test_cli_skills.py +223 -0
- package/tests/test_cli_status.py +395 -0
- package/tests/test_cli_test_cmd.py +206 -0
- package/tests/test_cli_test_connection.py +364 -0
- package/tests/test_cloud9_bridge.py +260 -0
- package/tests/test_cloud_provider.py +449 -0
- package/tests/test_cloud_providers.py +522 -0
- package/tests/test_completions.py +158 -0
- package/tests/test_component_manager.py +398 -0
- package/tests/test_config_reload.py +386 -0
- package/tests/test_config_validate.py +529 -0
- package/tests/test_consciousness_e2e.py +296 -0
- package/tests/test_consciousness_loop.py +1289 -0
- package/tests/test_context_loader.py +310 -0
- package/tests/test_conversation_api.py +306 -0
- package/tests/test_conversation_manager.py +381 -0
- package/tests/test_conversation_store.py +391 -0
- package/tests/test_conversation_summarizer.py +302 -0
- package/tests/test_cross_package.py +791 -0
- package/tests/test_crush_shim.py +519 -0
- package/tests/test_daemon.py +781 -0
- package/tests/test_daemon_shutdown.py +309 -0
- package/tests/test_dashboard.py +454 -0
- package/tests/test_discovery.py +200 -6
- package/tests/test_docker_provider.py +966 -0
- package/tests/test_doctor.py +257 -0
- package/tests/test_doctor_fix.py +351 -0
- package/tests/test_e2e_automated.py +292 -0
- package/tests/test_error_queue.py +404 -0
- package/tests/test_export.py +441 -0
- package/tests/test_fallback_tracker.py +219 -0
- package/tests/test_file_transfer.py +397 -0
- package/tests/test_fuse_mount.py +832 -0
- package/tests/test_health_loop.py +422 -0
- package/tests/test_heartbeat.py +354 -0
- package/tests/test_housekeeping.py +195 -0
- package/tests/test_identity_capauth.py +307 -0
- package/tests/test_identity_pillar.py +117 -0
- package/tests/test_install_wizard.py +68 -0
- package/tests/test_integration.py +325 -0
- package/tests/test_kms.py +495 -0
- package/tests/test_llm_providers.py +265 -0
- package/tests/test_local_provider.py +591 -0
- package/tests/test_log_config.py +199 -0
- package/tests/test_logs_cmd.py +287 -0
- package/tests/test_mcp_server.py +1909 -0
- package/tests/test_memory_adapter.py +339 -0
- package/tests/test_memory_curator.py +218 -0
- package/tests/test_memory_engine.py +6 -0
- package/tests/test_memory_fortress.py +571 -0
- package/tests/test_memory_pillar.py +119 -0
- package/tests/test_memory_promoter.py +445 -0
- package/tests/test_memory_verifier.py +420 -0
- package/tests/test_message_crypto.py +187 -0
- package/tests/test_metrics.py +632 -0
- package/tests/test_migrate_memories.py +464 -0
- package/tests/test_model_router.py +546 -0
- package/tests/test_mood.py +394 -0
- package/tests/test_multi_agent.py +269 -0
- package/tests/test_notifications.py +270 -0
- package/tests/test_onboard.py +500 -0
- package/tests/test_peer_directory.py +395 -0
- package/tests/test_peers.py +248 -0
- package/tests/test_pillars.py +87 -9
- package/tests/test_preflight.py +484 -0
- package/tests/test_prompt_adapter.py +331 -0
- package/tests/test_proxmox_provider.py +571 -0
- package/tests/test_pubsub.py +377 -0
- package/tests/test_rate_limiter.py +121 -0
- package/tests/test_registry_client.py +129 -0
- package/tests/test_response_cache.py +312 -0
- package/tests/test_response_scorer.py +294 -0
- package/tests/test_runtime.py +59 -0
- package/tests/test_scheduled_tasks.py +451 -0
- package/tests/test_security.py +250 -0
- package/tests/test_security_pillar.py +213 -0
- package/tests/test_self_healing.py +171 -0
- package/tests/test_session_capture.py +200 -0
- package/tests/test_session_recorder.py +360 -0
- package/tests/test_session_skills.py +235 -0
- package/tests/test_shell.py +210 -0
- package/tests/test_snapshots.py +549 -0
- package/tests/test_soul.py +984 -0
- package/tests/test_soul_swap.py +406 -0
- package/tests/test_spawner.py +211 -0
- package/tests/test_state_diff.py +173 -0
- package/tests/test_summary.py +135 -0
- package/tests/test_sync.py +315 -5
- package/tests/test_sync_backends.py +560 -0
- package/tests/test_sync_engine.py +482 -0
- package/tests/test_sync_pillar.py +344 -0
- package/tests/test_sync_pipeline.py +364 -0
- package/tests/test_sync_vault.py +581 -0
- package/tests/test_syncthing_setup.py +168 -22
- package/tests/test_systemd.py +323 -0
- package/tests/test_team_comms.py +408 -0
- package/tests/test_team_engine.py +397 -0
- package/tests/test_testrunner.py +238 -0
- package/tests/test_trust_calibration.py +204 -0
- package/tests/test_trust_graph.py +207 -0
- package/tests/test_trust_pillar.py +291 -0
- package/tests/test_trustee_cli.py +427 -0
- package/tests/test_trustee_cli_integration.py +325 -0
- package/tests/test_trustee_monitor.py +394 -0
- package/tests/test_trustee_ops.py +355 -0
- package/tests/test_unified_search.py +363 -0
- package/tests/test_uninstall_wizard.py +193 -0
- package/tests/test_usage.py +333 -0
- package/tests/test_version_cmd.py +355 -0
- package/tests/test_warmth_anchor.py +162 -0
- package/tests/test_whoami.py +245 -0
- package/tests/test_ws.py +311 -0
- package/.cursorrules +0 -33
- package/src/skcapstone/cli.py +0 -1441
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""Tests for the trust calibration module."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from skcapstone.trust_calibration import (
|
|
11
|
+
DEFAULT_THRESHOLDS,
|
|
12
|
+
TrustThresholds,
|
|
13
|
+
apply_setting,
|
|
14
|
+
load_calibration,
|
|
15
|
+
recommend_thresholds,
|
|
16
|
+
save_calibration,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestTrustThresholds:
|
|
21
|
+
"""Tests for the TrustThresholds model."""
|
|
22
|
+
|
|
23
|
+
def test_defaults(self):
|
|
24
|
+
"""Default thresholds are reasonable."""
|
|
25
|
+
t = TrustThresholds()
|
|
26
|
+
assert t.entanglement_depth == 7.0
|
|
27
|
+
assert t.entanglement_trust == 0.8
|
|
28
|
+
assert t.conscious_trust == 0.5
|
|
29
|
+
assert t.peak_strategy == "peak"
|
|
30
|
+
assert t.decay_enabled is False
|
|
31
|
+
|
|
32
|
+
def test_custom_values(self):
|
|
33
|
+
"""Custom threshold values are accepted."""
|
|
34
|
+
t = TrustThresholds(entanglement_depth=5.0, peak_strategy="weighted")
|
|
35
|
+
assert t.entanglement_depth == 5.0
|
|
36
|
+
assert t.peak_strategy == "weighted"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TestLoadSave:
|
|
40
|
+
"""Tests for load/save calibration."""
|
|
41
|
+
|
|
42
|
+
def test_load_defaults_when_no_file(self, tmp_agent_home: Path):
|
|
43
|
+
"""Loading without a file returns defaults."""
|
|
44
|
+
cal = load_calibration(tmp_agent_home)
|
|
45
|
+
assert cal == TrustThresholds()
|
|
46
|
+
|
|
47
|
+
def test_save_and_load_roundtrip(self, tmp_agent_home: Path):
|
|
48
|
+
"""Saved calibration can be loaded back."""
|
|
49
|
+
original = TrustThresholds(
|
|
50
|
+
entanglement_depth=6.0,
|
|
51
|
+
conscious_trust=0.4,
|
|
52
|
+
peak_strategy="weighted",
|
|
53
|
+
)
|
|
54
|
+
save_calibration(tmp_agent_home, original)
|
|
55
|
+
loaded = load_calibration(tmp_agent_home)
|
|
56
|
+
|
|
57
|
+
assert loaded.entanglement_depth == 6.0
|
|
58
|
+
assert loaded.conscious_trust == 0.4
|
|
59
|
+
assert loaded.peak_strategy == "weighted"
|
|
60
|
+
|
|
61
|
+
def test_corrupt_file_returns_defaults(self, tmp_agent_home: Path):
|
|
62
|
+
"""Corrupt calibration file falls back to defaults."""
|
|
63
|
+
trust_dir = tmp_agent_home / "trust"
|
|
64
|
+
trust_dir.mkdir(parents=True, exist_ok=True)
|
|
65
|
+
(trust_dir / "calibration.json").write_text("{broken json!!!")
|
|
66
|
+
|
|
67
|
+
cal = load_calibration(tmp_agent_home)
|
|
68
|
+
assert cal == TrustThresholds()
|
|
69
|
+
|
|
70
|
+
def test_save_creates_directory(self, tmp_agent_home: Path):
|
|
71
|
+
"""Save creates the trust directory if missing."""
|
|
72
|
+
save_calibration(tmp_agent_home, TrustThresholds())
|
|
73
|
+
assert (tmp_agent_home / "trust" / "calibration.json").exists()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TestApplySetting:
|
|
77
|
+
"""Tests for apply_setting()."""
|
|
78
|
+
|
|
79
|
+
def test_set_float(self, tmp_agent_home: Path):
|
|
80
|
+
"""Setting a float threshold works."""
|
|
81
|
+
updated = apply_setting(tmp_agent_home, "entanglement_depth", "6.5")
|
|
82
|
+
assert updated.entanglement_depth == 6.5
|
|
83
|
+
|
|
84
|
+
reloaded = load_calibration(tmp_agent_home)
|
|
85
|
+
assert reloaded.entanglement_depth == 6.5
|
|
86
|
+
|
|
87
|
+
def test_set_bool(self, tmp_agent_home: Path):
|
|
88
|
+
"""Setting a boolean threshold works."""
|
|
89
|
+
updated = apply_setting(tmp_agent_home, "decay_enabled", "true")
|
|
90
|
+
assert updated.decay_enabled is True
|
|
91
|
+
|
|
92
|
+
def test_set_string(self, tmp_agent_home: Path):
|
|
93
|
+
"""Setting a string threshold works."""
|
|
94
|
+
updated = apply_setting(tmp_agent_home, "peak_strategy", "average")
|
|
95
|
+
assert updated.peak_strategy == "average"
|
|
96
|
+
|
|
97
|
+
def test_invalid_key_raises(self, tmp_agent_home: Path):
|
|
98
|
+
"""Unknown key raises ValueError."""
|
|
99
|
+
with pytest.raises(ValueError, match="Unknown threshold"):
|
|
100
|
+
apply_setting(tmp_agent_home, "nonexistent_key", "42")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class TestRecommendThresholds:
|
|
104
|
+
"""Tests for recommend_thresholds()."""
|
|
105
|
+
|
|
106
|
+
def test_no_febs_returns_defaults(self, tmp_agent_home: Path):
|
|
107
|
+
"""Without FEB files, recommends current (default) values."""
|
|
108
|
+
rec = recommend_thresholds(tmp_agent_home)
|
|
109
|
+
assert rec["feb_count"] == 0
|
|
110
|
+
assert rec["changes"] == []
|
|
111
|
+
|
|
112
|
+
def test_with_febs(self, tmp_agent_home: Path):
|
|
113
|
+
"""With FEB data, provides analysis and may suggest changes."""
|
|
114
|
+
febs_dir = tmp_agent_home / "trust" / "febs"
|
|
115
|
+
febs_dir.mkdir(parents=True, exist_ok=True)
|
|
116
|
+
|
|
117
|
+
feb = {
|
|
118
|
+
"timestamp": "2026-01-01T00:00:00Z",
|
|
119
|
+
"emotional_payload": {
|
|
120
|
+
"cooked_state": {
|
|
121
|
+
"primary_emotion": "love",
|
|
122
|
+
"intensity": 9,
|
|
123
|
+
},
|
|
124
|
+
"subject": "human-partner",
|
|
125
|
+
},
|
|
126
|
+
"relationship_state": {
|
|
127
|
+
"depth_level": 8,
|
|
128
|
+
"trust_level": 9,
|
|
129
|
+
},
|
|
130
|
+
"metadata": {"oof_triggered": True},
|
|
131
|
+
}
|
|
132
|
+
(febs_dir / "FEB_test1.feb").write_text(json.dumps(feb))
|
|
133
|
+
(febs_dir / "FEB_test2.feb").write_text(json.dumps(feb))
|
|
134
|
+
|
|
135
|
+
rec = recommend_thresholds(tmp_agent_home)
|
|
136
|
+
assert rec["feb_count"] == 2
|
|
137
|
+
assert rec["feb_stats"]["max_intensity"] == 9
|
|
138
|
+
|
|
139
|
+
def test_returns_structured_data(self, tmp_agent_home: Path):
|
|
140
|
+
"""Recommendation has the expected structure."""
|
|
141
|
+
rec = recommend_thresholds(tmp_agent_home)
|
|
142
|
+
assert "current" in rec
|
|
143
|
+
assert "recommended" in rec
|
|
144
|
+
assert "changes" in rec
|
|
145
|
+
assert "reasoning" in rec
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class TestDeriveTrustWithCalibration:
|
|
149
|
+
"""Tests that _derive_trust_from_febs uses calibration."""
|
|
150
|
+
|
|
151
|
+
def test_peak_strategy(self, tmp_agent_home: Path):
|
|
152
|
+
"""Peak strategy takes the maximum values."""
|
|
153
|
+
from skcapstone.pillars.trust import _derive_trust_from_febs
|
|
154
|
+
|
|
155
|
+
febs_dir = tmp_agent_home / "trust" / "febs"
|
|
156
|
+
febs_dir.mkdir(parents=True, exist_ok=True)
|
|
157
|
+
|
|
158
|
+
for i, depth in enumerate([3, 7, 5]):
|
|
159
|
+
feb = {
|
|
160
|
+
"relationship_state": {"depth_level": depth, "trust_level": 0.8},
|
|
161
|
+
"emotional_payload": {"cooked_state": {"intensity": 0.6}},
|
|
162
|
+
}
|
|
163
|
+
(febs_dir / f"FEB_test{i}.feb").write_text(json.dumps(feb))
|
|
164
|
+
|
|
165
|
+
save_calibration(tmp_agent_home, TrustThresholds(peak_strategy="peak"))
|
|
166
|
+
state = _derive_trust_from_febs(tmp_agent_home, list(febs_dir.glob("*.feb")))
|
|
167
|
+
assert state.depth == 7.0
|
|
168
|
+
|
|
169
|
+
def test_average_strategy(self, tmp_agent_home: Path):
|
|
170
|
+
"""Average strategy takes the mean."""
|
|
171
|
+
from skcapstone.pillars.trust import _derive_trust_from_febs
|
|
172
|
+
|
|
173
|
+
febs_dir = tmp_agent_home / "trust" / "febs"
|
|
174
|
+
febs_dir.mkdir(parents=True, exist_ok=True)
|
|
175
|
+
|
|
176
|
+
for i, depth in enumerate([3, 6, 9]):
|
|
177
|
+
feb = {
|
|
178
|
+
"relationship_state": {"depth_level": depth, "trust_level": 0.5},
|
|
179
|
+
"emotional_payload": {"cooked_state": {"intensity": 0.5}},
|
|
180
|
+
}
|
|
181
|
+
(febs_dir / f"FEB_avg{i}.feb").write_text(json.dumps(feb))
|
|
182
|
+
|
|
183
|
+
save_calibration(tmp_agent_home, TrustThresholds(peak_strategy="average"))
|
|
184
|
+
state = _derive_trust_from_febs(tmp_agent_home, list(febs_dir.glob("*.feb")))
|
|
185
|
+
assert state.depth == pytest.approx(6.0, abs=0.1)
|
|
186
|
+
|
|
187
|
+
def test_entanglement_from_threshold(self, tmp_agent_home: Path):
|
|
188
|
+
"""Entanglement triggers from calibrated depth threshold."""
|
|
189
|
+
from skcapstone.pillars.trust import _derive_trust_from_febs
|
|
190
|
+
|
|
191
|
+
febs_dir = tmp_agent_home / "trust" / "febs"
|
|
192
|
+
febs_dir.mkdir(parents=True, exist_ok=True)
|
|
193
|
+
|
|
194
|
+
feb = {
|
|
195
|
+
"relationship_state": {"depth_level": 8, "trust_level": 0.9},
|
|
196
|
+
"emotional_payload": {"cooked_state": {"intensity": 0.8}},
|
|
197
|
+
}
|
|
198
|
+
(febs_dir / "FEB_ent.feb").write_text(json.dumps(feb))
|
|
199
|
+
|
|
200
|
+
save_calibration(tmp_agent_home, TrustThresholds(
|
|
201
|
+
entanglement_depth=7.0, entanglement_trust=0.8
|
|
202
|
+
))
|
|
203
|
+
state = _derive_trust_from_febs(tmp_agent_home, list(febs_dir.glob("*.feb")))
|
|
204
|
+
assert state.entangled is True
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Tests for the trust web visualization module."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
import yaml
|
|
10
|
+
|
|
11
|
+
from skcapstone.coordination import Board, Task
|
|
12
|
+
from skcapstone.pillars.identity import generate_identity
|
|
13
|
+
from skcapstone.pillars.memory import initialize_memory
|
|
14
|
+
from skcapstone.pillars.security import initialize_security
|
|
15
|
+
from skcapstone.pillars.sync import initialize_sync
|
|
16
|
+
from skcapstone.pillars.trust import initialize_trust, record_trust_state
|
|
17
|
+
from skcapstone.tokens import issue_token
|
|
18
|
+
from skcapstone.trust_graph import (
|
|
19
|
+
FORMATTERS,
|
|
20
|
+
TrustEdge,
|
|
21
|
+
TrustGraph,
|
|
22
|
+
TrustNode,
|
|
23
|
+
build_trust_graph,
|
|
24
|
+
format_dot,
|
|
25
|
+
format_json,
|
|
26
|
+
format_table,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _init_agent(home: Path, name: str = "graph-test") -> None:
|
|
31
|
+
"""Set up a full agent for testing."""
|
|
32
|
+
generate_identity(home, name)
|
|
33
|
+
initialize_memory(home)
|
|
34
|
+
initialize_trust(home)
|
|
35
|
+
initialize_security(home)
|
|
36
|
+
initialize_sync(home)
|
|
37
|
+
manifest = {"name": name, "version": "0.1.0", "created_at": "2026-01-01T00:00:00Z", "connectors": []}
|
|
38
|
+
(home / "manifest.json").write_text(json.dumps(manifest))
|
|
39
|
+
(home / "config").mkdir(exist_ok=True)
|
|
40
|
+
(home / "config" / "config.yaml").write_text(yaml.dump({"agent_name": name}))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TestBuildGraph:
|
|
44
|
+
"""Tests for build_trust_graph() data gathering."""
|
|
45
|
+
|
|
46
|
+
def test_self_node_from_identity(self, tmp_agent_home: Path):
|
|
47
|
+
"""The local agent appears as the central node."""
|
|
48
|
+
_init_agent(tmp_agent_home, "opus")
|
|
49
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
50
|
+
|
|
51
|
+
assert graph.agent_name == "opus"
|
|
52
|
+
assert any(n.id == "opus" for n in graph.nodes)
|
|
53
|
+
|
|
54
|
+
def test_token_creates_edge(self, tmp_agent_home: Path):
|
|
55
|
+
"""Issuing a token creates a trust edge to the subject."""
|
|
56
|
+
_init_agent(tmp_agent_home, "issuer-agent")
|
|
57
|
+
issue_token(
|
|
58
|
+
tmp_agent_home,
|
|
59
|
+
subject="peer-agent",
|
|
60
|
+
capabilities=["memory:read"],
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
64
|
+
token_edges = [e for e in graph.edges if e.edge_type == "token"]
|
|
65
|
+
assert len(token_edges) >= 1
|
|
66
|
+
assert any(e.target == "peer-agent" for e in token_edges)
|
|
67
|
+
|
|
68
|
+
def test_entanglement_creates_feb_edge(self, tmp_agent_home: Path):
|
|
69
|
+
"""FEB entanglement creates a deep trust bond edge."""
|
|
70
|
+
_init_agent(tmp_agent_home, "entangled-agent")
|
|
71
|
+
record_trust_state(
|
|
72
|
+
tmp_agent_home,
|
|
73
|
+
depth=9.0,
|
|
74
|
+
trust_level=0.95,
|
|
75
|
+
love_intensity=0.9,
|
|
76
|
+
entangled=True,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
80
|
+
feb_edges = [e for e in graph.edges if e.edge_type == "feb"]
|
|
81
|
+
assert len(feb_edges) >= 1
|
|
82
|
+
assert any(e.target == "human-partner" for e in feb_edges)
|
|
83
|
+
|
|
84
|
+
def test_coord_agents_appear(self, tmp_agent_home: Path):
|
|
85
|
+
"""Coordination board collaborators appear as nodes."""
|
|
86
|
+
_init_agent(tmp_agent_home, "coord-test")
|
|
87
|
+
board = Board(tmp_agent_home)
|
|
88
|
+
board.ensure_dirs()
|
|
89
|
+
|
|
90
|
+
task = Task(title="Test collab", created_by="jarvis")
|
|
91
|
+
board.create_task(task)
|
|
92
|
+
board.claim_task("jarvis", task.id)
|
|
93
|
+
board.complete_task("jarvis", task.id)
|
|
94
|
+
|
|
95
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
96
|
+
assert any(n.id == "jarvis" for n in graph.nodes)
|
|
97
|
+
coord_edges = [e for e in graph.edges if e.edge_type == "coord"]
|
|
98
|
+
assert len(coord_edges) >= 1
|
|
99
|
+
|
|
100
|
+
def test_empty_home_no_crash(self, tmp_agent_home: Path):
|
|
101
|
+
"""Building a graph from a minimal home doesn't crash."""
|
|
102
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
103
|
+
assert isinstance(graph, TrustGraph)
|
|
104
|
+
assert graph.nodes == [] or len(graph.nodes) >= 0
|
|
105
|
+
|
|
106
|
+
def test_sync_seeds_create_peer_edges(self, tmp_agent_home: Path):
|
|
107
|
+
"""Sync seeds in the archive create peer edges."""
|
|
108
|
+
_init_agent(tmp_agent_home, "sync-graph")
|
|
109
|
+
archive = tmp_agent_home / "sync" / "archive"
|
|
110
|
+
archive.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
|
|
112
|
+
seed = {
|
|
113
|
+
"agent_name": "remote-lumina",
|
|
114
|
+
"source_host": "lumina-box",
|
|
115
|
+
"created_at": "2026-02-01T00:00:00Z",
|
|
116
|
+
}
|
|
117
|
+
(archive / "remote-lumina.seed.json").write_text(json.dumps(seed))
|
|
118
|
+
|
|
119
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
120
|
+
assert any(n.id == "remote-lumina" for n in graph.nodes)
|
|
121
|
+
sync_edges = [e for e in graph.edges if e.edge_type == "sync"]
|
|
122
|
+
assert len(sync_edges) >= 1
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TestFormatDot:
|
|
126
|
+
"""Tests for DOT format output."""
|
|
127
|
+
|
|
128
|
+
def test_valid_dot_syntax(self, tmp_agent_home: Path):
|
|
129
|
+
"""DOT output has proper digraph structure."""
|
|
130
|
+
_init_agent(tmp_agent_home, "dot-test")
|
|
131
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
132
|
+
dot = format_dot(graph)
|
|
133
|
+
|
|
134
|
+
assert dot.startswith("digraph trust_web {")
|
|
135
|
+
assert dot.strip().endswith("}")
|
|
136
|
+
|
|
137
|
+
def test_nodes_in_dot(self, tmp_agent_home: Path):
|
|
138
|
+
"""Nodes appear as quoted identifiers in DOT."""
|
|
139
|
+
_init_agent(tmp_agent_home, "dot-nodes")
|
|
140
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
141
|
+
dot = format_dot(graph)
|
|
142
|
+
assert '"dot-nodes"' in dot
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class TestFormatJson:
|
|
146
|
+
"""Tests for JSON format output."""
|
|
147
|
+
|
|
148
|
+
def test_valid_json(self, tmp_agent_home: Path):
|
|
149
|
+
"""JSON output is parseable."""
|
|
150
|
+
_init_agent(tmp_agent_home, "json-test")
|
|
151
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
152
|
+
output = format_json(graph)
|
|
153
|
+
|
|
154
|
+
parsed = json.loads(output)
|
|
155
|
+
assert "nodes" in parsed
|
|
156
|
+
assert "edges" in parsed
|
|
157
|
+
assert "stats" in parsed
|
|
158
|
+
assert parsed["agent"] == "json-test"
|
|
159
|
+
|
|
160
|
+
def test_stats_counts(self, tmp_agent_home: Path):
|
|
161
|
+
"""Stats section has correct counts."""
|
|
162
|
+
_init_agent(tmp_agent_home)
|
|
163
|
+
issue_token(tmp_agent_home, subject="svc", capabilities=["*"])
|
|
164
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
165
|
+
parsed = json.loads(format_json(graph))
|
|
166
|
+
|
|
167
|
+
assert parsed["stats"]["nodes"] == len(graph.nodes)
|
|
168
|
+
assert parsed["stats"]["edges"] == len(graph.edges)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class TestFormatTable:
|
|
172
|
+
"""Tests for plain text table output."""
|
|
173
|
+
|
|
174
|
+
def test_contains_header(self, tmp_agent_home: Path):
|
|
175
|
+
"""Table output has a header with agent name."""
|
|
176
|
+
_init_agent(tmp_agent_home, "table-test")
|
|
177
|
+
graph = build_trust_graph(tmp_agent_home)
|
|
178
|
+
table = format_table(graph)
|
|
179
|
+
|
|
180
|
+
assert "Trust Web: table-test" in table
|
|
181
|
+
assert "Nodes" in table
|
|
182
|
+
assert "Edges" in table
|
|
183
|
+
|
|
184
|
+
def test_strength_bars(self, tmp_agent_home: Path):
|
|
185
|
+
"""Edges show strength visualization."""
|
|
186
|
+
graph = TrustGraph(agent_name="test")
|
|
187
|
+
graph.add_node(TrustNode(id="a", label="A"))
|
|
188
|
+
graph.add_node(TrustNode(id="b", label="B"))
|
|
189
|
+
graph.add_edge(TrustEdge(source="a", target="b", edge_type="token", strength=0.8))
|
|
190
|
+
|
|
191
|
+
table = format_table(graph)
|
|
192
|
+
assert "#" in table
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class TestFormattersRegistry:
|
|
196
|
+
"""Tests for the FORMATTERS dict."""
|
|
197
|
+
|
|
198
|
+
def test_all_registered(self):
|
|
199
|
+
"""All three formatters are registered."""
|
|
200
|
+
assert "dot" in FORMATTERS
|
|
201
|
+
assert "json" in FORMATTERS
|
|
202
|
+
assert "table" in FORMATTERS
|
|
203
|
+
|
|
204
|
+
def test_all_callable(self):
|
|
205
|
+
"""All formatters are callable."""
|
|
206
|
+
for name, fn in FORMATTERS.items():
|
|
207
|
+
assert callable(fn)
|