apsimo 1.3.0__py3-none-any.whl
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.
- apsimo/__init__.py +38 -0
- apsimo/__main__.py +6 -0
- apsimo/agent/__init__.py +6 -0
- apsimo/agent/client.py +276 -0
- apsimo/agent/models.py +46 -0
- apsimo/agents/__init__.py +20 -0
- apsimo/agents/models.py +264 -0
- apsimo/agents/store.py +861 -0
- apsimo/agents/websocket.py +522 -0
- apsimo/api/__init__.py +1 -0
- apsimo/api/auth_telemetry.py +287 -0
- apsimo/api/authority.py +1203 -0
- apsimo/api/contact_grants.py +347 -0
- apsimo/api/middleware.py +483 -0
- apsimo/api/routers/__init__.py +1 -0
- apsimo/api/routers/commitment_work.py +265 -0
- apsimo/api/routers/context_gate.py +123 -0
- apsimo/api/routers/executions.py +140 -0
- apsimo/api/routers/followup_plans.py +147 -0
- apsimo/api/routers/governed_actions.py +162 -0
- apsimo/api/routers/host.py +14473 -0
- apsimo/api/routers/initiative_work.py +115 -0
- apsimo/api/routers/mining.py +104 -0
- apsimo/api/routers/observations.py +110 -0
- apsimo/api/routers/social_state.py +225 -0
- apsimo/api/routers/task_queue.py +2715 -0
- apsimo/api/routers/temporal_followups.py +251 -0
- apsimo/api/routers/transport.py +110 -0
- apsimo/api/routers/transport_ingress_api.py +240 -0
- apsimo/api/schemas/__init__.py +1 -0
- apsimo/api/schemas/host.py +1949 -0
- apsimo/autonomy/cli.py +110 -0
- apsimo/autonomy/condition_worker.py +437 -0
- apsimo/autonomy/config.py +424 -0
- apsimo/autonomy/loop.py +4316 -0
- apsimo/autonomy/registry.py +339 -0
- apsimo/autonomy/scheduler.py +1822 -0
- apsimo/autonomy/synthesis.py +449 -0
- apsimo/backup.py +962 -0
- apsimo/beliefs/__init__.py +23 -0
- apsimo/beliefs/contradictions.py +109 -0
- apsimo/beliefs/decay.py +61 -0
- apsimo/beliefs/engine.py +479 -0
- apsimo/beliefs/models.py +67 -0
- apsimo/beliefs/promotion.py +41 -0
- apsimo/beliefs/resolve.py +58 -0
- apsimo/beliefs/source_claims.py +690 -0
- apsimo/beliefs/source_projection.py +883 -0
- apsimo/beliefs/source_time.py +208 -0
- apsimo/beliefs/store.py +133 -0
- apsimo/briefings/aggregators.py +824 -0
- apsimo/briefings/composer.py +420 -0
- apsimo/briefings/config.py +55 -0
- apsimo/briefings/delivery.py +439 -0
- apsimo/briefings/engagement.py +97 -0
- apsimo/briefings/engine.py +274 -0
- apsimo/briefings/enhancer.py +99 -0
- apsimo/briefings/models.py +183 -0
- apsimo/briefings/scheduler.py +382 -0
- apsimo/briefings/store.py +435 -0
- apsimo/chain/__init__.py +48 -0
- apsimo/chain/block.py +100 -0
- apsimo/chain/cli.py +704 -0
- apsimo/chain/genesis.py +443 -0
- apsimo/chain/identity.py +416 -0
- apsimo/chain/keys.py +1025 -0
- apsimo/chain/local_keys.py +187 -0
- apsimo/chain/manager.py +290 -0
- apsimo/chain/node.py +163 -0
- apsimo/chain/plugin_transactions.py +371 -0
- apsimo/chain/protocol.py +220 -0
- apsimo/chain/state_machine.py +676 -0
- apsimo/chain/storage.py +503 -0
- apsimo/chain/transactions.py +250 -0
- apsimo/chain/validation.py +397 -0
- apsimo/channels/__init__.py +1 -0
- apsimo/channels/manifest.py +31 -0
- apsimo/channels/migrations/001_channels_schema.sql +12 -0
- apsimo/channels/phone_gateways.py +42 -0
- apsimo/channels/presence.py +188 -0
- apsimo/channels/router.py +235 -0
- apsimo/channels/store.py +231 -0
- apsimo/cli.py +2688 -0
- apsimo/cognition/__init__.py +11 -0
- apsimo/cognition/charter.py +398 -0
- apsimo/cognition/drive_governance.py +3530 -0
- apsimo/cognition/evidence_pipeline.py +1627 -0
- apsimo/cognition/external_events.py +932 -0
- apsimo/cognition/goal_spine.py +3488 -0
- apsimo/cognition/introspection.py +214 -0
- apsimo/cognition/prompt.py +150 -0
- apsimo/cognition/runtime.py +108 -0
- apsimo/cognition/trigger.py +154 -0
- apsimo/commitments/__init__.py +18 -0
- apsimo/commitments/local_work.py +355 -0
- apsimo/commitments/store.py +1052 -0
- apsimo/commitments/work.py +91 -0
- apsimo/compat.py +53 -0
- apsimo/compression/__init__.py +467 -0
- apsimo/connectors/__init__.py +21 -0
- apsimo/connectors/base.py +152 -0
- apsimo/connectors/caldav_calendar.py +125 -0
- apsimo/connectors/fs_documents.py +85 -0
- apsimo/connectors/imap_email.py +138 -0
- apsimo/connectors/manager.py +218 -0
- apsimo/connectors/webhook_pull.py +88 -0
- apsimo/contacts/__init__.py +33 -0
- apsimo/contacts/comms.py +357 -0
- apsimo/contacts/config.py +79 -0
- apsimo/contacts/exporters/__init__.py +1 -0
- apsimo/contacts/exporters/vcard.py +71 -0
- apsimo/contacts/identity_links.py +251 -0
- apsimo/contacts/importer.py +280 -0
- apsimo/contacts/importers/__init__.py +1 -0
- apsimo/contacts/importers/batch.py +43 -0
- apsimo/contacts/importers/macos_contacts.py +101 -0
- apsimo/contacts/migrations/001_contacts_schema.sql +141 -0
- apsimo/contacts/migrations/002_trust_scopes.sql +36 -0
- apsimo/contacts/migrations/003_open_gateway_enum.sql +32 -0
- apsimo/contacts/migrations/004_contact_provision_operations.sql +18 -0
- apsimo/contacts/migrations/005_identity_links.sql +27 -0
- apsimo/contacts/models.py +308 -0
- apsimo/contacts/scoring.py +16 -0
- apsimo/contacts/store.py +1623 -0
- apsimo/contacts/transport_ingress.py +252 -0
- apsimo/contacts/world_bridge.py +314 -0
- apsimo/contextgate/__init__.py +69 -0
- apsimo/contextgate/chunker.py +169 -0
- apsimo/contextgate/estimate.py +54 -0
- apsimo/contextgate/gate.py +313 -0
- apsimo/contextgate/retrieve.py +115 -0
- apsimo/delivery/__init__.py +16 -0
- apsimo/delivery/bridge.py +1260 -0
- apsimo/delivery/channels.py +526 -0
- apsimo/delivery/classification.py +50 -0
- apsimo/delivery/rate_limiter.py +268 -0
- apsimo/delivery/reachout_policy.py +206 -0
- apsimo/directed/__init__.py +22 -0
- apsimo/directed/audit.py +167 -0
- apsimo/directed/intake.py +95 -0
- apsimo/directed/models.py +191 -0
- apsimo/directed/service.py +509 -0
- apsimo/directives/__init__.py +25 -0
- apsimo/directives/evidence.py +87 -0
- apsimo/directives/extractor.py +188 -0
- apsimo/directives/guard.py +364 -0
- apsimo/directives/models.py +206 -0
- apsimo/directives/service.py +372 -0
- apsimo/directives/store.py +167 -0
- apsimo/doctor.py +2173 -0
- apsimo/environment.py +43 -0
- apsimo/events/__init__.py +33 -0
- apsimo/events/broadcaster.py +98 -0
- apsimo/events/bus.py +217 -0
- apsimo/events/journal.py +863 -0
- apsimo/events/stream.py +131 -0
- apsimo/events/types.py +150 -0
- apsimo/execution_results.py +357 -0
- apsimo/feedback/__init__.py +5 -0
- apsimo/feedback/store.py +76 -0
- apsimo/feeds/__init__.py +19 -0
- apsimo/feeds/cli.py +84 -0
- apsimo/feeds/engine.py +437 -0
- apsimo/feeds/example-feed.yaml +77 -0
- apsimo/feeds/hermes_cron.py +126 -0
- apsimo/feeds/manager.py +235 -0
- apsimo/feeds/spec.py +250 -0
- apsimo/feeds/template.py +202 -0
- apsimo/gate/__init__.py +18 -0
- apsimo/gate/audit.py +61 -0
- apsimo/gate/communication_policy.py +166 -0
- apsimo/gate/config.py +72 -0
- apsimo/gate/context_provenance.py +170 -0
- apsimo/gate/env_risk.py +226 -0
- apsimo/gate/guard_audit.py +353 -0
- apsimo/gate/layers/__init__.py +1 -0
- apsimo/gate/layers/base.py +15 -0
- apsimo/gate/layers/l1_recipient.py +66 -0
- apsimo/gate/layers/l2_pii.py +134 -0
- apsimo/gate/layers/l3_cross_context.py +50 -0
- apsimo/gate/layers/l4_trust_tier.py +78 -0
- apsimo/gate/layers/l5_injection.py +199 -0
- apsimo/gate/layers/l6_review.py +86 -0
- apsimo/gate/layers/l7_delay.py +100 -0
- apsimo/gate/layers/tom2_epistemic.py +185 -0
- apsimo/gate/models.py +64 -0
- apsimo/gate/pending_dispatch.py +5 -0
- apsimo/gate/pipeline.py +206 -0
- apsimo/gate/rejection.py +259 -0
- apsimo/gate/response_guard.py +700 -0
- apsimo/gate/rulesets/injection_v1.yaml +51 -0
- apsimo/gate/surface_policy.py +189 -0
- apsimo/gate/taint.py +226 -0
- apsimo/genesis.json +9 -0
- apsimo/goals/__init__.py +100 -0
- apsimo/goals/config.py +38 -0
- apsimo/goals/decomposer.py +421 -0
- apsimo/goals/engine.py +617 -0
- apsimo/goals/inference.py +354 -0
- apsimo/goals/models.py +302 -0
- apsimo/goals/priority.py +270 -0
- apsimo/goals/queue_bridge.py +149 -0
- apsimo/goals/replan.py +450 -0
- apsimo/goals/schema.sql +89 -0
- apsimo/goals/store.py +692 -0
- apsimo/governed_actions.py +1708 -0
- apsimo/harness_integration/__init__.py +45 -0
- apsimo/harness_integration/context.py +41 -0
- apsimo/harness_integration/skills.py +231 -0
- apsimo/identity/__init__.py +26 -0
- apsimo/identity/participants.py +181 -0
- apsimo/identity/resolver.py +329 -0
- apsimo/identity_bootstrap/__init__.py +5 -0
- apsimo/identity_bootstrap/builder.py +208 -0
- apsimo/identity_bootstrap/corpus.py +443 -0
- apsimo/identity_bootstrap/models.py +54 -0
- apsimo/identity_bootstrap/runner.py +353 -0
- apsimo/identity_bootstrap/seeders/__init__.py +25 -0
- apsimo/identity_bootstrap/seeders/briefings.py +109 -0
- apsimo/identity_bootstrap/seeders/chain.py +57 -0
- apsimo/identity_bootstrap/seeders/goals.py +128 -0
- apsimo/identity_bootstrap/seeders/memory.py +191 -0
- apsimo/identity_bootstrap/seeders/neo4j_cognition.py +79 -0
- apsimo/identity_bootstrap/seeders/relationship.py +152 -0
- apsimo/identity_bootstrap/seeders/sessions.py +67 -0
- apsimo/identity_bootstrap/seeders/skills.py +92 -0
- apsimo/identity_bootstrap/seeders/task_queue.py +72 -0
- apsimo/identity_bootstrap/seeders/world_model.py +143 -0
- apsimo/identity_bootstrap/self_query.py +92 -0
- apsimo/identity_bootstrap/self_reflection.py +155 -0
- apsimo/identity_bootstrap/skill.py +37 -0
- apsimo/identity_bootstrap/verifier.py +436 -0
- apsimo/initiatives/__init__.py +20 -0
- apsimo/initiatives/action_registry.py +454 -0
- apsimo/initiatives/approval_authority.py +2105 -0
- apsimo/initiatives/approval_policy.py +123 -0
- apsimo/initiatives/assignment.py +263 -0
- apsimo/initiatives/backup_evidence.py +100 -0
- apsimo/initiatives/context_freshness.py +103 -0
- apsimo/initiatives/models.py +318 -0
- apsimo/initiatives/native_work.py +270 -0
- apsimo/initiatives/standing_approvals.py +232 -0
- apsimo/initiatives/store.py +1081 -0
- apsimo/initiatives/temporal_followup.py +410 -0
- apsimo/intelligence/__init__.py +1 -0
- apsimo/intelligence/cognition/__init__.py +24 -0
- apsimo/intelligence/cognition/gap_detector.py +148 -0
- apsimo/intelligence/cognition/metalearner.py +547 -0
- apsimo/intelligence/cognition/metrics_collector.py +217 -0
- apsimo/intelligence/cognition/performance_index.py +299 -0
- apsimo/intelligence/cognition/registry.py +192 -0
- apsimo/intelligence/cognition/strategy_adjuster.py +222 -0
- apsimo/intelligence/cognition/types.py +16 -0
- apsimo/intelligence/components/__init__.py +66 -0
- apsimo/intelligence/components/anomaly_detector.py +413 -0
- apsimo/intelligence/components/initiative_engine.py +2643 -0
- apsimo/intelligence/components/preference_learner.py +521 -0
- apsimo/intelligence/components/research_orchestrator.py +358 -0
- apsimo/intelligence/components/self_directed_thinker.py +221 -0
- apsimo/intelligence/components/self_reflector.py +252 -0
- apsimo/intelligence/components/session_continuity.py +154 -0
- apsimo/intelligence/components/task_planner.py +320 -0
- apsimo/intelligence/components/tool_learner.py +217 -0
- apsimo/intelligence/graph/__init__.py +79 -0
- apsimo/intelligence/graph/client.py +2483 -0
- apsimo/intelligence/graph/consolidator.py +405 -0
- apsimo/intelligence/graph/distiller.py +312 -0
- apsimo/intelligence/graph/migrations.py +129 -0
- apsimo/intelligence/graph/queries.py +248 -0
- apsimo/intelligence/graph/recall.py +281 -0
- apsimo/intelligence/graph/reconciler.py +144 -0
- apsimo/intelligence/graph/schema.py +337 -0
- apsimo/intelligence/graph/selection.py +252 -0
- apsimo/intelligence/learning/__init__.py +17 -0
- apsimo/intelligence/learning/continuous_learner.py +245 -0
- apsimo/intelligence/learning/feedback_store.py +321 -0
- apsimo/intelligence/mind_model/__init__.py +1 -0
- apsimo/intelligence/mind_model/graph_baseline.py +136 -0
- apsimo/intelligence/mind_model/signal_collector.py +361 -0
- apsimo/intelligence/relationships/__init__.py +11 -0
- apsimo/intelligence/relationships/profiler.py +389 -0
- apsimo/intelligence/relationships/scorer.py +560 -0
- apsimo/intelligence/relationships/signal_floor.py +66 -0
- apsimo/intelligence/relationships/trust_tiers.py +300 -0
- apsimo/intelligence/synthesis/__init__.py +40 -0
- apsimo/intelligence/synthesis/connection_discoverer.py +379 -0
- apsimo/intelligence/synthesis/cross_domain_analyzer.py +287 -0
- apsimo/intelligence/synthesis/insight_deliverer.py +171 -0
- apsimo/intelligence/synthesis/insight_store.py +79 -0
- apsimo/intelligence/synthesis/insight_validator.py +183 -0
- apsimo/intelligence/synthesis/novelty_scorer.py +267 -0
- apsimo/intelligence/turn_middleware/__init__.py +15 -0
- apsimo/intelligence/turn_middleware/memory_sync.py +119 -0
- apsimo/mcp/__init__.py +41 -0
- apsimo/mcp/__main__.py +6 -0
- apsimo/mcp/config.py +287 -0
- apsimo/mcp/server.py +501 -0
- apsimo/migrations.py +187 -0
- apsimo/mining/__init__.py +27 -0
- apsimo/mining/corpus.py +239 -0
- apsimo/mining/escalations.py +289 -0
- apsimo/mining/models.py +169 -0
- apsimo/mining/store.py +210 -0
- apsimo/models/__init__.py +30 -0
- apsimo/models/memory.py +80 -0
- apsimo/models/mesh.py +72 -0
- apsimo/models/person.py +104 -0
- apsimo/models/signal.py +108 -0
- apsimo/observations/__init__.py +15 -0
- apsimo/observations/store.py +277 -0
- apsimo/patterns/__init__.py +6 -0
- apsimo/patterns/extract.py +187 -0
- apsimo/patterns/store.py +227 -0
- apsimo/persona/__init__.py +1 -0
- apsimo/persona/engine.py +611 -0
- apsimo/persona/manifest.py +140 -0
- apsimo/projects/__init__.py +28 -0
- apsimo/projects/engine.py +1681 -0
- apsimo/projects/event_outbox.py +188 -0
- apsimo/projects/models.py +216 -0
- apsimo/projects/planner.py +181 -0
- apsimo/projects/store.py +1446 -0
- apsimo/proposals/__init__.py +12 -0
- apsimo/proposals/engine.py +114 -0
- apsimo/proposals/models.py +207 -0
- apsimo/qualification/__init__.py +1 -0
- apsimo/qualification/cases.py +75 -0
- apsimo/qualification/cli.py +51 -0
- apsimo/qualification/memory_cases.py +209 -0
- apsimo/qualification/records.py +92 -0
- apsimo/qualification/report.py +87 -0
- apsimo/qualification/runner.py +311 -0
- apsimo/qualification/structured_cases.py +131 -0
- apsimo/reasoning/__init__.py +13 -0
- apsimo/reasoning/executor.py +506 -0
- apsimo/reasoning/loop.py +373 -0
- apsimo/reasoning/native_tools/__init__.py +16 -0
- apsimo/reasoning/native_tools/calculate.py +141 -0
- apsimo/reasoning/native_tools/file_ops.py +150 -0
- apsimo/reasoning/native_tools/web_search.py +49 -0
- apsimo/reasoning/tool_policy.py +182 -0
- apsimo/redact/__init__.py +176 -0
- apsimo/repos/__init__.py +5 -0
- apsimo/repos/mirrors.py +204 -0
- apsimo/research/__init__.py +41 -0
- apsimo/research/artifact.py +482 -0
- apsimo/research/gatherer.py +387 -0
- apsimo/research/pipeline.py +513 -0
- apsimo/research/search/__init__.py +7 -0
- apsimo/research/search/base.py +41 -0
- apsimo/research/search/brave.py +59 -0
- apsimo/research/search/cache.py +51 -0
- apsimo/research/search/duckduckgo.py +103 -0
- apsimo/research/search/orchestrator.py +119 -0
- apsimo/research/search/serpapi.py +59 -0
- apsimo/research/search/tavily.py +59 -0
- apsimo/research/synthesizer.py +309 -0
- apsimo/router/__init__.py +30 -0
- apsimo/router/complexity_scorer.py +148 -0
- apsimo/router/endpoints.py +153 -0
- apsimo/router/fallback.py +58 -0
- apsimo/router/functions.py +243 -0
- apsimo/router/native_policy.py +52 -0
- apsimo/router/router.py +762 -0
- apsimo/router/self_learning.py +174 -0
- apsimo/router/tiers.py +677 -0
- apsimo/sandbox/__init__.py +21 -0
- apsimo/sandbox/backend.py +195 -0
- apsimo/sandbox/manager.py +173 -0
- apsimo/scope_bounds.py +7 -0
- apsimo/secrets/__init__.py +6 -0
- apsimo/secrets/backends/__init__.py +8 -0
- apsimo/secrets/backends/base.py +42 -0
- apsimo/secrets/backends/env.py +110 -0
- apsimo/secrets/backends/keyring.py +72 -0
- apsimo/secrets/backends/onepassword.py +232 -0
- apsimo/secrets/cli.py +191 -0
- apsimo/secrets/manager.py +160 -0
- apsimo/secrets/migration.py +101 -0
- apsimo/secrets/types.py +98 -0
- apsimo/seed.py +41 -0
- apsimo/self_model/__init__.py +37 -0
- apsimo/self_model/appraisals.py +673 -0
- apsimo/self_model/benchmark.py +1314 -0
- apsimo/self_model/brief.py +40 -0
- apsimo/self_model/event_concerns.py +1128 -0
- apsimo/self_model/execution_forecasts.py +353 -0
- apsimo/self_model/expectations.py +1595 -0
- apsimo/self_model/experiments.py +1150 -0
- apsimo/self_model/journal.py +148 -0
- apsimo/self_model/judgments.py +705 -0
- apsimo/self_model/native_outcomes.py +55 -0
- apsimo/self_model/params.py +220 -0
- apsimo/self_model/perspective.py +246 -0
- apsimo/self_model/reconcile.py +183 -0
- apsimo/self_model/reply_forecasts.py +381 -0
- apsimo/self_model/runtime_forecasts.py +296 -0
- apsimo/self_model/runtime_models.py +67 -0
- apsimo/self_model/settlement.py +207 -0
- apsimo/self_model/situation.py +1731 -0
- apsimo/self_model/store.py +883 -0
- apsimo/self_model/supervised.py +137 -0
- apsimo/self_model/thinker.py +99 -0
- apsimo/self_model/trust.py +388 -0
- apsimo/self_model/workspace.py +2388 -0
- apsimo/server.py +4197 -0
- apsimo/services/__init__.py +1 -0
- apsimo/services/agent_bridge.py +474 -0
- apsimo/services/initiative_executor.py +914 -0
- apsimo/services/instance.py +297 -0
- apsimo/sessions/__init__.py +22 -0
- apsimo/sessions/config.py +13 -0
- apsimo/sessions/context_loader.py +88 -0
- apsimo/sessions/federation_session.py +75 -0
- apsimo/sessions/isolated_session.py +98 -0
- apsimo/sessions/reports.py +84 -0
- apsimo/sessions/store.py +148 -0
- apsimo/setup.py +2818 -0
- apsimo/setup_hermes.py +879 -0
- apsimo/setup_local_work.py +218 -0
- apsimo/setup_native_goals.py +134 -0
- apsimo/setup_native_reviews.py +115 -0
- apsimo/skills/__init__.py +10 -0
- apsimo/skills/base.py +108 -0
- apsimo/skills/budget.py +28 -0
- apsimo/skills/executor.py +493 -0
- apsimo/skills/executors/__init__.py +1 -0
- apsimo/skills/executors/behavioral_correction.py +75 -0
- apsimo/skills/executors/capability_gap.py +38 -0
- apsimo/skills/executors/data_quality.py +163 -0
- apsimo/skills/executors/knowledge_acquisition.py +41 -0
- apsimo/skills/executors/operational_hygiene.py +185 -0
- apsimo/skills/executors/subsystem_health.py +169 -0
- apsimo/skills/hermes_export.py +431 -0
- apsimo/skills/index.py +123 -0
- apsimo/skills/learning/__init__.py +21 -0
- apsimo/skills/learning/novelty_detector.py +206 -0
- apsimo/skills/learning/pattern_extractor.py +199 -0
- apsimo/skills/learning/triggers.py +159 -0
- apsimo/skills/loader.py +246 -0
- apsimo/skills/migrations/002_progressive_loading.sql +6 -0
- apsimo/skills/migrations/backfill_triggers.py +20 -0
- apsimo/skills/models.py +202 -0
- apsimo/skills/packager.py +128 -0
- apsimo/skills/protocols.py +70 -0
- apsimo/skills/registry.py +191 -0
- apsimo/skills/runtime.py +58 -0
- apsimo/skills/sandbox_runner.py +229 -0
- apsimo/skills/scheduler.py +129 -0
- apsimo/skills/schema.py +79 -0
- apsimo/skills/security/__init__.py +12 -0
- apsimo/skills/security/guards.py +53 -0
- apsimo/skills/security/scanner.py +223 -0
- apsimo/skills_memory/__init__.py +26 -0
- apsimo/skills_memory/distill.py +159 -0
- apsimo/skills_memory/models.py +85 -0
- apsimo/skills_memory/retrieve.py +62 -0
- apsimo/skills_memory/store.py +172 -0
- apsimo/surprise/__init__.py +6 -0
- apsimo/surprise/accumulation.py +57 -0
- apsimo/surprise/scorer.py +102 -0
- apsimo/surprise/store.py +203 -0
- apsimo/task_queue/__init__.py +69 -0
- apsimo/task_queue/action_receipts.py +148 -0
- apsimo/task_queue/approval_relay_canary.py +108 -0
- apsimo/task_queue/config.py +85 -0
- apsimo/task_queue/contract.py +361 -0
- apsimo/task_queue/events.py +130 -0
- apsimo/task_queue/governor.py +1031 -0
- apsimo/task_queue/handlers/__init__.py +16 -0
- apsimo/task_queue/handlers/base.py +37 -0
- apsimo/task_queue/handlers/inference.py +640 -0
- apsimo/task_queue/handlers/monitoring.py +116 -0
- apsimo/task_queue/handlers/registry.py +75 -0
- apsimo/task_queue/handlers/subtask_handler.py +173 -0
- apsimo/task_queue/handlers/system_maintenance.py +147 -0
- apsimo/task_queue/mesh_integration.py +111 -0
- apsimo/task_queue/models.py +317 -0
- apsimo/task_queue/queue_manager.py +8286 -0
- apsimo/task_queue/routing.py +287 -0
- apsimo/task_queue/scheduler.py +252 -0
- apsimo/task_queue/schema.sql +197 -0
- apsimo/task_queue/work_control.py +342 -0
- apsimo/task_queue/worker.py +993 -0
- apsimo/telemetry.py +145 -0
- apsimo/tom/__init__.py +6 -0
- apsimo/tom/affect.py +387 -0
- apsimo/tom/approvals.py +171 -0
- apsimo/tom/arcs.py +896 -0
- apsimo/tom/asymmetry.py +131 -0
- apsimo/tom/eligibility.py +248 -0
- apsimo/tom/engagement.py +214 -0
- apsimo/tom/exposure.py +214 -0
- apsimo/tom/extractor.py +306 -0
- apsimo/tom/fact_adapters.py +144 -0
- apsimo/tom/facts.py +326 -0
- apsimo/tom/integration.py +592 -0
- apsimo/tom/leveled.py +118 -0
- apsimo/tom/levels.py +247 -0
- apsimo/tom/recipient_audit.py +995 -0
- apsimo/tom/recipient_simulator.py +593 -0
- apsimo/tom/source_lineage.py +93 -0
- apsimo/tom/tom2.py +277 -0
- apsimo/tom/visibility.py +559 -0
- apsimo/tom/visibility_store.py +414 -0
- apsimo/tools/__init__.py +0 -0
- apsimo/tools/definitions.py +740 -0
- apsimo/tools/handlers.py +943 -0
- apsimo/toolsmith/__init__.py +26 -0
- apsimo/toolsmith/authority.py +166 -0
- apsimo/toolsmith/engine.py +559 -0
- apsimo/toolsmith/integrity.py +100 -0
- apsimo/toolsmith/miner.py +145 -0
- apsimo/toolsmith/policy.py +110 -0
- apsimo/toolsmith/registry.py +635 -0
- apsimo/turns/__init__.py +17 -0
- apsimo/turns/audio.py +134 -0
- apsimo/turns/documents.py +235 -0
- apsimo/turns/executions.py +486 -0
- apsimo/turns/hermes_history.py +245 -0
- apsimo/turns/hermes_kanban.py +268 -0
- apsimo/turns/hermes_work.py +96 -0
- apsimo/turns/idempotency.py +752 -0
- apsimo/turns/local_work.py +115 -0
- apsimo/turns/media.py +581 -0
- apsimo/turns/reported_workers.py +196 -0
- apsimo/turns/source_annotations.py +283 -0
- apsimo/turns/source_attribution.py +154 -0
- apsimo/turns/source_read.py +351 -0
- apsimo/turns/source_vectors.py +263 -0
- apsimo/turns/video.py +210 -0
- apsimo/util/autonomy_preset.py +220 -0
- apsimo/util/instance.py +92 -0
- apsimo/util/model_output.py +25 -0
- apsimo/util/quiet_hours.py +27 -0
- apsimo/util/session_safety.py +37 -0
- apsimo/util/temporal.py +343 -0
- apsimo/vector/__init__.py +75 -0
- apsimo/vector/backfill.py +171 -0
- apsimo/vector/caption.py +114 -0
- apsimo/vector/collections.py +51 -0
- apsimo/vector/config.py +102 -0
- apsimo/vector/embedder.py +670 -0
- apsimo/vector/image_preprocess.py +406 -0
- apsimo/vector/image_store.py +296 -0
- apsimo/vector/indexes.py +162 -0
- apsimo/vector/migrate.py +334 -0
- apsimo/vector/multimodal_provider.py +417 -0
- apsimo/vector/multimodal_types.py +87 -0
- apsimo/vector/openai_provider.py +119 -0
- apsimo/vector/query.py +49 -0
- apsimo/vector/reranker.py +565 -0
- apsimo/vector/safety_image.py +159 -0
- apsimo/vector/scanner.py +197 -0
- apsimo/vector/setup.py +289 -0
- apsimo/vector/store.py +533 -0
- apsimo/vector/tiers.py +263 -0
- apsimo/work_orders.py +925 -0
- apsimo/workers/__init__.py +21 -0
- apsimo/workers/agent_bridge.py +640 -0
- apsimo/workers/colony_worker.py +382 -0
- apsimo/workers/queue_worker.py +441 -0
- apsimo/workers/skills_sync.py +152 -0
- apsimo/world_model/__init__.py +71 -0
- apsimo/world_model/causal_maintenance.py +131 -0
- apsimo/world_model/causal_policy.py +43 -0
- apsimo/world_model/causal_query.py +125 -0
- apsimo/world_model/confidence.py +54 -0
- apsimo/world_model/config.py +64 -0
- apsimo/world_model/constants.py +97 -0
- apsimo/world_model/entities.py +145 -0
- apsimo/world_model/expectation_resolvers.py +177 -0
- apsimo/world_model/extraction/__init__.py +7 -0
- apsimo/world_model/extraction/base.py +62 -0
- apsimo/world_model/extraction/conversation_extractor.py +262 -0
- apsimo/world_model/extraction/detector.py +74 -0
- apsimo/world_model/extraction/document_extractor.py +78 -0
- apsimo/world_model/extraction/formats/__init__.py +24 -0
- apsimo/world_model/extraction/formats/csv_fmt.py +68 -0
- apsimo/world_model/extraction/formats/html_fmt.py +72 -0
- apsimo/world_model/extraction/formats/json_fmt.py +68 -0
- apsimo/world_model/extraction/formats/pdf.py +43 -0
- apsimo/world_model/extraction/formats/text.py +27 -0
- apsimo/world_model/extraction/llm_extractor.py +164 -0
- apsimo/world_model/extraction/pipeline.py +73 -0
- apsimo/world_model/integrations/__init__.py +5 -0
- apsimo/world_model/integrations/mind_model_bridge.py +115 -0
- apsimo/world_model/integrations/social_intel_bridge.py +120 -0
- apsimo/world_model/jobs/__init__.py +4 -0
- apsimo/world_model/jobs/extraction_job.py +168 -0
- apsimo/world_model/llm_extract.py +572 -0
- apsimo/world_model/neo4j/__init__.py +5 -0
- apsimo/world_model/neo4j/backend.py +654 -0
- apsimo/world_model/observations.py +155 -0
- apsimo/world_model/populator.py +307 -0
- apsimo/world_model/postgres/__init__.py +1 -0
- apsimo/world_model/postgres/backend.py +683 -0
- apsimo/world_model/relationships.py +25 -0
- apsimo/world_model/resolution/__init__.py +13 -0
- apsimo/world_model/resolution/entity_resolver.py +232 -0
- apsimo/world_model/resolution/merge_audit.py +16 -0
- apsimo/world_model/resolution/merge_workflow.py +117 -0
- apsimo/world_model/source_reports.py +121 -0
- apsimo/world_model/sqlite/__init__.py +4 -0
- apsimo/world_model/sqlite/backend.py +855 -0
- apsimo/world_model/sqlite/schema.sql +132 -0
- apsimo/world_model/store.py +545 -0
- apsimo-1.3.0.dist-info/METADATA +78 -0
- apsimo-1.3.0.dist-info/RECORD +614 -0
- apsimo-1.3.0.dist-info/WHEEL +5 -0
- apsimo-1.3.0.dist-info/entry_points.txt +11 -0
- apsimo-1.3.0.dist-info/licenses/LICENSE +21 -0
- apsimo-1.3.0.dist-info/top_level.txt +2 -0
- colony_sidecar/__init__.py +4 -0
apsimo/chain/cli.py
ADDED
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
"""CLI commands for ColonyChain management.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
colony chain status # Show chain state summary
|
|
5
|
+
colony chain genesis --name NAME # Initialize genesis block
|
|
6
|
+
colony chain info --block N # Show block details
|
|
7
|
+
colony chain tx --tx-id ID # Show transaction details
|
|
8
|
+
colony chain list-colonies # List registered colonies
|
|
9
|
+
colony chain list-sentinels # List active sentinels
|
|
10
|
+
colony chain verify # Verify chain integrity
|
|
11
|
+
colony chain mempool # Show pending mempool transactions
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import hashlib
|
|
17
|
+
import json
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
_DEFAULT_DB = Path.home() / ".colony" / "chain.db"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _load_store(db_path: str | None = None) -> "ChainStore":
|
|
26
|
+
from apsimo.chain.storage import ChainStore
|
|
27
|
+
path = Path(db_path) if db_path else _DEFAULT_DB
|
|
28
|
+
return ChainStore(path)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _load_state(db_path: str | None = None) -> "ChainState":
|
|
32
|
+
from apsimo.chain.state_machine import ChainStateMachine
|
|
33
|
+
store = _load_store(db_path)
|
|
34
|
+
sm = ChainStateMachine(store)
|
|
35
|
+
return sm.get_current_state()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def cmd_chain_status(args) -> int:
|
|
39
|
+
"""Show chain state summary."""
|
|
40
|
+
try:
|
|
41
|
+
store = _load_store(getattr(args, "db", None))
|
|
42
|
+
from apsimo.chain.state_machine import ChainStateMachine
|
|
43
|
+
sm = ChainStateMachine(store)
|
|
44
|
+
state = sm.get_current_state()
|
|
45
|
+
height = store.get_height()
|
|
46
|
+
|
|
47
|
+
print("ColonyChain Status")
|
|
48
|
+
print("==================")
|
|
49
|
+
print(f" Height: {height}")
|
|
50
|
+
print(f" Last block hash: {state.last_block_hash[:24]}...")
|
|
51
|
+
print(f" Network ID: {state.network_id[:24]}..." if state.network_id else " Network ID: (none)")
|
|
52
|
+
print(f" Genesis admin: {state.genesis_admin_id or '(none)'}")
|
|
53
|
+
print(f" Colonies: {len(state.colony_registry)}")
|
|
54
|
+
print(f" Suspended: {len(state.suspended_colonies)}")
|
|
55
|
+
print(f" Sentinels: {len(state.active_sentinels())}")
|
|
56
|
+
print(f" Trust edges: {len(state.trust_graph)}")
|
|
57
|
+
print(f" Mempool size: {store.mempool_size()}")
|
|
58
|
+
print(f" Block interval: {state.protocol_config.block_interval_secs}s")
|
|
59
|
+
print(f" Untrust threshold:{state.protocol_config.untrust_threshold}")
|
|
60
|
+
return 0
|
|
61
|
+
except Exception as exc:
|
|
62
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
63
|
+
return 1
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def cmd_chain_genesis(args) -> int:
|
|
67
|
+
"""Initialize a new ColonyChain with a genesis block."""
|
|
68
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
69
|
+
from cryptography.hazmat.primitives.serialization import (
|
|
70
|
+
Encoding, PublicFormat, PrivateFormat, NoEncryption
|
|
71
|
+
)
|
|
72
|
+
from apsimo.chain.genesis import GenesisConfig, create_genesis_block
|
|
73
|
+
from apsimo.chain.storage import ChainStore
|
|
74
|
+
|
|
75
|
+
name = getattr(args, "name", None) or "genesis"
|
|
76
|
+
db_path = getattr(args, "db", None)
|
|
77
|
+
key_file = getattr(args, "key_file", None)
|
|
78
|
+
|
|
79
|
+
db = Path(db_path) if db_path else _DEFAULT_DB
|
|
80
|
+
db.parent.mkdir(parents=True, exist_ok=True)
|
|
81
|
+
|
|
82
|
+
store = ChainStore(db)
|
|
83
|
+
if store.get_height() >= 0:
|
|
84
|
+
print("Error: chain already initialized (genesis block exists)", file=sys.stderr)
|
|
85
|
+
return 1
|
|
86
|
+
|
|
87
|
+
# Generate or load key
|
|
88
|
+
if key_file and Path(key_file).exists():
|
|
89
|
+
raw = bytes.fromhex(Path(key_file).read_text().strip())
|
|
90
|
+
priv = Ed25519PrivateKey.from_private_bytes(raw)
|
|
91
|
+
print(f"Loaded key from {key_file}")
|
|
92
|
+
else:
|
|
93
|
+
priv = Ed25519PrivateKey.generate()
|
|
94
|
+
if key_file:
|
|
95
|
+
raw_bytes = priv.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
|
|
96
|
+
Path(key_file).write_text(raw_bytes.hex())
|
|
97
|
+
print(f"Generated new key → {key_file}")
|
|
98
|
+
else:
|
|
99
|
+
print("Generated ephemeral key (not saved). Use --key-file to persist.")
|
|
100
|
+
|
|
101
|
+
pub = priv.public_key()
|
|
102
|
+
pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
|
|
103
|
+
colony_id = hashlib.sha256(bytes.fromhex(pub_hex)).hexdigest()
|
|
104
|
+
|
|
105
|
+
def sign_fn(data: bytes) -> str:
|
|
106
|
+
return priv.sign(data).hex()
|
|
107
|
+
|
|
108
|
+
cfg = GenesisConfig(
|
|
109
|
+
genesis_colony_name=name,
|
|
110
|
+
genesis_colony_id=colony_id,
|
|
111
|
+
genesis_pubkey_hex=pub_hex,
|
|
112
|
+
)
|
|
113
|
+
block = create_genesis_block(cfg, sign_fn=sign_fn)
|
|
114
|
+
store.append_block(block)
|
|
115
|
+
|
|
116
|
+
print(f"Genesis block created:")
|
|
117
|
+
print(f" Colony name: {name}")
|
|
118
|
+
print(f" Colony ID: {colony_id}")
|
|
119
|
+
print(f" Block hash: {block.block_hash[:24]}...")
|
|
120
|
+
print(f" Network ID: {block.metadata.get('network_id', '')[:24]}...")
|
|
121
|
+
print(f" DB path: {db}")
|
|
122
|
+
return 0
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def cmd_chain_info(args) -> int:
|
|
126
|
+
"""Show block details."""
|
|
127
|
+
block_index = getattr(args, "block", None)
|
|
128
|
+
if block_index is None:
|
|
129
|
+
print("Error: --block N required", file=sys.stderr)
|
|
130
|
+
return 1
|
|
131
|
+
try:
|
|
132
|
+
block_index = int(block_index)
|
|
133
|
+
store = _load_store(getattr(args, "db", None))
|
|
134
|
+
block = store.get_block(block_index)
|
|
135
|
+
if block is None:
|
|
136
|
+
print(f"Block {block_index} not found", file=sys.stderr)
|
|
137
|
+
return 1
|
|
138
|
+
d = block.to_dict()
|
|
139
|
+
# Truncate tx list for display
|
|
140
|
+
tx_count = len(d["transactions"])
|
|
141
|
+
d["transactions"] = f"<{tx_count} transactions>"
|
|
142
|
+
print(json.dumps(d, indent=2, default=str))
|
|
143
|
+
return 0
|
|
144
|
+
except Exception as exc:
|
|
145
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
146
|
+
return 1
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def cmd_chain_tx(args) -> int:
|
|
150
|
+
"""Show transaction details."""
|
|
151
|
+
tx_id = getattr(args, "tx_id", None)
|
|
152
|
+
if not tx_id:
|
|
153
|
+
print("Error: --tx-id required", file=sys.stderr)
|
|
154
|
+
return 1
|
|
155
|
+
try:
|
|
156
|
+
store = _load_store(getattr(args, "db", None))
|
|
157
|
+
txs = store.get_transactions_for_colony("")
|
|
158
|
+
# search all by fetching blocks
|
|
159
|
+
height = store.get_height()
|
|
160
|
+
for idx in range(height + 1):
|
|
161
|
+
block = store.get_block(idx)
|
|
162
|
+
if block:
|
|
163
|
+
for tx in block.transactions:
|
|
164
|
+
if tx.tx_id == tx_id:
|
|
165
|
+
d = tx.to_dict()
|
|
166
|
+
d["block_index"] = idx
|
|
167
|
+
print(json.dumps(d, indent=2, default=str))
|
|
168
|
+
return 0
|
|
169
|
+
print(f"Transaction {tx_id!r} not found", file=sys.stderr)
|
|
170
|
+
return 1
|
|
171
|
+
except Exception as exc:
|
|
172
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
173
|
+
return 1
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def cmd_chain_list_colonies(args) -> int:
|
|
177
|
+
"""List all registered colonies."""
|
|
178
|
+
try:
|
|
179
|
+
state = _load_state(getattr(args, "db", None))
|
|
180
|
+
if not state.colony_registry:
|
|
181
|
+
print("No colonies registered.")
|
|
182
|
+
return 0
|
|
183
|
+
fmt = "{:<20} {:<12} {:<16} {}"
|
|
184
|
+
print(fmt.format("NAME", "STATUS", "COLONY_ID (prefix)", "ENDPOINT"))
|
|
185
|
+
print("-" * 80)
|
|
186
|
+
for colony_id, record in sorted(state.colony_registry.items(), key=lambda x: x[1].name):
|
|
187
|
+
flags = ""
|
|
188
|
+
if record.is_genesis_admin:
|
|
189
|
+
flags = " [genesis]"
|
|
190
|
+
print(fmt.format(
|
|
191
|
+
record.name + flags,
|
|
192
|
+
record.status,
|
|
193
|
+
colony_id[:16],
|
|
194
|
+
record.endpoint or "(local)",
|
|
195
|
+
))
|
|
196
|
+
return 0
|
|
197
|
+
except Exception as exc:
|
|
198
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
199
|
+
return 1
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def cmd_chain_list_sentinels(args) -> int:
|
|
203
|
+
"""List Sentinel validators."""
|
|
204
|
+
try:
|
|
205
|
+
state = _load_state(getattr(args, "db", None))
|
|
206
|
+
if not state.sentinel_roster:
|
|
207
|
+
print("No sentinels registered.")
|
|
208
|
+
return 0
|
|
209
|
+
fmt = "{:<36} {:<12} {:<20} {}"
|
|
210
|
+
print(fmt.format("SENTINEL_ID", "STATUS", "HOST:PORT", "COLONY_ID (prefix)"))
|
|
211
|
+
print("-" * 80)
|
|
212
|
+
for sid, record in state.sentinel_roster.items():
|
|
213
|
+
print(fmt.format(
|
|
214
|
+
sid,
|
|
215
|
+
record.status,
|
|
216
|
+
f"{record.host}:{record.port}",
|
|
217
|
+
record.colony_id[:16],
|
|
218
|
+
))
|
|
219
|
+
return 0
|
|
220
|
+
except Exception as exc:
|
|
221
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
222
|
+
return 1
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def cmd_chain_verify(args) -> int:
|
|
226
|
+
"""Verify chain hash integrity from genesis."""
|
|
227
|
+
try:
|
|
228
|
+
store = _load_store(getattr(args, "db", None))
|
|
229
|
+
height = store.get_height()
|
|
230
|
+
if height < 0:
|
|
231
|
+
print("Chain is empty (no blocks).")
|
|
232
|
+
return 0
|
|
233
|
+
|
|
234
|
+
errors = 0
|
|
235
|
+
prev_hash = "0" * 64
|
|
236
|
+
for idx in range(height + 1):
|
|
237
|
+
block = store.get_block(idx)
|
|
238
|
+
if block is None:
|
|
239
|
+
print(f" MISSING block {idx}", file=sys.stderr)
|
|
240
|
+
errors += 1
|
|
241
|
+
continue
|
|
242
|
+
|
|
243
|
+
if idx == 0:
|
|
244
|
+
if block.previous_hash != "0" * 64:
|
|
245
|
+
print(f" FAIL block 0: previous_hash must be zeros")
|
|
246
|
+
errors += 1
|
|
247
|
+
else:
|
|
248
|
+
if block.previous_hash != prev_hash:
|
|
249
|
+
print(f" FAIL block {idx}: previous_hash mismatch")
|
|
250
|
+
errors += 1
|
|
251
|
+
|
|
252
|
+
from apsimo.chain.block import build_merkle_root
|
|
253
|
+
tx_ids = [tx.tx_id for tx in block.transactions]
|
|
254
|
+
expected_merkle = build_merkle_root(tx_ids)
|
|
255
|
+
if block.merkle_root != expected_merkle:
|
|
256
|
+
print(f" FAIL block {idx}: merkle_root mismatch")
|
|
257
|
+
errors += 1
|
|
258
|
+
|
|
259
|
+
prev_hash = block.block_hash
|
|
260
|
+
|
|
261
|
+
if errors == 0:
|
|
262
|
+
print(f"Chain verified OK: {height + 1} blocks, no errors.")
|
|
263
|
+
return 0
|
|
264
|
+
else:
|
|
265
|
+
print(f"Chain verification FAILED: {errors} error(s).", file=sys.stderr)
|
|
266
|
+
return 1
|
|
267
|
+
except Exception as exc:
|
|
268
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
269
|
+
return 1
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def cmd_chain_mempool(args) -> int:
|
|
273
|
+
"""Show pending mempool transactions."""
|
|
274
|
+
try:
|
|
275
|
+
store = _load_store(getattr(args, "db", None))
|
|
276
|
+
txs = store.get_mempool(limit=100)
|
|
277
|
+
if not txs:
|
|
278
|
+
print("Mempool is empty.")
|
|
279
|
+
return 0
|
|
280
|
+
print(f"Mempool: {len(txs)} pending transaction(s)")
|
|
281
|
+
fmt = "{:<36} {:<24} {:<8} {}"
|
|
282
|
+
print(fmt.format("TX_ID", "TYPE", "NONCE", "FROM (prefix)"))
|
|
283
|
+
print("-" * 80)
|
|
284
|
+
for tx in txs:
|
|
285
|
+
print(fmt.format(
|
|
286
|
+
tx.tx_id,
|
|
287
|
+
tx.type.value if hasattr(tx.type, "value") else str(tx.type),
|
|
288
|
+
str(tx.nonce),
|
|
289
|
+
tx.from_colony_id[:16],
|
|
290
|
+
))
|
|
291
|
+
return 0
|
|
292
|
+
except Exception as exc:
|
|
293
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
294
|
+
return 1
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def cmd_chain_state(args) -> int:
|
|
298
|
+
"""Dump current chain state summary."""
|
|
299
|
+
try:
|
|
300
|
+
state = _load_state(getattr(args, "db", None))
|
|
301
|
+
import json as _json
|
|
302
|
+
summary = {
|
|
303
|
+
"height": state.height,
|
|
304
|
+
"last_block_hash": state.last_block_hash,
|
|
305
|
+
"network_id": state.network_id,
|
|
306
|
+
"genesis_admin_id": state.genesis_admin_id,
|
|
307
|
+
"colony_count": len(state.colony_registry),
|
|
308
|
+
"suspended_count": len(state.suspended_colonies),
|
|
309
|
+
"sentinel_count": len(state.active_sentinels()),
|
|
310
|
+
"trust_edges": len(state.trust_graph),
|
|
311
|
+
"protocol_config": {
|
|
312
|
+
"block_interval_secs": state.protocol_config.block_interval_secs,
|
|
313
|
+
"untrust_threshold": state.protocol_config.untrust_threshold,
|
|
314
|
+
"min_sentinels": state.protocol_config.min_sentinels,
|
|
315
|
+
},
|
|
316
|
+
"upgrade_history_count": len(state.upgrade_history),
|
|
317
|
+
}
|
|
318
|
+
print(_json.dumps(summary, indent=2, default=str))
|
|
319
|
+
return 0
|
|
320
|
+
except Exception as exc:
|
|
321
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
322
|
+
return 1
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def cmd_chain_register(args) -> int:
|
|
326
|
+
"""Register this colony on-chain (colony_register transaction)."""
|
|
327
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
328
|
+
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat, PrivateFormat, NoEncryption
|
|
329
|
+
from apsimo.chain.transactions import TxType, Transaction
|
|
330
|
+
import hashlib
|
|
331
|
+
|
|
332
|
+
key_file = getattr(args, "key_file", None)
|
|
333
|
+
name = getattr(args, "name", None)
|
|
334
|
+
endpoint = getattr(args, "endpoint", "") or ""
|
|
335
|
+
description = getattr(args, "description", "") or ""
|
|
336
|
+
db_path = getattr(args, "db", None)
|
|
337
|
+
|
|
338
|
+
if not name:
|
|
339
|
+
print("Error: --name required", file=sys.stderr)
|
|
340
|
+
return 1
|
|
341
|
+
if not key_file:
|
|
342
|
+
print("Error: --key-file required", file=sys.stderr)
|
|
343
|
+
return 1
|
|
344
|
+
if not Path(key_file).exists():
|
|
345
|
+
print(f"Error: key file not found: {key_file}", file=sys.stderr)
|
|
346
|
+
return 1
|
|
347
|
+
|
|
348
|
+
try:
|
|
349
|
+
raw = bytes.fromhex(Path(key_file).read_text().strip())
|
|
350
|
+
priv = Ed25519PrivateKey.from_private_bytes(raw)
|
|
351
|
+
pub = priv.public_key()
|
|
352
|
+
pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
|
|
353
|
+
colony_id = hashlib.sha256(bytes.fromhex(pub_hex)).hexdigest()
|
|
354
|
+
|
|
355
|
+
def sign_fn(data: bytes) -> str:
|
|
356
|
+
return priv.sign(data).hex()
|
|
357
|
+
|
|
358
|
+
store = _load_store(db_path)
|
|
359
|
+
from apsimo.chain.state_machine import ChainStateMachine
|
|
360
|
+
sm = ChainStateMachine(store)
|
|
361
|
+
state = sm.get_current_state()
|
|
362
|
+
|
|
363
|
+
nonce_map = {}
|
|
364
|
+
for cid, rec in state.colony_registry.items():
|
|
365
|
+
pass
|
|
366
|
+
last_nonce = 0
|
|
367
|
+
for block_idx in range(store.get_height() + 1):
|
|
368
|
+
block = store.get_block(block_idx)
|
|
369
|
+
if block:
|
|
370
|
+
for tx in block.transactions:
|
|
371
|
+
if tx.from_colony_id == colony_id and tx.nonce > last_nonce:
|
|
372
|
+
last_nonce = tx.nonce
|
|
373
|
+
|
|
374
|
+
tx = Transaction.create(
|
|
375
|
+
tx_type=TxType.COLONY_REGISTER,
|
|
376
|
+
from_colony_id=colony_id,
|
|
377
|
+
nonce=last_nonce + 1,
|
|
378
|
+
payload={
|
|
379
|
+
"name": name,
|
|
380
|
+
"public_key_hex": pub_hex,
|
|
381
|
+
"colony_id": colony_id,
|
|
382
|
+
"endpoint": endpoint,
|
|
383
|
+
"description": description[:256],
|
|
384
|
+
"protocol_version": "1.0.0",
|
|
385
|
+
"capabilities": ["task_delegation", "memory_sharing"],
|
|
386
|
+
"genesis_admin": False,
|
|
387
|
+
"metadata": {},
|
|
388
|
+
},
|
|
389
|
+
sign_fn=sign_fn,
|
|
390
|
+
)
|
|
391
|
+
store.add_to_mempool(tx)
|
|
392
|
+
print(f"Submitted colony_register to mempool:")
|
|
393
|
+
print(f" tx_id: {tx.tx_id}")
|
|
394
|
+
print(f" colony_id: {colony_id}")
|
|
395
|
+
print(f" name: {name}")
|
|
396
|
+
return 0
|
|
397
|
+
except Exception as exc:
|
|
398
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
399
|
+
return 1
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def cmd_chain_rotate_key(args) -> int:
|
|
403
|
+
"""Rotate this colony's Ed25519 key on-chain."""
|
|
404
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
405
|
+
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat, PrivateFormat, NoEncryption
|
|
406
|
+
from apsimo.chain.transactions import TxType, Transaction
|
|
407
|
+
import hashlib
|
|
408
|
+
|
|
409
|
+
old_key_file = getattr(args, "old_key_file", None)
|
|
410
|
+
new_key_file = getattr(args, "new_key_file", None)
|
|
411
|
+
db_path = getattr(args, "db", None)
|
|
412
|
+
|
|
413
|
+
if not old_key_file or not new_key_file:
|
|
414
|
+
print("Error: --old-key-file and --new-key-file required", file=sys.stderr)
|
|
415
|
+
return 1
|
|
416
|
+
|
|
417
|
+
try:
|
|
418
|
+
old_raw = bytes.fromhex(Path(old_key_file).read_text().strip())
|
|
419
|
+
old_priv = Ed25519PrivateKey.from_private_bytes(old_raw)
|
|
420
|
+
old_pub = old_priv.public_key()
|
|
421
|
+
old_pub_hex = old_pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
|
|
422
|
+
colony_id = hashlib.sha256(bytes.fromhex(old_pub_hex)).hexdigest()
|
|
423
|
+
|
|
424
|
+
if Path(new_key_file).exists():
|
|
425
|
+
new_raw = bytes.fromhex(Path(new_key_file).read_text().strip())
|
|
426
|
+
new_priv = Ed25519PrivateKey.from_private_bytes(new_raw)
|
|
427
|
+
else:
|
|
428
|
+
new_priv = Ed25519PrivateKey.generate()
|
|
429
|
+
new_raw_bytes = new_priv.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
|
|
430
|
+
Path(new_key_file).write_text(new_raw_bytes.hex())
|
|
431
|
+
print(f"Generated new key → {new_key_file}")
|
|
432
|
+
|
|
433
|
+
new_pub = new_priv.public_key()
|
|
434
|
+
new_pub_hex = new_pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
|
|
435
|
+
|
|
436
|
+
def sign_fn(data: bytes) -> str:
|
|
437
|
+
return old_priv.sign(data).hex()
|
|
438
|
+
|
|
439
|
+
store = _load_store(db_path)
|
|
440
|
+
last_nonce = 0
|
|
441
|
+
for block_idx in range(store.get_height() + 1):
|
|
442
|
+
block = store.get_block(block_idx)
|
|
443
|
+
if block:
|
|
444
|
+
for tx in block.transactions:
|
|
445
|
+
if tx.from_colony_id == colony_id and tx.nonce > last_nonce:
|
|
446
|
+
last_nonce = tx.nonce
|
|
447
|
+
|
|
448
|
+
tx = Transaction.create(
|
|
449
|
+
tx_type=TxType.COLONY_ROTATE_KEY,
|
|
450
|
+
from_colony_id=colony_id,
|
|
451
|
+
nonce=last_nonce + 1,
|
|
452
|
+
payload={
|
|
453
|
+
"new_public_key_hex": new_pub_hex,
|
|
454
|
+
"old_public_key_hex": old_pub_hex,
|
|
455
|
+
"reason": "scheduled_rotation",
|
|
456
|
+
},
|
|
457
|
+
sign_fn=sign_fn,
|
|
458
|
+
)
|
|
459
|
+
store.add_to_mempool(tx)
|
|
460
|
+
print(f"Submitted colony_rotate_key to mempool:")
|
|
461
|
+
print(f" tx_id: {tx.tx_id}")
|
|
462
|
+
print(f" colony_id: {colony_id}")
|
|
463
|
+
print(f" new_pubkey: {new_pub_hex[:24]}...")
|
|
464
|
+
return 0
|
|
465
|
+
except Exception as exc:
|
|
466
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
467
|
+
return 1
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def cmd_chain_trust(args) -> int:
|
|
471
|
+
"""Submit trust_attest for a peer colony."""
|
|
472
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
473
|
+
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
|
|
474
|
+
from apsimo.chain.transactions import TxType, Transaction
|
|
475
|
+
import hashlib
|
|
476
|
+
|
|
477
|
+
key_file = getattr(args, "key_file", None)
|
|
478
|
+
target = getattr(args, "target", None) or getattr(args, "colony", None)
|
|
479
|
+
level_raw = getattr(args, "level", None) or getattr(args, "trust_level", "1")
|
|
480
|
+
db_path = getattr(args, "db", None)
|
|
481
|
+
|
|
482
|
+
if not key_file or not target:
|
|
483
|
+
print("Error: --key-file and --target (or positional colony name) required", file=sys.stderr)
|
|
484
|
+
return 1
|
|
485
|
+
|
|
486
|
+
try:
|
|
487
|
+
level = int(level_raw)
|
|
488
|
+
if not 0 <= level <= 4:
|
|
489
|
+
print("Error: trust level must be 0-4", file=sys.stderr)
|
|
490
|
+
return 1
|
|
491
|
+
|
|
492
|
+
raw = bytes.fromhex(Path(key_file).read_text().strip())
|
|
493
|
+
priv = Ed25519PrivateKey.from_private_bytes(raw)
|
|
494
|
+
pub = priv.public_key()
|
|
495
|
+
pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
|
|
496
|
+
colony_id = hashlib.sha256(bytes.fromhex(pub_hex)).hexdigest()
|
|
497
|
+
|
|
498
|
+
def sign_fn(data: bytes) -> str:
|
|
499
|
+
return priv.sign(data).hex()
|
|
500
|
+
|
|
501
|
+
store = _load_store(db_path)
|
|
502
|
+
state = _load_state(db_path)
|
|
503
|
+
|
|
504
|
+
# Resolve target: may be a name or colony_id
|
|
505
|
+
target_id = state.colony_id_for_name(target) or (target if target in state.colony_registry else None)
|
|
506
|
+
if not target_id:
|
|
507
|
+
print(f"Error: colony {target!r} not found in chain state", file=sys.stderr)
|
|
508
|
+
return 1
|
|
509
|
+
|
|
510
|
+
last_nonce = 0
|
|
511
|
+
for block_idx in range(store.get_height() + 1):
|
|
512
|
+
block = store.get_block(block_idx)
|
|
513
|
+
if block:
|
|
514
|
+
for tx in block.transactions:
|
|
515
|
+
if tx.from_colony_id == colony_id and tx.nonce > last_nonce:
|
|
516
|
+
last_nonce = tx.nonce
|
|
517
|
+
|
|
518
|
+
tx = Transaction.create(
|
|
519
|
+
tx_type=TxType.TRUST_ATTEST,
|
|
520
|
+
from_colony_id=colony_id,
|
|
521
|
+
nonce=last_nonce + 1,
|
|
522
|
+
payload={
|
|
523
|
+
"to_colony_id": target_id,
|
|
524
|
+
"trust_level": level,
|
|
525
|
+
"evidence_tx_ids": [],
|
|
526
|
+
},
|
|
527
|
+
sign_fn=sign_fn,
|
|
528
|
+
)
|
|
529
|
+
store.add_to_mempool(tx)
|
|
530
|
+
print(f"Submitted trust_attest to mempool:")
|
|
531
|
+
print(f" tx_id: {tx.tx_id}")
|
|
532
|
+
print(f" target: {target_id[:24]}... (level={level})")
|
|
533
|
+
return 0
|
|
534
|
+
except Exception as exc:
|
|
535
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
536
|
+
return 1
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def cmd_chain_untrust(args) -> int:
|
|
540
|
+
"""Submit untrust_attest for a peer colony."""
|
|
541
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
542
|
+
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
|
|
543
|
+
from apsimo.chain.transactions import TxType, Transaction
|
|
544
|
+
import hashlib
|
|
545
|
+
|
|
546
|
+
key_file = getattr(args, "key_file", None)
|
|
547
|
+
target = getattr(args, "target", None) or getattr(args, "colony", None)
|
|
548
|
+
db_path = getattr(args, "db", None)
|
|
549
|
+
report_abuse = getattr(args, "report_abuse", False)
|
|
550
|
+
|
|
551
|
+
if not key_file or not target:
|
|
552
|
+
print("Error: --key-file and --target required", file=sys.stderr)
|
|
553
|
+
return 1
|
|
554
|
+
|
|
555
|
+
try:
|
|
556
|
+
raw = bytes.fromhex(Path(key_file).read_text().strip())
|
|
557
|
+
priv = Ed25519PrivateKey.from_private_bytes(raw)
|
|
558
|
+
pub = priv.public_key()
|
|
559
|
+
pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
|
|
560
|
+
colony_id = hashlib.sha256(bytes.fromhex(pub_hex)).hexdigest()
|
|
561
|
+
|
|
562
|
+
def sign_fn(data: bytes) -> str:
|
|
563
|
+
return priv.sign(data).hex()
|
|
564
|
+
|
|
565
|
+
store = _load_store(db_path)
|
|
566
|
+
state = _load_state(db_path)
|
|
567
|
+
|
|
568
|
+
target_id = state.colony_id_for_name(target) or (target if target in state.colony_registry else None)
|
|
569
|
+
if not target_id:
|
|
570
|
+
print(f"Error: colony {target!r} not found", file=sys.stderr)
|
|
571
|
+
return 1
|
|
572
|
+
|
|
573
|
+
last_nonce = 0
|
|
574
|
+
for block_idx in range(store.get_height() + 1):
|
|
575
|
+
block = store.get_block(block_idx)
|
|
576
|
+
if block:
|
|
577
|
+
for tx in block.transactions:
|
|
578
|
+
if tx.from_colony_id == colony_id and tx.nonce > last_nonce:
|
|
579
|
+
last_nonce = tx.nonce
|
|
580
|
+
|
|
581
|
+
tx = Transaction.create(
|
|
582
|
+
tx_type=TxType.UNTRUST_ATTEST,
|
|
583
|
+
from_colony_id=colony_id,
|
|
584
|
+
nonce=last_nonce + 1,
|
|
585
|
+
payload={
|
|
586
|
+
"to_colony_id": target_id,
|
|
587
|
+
"reason": getattr(args, "reason", "") or "",
|
|
588
|
+
"report_abuse": bool(report_abuse),
|
|
589
|
+
"evidence_tx_ids": [],
|
|
590
|
+
},
|
|
591
|
+
sign_fn=sign_fn,
|
|
592
|
+
)
|
|
593
|
+
store.add_to_mempool(tx)
|
|
594
|
+
print(f"Submitted untrust_attest to mempool:")
|
|
595
|
+
print(f" tx_id: {tx.tx_id}")
|
|
596
|
+
print(f" target: {target_id[:24]}...")
|
|
597
|
+
return 0
|
|
598
|
+
except Exception as exc:
|
|
599
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
600
|
+
return 1
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
def run_chain_command(args: list) -> int:
|
|
604
|
+
"""Dispatch 'colony chain <subcommand>'."""
|
|
605
|
+
if not args:
|
|
606
|
+
_print_chain_help()
|
|
607
|
+
return 1
|
|
608
|
+
|
|
609
|
+
sub = args[0]
|
|
610
|
+
remaining = args[1:]
|
|
611
|
+
|
|
612
|
+
# Parse simple key=value style args from remaining
|
|
613
|
+
parsed = _parse_args(remaining)
|
|
614
|
+
|
|
615
|
+
class FakeArgs:
|
|
616
|
+
pass
|
|
617
|
+
|
|
618
|
+
fa = FakeArgs()
|
|
619
|
+
for k, v in parsed.items():
|
|
620
|
+
setattr(fa, k, v)
|
|
621
|
+
|
|
622
|
+
dispatch = {
|
|
623
|
+
"status": cmd_chain_status,
|
|
624
|
+
"genesis": cmd_chain_genesis,
|
|
625
|
+
"info": cmd_chain_info,
|
|
626
|
+
"block": cmd_chain_info,
|
|
627
|
+
"tx": cmd_chain_tx,
|
|
628
|
+
"state": cmd_chain_state,
|
|
629
|
+
"list-colonies": cmd_chain_list_colonies,
|
|
630
|
+
"list_colonies": cmd_chain_list_colonies,
|
|
631
|
+
"list-sentinels": cmd_chain_list_sentinels,
|
|
632
|
+
"list_sentinels": cmd_chain_list_sentinels,
|
|
633
|
+
"verify": cmd_chain_verify,
|
|
634
|
+
"mempool": cmd_chain_mempool,
|
|
635
|
+
"register": cmd_chain_register,
|
|
636
|
+
"rotate-key": cmd_chain_rotate_key,
|
|
637
|
+
"rotate_key": cmd_chain_rotate_key,
|
|
638
|
+
"trust": cmd_chain_trust,
|
|
639
|
+
"untrust": cmd_chain_untrust,
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
handler = dispatch.get(sub)
|
|
643
|
+
if handler is None:
|
|
644
|
+
print(f"Unknown chain subcommand: {sub!r}", file=sys.stderr)
|
|
645
|
+
_print_chain_help()
|
|
646
|
+
return 1
|
|
647
|
+
|
|
648
|
+
return handler(fa)
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def _parse_args(args: list) -> dict:
|
|
652
|
+
"""Parse --key value or --key=value pairs into a dict."""
|
|
653
|
+
result: dict[str, Any] = {}
|
|
654
|
+
i = 0
|
|
655
|
+
while i < len(args):
|
|
656
|
+
arg = args[i]
|
|
657
|
+
if arg.startswith("--"):
|
|
658
|
+
stripped = arg[2:]
|
|
659
|
+
if "=" in stripped:
|
|
660
|
+
raw_key, v = stripped.split("=", 1)
|
|
661
|
+
k = raw_key.replace("-", "_")
|
|
662
|
+
result[k] = v
|
|
663
|
+
else:
|
|
664
|
+
key = stripped.replace("-", "_")
|
|
665
|
+
if i + 1 < len(args) and not args[i + 1].startswith("--"):
|
|
666
|
+
result[key] = args[i + 1]
|
|
667
|
+
i += 1
|
|
668
|
+
else:
|
|
669
|
+
result[key] = True
|
|
670
|
+
i += 1
|
|
671
|
+
return result
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def _print_chain_help() -> None:
|
|
675
|
+
print("""Usage: colony chain <subcommand> [options]
|
|
676
|
+
|
|
677
|
+
Subcommands:
|
|
678
|
+
status Show chain state summary
|
|
679
|
+
state Dump full chain state as JSON
|
|
680
|
+
genesis Initialize genesis block
|
|
681
|
+
info / block Show block details (--block N)
|
|
682
|
+
tx Show transaction (--tx-id ID)
|
|
683
|
+
list-colonies List registered colonies
|
|
684
|
+
list-sentinels List sentinel validators
|
|
685
|
+
verify Verify chain hash integrity
|
|
686
|
+
mempool Show pending mempool transactions
|
|
687
|
+
register Register this colony on-chain
|
|
688
|
+
rotate-key Rotate colony Ed25519 key on-chain
|
|
689
|
+
trust Submit trust_attest (--target NAME --level 0-4)
|
|
690
|
+
untrust Submit untrust_attest (--target NAME)
|
|
691
|
+
|
|
692
|
+
Options:
|
|
693
|
+
--db PATH SQLite database path (default: ~/.colony/chain.db)
|
|
694
|
+
--name NAME Colony name
|
|
695
|
+
--key-file PATH Ed25519 private key file (hex)
|
|
696
|
+
--old-key-file PATH Current key file (for rotate-key)
|
|
697
|
+
--new-key-file PATH New key file (for rotate-key)
|
|
698
|
+
--block N Block index for info command
|
|
699
|
+
--tx-id ID Transaction ID for tx command
|
|
700
|
+
--target NAME Target colony name or ID (trust/untrust)
|
|
701
|
+
--level N Trust level 0-4 (trust command)
|
|
702
|
+
--endpoint URL Colony endpoint URL (register)
|
|
703
|
+
--description TEXT Colony description (register)
|
|
704
|
+
""")
|