kirby-api 0.2.0__tar.gz → 0.2.2__tar.gz
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.
- {kirby_api-0.2.0/kirby_api.egg-info → kirby_api-0.2.2}/PKG-INFO +2 -2
- kirby_api-0.2.2/kirby/_migrations/versions/20261005_0001_knowledge_indexes.py +41 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/category_extraction.py +4 -19
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/combatant_loader.py +7 -80
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/power_library_service.py +0 -37
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/extract.py +3 -35
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/routes.py +22 -22
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/services/villain_extractor.py +3 -10
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/__init__.py +7 -9
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/comic_canon/__init__.py +4 -3
- {kirby_api-0.2.0 → kirby_api-0.2.2/kirby_api.egg-info}/PKG-INFO +2 -2
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby_api.egg-info/SOURCES.txt +2 -6
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby_api.egg-info/requires.txt +1 -1
- {kirby_api-0.2.0 → kirby_api-0.2.2}/pyproject.toml +3 -5
- kirby_api-0.2.2/tests/test_knowledge_indexes_migration.py +28 -0
- kirby_api-0.2.0/kirby/builds/concept_to_build.py +0 -505
- kirby_api-0.2.0/kirby/builds/hdc_exporter.py +0 -107
- kirby_api-0.2.0/kirby/characters/services/entity_service.py +0 -430
- kirby_api-0.2.0/kirby/comic_canon/services/comic_vine.py +0 -215
- kirby_api-0.2.0/kirby/comic_canon/services/prewarm.py +0 -455
- kirby_api-0.2.0/kirby/comic_canon/services/text_clean.py +0 -28
- {kirby_api-0.2.0 → kirby_api-0.2.2}/LICENSE +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/README.md +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/README +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/alembic.ini +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/env.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/script.py.mako +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/1b7affd8668e_initial_schema_users_tenants_characters_.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260424_0001_combat_tables.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260429_0001_add_combatant_jsonb.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260501_0001_codex_targeted_pages.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260501_0002_hd_relational_schema.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260501_0003_definitions_codex_chunk_id.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260503_0001_per_template_base_values.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0001_pr1_relational_combat_schema.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0002_seed_tactics_and_profiles.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0003_backfill_combat_relational.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0004_drop_combat_jsonb_columns.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0005_pr1_index_audit_fills.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0006_pending_phase_modifiers.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0007_combat_session_scene_id.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0008_morale_expires_at_seq.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0009_is_stunned.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0010_tactic_catalog_expansion.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0011_slam_velocity_tactic.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0012_mind_control_state.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0013_mental_illusion_state.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0014_mental_entangle_state.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0015_was_surprised.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0016_catalog_expansion_for_new_actions.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0017_combat_started.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0018_physical_entangle.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0019_stat_drains.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0020_continuous_effects.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0021_lockout_state.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260504_0022_dispelled_powers.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260506_0001_campaign_management_v1.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260506_0002_extend_characters_for_pc.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260506_0003_combatant_control_mode.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260506_0004_brain_embeddings.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260507_0001_knowledge_tier.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260507_0002_normalize_jsonb.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260507_0003_drop_legacy_jsonb.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260507_0004_canon_embeddings.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260508_0001_comic_canon_init.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260511_0001_power_library_init.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260514_0001_combat_session_ai_provider.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260528_0001_coordinate_raw_tables.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260528_0002_coordination_initiator.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0001_character_def_rename.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0002_character_instance.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0003_team_def.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0004_team_member_def.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0005_team_instance.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0006_team_def_real_history.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0007_team_page.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0008_team_narrative.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260529_0009_migrate_org_journal_entries_to_team.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260530_0002_templates_catalog_columns.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260530_0003_reconcile_template_category_vocab.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260531_0001_align_catalog_to_engine_schema.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260601_0001_build_doc_fields.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260605_0001_proposals.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260605_0002_membership_roster.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260605_0003_xp_award.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260606_0001_base_drift_guard.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260607_0001_maneuver_details.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260609_0001_scene_wall_def_value.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260609_0002_combat_session_constructs.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260611_0001_arena_hazard_kind_status_tokens.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260611_0002_tactic_entry_role.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260611_0003_seed_archetype_profiles.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260612_0001_combatant_held_construct.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260613_0001_combatant_is_hidden.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260613_0002_combatant_flashed_sense.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260614_0001_construct_sense_group.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260614_0002_image_decoy.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260618_0001_character_extraction_tables.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260621_0001_combat_session_combatant_slot.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260621_0002_vpp_power.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260623_0001_power_categories.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260726_0001_combat_intent.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260727_0001_intent_checks_since_form.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260728_0001_stunned_at_sequence.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260729_0001_intent_budget_turns.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260730_0001_standable_structures.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260731_0001_climb_difficulty.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260731_0002_widen_character_object_alias.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260802_0001_identity_by_id_not_xmlid.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260803_0001_combatant_opening_state.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260804_0001_combat_random_fight.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260804_0002_presence_attack_effects.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260816_0001_template_level_power.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260831_0001_construct_no_teleport.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260831_0002_physical_entangle_state.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260831_0003_character_object_text.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260902_0001_combatant_in_hero_id.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260902_0002_object_affects_flags.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260917_0001_session_names_a_seat.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260918_0000_drop_combat_tables.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260918_0001_harness_tables.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/20260918_0002_narration_speaker_id.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/21980c836860_add_asset_id_refs.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/_migrations/versions/ba28e71c955d_codex_init.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/admin/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/auth/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/auth/authz.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/auth/dependencies.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/auth/jwt.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/auth/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/auth/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/auth/users.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/build_doc_store.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/cli.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/codex_linker.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/importer.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/json_exporter.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/json_importer.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/power_categories.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/power_library_importer.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/recompute.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/builds/template_provider.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/_shared.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/membership_service.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_acl.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_brain.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_documents.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_knowledge.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_membership.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_relationships.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_roster.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_sessions_events.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/routes_xp.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/brain.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/conflicts.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/embeddings.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/generation.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/legacy_translation.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/permissions.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/campaigns/services/recap.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/_shared.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/build_routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/combat_seed.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/corpus_copy.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/proposals/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/proposals/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/proposals/service.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/services/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/services/character_info_backfill.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/services/effective.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/services/writeup_persistence.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/variants_service.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/characters/xp_service.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/cli.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/cli.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/deps.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/repositories.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/schemas.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/services/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/services/embed.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/services/extract.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/services/index.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/services/orchestrator.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/services/search.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/services/villain_writeup_linker.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/codex/workers.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/choosers.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/create.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/events.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/harness.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/outcome.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/roster.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/runner.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/schemas.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/session.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/random_fight/worker.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/schemas.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/services/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/services/connection_hub.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/services/publish.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/combat/services/subscriber.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/comic_canon/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/comic_canon/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/comic_canon/services/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/comic_canon/services/archetypes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/comic_canon/services/embeddings.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/engines/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/engines/cost/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/engines/cost/hdc.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/library/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/main.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/media/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/media/asset_uses.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/media/client.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/media/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/media/schemas.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/media/taxonomy.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/settings.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/shared/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/shared/db.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/teams/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/teams/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/teams/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/teams/schemas.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/teams/services/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/teams/services/effective.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/templates/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/tenants/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/tenants/models.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/tenants/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/users/__init__.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/users/routes.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby/version.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby_api.egg-info/dependency_links.txt +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby_api.egg-info/entry_points.txt +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/kirby_api.egg-info/top_level.txt +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/setup.cfg +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/tests/test_public_vocabulary.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/tests/test_teardown.py +0 -0
- {kirby_api-0.2.0 → kirby_api-0.2.2}/tests/test_wheel_contents.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kirby-api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Kirby — HERO System VTT backend API (FastAPI mono)
|
|
5
5
|
Author: PeterB
|
|
6
6
|
License: PolyForm Noncommercial License 1.0.0
|
|
@@ -32,7 +32,7 @@ Requires-Dist: pgvector>=0.3
|
|
|
32
32
|
Requires-Dist: pypdfium2>=4.30
|
|
33
33
|
Requires-Dist: kirby-combat==0.18.5
|
|
34
34
|
Requires-Dist: kirby-dice>=0.1.0
|
|
35
|
-
Requires-Dist: kirby-ai>=0.
|
|
35
|
+
Requires-Dist: kirby-ai>=0.7.0
|
|
36
36
|
Requires-Dist: prometheus-client>=0.21
|
|
37
37
|
Requires-Dist: prometheus-fastapi-instrumentator>=7.0
|
|
38
38
|
Requires-Dist: tenacity>=8.0
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""the three knowledge indexes the models declared and no migration made
|
|
2
|
+
|
|
3
|
+
A schema-drift check (models vs a migrated database) found three
|
|
4
|
+
``index=True`` columns that no migration ever created, in production as
|
|
5
|
+
well as in a fresh ``alembic upgrade head``:
|
|
6
|
+
|
|
7
|
+
* ``knowledge_link.campaign_id`` -> ``ix_knowledge_link_campaign_id``
|
|
8
|
+
* ``knowledge_link.tenant_id`` -> ``ix_knowledge_link_tenant_id``
|
|
9
|
+
* ``knowledge_unlock.tenant_id`` -> ``ix_knowledge_unlock_tenant_id``
|
|
10
|
+
|
|
11
|
+
Purely additive and idempotent (``if_not_exists``): safe on a database
|
|
12
|
+
where someone already created them by hand. The fourth drift item,
|
|
13
|
+
``codex_chunk.idx_codex_chunk_embedding``, is deliberately NOT here —
|
|
14
|
+
codex is moving to kirby-codex.
|
|
15
|
+
|
|
16
|
+
Revision ID: 20261005_0001
|
|
17
|
+
Revises: 20260918_0002
|
|
18
|
+
Create Date: 2026-10-05
|
|
19
|
+
"""
|
|
20
|
+
from alembic import op
|
|
21
|
+
|
|
22
|
+
revision = "20261005_0001"
|
|
23
|
+
down_revision = "20260918_0002"
|
|
24
|
+
branch_labels = None
|
|
25
|
+
depends_on = None
|
|
26
|
+
|
|
27
|
+
_INDEXES = (
|
|
28
|
+
("ix_knowledge_link_campaign_id", "knowledge_link", "campaign_id"),
|
|
29
|
+
("ix_knowledge_link_tenant_id", "knowledge_link", "tenant_id"),
|
|
30
|
+
("ix_knowledge_unlock_tenant_id", "knowledge_unlock", "tenant_id"),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def upgrade() -> None:
|
|
35
|
+
for name, table, column in _INDEXES:
|
|
36
|
+
op.create_index(name, table, [column], if_not_exists=True)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def downgrade() -> None:
|
|
40
|
+
for name, table, _column in _INDEXES:
|
|
41
|
+
op.drop_index(name, table_name=table, if_exists=True)
|
|
@@ -13,7 +13,7 @@ from __future__ import annotations
|
|
|
13
13
|
import json
|
|
14
14
|
import logging
|
|
15
15
|
|
|
16
|
-
from kirby_ai import GenerationClient,
|
|
16
|
+
from kirby_ai import GenerationClient, extract_json_array
|
|
17
17
|
|
|
18
18
|
from kirby.settings import settings
|
|
19
19
|
|
|
@@ -27,26 +27,11 @@ not the game mechanic. Emit ONLY the JSON array, no prose."""
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def _extract_json_array(raw: str) -> list:
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
The sibling ``kirby_ai.extract_json_object`` handles objects; this is its
|
|
33
|
-
array counterpart — kirby-ai has no array extractor. Falls back to
|
|
34
|
-
slicing the outermost brackets so a model that wraps the array in prose
|
|
35
|
-
still parses.
|
|
36
|
-
"""
|
|
37
|
-
text = strip_code_fences(raw)
|
|
30
|
+
"""The model's slug array, or ``[]`` when there is none to find."""
|
|
38
31
|
try:
|
|
39
|
-
|
|
32
|
+
return extract_json_array(raw)
|
|
40
33
|
except json.JSONDecodeError:
|
|
41
|
-
|
|
42
|
-
if s != -1 and e != -1 and e > s:
|
|
43
|
-
try:
|
|
44
|
-
v = json.loads(text[s:e + 1])
|
|
45
|
-
except json.JSONDecodeError:
|
|
46
|
-
return []
|
|
47
|
-
else:
|
|
48
|
-
return []
|
|
49
|
-
return v if isinstance(v, list) else []
|
|
34
|
+
return []
|
|
50
35
|
|
|
51
36
|
|
|
52
37
|
def extract_category_slugs(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""``HeroCombatant.from_db()``
|
|
1
|
+
"""``HeroCombatant.from_db()`` — a stored build becomes a combatant.
|
|
2
2
|
|
|
3
3
|
These helpers attach to (rather than monkey-patch into)
|
|
4
4
|
``kirby_combat.hero_view``. The reason: hero_view.py lives in the
|
|
@@ -18,12 +18,7 @@ from uuid import UUID
|
|
|
18
18
|
|
|
19
19
|
from sqlalchemy.orm import Session
|
|
20
20
|
|
|
21
|
-
from kirby_combat.hero_view import
|
|
22
|
-
HeroCombatant,
|
|
23
|
-
HeroCombatState,
|
|
24
|
-
_compute_stats_from_hero,
|
|
25
|
-
)
|
|
26
|
-
from kirby_combat.models import Combatant
|
|
21
|
+
from kirby_combat.hero_view import HeroCombatant
|
|
27
22
|
|
|
28
23
|
from kirby.builds.build_doc_store import build_doc_from_rows
|
|
29
24
|
from kirby.characters.models import CharacterDef
|
|
@@ -82,17 +77,11 @@ def hero_combatant_from_build_doc(
|
|
|
82
77
|
if id is None:
|
|
83
78
|
id = (hero.name.lower().replace(" ", "_") if hero.name
|
|
84
79
|
else str(fallback_id))
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
current_stun=stats.max_stun,
|
|
91
|
-
current_body=stats.max_body,
|
|
92
|
-
current_end=stats.max_end,
|
|
93
|
-
),
|
|
94
|
-
knockback_resistance=0,
|
|
95
|
-
)
|
|
80
|
+
# The engine's own door, not a copy of it: this used to construct the
|
|
81
|
+
# HeroCombatant here from the engine's PRIVATE `_compute_stats_from_hero`,
|
|
82
|
+
# agreeing with `from_build` only because the two happen to call the same
|
|
83
|
+
# function today.
|
|
84
|
+
return HeroCombatant.from_build(hero, id=id)
|
|
96
85
|
|
|
97
86
|
|
|
98
87
|
def hero_combatant_from_db(
|
|
@@ -116,65 +105,3 @@ def hero_combatant_from_db(
|
|
|
116
105
|
source=f"character {character_id}",
|
|
117
106
|
)
|
|
118
107
|
|
|
119
|
-
|
|
120
|
-
def to_legacy_combatant(hc: HeroCombatant) -> Combatant:
|
|
121
|
-
"""Convert a HeroCombatant to the legacy flat ``Combatant`` shape.
|
|
122
|
-
|
|
123
|
-
DEPRECATED as of 2026-05-02 (combatant-redesign step 4 complete).
|
|
124
|
-
The engine now accepts HeroCombatant directly via the uniform
|
|
125
|
-
``combat_stats()`` / flat-property interface added by step 6.
|
|
126
|
-
Pass ``HeroCombatant`` straight into ``AttackInput``; the engine
|
|
127
|
-
handles either shape.
|
|
128
|
-
|
|
129
|
-
Kept for backward compatibility with callers that haven't migrated.
|
|
130
|
-
Will be removed in a future kirby-api release.
|
|
131
|
-
"""
|
|
132
|
-
s = hc.combat_stats()
|
|
133
|
-
defs = hc.defense_view()
|
|
134
|
-
attacks = []
|
|
135
|
-
attack_xmlids = {"ENERGYBLAST", "RKA", "HKA", "EGOATTACK",
|
|
136
|
-
"MENTALBLAST", "KILLINGATTACKRANGED",
|
|
137
|
-
"KILLINGATTACKHTH"}
|
|
138
|
-
seen_xmlids: set[str] = set()
|
|
139
|
-
|
|
140
|
-
def _collect_attacks(power_list) -> None:
|
|
141
|
-
"""Walk top-level + nested (multipower/VPP slot) powers."""
|
|
142
|
-
for p in power_list or []:
|
|
143
|
-
x = (getattr(p, "xmlid", None) or "").upper()
|
|
144
|
-
if x in attack_xmlids and x not in seen_xmlids:
|
|
145
|
-
# attack_view picks the first match by xmlid; if a
|
|
146
|
-
# combatant has multiple ENERGYBLASTs we still get
|
|
147
|
-
# only the first slot. That's fine for the v1 demo;
|
|
148
|
-
# step 3 wires slot_xmlid for proper Multipower
|
|
149
|
-
# selection.
|
|
150
|
-
try:
|
|
151
|
-
attacks.append(hc.attack_view(p.xmlid))
|
|
152
|
-
seen_xmlids.add(x)
|
|
153
|
-
except ValueError:
|
|
154
|
-
pass
|
|
155
|
-
# Recurse into sub_powers — Multipower / VPP slots live here.
|
|
156
|
-
sub = getattr(p, "sub_powers", None)
|
|
157
|
-
if sub:
|
|
158
|
-
_collect_attacks(sub)
|
|
159
|
-
|
|
160
|
-
_collect_attacks(hc.hero.powers) # type: ignore[union-attr]
|
|
161
|
-
name = (
|
|
162
|
-
getattr(hc.hero, "name", None) or hc.id
|
|
163
|
-
)
|
|
164
|
-
return Combatant(
|
|
165
|
-
id=hc.id,
|
|
166
|
-
name=name,
|
|
167
|
-
ocv=s.ocv, dcv=s.dcv, omcv=s.omcv, dmcv=s.dmcv,
|
|
168
|
-
spd=s.spd,
|
|
169
|
-
dex=s.dex, ego=s.ego, str_=s.str_, con=s.con, pre=s.pre, rec=s.rec,
|
|
170
|
-
pd=s.pd, ed=s.ed,
|
|
171
|
-
rpd=s.rpd, red=s.red, md=s.md,
|
|
172
|
-
power_defense=s.power_defense, flash_defense=s.flash_defense,
|
|
173
|
-
max_stun=s.max_stun, max_body=s.max_body, max_end=s.max_end,
|
|
174
|
-
current_stun=hc.state.current_stun,
|
|
175
|
-
current_body=hc.state.current_body,
|
|
176
|
-
current_end=hc.state.current_end,
|
|
177
|
-
attacks=attacks,
|
|
178
|
-
defenses=defs,
|
|
179
|
-
knockback_resistance=hc.knockback_resistance,
|
|
180
|
-
)
|
|
@@ -219,40 +219,3 @@ def get_power_tree(db: Session, power_root_object_id: int) -> dict[str, Any] | N
|
|
|
219
219
|
|
|
220
220
|
|
|
221
221
|
# ── convenience: render a hit for prompt context ────────────────────────────
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
def render_hit_for_prompt(
|
|
225
|
-
db: Session,
|
|
226
|
-
hit: PowerLibraryHit,
|
|
227
|
-
*,
|
|
228
|
-
include_tree: bool = False,
|
|
229
|
-
) -> str:
|
|
230
|
-
"""Format one hit as a prompt-ready block. Pass 1 typically uses
|
|
231
|
-
``include_tree=False`` (prose + tags only); Pass 2 uses
|
|
232
|
-
``include_tree=True`` to give the structured-output model the exact
|
|
233
|
-
JSON shape it should produce.
|
|
234
|
-
"""
|
|
235
|
-
parts: list[str] = []
|
|
236
|
-
parts.append(f"## {hit.name}")
|
|
237
|
-
if hit.base_name and hit.base_name != hit.name:
|
|
238
|
-
parts.append(f" (variant of {hit.base_name})")
|
|
239
|
-
tags = ", ".join(hit.sfx_tags + hit.mechanical_tags)
|
|
240
|
-
parts.append(f" Tags: {tags}")
|
|
241
|
-
ap = f"{hit.active_cost}" if hit.active_cost is not None else "?"
|
|
242
|
-
rc = f"{hit.real_cost}" if hit.real_cost is not None else "?"
|
|
243
|
-
parts.append(f" Active: {ap} Real: {rc} Kind: {hit.kind}")
|
|
244
|
-
if hit.description:
|
|
245
|
-
snippet = hit.description.strip()
|
|
246
|
-
if len(snippet) > 1200:
|
|
247
|
-
snippet = snippet[:1200].rsplit(" ", 1)[0] + "…"
|
|
248
|
-
parts.append("")
|
|
249
|
-
parts.append(snippet)
|
|
250
|
-
|
|
251
|
-
if include_tree:
|
|
252
|
-
import json
|
|
253
|
-
tree = get_power_tree(db, hit.power_root_object_id)
|
|
254
|
-
parts.append("")
|
|
255
|
-
parts.append("```json")
|
|
256
|
-
parts.append(json.dumps(tree, indent=2, default=str))
|
|
257
|
-
parts.append("```")
|
|
258
|
-
return "\n".join(parts)
|
|
@@ -28,12 +28,11 @@ section/paragraph they came from.
|
|
|
28
28
|
from __future__ import annotations
|
|
29
29
|
|
|
30
30
|
import json
|
|
31
|
-
import re
|
|
32
31
|
from dataclasses import asdict, dataclass, field
|
|
33
32
|
from typing import Any, Optional
|
|
34
33
|
from uuid import UUID
|
|
35
34
|
|
|
36
|
-
from kirby_ai import GenerationClient
|
|
35
|
+
from kirby_ai import GenerationClient, extract_json_array
|
|
37
36
|
from sqlalchemy.orm import Session
|
|
38
37
|
|
|
39
38
|
from kirby.settings import settings
|
|
@@ -123,48 +122,17 @@ def parse_drafts_json(raw: str) -> list[ExtractedDraft]:
|
|
|
123
122
|
|
|
124
123
|
Tolerant of:
|
|
125
124
|
- Markdown code fences around the JSON (strip them)
|
|
126
|
-
-
|
|
125
|
+
- Prose on either side of the array (kirby_ai.extract_json_array)
|
|
127
126
|
- Individual draft items missing optional fields
|
|
128
127
|
|
|
129
128
|
Returns the drafts that parsed cleanly. Skips malformed entries
|
|
130
129
|
rather than failing the whole import.
|
|
131
130
|
"""
|
|
132
|
-
cleaned = raw.strip()
|
|
133
|
-
# Strip markdown fences
|
|
134
|
-
if cleaned.startswith("```"):
|
|
135
|
-
cleaned = re.sub(r"^```(?:json)?\s*", "", cleaned)
|
|
136
|
-
cleaned = re.sub(r"\s*```\s*$", "", cleaned)
|
|
137
|
-
cleaned = cleaned.strip()
|
|
138
|
-
|
|
139
|
-
# Find the first balanced [...] in the string. The LLM occasionally
|
|
140
|
-
# emits trailing chatter; bracket-counting locates the canonical array.
|
|
141
|
-
start = cleaned.find("[")
|
|
142
|
-
if start < 0:
|
|
143
|
-
return []
|
|
144
|
-
|
|
145
|
-
depth = 0
|
|
146
|
-
end = -1
|
|
147
|
-
for i in range(start, len(cleaned)):
|
|
148
|
-
c = cleaned[i]
|
|
149
|
-
if c == "[":
|
|
150
|
-
depth += 1
|
|
151
|
-
elif c == "]":
|
|
152
|
-
depth -= 1
|
|
153
|
-
if depth == 0:
|
|
154
|
-
end = i + 1
|
|
155
|
-
break
|
|
156
|
-
if end < 0:
|
|
157
|
-
return []
|
|
158
|
-
|
|
159
|
-
json_str = cleaned[start:end]
|
|
160
131
|
try:
|
|
161
|
-
parsed =
|
|
132
|
+
parsed = extract_json_array(raw)
|
|
162
133
|
except json.JSONDecodeError:
|
|
163
134
|
return []
|
|
164
135
|
|
|
165
|
-
if not isinstance(parsed, list):
|
|
166
|
-
return []
|
|
167
|
-
|
|
168
136
|
drafts: list[ExtractedDraft] = []
|
|
169
137
|
for item in parsed:
|
|
170
138
|
if not isinstance(item, dict):
|
|
@@ -462,28 +462,27 @@ async def import_hdc(
|
|
|
462
462
|
content = await file.read()
|
|
463
463
|
filename = file.filename or "unknown.hdc"
|
|
464
464
|
|
|
465
|
-
#
|
|
466
|
-
#
|
|
467
|
-
#
|
|
468
|
-
#
|
|
469
|
-
#
|
|
470
|
-
#
|
|
471
|
-
|
|
465
|
+
# The canonical import: the engine loads and costs the file, the build is
|
|
466
|
+
# persisted relationally (so combat can load it), and the opening vitals
|
|
467
|
+
# are the engine's own (`HeroCombatant.from_build`, the same door a fight
|
|
468
|
+
# uses). This route used to run a private translator that built its own
|
|
469
|
+
# combatant -- base + CHARACTERISTICS levels only, so a character with
|
|
470
|
+
# Resistant Protection got rPD 0 -- kept only STUN/BODY/END from it, and
|
|
471
|
+
# never persisted the build at all, so combat refused the character.
|
|
472
|
+
from kirby.builds.build_doc_store import persist_loaded
|
|
473
|
+
from kirby.engines.cost.hdc import load_hdc
|
|
474
|
+
from kirby_combat.hero_view import HeroCombatant
|
|
472
475
|
|
|
473
476
|
try:
|
|
474
|
-
imported =
|
|
475
|
-
except
|
|
477
|
+
imported = load_hdc(content)
|
|
478
|
+
except Exception as exc:
|
|
476
479
|
raise HTTPException(
|
|
477
480
|
status_code=400,
|
|
478
481
|
detail=f"Failed to parse HDC: {exc}",
|
|
479
482
|
)
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
# the combatant-derived transient state stays None and the row
|
|
484
|
-
# can't be added to a session.
|
|
485
|
-
name = imported.name or filename.replace(".hdc", "").replace("_", " ")
|
|
486
|
-
cb = imported.combatant
|
|
483
|
+
hero = imported.hero
|
|
484
|
+
vitals = HeroCombatant.from_build(hero).state
|
|
485
|
+
name = (hero.name or "").strip() or filename.replace(".hdc", "").replace("_", " ")
|
|
487
486
|
|
|
488
487
|
char = CharacterDef(
|
|
489
488
|
tenant_id=tid,
|
|
@@ -491,14 +490,15 @@ async def import_hdc(
|
|
|
491
490
|
name=name,
|
|
492
491
|
hdc_filename=filename,
|
|
493
492
|
source="hdc_import",
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
current_end=cb.current_end if cb is not None else None,
|
|
493
|
+
# A file upload is a character; the GM marks NPCs as with any field.
|
|
494
|
+
is_npc=False,
|
|
495
|
+
current_stun=vitals.current_stun,
|
|
496
|
+
current_body=vitals.current_body,
|
|
497
|
+
current_end=vitals.current_end,
|
|
500
498
|
)
|
|
501
499
|
db.add(char)
|
|
500
|
+
db.flush()
|
|
501
|
+
persist_loaded(db, char, hero)
|
|
502
502
|
db.commit()
|
|
503
503
|
db.refresh(char)
|
|
504
504
|
return char
|
|
@@ -7,10 +7,9 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
9
|
import logging
|
|
10
|
-
import re
|
|
11
10
|
from dataclasses import dataclass, field
|
|
12
11
|
|
|
13
|
-
from kirby_ai import GenerationClient
|
|
12
|
+
from kirby_ai import GenerationClient, extract_json_object
|
|
14
13
|
|
|
15
14
|
from kirby.settings import settings
|
|
16
15
|
|
|
@@ -78,16 +77,10 @@ minions", "Avoid melee with bricks") tied to a source_snippet quoted from the te
|
|
|
78
77
|
|
|
79
78
|
def _extract_json(raw: str) -> dict:
|
|
80
79
|
"""Pull the first JSON object out of model output (tolerates fences/prose)."""
|
|
81
|
-
fenced = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", raw, re.DOTALL)
|
|
82
|
-
candidate = fenced.group(1) if fenced else raw
|
|
83
|
-
start = candidate.find("{")
|
|
84
|
-
end = candidate.rfind("}")
|
|
85
|
-
if start == -1 or end == -1 or end < start:
|
|
86
|
-
raise ExtractionError(f"no JSON object in model output: {raw[:200]!r}")
|
|
87
80
|
try:
|
|
88
|
-
return
|
|
81
|
+
return extract_json_object(raw)
|
|
89
82
|
except json.JSONDecodeError as exc:
|
|
90
|
-
raise ExtractionError(f"
|
|
83
|
+
raise ExtractionError(f"no JSON object in model output: {raw[:200]!r}") from exc
|
|
91
84
|
|
|
92
85
|
|
|
93
86
|
def parse_villain_writeup(raw: str) -> VillainWriteup:
|
|
@@ -18,15 +18,13 @@ tables, its routes and its tests. What stands today:
|
|
|
18
18
|
runner's turn and step caps; its seeding and its
|
|
19
19
|
worker await the harness (plan C5)
|
|
20
20
|
|
|
21
|
-
``services/entity_service`` IS
|
|
22
|
-
characters
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
``
|
|
27
|
-
|
|
28
|
-
engine's rule vocabulary, turned on this SOURCE tree — so the next one
|
|
29
|
-
is caught rather than certified.
|
|
21
|
+
``services/entity_service`` IS GONE. It moved from here to
|
|
22
|
+
``kirby/characters/`` after the 2026-09-17 review found a parser, a classifier
|
|
23
|
+
and substituted 6E numbers inside it, and was deleted 2026-10-04: the HDC
|
|
24
|
+
upload now takes the canonical import (``load_hdc`` -> ``persist_loaded``) and
|
|
25
|
+
the engine's own ``HeroCombatant.from_build`` for its opening vitals.
|
|
26
|
+
``tests/combat/test_no_rules_here.py`` scans the WHOLE ``kirby/`` source tree
|
|
27
|
+
for rule numbers now, so moving a file out of ``combat/`` hides nothing.
|
|
30
28
|
|
|
31
29
|
``async_db`` IS NOT HERE ANY MORE EITHER. It was the deleted
|
|
32
30
|
``websocket.py``'s dependency, it had no consumer left anywhere in
|
|
@@ -7,15 +7,16 @@ Design mirrors codex:
|
|
|
7
7
|
comic_character, comic_storyarc, comic_chunk,
|
|
8
8
|
comic_archetype, comic_book_tenant)
|
|
9
9
|
services/
|
|
10
|
-
comic_vine.py — async Comic Vine API client (port from
|
|
11
|
-
comic-mcp standalone)
|
|
12
10
|
archetypes.py — YAML loader → DB sync, tenant-scoped
|
|
13
|
-
prewarm.py — pre-warm pipeline; tenant + group aware
|
|
14
11
|
search.py — cosine search over comic_chunk + retrieval
|
|
15
12
|
helpers used by brain.py
|
|
16
13
|
routes.py — FastAPI routes for archetype CRUD + cache stats
|
|
17
14
|
schemas.py — Pydantic schemas
|
|
18
15
|
|
|
16
|
+
The Comic Vine client and pre-warm pipeline were removed 2026-10-04: nothing
|
|
17
|
+
imported them. Their live home is the standalone comic-mcp
|
|
18
|
+
(`comic_mcp/{comic_vine,prewarm,text_clean}.py`).
|
|
19
|
+
|
|
19
20
|
Tenant pattern: comic_book_tenant junction grants tenant access to
|
|
20
21
|
specific Comic Vine resources, paralleling codex_book_tenant. Tenants
|
|
21
22
|
inherit a universal-baseline archetype set and can author their own
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kirby-api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Kirby — HERO System VTT backend API (FastAPI mono)
|
|
5
5
|
Author: PeterB
|
|
6
6
|
License: PolyForm Noncommercial License 1.0.0
|
|
@@ -32,7 +32,7 @@ Requires-Dist: pgvector>=0.3
|
|
|
32
32
|
Requires-Dist: pypdfium2>=4.30
|
|
33
33
|
Requires-Dist: kirby-combat==0.18.5
|
|
34
34
|
Requires-Dist: kirby-dice>=0.1.0
|
|
35
|
-
Requires-Dist: kirby-ai>=0.
|
|
35
|
+
Requires-Dist: kirby-ai>=0.7.0
|
|
36
36
|
Requires-Dist: prometheus-client>=0.21
|
|
37
37
|
Requires-Dist: prometheus-fastapi-instrumentator>=7.0
|
|
38
38
|
Requires-Dist: tenacity>=8.0
|
|
@@ -105,6 +105,7 @@ kirby/_migrations/versions/20260917_0001_session_names_a_seat.py
|
|
|
105
105
|
kirby/_migrations/versions/20260918_0000_drop_combat_tables.py
|
|
106
106
|
kirby/_migrations/versions/20260918_0001_harness_tables.py
|
|
107
107
|
kirby/_migrations/versions/20260918_0002_narration_speaker_id.py
|
|
108
|
+
kirby/_migrations/versions/20261005_0001_knowledge_indexes.py
|
|
108
109
|
kirby/_migrations/versions/21980c836860_add_asset_id_refs.py
|
|
109
110
|
kirby/_migrations/versions/ba28e71c955d_codex_init.py
|
|
110
111
|
kirby/admin/__init__.py
|
|
@@ -121,8 +122,6 @@ kirby/builds/category_extraction.py
|
|
|
121
122
|
kirby/builds/cli.py
|
|
122
123
|
kirby/builds/codex_linker.py
|
|
123
124
|
kirby/builds/combatant_loader.py
|
|
124
|
-
kirby/builds/concept_to_build.py
|
|
125
|
-
kirby/builds/hdc_exporter.py
|
|
126
125
|
kirby/builds/importer.py
|
|
127
126
|
kirby/builds/json_exporter.py
|
|
128
127
|
kirby/builds/json_importer.py
|
|
@@ -171,7 +170,6 @@ kirby/characters/proposals/service.py
|
|
|
171
170
|
kirby/characters/services/__init__.py
|
|
172
171
|
kirby/characters/services/character_info_backfill.py
|
|
173
172
|
kirby/characters/services/effective.py
|
|
174
|
-
kirby/characters/services/entity_service.py
|
|
175
173
|
kirby/characters/services/writeup_persistence.py
|
|
176
174
|
kirby/codex/__init__.py
|
|
177
175
|
kirby/codex/cli.py
|
|
@@ -215,10 +213,7 @@ kirby/comic_canon/models.py
|
|
|
215
213
|
kirby/comic_canon/routes.py
|
|
216
214
|
kirby/comic_canon/services/__init__.py
|
|
217
215
|
kirby/comic_canon/services/archetypes.py
|
|
218
|
-
kirby/comic_canon/services/comic_vine.py
|
|
219
216
|
kirby/comic_canon/services/embeddings.py
|
|
220
|
-
kirby/comic_canon/services/prewarm.py
|
|
221
|
-
kirby/comic_canon/services/text_clean.py
|
|
222
217
|
kirby/engines/__init__.py
|
|
223
218
|
kirby/engines/cost/__init__.py
|
|
224
219
|
kirby/engines/cost/hdc.py
|
|
@@ -249,6 +244,7 @@ kirby_api.egg-info/dependency_links.txt
|
|
|
249
244
|
kirby_api.egg-info/entry_points.txt
|
|
250
245
|
kirby_api.egg-info/requires.txt
|
|
251
246
|
kirby_api.egg-info/top_level.txt
|
|
247
|
+
tests/test_knowledge_indexes_migration.py
|
|
252
248
|
tests/test_public_vocabulary.py
|
|
253
249
|
tests/test_teardown.py
|
|
254
250
|
tests/test_wheel_contents.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "kirby-api"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.2"
|
|
4
4
|
description = "Kirby — HERO System VTT backend API (FastAPI mono)"
|
|
5
5
|
# Published to public PyPI. Every runtime dependency below resolves from
|
|
6
6
|
# public PyPI too — kirby-cost, kirby-combat, kirby-dice and kirby-ai all
|
|
@@ -196,9 +196,7 @@ dependencies = [
|
|
|
196
196
|
# better a public `EVENT_KINDS` mapping the engine owns and both
|
|
197
197
|
# repos read (it already builds one to key its own serializer).
|
|
198
198
|
# When that lands, `events.py` reads the public name and this goes
|
|
199
|
-
# back to `>=`.
|
|
200
|
-
# against kirby-cost (`from kirby_cost.io.build_json import
|
|
201
|
-
# _root_from_doc`) and wants the same ask.
|
|
199
|
+
# back to `>=`.
|
|
202
200
|
"kirby-combat==0.18.5",
|
|
203
201
|
|
|
204
202
|
# The dice roller left kirby-combat at 0.10.0 for its own package, so
|
|
@@ -217,7 +215,7 @@ dependencies = [
|
|
|
217
215
|
# `AttributeError` inside a fight — and every earlier version silently
|
|
218
216
|
# substitutes `FirstLegalChooser`, which is a model playing on without
|
|
219
217
|
# having answered. `IntentChooser` also arrives in 0.3.0.
|
|
220
|
-
"kirby-ai>=0.
|
|
218
|
+
"kirby-ai>=0.7.0",
|
|
221
219
|
"prometheus-client>=0.21",
|
|
222
220
|
"prometheus-fastapi-instrumentator>=7.0",
|
|
223
221
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""The knowledge indexes the models declare must exist after migrating."""
|
|
2
|
+
import pytest
|
|
3
|
+
from sqlalchemy import text
|
|
4
|
+
|
|
5
|
+
from kirby.shared.db import SessionLocal
|
|
6
|
+
|
|
7
|
+
EXPECTED = {
|
|
8
|
+
("knowledge_link", "ix_knowledge_link_campaign_id"),
|
|
9
|
+
("knowledge_link", "ix_knowledge_link_tenant_id"),
|
|
10
|
+
("knowledge_unlock", "ix_knowledge_unlock_tenant_id"),
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_knowledge_indexes_exist():
|
|
15
|
+
db = SessionLocal()
|
|
16
|
+
try:
|
|
17
|
+
if db.get_bind().dialect.name != "postgresql":
|
|
18
|
+
pytest.skip("pg_indexes needs Postgres")
|
|
19
|
+
rows = db.execute(
|
|
20
|
+
text(
|
|
21
|
+
"SELECT tablename, indexname FROM pg_indexes "
|
|
22
|
+
"WHERE indexname = ANY(:names)"
|
|
23
|
+
),
|
|
24
|
+
{"names": [n for _, n in EXPECTED]},
|
|
25
|
+
).all()
|
|
26
|
+
assert {tuple(r) for r in rows} == EXPECTED
|
|
27
|
+
finally:
|
|
28
|
+
db.close()
|