rosett-ai 1.3.3 → 1.5.9
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +398 -22
- data/README.md +56 -42
- data/bin/raictl +13 -0
- data/conf/adopt_redactions.yml +2 -0
- data/conf/compliance/cra_rules.yml +2 -0
- data/conf/compliance/license_rules.yml +2 -0
- data/conf/mcp/server_defaults.yml +2 -0
- data/conf/mcp/trust.yml +1 -0
- data/conf/packaging/core.yml +2 -0
- data/conf/packaging/gtk4.yml +2 -0
- data/conf/packaging/qt6.yml +2 -0
- data/conf/policy/default_deny_list.yml +2 -0
- data/conf/review/cli-command-audit.yml +2 -0
- data/conf/review/design-docs.yml +2 -0
- data/conf/review/design-questionnaire.yml +2 -0
- data/conf/review/questionnaire.yml +2 -0
- data/conf/review/rosett-ai-core.yml +2 -0
- data/conf/schemas/ai_config_schema.json +14 -2
- data/conf/schemas/autoqueue.schema.json +153 -0
- data/conf/schemas/behaviour_schema.json +31 -7
- data/conf/schemas/compliance_rule_schema.json +17 -4
- data/conf/schemas/content_pack_manifest_schema.json +23 -4
- data/conf/schemas/design_schema.json +177 -42
- data/conf/schemas/engine_manifest_schema.json +22 -5
- data/conf/schemas/lockfile_schema.json +26 -4
- data/conf/schemas/mcp_server_schema.json +50 -9
- data/conf/schemas/packaging_schema.json +23 -5
- data/conf/schemas/policy_schema.json +35 -9
- data/conf/schemas/provenance_schema.json +33 -5
- data/conf/schemas/rai_config_schema.json +6 -2
- data/conf/schemas/rai_project_schema.json +8 -2
- data/conf/schemas/scope_hierarchy_schema.json +22 -5
- data/conf/schemas/target_schema.json +33 -6
- data/conf/schemas/tooling_schema.json +53 -12
- data/conf/schemas/workflow_schema.json +39 -9
- data/conf/targets/agents_md.yml +1 -0
- data/conf/targets/claude.yml +2 -0
- data/conf/tooling/tools.yml +2 -0
- data/lib/rosett_ai/adopter/local_analysis_collector.rb +5 -0
- data/lib/rosett_ai/adopter/rule_adopter.rb +40 -0
- data/lib/rosett_ai/ai_config/context_window.rb +3 -0
- data/lib/rosett_ai/ai_config/cost_controls.rb +1 -0
- data/lib/rosett_ai/ai_config/fallback_chain.rb +1 -0
- data/lib/rosett_ai/ai_config/model_router.rb +1 -0
- data/lib/rosett_ai/ai_config/validator.rb +2 -0
- data/lib/rosett_ai/authorship/attribution_compiler.rb +1 -0
- data/lib/rosett_ai/authorship/disclosure_policy.rb +2 -0
- data/lib/rosett_ai/authorship/review_validator.rb +1 -0
- data/lib/rosett_ai/authorship/trailer_generator.rb +1 -0
- data/lib/rosett_ai/backup/compressor.rb +3 -0
- data/lib/rosett_ai/backup/destination.rb +1 -0
- data/lib/rosett_ai/behaviour/manager.rb +1 -0
- data/lib/rosett_ai/compiler/backend.rb +3 -0
- data/lib/rosett_ai/compiler/backends/agents_md_backend.rb +1 -0
- data/lib/rosett_ai/compiler/backends/claude_backend.rb +1 -0
- data/lib/rosett_ai/compiler/behaviour_compiler.rb +1 -0
- data/lib/rosett_ai/compiler/compilation_pipeline.rb +1 -7
- data/lib/rosett_ai/compiler/locale_compiler.rb +2 -0
- data/lib/rosett_ai/compiler/target_profile.rb +11 -0
- data/lib/rosett_ai/completion/generator.rb +2 -0
- data/lib/rosett_ai/completion/shells/zsh_generator.rb +1 -0
- data/lib/rosett_ai/comply/checkers/cra_checker.rb +1 -0
- data/lib/rosett_ai/comply/checkers/license_checker.rb +2 -0
- data/lib/rosett_ai/comply/checkers/spdx_header_checker.rb +4 -0
- data/lib/rosett_ai/comply/runner.rb +2 -0
- data/lib/rosett_ai/composition/composer.rb +1 -0
- data/lib/rosett_ai/composition/lockfile.rb +1 -0
- data/lib/rosett_ai/composition/merge_strategy.rb +1 -0
- data/lib/rosett_ai/config/masking_secret_resolver.rb +9 -0
- data/lib/rosett_ai/config/secret_resolver.rb +4 -0
- data/lib/rosett_ai/configuration.rb +4 -0
- data/lib/rosett_ai/content/content_client.rb +15 -0
- data/lib/rosett_ai/content/pack_installer.rb +1 -0
- data/lib/rosett_ai/content/pack_manifest.rb +21 -0
- data/lib/rosett_ai/content_packs/manager.rb +1 -0
- data/lib/rosett_ai/dbus/compositor_detector.rb +2 -0
- data/lib/rosett_ai/dbus/focus_adapters/base.rb +1 -0
- data/lib/rosett_ai/dbus/focus_adapters/gnome_adapter.rb +5 -0
- data/lib/rosett_ai/dbus/focus_adapters/hyprland_adapter.rb +4 -0
- data/lib/rosett_ai/dbus/focus_adapters/i3_adapter.rb +4 -0
- data/lib/rosett_ai/dbus/focus_adapters/kwin_adapter.rb +4 -0
- data/lib/rosett_ai/dbus/focus_adapters/x11_adapter.rb +4 -0
- data/lib/rosett_ai/dbus/focus_monitor_interface.rb +1 -0
- data/lib/rosett_ai/dbus/manager_interface.rb +1 -0
- data/lib/rosett_ai/dbus/plugin_manager_interface.rb +2 -0
- data/lib/rosett_ai/dbus/rate_limiter.rb +1 -0
- data/lib/rosett_ai/dbus/service.rb +3 -0
- data/lib/rosett_ai/dbus/status_notifier_interface.rb +14 -0
- data/lib/rosett_ai/desktop/dbus_client.rb +6 -0
- data/lib/rosett_ai/desktop/gtk4_app.rb +3 -0
- data/lib/rosett_ai/desktop/gtk4_preferences.rb +1 -0
- data/lib/rosett_ai/desktop/gui_logger.rb +2 -0
- data/lib/rosett_ai/doctor/check.rb +1 -1
- data/lib/rosett_ai/doctor/checks/cache_health_check.rb +1 -0
- data/lib/rosett_ai/doctor.rb +1 -0
- data/lib/rosett_ai/documentation/reference_compiler.rb +9 -0
- data/lib/rosett_ai/documentation/translator.rb +8 -0
- data/lib/rosett_ai/engines/base_config_compiler.rb +71 -1
- data/lib/rosett_ai/engines/detector.rb +5 -0
- data/lib/rosett_ai/engines/registry.rb +7 -0
- data/lib/rosett_ai/exit_codes.rb +6 -0
- data/lib/rosett_ai/formatting.rb +1 -0
- data/lib/rosett_ai/gem_consistency_checker.rb +6 -0
- data/lib/rosett_ai/git_hooks/chain_detector.rb +1 -0
- data/lib/rosett_ai/git_hooks/installer.rb +4 -0
- data/lib/rosett_ai/git_hooks/script_generator.rb +2 -0
- data/lib/rosett_ai/gitlab/validators/supplementary_gitlab_ci_yaml_validator.rb +6 -0
- data/lib/rosett_ai/i18n/utf8_checker.rb +1 -0
- data/lib/rosett_ai/init/config_file_writer.rb +4 -0
- data/lib/rosett_ai/init/directory_builder.rb +15 -0
- data/lib/rosett_ai/init/file_copier.rb +51 -0
- data/lib/rosett_ai/init/mcp_registrar.rb +1 -0
- data/lib/rosett_ai/init/project_initializer.rb +1 -0
- data/lib/rosett_ai/licensing/license_key.rb +4 -0
- data/lib/rosett_ai/licensing/license_store.rb +11 -0
- data/lib/rosett_ai/licensing/tier.rb +9 -0
- data/lib/rosett_ai/mcp/admin/auditor.rb +1 -0
- data/lib/rosett_ai/mcp/admin/health_checker.rb +1 -0
- data/lib/rosett_ai/mcp/admin/registry.rb +1 -0
- data/lib/rosett_ai/mcp/enforcement/hook_generator.rb +27 -4
- data/lib/rosett_ai/mcp/enforcement/validator.rb +24 -3
- data/lib/rosett_ai/mcp/governance.rb +9 -0
- data/lib/rosett_ai/mcp/http_security_config.rb +22 -0
- data/lib/rosett_ai/mcp/key_hasher.rb +4 -2
- data/lib/rosett_ai/mcp/keyfile.rb +4 -0
- data/lib/rosett_ai/mcp/middleware/cors.rb +4 -0
- data/lib/rosett_ai/mcp/middleware/origin_validation.rb +1 -0
- data/lib/rosett_ai/mcp/middleware/rate_limit.rb +3 -0
- data/lib/rosett_ai/mcp/plugins.rb +1 -0
- data/lib/rosett_ai/mcp/prompts/compilation_prompt.rb +2 -0
- data/lib/rosett_ai/mcp/prompts/compliance_prompt.rb +3 -0
- data/lib/rosett_ai/mcp/prompts/diagnostics_prompt.rb +2 -0
- data/lib/rosett_ai/mcp/prompts/validation_prompt.rb +2 -0
- data/lib/rosett_ai/mcp/resources/behaviour_resource.rb +2 -0
- data/lib/rosett_ai/mcp/resources/config_resource.rb +2 -0
- data/lib/rosett_ai/mcp/resources/design_resource.rb +1 -0
- data/lib/rosett_ai/mcp/resources/hooks_resource.rb +3 -0
- data/lib/rosett_ai/mcp/resources/provenance_resource.rb +2 -0
- data/lib/rosett_ai/mcp/resources/rules_resource.rb +1 -0
- data/lib/rosett_ai/mcp/resources/schema_resource.rb +1 -0
- data/lib/rosett_ai/mcp/server.rb +7 -1
- data/lib/rosett_ai/mcp/settings/trust_manager.rb +3 -0
- data/lib/rosett_ai/mcp/tools/adopt_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/backup_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/behaviour_display_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/behaviour_list_tool.rb +3 -0
- data/lib/rosett_ai/mcp/tools/behaviour_manage_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/behaviour_show_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/compile_status_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/compile_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/comply_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/config_compile_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/config_status_tool.rb +3 -0
- data/lib/rosett_ai/mcp/tools/content_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/context_query_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/design_list_tool.rb +3 -0
- data/lib/rosett_ai/mcp/tools/design_show_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/doctor_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/documentation_status_tool.rb +3 -0
- data/lib/rosett_ai/mcp/tools/engines_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/hook_install_tool.rb +7 -0
- data/lib/rosett_ai/mcp/tools/hook_preview_tool.rb +33 -8
- data/lib/rosett_ai/mcp/tools/hooks_status_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/init_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/license_status_tool.rb +3 -0
- data/lib/rosett_ai/mcp/tools/project_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/provenance_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/provenance_write_tool.rb +3 -0
- data/lib/rosett_ai/mcp/tools/retrofit_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/rule_search_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/schema_get_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/tooling_tool.rb +5 -0
- data/lib/rosett_ai/mcp/tools/validate_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/workflow_execute_tool.rb +4 -0
- data/lib/rosett_ai/mcp/tools/workflow_tool.rb +5 -0
- data/lib/rosett_ai/migration/detector.rb +1 -0
- data/lib/rosett_ai/migration/nncc_config_migrator.rb +2 -0
- data/lib/rosett_ai/migration/xdg_migrator.rb +3 -1
- data/lib/rosett_ai/package_manager/apt.rb +5 -0
- data/lib/rosett_ai/package_manager/base.rb +1 -0
- data/lib/rosett_ai/package_manager/gem_backend.rb +1 -0
- data/lib/rosett_ai/packaging/variant_config.rb +12 -0
- data/lib/rosett_ai/plugins/contract.rb +1 -0
- data/lib/rosett_ai/plugins/engine_contract.rb +2 -0
- data/lib/rosett_ai/plugins/gui_contract.rb +2 -0
- data/lib/rosett_ai/plugins/mcp_contract.rb +2 -0
- data/lib/rosett_ai/plugins/registry.rb +10 -0
- data/lib/rosett_ai/policy/auditor.rb +1 -0
- data/lib/rosett_ai/policy/opt_out_scanner.rb +1 -0
- data/lib/rosett_ai/policy/tier_hierarchy.rb +2 -0
- data/lib/rosett_ai/policy/validator.rb +1 -0
- data/lib/rosett_ai/profiler.rb +7 -0
- data/lib/rosett_ai/project/drift_detector.rb +1 -0
- data/lib/rosett_ai/project/manager.rb +1 -0
- data/lib/rosett_ai/project/template_applier.rb +1 -0
- data/lib/rosett_ai/provenance/entry.rb +2 -0
- data/lib/rosett_ai/provenance/source.rb +1 -0
- data/lib/rosett_ai/provenance/store.rb +3 -0
- data/lib/rosett_ai/provenance/validator.rb +1 -0
- data/lib/rosett_ai/quorum/collector.rb +1 -0
- data/lib/rosett_ai/quorum/comparator.rb +2 -0
- data/lib/rosett_ai/quorum/strategies/adopt.rb +1 -0
- data/lib/rosett_ai/rai_config.rb +9 -0
- data/lib/rosett_ai/retrofit/engine.rb +2 -0
- data/lib/rosett_ai/retrofit/parsers/agents_md_parser.rb +8 -0
- data/lib/rosett_ai/retrofit/parsers/claude_parser.rb +10 -0
- data/lib/rosett_ai/retrofit/parsers/cursor_parser.rb +9 -0
- data/lib/rosett_ai/retrofit/secret_detector.rb +3 -0
- data/lib/rosett_ai/secrets_resolver.rb +1 -0
- data/lib/rosett_ai/session_hooks/installer.rb +130 -0
- data/lib/rosett_ai/smart_feedback/suggester.rb +4 -0
- data/lib/rosett_ai/smart_feedback/thor_middleware.rb +7 -0
- data/lib/rosett_ai/structured_logger.rb +1 -0
- data/lib/rosett_ai/telemetry/log_rotator.rb +1 -0
- data/lib/rosett_ai/telemetry.rb +1 -0
- data/lib/rosett_ai/thor/cli.rb +9 -0
- data/lib/rosett_ai/thor/tasks/adopt.rb +2 -0
- data/lib/rosett_ai/thor/tasks/backfill_user_yml.rb +207 -0
- data/lib/rosett_ai/thor/tasks/backup.rb +6 -0
- data/lib/rosett_ai/thor/tasks/behaviour.rb +12 -0
- data/lib/rosett_ai/thor/tasks/build.rb +87 -4
- data/lib/rosett_ai/thor/tasks/compile.rb +76 -32
- data/lib/rosett_ai/thor/tasks/completion.rb +9 -0
- data/lib/rosett_ai/thor/tasks/comply.rb +2 -0
- data/lib/rosett_ai/thor/tasks/config.rb +21 -5
- data/lib/rosett_ai/thor/tasks/content.rb +8 -0
- data/lib/rosett_ai/thor/tasks/dbus.rb +13 -0
- data/lib/rosett_ai/thor/tasks/design.rb +2 -0
- data/lib/rosett_ai/thor/tasks/desktop.rb +4 -0
- data/lib/rosett_ai/thor/tasks/doctor.rb +2 -0
- data/lib/rosett_ai/thor/tasks/documentation.rb +7 -0
- data/lib/rosett_ai/thor/tasks/engines.rb +8 -0
- data/lib/rosett_ai/thor/tasks/hooks.rb +8 -0
- data/lib/rosett_ai/thor/tasks/init.rb +1 -0
- data/lib/rosett_ai/thor/tasks/license.rb +8 -0
- data/lib/rosett_ai/thor/tasks/mcp.rb +40 -0
- data/lib/rosett_ai/thor/tasks/migrate.rb +2 -0
- data/lib/rosett_ai/thor/tasks/plugins.rb +15 -0
- data/lib/rosett_ai/thor/tasks/project.rb +8 -0
- data/lib/rosett_ai/thor/tasks/provenance.rb +8 -0
- data/lib/rosett_ai/thor/tasks/release.rb +8 -0
- data/lib/rosett_ai/thor/tasks/retrofit.rb +4 -0
- data/lib/rosett_ai/thor/tasks/validate.rb +1 -0
- data/lib/rosett_ai/thor/tasks/workflow.rb +14 -0
- data/lib/rosett_ai/tooling/version_checker.rb +1 -0
- data/lib/rosett_ai/ui/accessible_tui.rb +18 -0
- data/lib/rosett_ai/ui/base.rb +3 -0
- data/lib/rosett_ai/ui/gtk4.rb +19 -0
- data/lib/rosett_ai/ui/kde.rb +1 -0
- data/lib/rosett_ai/ui/qt6.rb +1 -0
- data/lib/rosett_ai/ui/registry.rb +15 -0
- data/lib/rosett_ai/ui/tui.rb +22 -0
- data/lib/rosett_ai/validators/behaviour_validator.rb +1 -0
- data/lib/rosett_ai/validators/design_validator.rb +2 -0
- data/lib/rosett_ai/validators/schema_validator.rb +4 -0
- data/lib/rosett_ai/validators/tooling_validator.rb +1 -0
- data/lib/rosett_ai/version.rb +2 -1
- data/lib/rosett_ai/version_consistency_checker.rb +6 -0
- data/lib/rosett_ai/workflow/engine.rb +1 -0
- data/lib/rosett_ai/workflow/manager.rb +1 -0
- data/lib/rosett_ai/workflow/schema_validator.rb +2 -0
- data/lib/rosett_ai/workflow/step_runner.rb +1 -0
- data/lib/rosett_ai/workflow/steps/rai_step.rb +1 -0
- data/lib/rosett_ai/yaml_loader.rb +2 -0
- data/lib/rosett_ai.rb +2 -0
- data/lib/scripts/generated/docker_hub_tags.rb +2 -0
- data/locales/ar.yml +2 -0
- data/locales/en.yml +5 -0
- data/locales/fr.yml +2 -0
- metadata +9 -189
- data/.ai-provenance.yml +0 -119
- data/.debride_whitelist +0 -186
- data/.fasterer.yml +0 -29
- data/.mdl_style.rb +0 -10
- data/.mdlrc +0 -3
- data/.mutant.yml +0 -49
- data/.namespace-allowlist +0 -42
- data/.reek.yml +0 -1040
- data/.rosett-ai/config.yml +0 -3
- data/.rspec +0 -5
- data/.rubocop.yml +0 -380
- data/.ruby-version +0 -1
- data/.yamllint +0 -51
- data/.yardopts +0 -12
- data/AI-DISCLOSURE.md +0 -48
- data/CLAUDE.md +0 -141
- data/CONTRIBUTING.md +0 -734
- data/INSTALL.md +0 -154
- data/LICENSE.md +0 -675
- data/QUICKSTART.md +0 -73
- data/Rakefile +0 -200
- data/SECURITY.md +0 -114
- data/cliff.toml +0 -52
- data/conf/behaviour/.gitkeep +0 -0
- data/conf/design/aaif_alignment.yml +0 -181
- data/conf/design/ab_testing.yml +0 -172
- data/conf/design/accessibility.yml +0 -84
- data/conf/design/ai_authorship.yml +0 -210
- data/conf/design/ai_provenance.yml +0 -224
- data/conf/design/ai_tool_configuration.yml +0 -207
- data/conf/design/architecture.yml +0 -139
- data/conf/design/autocompletion.yml +0 -115
- data/conf/design/backward_compatibility.yml +0 -112
- data/conf/design/behaviour_composition.yml +0 -246
- data/conf/design/build_rake_extraction.yml +0 -57
- data/conf/design/ci_pipeline.yml +0 -100
- data/conf/design/claude_code_configuration.yml +0 -157
- data/conf/design/compiler.yml +0 -128
- data/conf/design/comply.yml +0 -153
- data/conf/design/content_packs.yml +0 -84
- data/conf/design/desktop_integration.yml +0 -289
- data/conf/design/distribution.yml +0 -216
- data/conf/design/doctor.yml +0 -184
- data/conf/design/documentation.yml +0 -152
- data/conf/design/engine_architecture.yml +0 -257
- data/conf/design/error_handling.yml +0 -103
- data/conf/design/feature_flags.yml +0 -142
- data/conf/design/git_hooks.yml +0 -165
- data/conf/design/gui_plugins.yml +0 -475
- data/conf/design/i18n.yml +0 -84
- data/conf/design/integration_testing.yml +0 -56
- data/conf/design/licensing_system.yml +0 -88
- data/conf/design/lifecycle_management.yml +0 -208
- data/conf/design/mcp_integration.yml +0 -207
- data/conf/design/mcp_settings.yml +0 -126
- data/conf/design/migration.yml +0 -56
- data/conf/design/monitoring_observability.yml +0 -194
- data/conf/design/namespace_cleanup.yml +0 -145
- data/conf/design/plugin_test_segregation.yml +0 -145
- data/conf/design/policy_management.yml +0 -229
- data/conf/design/project_management.yml +0 -183
- data/conf/design/rai_mcp_asset_discovery.yml +0 -164
- data/conf/design/rai_mcp_server.yml +0 -605
- data/conf/design/release_management.yml +0 -117
- data/conf/design/retrofit.yml +0 -199
- data/conf/design/retrospective_analyzer.yml +0 -79
- data/conf/design/scope_hierarchy.yml +0 -352
- data/conf/design/security.yml +0 -115
- data/conf/design/session_retrospective.yml +0 -85
- data/conf/design/smart_ui_feedback.yml +0 -89
- data/conf/design/structured_logging.yml +0 -148
- data/conf/design/styles.yml +0 -123
- data/conf/design/test_peer_review.yml +0 -89
- data/conf/design/testing.yml +0 -136
- data/conf/design/threat_model.yml +0 -108
- data/conf/design/ui_framework.yml +0 -111
- data/conf/design/usage_optimization.yml +0 -122
- data/conf/design/version_management.yml +0 -60
- data/conf/design/workflow.yml +0 -227
- data/doc/AAIF_POSITIONING.md +0 -58
- data/doc/ADOPT.md +0 -224
- data/doc/AI_PROVENANCE.md +0 -139
- data/doc/ARCHITECTURE.md +0 -920
- data/doc/BEHAVIOUR.md +0 -409
- data/doc/BUILD.md +0 -138
- data/doc/CI_CD_RECIPES.md +0 -171
- data/doc/CLAUDE_SESSIONS_MOVED.md +0 -16
- data/doc/COMMAND_ANALYSIS.md +0 -229
- data/doc/CONFIGURATION.md +0 -281
- data/doc/DESIGN_AUDIT.md +0 -235
- data/doc/DESIGN_PEER_REVIEW.md +0 -771
- data/doc/DESKTOP.md +0 -447
- data/doc/ENGINES.md +0 -567
- data/doc/ENGINE_DEVELOPMENT_GUIDE.md +0 -417
- data/doc/FEATURE_AUDIT.md +0 -218
- data/doc/IMPLEMENTATION_PLAN.md +0 -669
- data/doc/INCIDENT_REPORT_2026-02-02.md +0 -251
- data/doc/MIGRATION_GUIDE.md +0 -88
- data/doc/PACKAGING.md +0 -232
- data/doc/PROJECT_DASHBOARD.md +0 -153
- data/doc/PULP_DEPLOYMENT.md +0 -164
- data/doc/QUALITY_FIX_SUMMARY.md +0 -110
- data/doc/QUICK_START.md +0 -162
- data/doc/REEK_CONFIGURATION.md +0 -166
- data/doc/REFERENCE.md +0 -253
- data/doc/REFERENCES.md +0 -324
- data/doc/SECURITY_REVIEW_CHECKLIST.md +0 -72
- data/doc/SESSION_2026-02-28_GTK4_HARDENING.md +0 -359
- data/doc/SETUP.md +0 -202
- data/doc/TEST_PEER_REVIEW.md +0 -152
- data/doc/THREAT_MODEL.md +0 -230
- data/doc/USAGE.md +0 -545
- data/doc/USER_MANUAL.md +0 -585
- data/doc/ai_test_review_checklist.md +0 -110
- data/doc/changes/2026-02-18-packaging-fpm.md +0 -155
- data/doc/changes/2026-02-19-testing-infrastructure.md +0 -221
- data/doc/changes/2026-02-20-security-implementation.md +0 -281
- data/doc/changes/2026-02-20-styles-implementation.md +0 -220
- data/doc/changes/2026-02-21-architecture-completion.md +0 -95
- data/doc/changes/2026-02-21-architecture-ui-layer.md +0 -253
- data/doc/changes/2026-02-21-cc-config-implementation.md +0 -108
- data/doc/changes/2026-02-21-ci-pipeline-implementation.md +0 -214
- data/doc/changes/2026-02-21-compiler-multi-target-pipeline.md +0 -241
- data/doc/changes/2026-02-21-config-design-show-commands.md +0 -61
- data/doc/changes/2026-02-21-design-implementation-overview.md +0 -455
- data/doc/changes/2026-02-21-lifecycle-management.md +0 -196
- data/doc/changes/2026-02-21-path-resolver.md +0 -128
- data/doc/changes/2026-02-24-ci-tmpdir-mutant-fetch.md +0 -45
- data/doc/changes/2026-03-01-ci-bundler-strategy.md +0 -120
- data/doc/changes/2026-03-20-security-hardening-phase2.md +0 -163
- data/doc/context/SESSION-HANDOFF.md +0 -69
- data/doc/context/ai-engine-usage-trends-2026.md +0 -80
- data/doc/context/plan-pluggable-engines.md +0 -590
- data/doc/decisions/001-flog-deferred.md +0 -32
- data/doc/decisions/002-path-resolution-strategy.md +0 -158
- data/doc/decisions/003-ui-adapter-selection.md +0 -193
- data/doc/decisions/004-design-document-validation.md +0 -179
- data/doc/decisions/005-package-splitting-strategy.md +0 -200
- data/doc/decisions/006-multi-engine-architecture.md +0 -147
- data/doc/decisions/007-engine-agnostic-pivot.md +0 -219
- data/doc/decisions/008-ci-bundler-strategy.md +0 -129
- data/doc/decisions/009-core-only-v1-release.md +0 -60
- data/doc/decisions/010-engine-debian-packaging.md +0 -66
- data/doc/decisions/011-context-aware-cli.md +0 -71
- data/doc/dependency_decisions.yml +0 -247
- data/doc/issues/001-wrapper-missing-environment-variables.md +0 -197
- data/doc/issues/002-embedded-ruby-wrong-prefix.md +0 -217
- data/doc/issues/003-smoke-test-false-positive.md +0 -127
- data/doc/issues/004-market-research-design-updates.md +0 -109
- data/doc/issues/005-compile-scope-coexistence.md +0 -161
- data/doc/locales/.gitkeep +0 -0
- data/doc/man/rai.1.ronn +0 -505
- data/doc/operations/packaging.md +0 -133
- data/doc/operations/rosett-ai-release.md +0 -65
- data/doc/reference/error-catalog.md +0 -107
- data/doc/reference/rosett-ai-technical-reference.pdf +0 -0
- data/doc/reference/src/Pictures/cover.jpg +0 -0
- data/doc/reference/src/Pictures/head1.jpg +0 -0
- data/doc/reference/src/Pictures/head2.jpg +0 -0
- data/doc/reference/src/Pictures/head3.jpg +0 -0
- data/doc/reference/src/Pictures/head4.jpg +0 -0
- data/doc/reference/src/Pictures/head5.jpg +0 -0
- data/doc/reference/src/Pictures/head6.jpg +0 -0
- data/doc/reference/src/Pictures/head7.jpg +0 -0
- data/doc/reference/src/Pictures/head8.jpg +0 -0
- data/doc/reference/src/StyleInd.ist +0 -4
- data/doc/reference/src/bibliography.bib +0 -79
- data/doc/reference/src/main.tex +0 -1288
- data/doc/reference/src/structure.tex +0 -303
- data/doc/rosett-ai-bookmarks.html +0 -301
- data/kitchen.yml +0 -46
- data/lib/rosett_ai/mcp/enforcement/.gitkeep +0 -0
- data/locales/.gitkeep +0 -0
- data/packaging/build-engine-deb.sh +0 -81
- data/packaging/scripts/postinst +0 -17
- data/packaging/scripts/postrm +0 -19
- data/packaging/scripts/prerm +0 -10
- data/packaging/wrapper.sh.template +0 -38
- data/rosett-ai.gemspec +0 -63
- data/rules/.gitkeep +0 -0
- data/scripts/publish/pulp_upload.sh +0 -123
- data/settings.json +0 -29
|
@@ -6,11 +6,16 @@
|
|
|
6
6
|
require 'fileutils'
|
|
7
7
|
|
|
8
8
|
module RosettAi
|
|
9
|
+
# Project and global directory initialization.
|
|
9
10
|
module Init
|
|
10
11
|
# Helper module for copying files during initialization
|
|
11
12
|
module FileCopier
|
|
12
13
|
module_function
|
|
13
14
|
|
|
15
|
+
# Copy global assets to the ~/.claude/ directory.
|
|
16
|
+
#
|
|
17
|
+
# @param base_dir [String] the target base directory
|
|
18
|
+
# @return [Array<String>] list of copied file names
|
|
14
19
|
def copy_global_assets(base_dir)
|
|
15
20
|
root = RosettAi.root
|
|
16
21
|
copied = []
|
|
@@ -25,6 +30,10 @@ module RosettAi
|
|
|
25
30
|
copied
|
|
26
31
|
end
|
|
27
32
|
|
|
33
|
+
# Copy local assets to the project .claude/ directory.
|
|
34
|
+
#
|
|
35
|
+
# @param base_dir [String] the target base directory
|
|
36
|
+
# @return [Array<String>] list of copied file names
|
|
28
37
|
def copy_local_assets(base_dir)
|
|
29
38
|
copied = []
|
|
30
39
|
# Local scope copies to .claude/conf/ (not XDG)
|
|
@@ -32,6 +41,12 @@ module RosettAi
|
|
|
32
41
|
copied
|
|
33
42
|
end
|
|
34
43
|
|
|
44
|
+
# Copy configuration assets (behaviours, schemas) to the target.
|
|
45
|
+
#
|
|
46
|
+
# @param source_root [Pathname] the source root directory
|
|
47
|
+
# @param conf_base [String] the target configuration directory
|
|
48
|
+
# @param copied [Array<String>] accumulator for copied file names
|
|
49
|
+
# @return [void]
|
|
35
50
|
def copy_conf_assets(source_root, conf_base, copied)
|
|
36
51
|
FileUtils.mkdir_p(File.join(conf_base, 'behaviour'))
|
|
37
52
|
FileUtils.mkdir_p(File.join(conf_base, 'schemas'))
|
|
@@ -45,6 +60,13 @@ module RosettAi
|
|
|
45
60
|
copied, 'conf/adopt_redactions.yml')
|
|
46
61
|
end
|
|
47
62
|
|
|
63
|
+
# Copy a single file to the target path.
|
|
64
|
+
#
|
|
65
|
+
# @param source [Pathname, String] source file path
|
|
66
|
+
# @param target [String] target file path
|
|
67
|
+
# @param copied [Array<String>] accumulator for copied file names
|
|
68
|
+
# @param name [String] display name for the copied file
|
|
69
|
+
# @return [void]
|
|
48
70
|
def copy_single_file(source, target, copied, name)
|
|
49
71
|
return if File.exist?(target) || !File.exist?(source)
|
|
50
72
|
|
|
@@ -52,6 +74,13 @@ module RosettAi
|
|
|
52
74
|
copied << name
|
|
53
75
|
end
|
|
54
76
|
|
|
77
|
+
# Copy an executable file preserving permissions.
|
|
78
|
+
#
|
|
79
|
+
# @param source [Pathname, String] source file path
|
|
80
|
+
# @param target [String] target file path
|
|
81
|
+
# @param copied [Array<String>] accumulator for copied file names
|
|
82
|
+
# @param name [String] display name for the copied file
|
|
83
|
+
# @return [void]
|
|
55
84
|
def copy_executable(source, target, copied, name)
|
|
56
85
|
return unless File.exist?(source)
|
|
57
86
|
|
|
@@ -60,6 +89,13 @@ module RosettAi
|
|
|
60
89
|
copied << name
|
|
61
90
|
end
|
|
62
91
|
|
|
92
|
+
# Recursively copy a directory tree to the target.
|
|
93
|
+
#
|
|
94
|
+
# @param source [Pathname, String] source directory path
|
|
95
|
+
# @param target [String] target directory path
|
|
96
|
+
# @param copied [Array<String>] accumulator for copied file names
|
|
97
|
+
# @param name [String] display name for the copied directory
|
|
98
|
+
# @return [void]
|
|
63
99
|
def copy_directory(source, target, copied, name)
|
|
64
100
|
return unless Dir.exist?(source)
|
|
65
101
|
|
|
@@ -67,6 +103,14 @@ module RosettAi
|
|
|
67
103
|
copied << name
|
|
68
104
|
end
|
|
69
105
|
|
|
106
|
+
# Copy files matching a glob pattern to the target directory.
|
|
107
|
+
#
|
|
108
|
+
# @param source_dir [Pathname, String] source directory to glob
|
|
109
|
+
# @param target_dir [String] target directory path
|
|
110
|
+
# @param pattern [String] glob pattern (e.g. '*.yml')
|
|
111
|
+
# @param prefix [String] display prefix for copied file names
|
|
112
|
+
# @param copied [Array<String>] accumulator for copied file names
|
|
113
|
+
# @return [void]
|
|
70
114
|
def copy_glob_files(source_dir, target_dir, pattern, prefix, copied)
|
|
71
115
|
return unless Dir.exist?(source_dir)
|
|
72
116
|
|
|
@@ -84,6 +128,13 @@ module RosettAi
|
|
|
84
128
|
end
|
|
85
129
|
end
|
|
86
130
|
|
|
131
|
+
# Copy a file only if the target does not already exist.
|
|
132
|
+
#
|
|
133
|
+
# @param source [Pathname, String] source file path
|
|
134
|
+
# @param target [String] target file path
|
|
135
|
+
# @param copied [Array<String>] accumulator for copied file names
|
|
136
|
+
# @param name [String] display name for the copied file
|
|
137
|
+
# @return [void]
|
|
87
138
|
def copy_if_new(source, target, copied, name)
|
|
88
139
|
return unless File.exist?(source) && !File.exist?(target)
|
|
89
140
|
|
|
@@ -15,9 +15,13 @@ module RosettAi
|
|
|
15
15
|
# only verify signatures, not forge them. The private signing key
|
|
16
16
|
# is held server-side and NEVER distributed.
|
|
17
17
|
class LicenseKey
|
|
18
|
+
# @return [String] Hex-encoded public key for license verification.
|
|
18
19
|
PUBLIC_KEY_HEX = '91f54336c0d42a7c88642b8d7f8bacab3adba4a4d633a33002fc15f676bfd8f0'
|
|
20
|
+
# @return [String] Prefix for rosett-ai license key strings.
|
|
19
21
|
RAI_PREFIX = 'NNCC-'
|
|
22
|
+
# @return [Integer] Days of grace period after license expiry.
|
|
20
23
|
GRACE_PERIOD_DAYS = 14
|
|
24
|
+
# @return [Integer] Days of offline operation before license revalidation.
|
|
21
25
|
OFFLINE_GRACE_DAYS = 30
|
|
22
26
|
|
|
23
27
|
attr_reader :claims
|
|
@@ -8,15 +8,23 @@ module RosettAi
|
|
|
8
8
|
# Persists the license key at ~/.config/rosett-ai/license.key with
|
|
9
9
|
# strict file permissions (0600, owned by current uid).
|
|
10
10
|
class LicenseStore
|
|
11
|
+
# @return [Object] File permission mode for secure files.
|
|
11
12
|
SAFE_FILE_MODE = 0o600
|
|
13
|
+
# @return [Object] Directory permission mode for secure directories.
|
|
12
14
|
SAFE_DIR_MODE = 0o700
|
|
13
15
|
|
|
16
|
+
# Save the license key to persistent storage.
|
|
17
|
+
#
|
|
18
|
+
# @param raw_key [Object] the raw key
|
|
19
|
+
# @return [void]
|
|
14
20
|
def save(raw_key)
|
|
15
21
|
ensure_parent_directory!
|
|
16
22
|
File.write(license_path.to_s, raw_key, mode: 'w', perm: SAFE_FILE_MODE)
|
|
17
23
|
validate_permissions!
|
|
18
24
|
end
|
|
19
25
|
|
|
26
|
+
# Load the license key from persistent storage.
|
|
27
|
+
# @return [LicenseKey, nil]
|
|
20
28
|
def load
|
|
21
29
|
return nil unless exists?
|
|
22
30
|
|
|
@@ -24,6 +32,9 @@ module RosettAi
|
|
|
24
32
|
File.read(license_path.to_s).chomp
|
|
25
33
|
end
|
|
26
34
|
|
|
35
|
+
# Remove the stored license key file.
|
|
36
|
+
#
|
|
37
|
+
# @return [void]
|
|
27
38
|
def remove!
|
|
28
39
|
File.delete(license_path.to_s) if exists?
|
|
29
40
|
end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
5
|
|
|
6
6
|
module RosettAi
|
|
7
|
+
# License key management and tier enforcement.
|
|
7
8
|
module Licensing
|
|
8
9
|
# Represents a license tier with comparable ordering.
|
|
9
10
|
#
|
|
@@ -12,7 +13,9 @@ module RosettAi
|
|
|
12
13
|
class Tier
|
|
13
14
|
include Comparable
|
|
14
15
|
|
|
16
|
+
# @return [Hash] Ordered tier hierarchy from lowest to highest.
|
|
15
17
|
HIERARCHY = { community: 0, supporter: 1, subscriber: 2, enterprise: 3 }.freeze
|
|
18
|
+
# @return [Object] Human-readable names for each tier.
|
|
16
19
|
NAMES = HIERARCHY.keys.freeze
|
|
17
20
|
|
|
18
21
|
attr_reader :name, :level
|
|
@@ -25,6 +28,10 @@ module RosettAi
|
|
|
25
28
|
@level = HIERARCHY[sym]
|
|
26
29
|
end
|
|
27
30
|
|
|
31
|
+
# Compare tier levels for sorting.
|
|
32
|
+
#
|
|
33
|
+
# @param other [Tier] the other tier to compare
|
|
34
|
+
# @return [Integer] -1, 0, or 1
|
|
28
35
|
def <=>(other)
|
|
29
36
|
level <=> other.level
|
|
30
37
|
end
|
|
@@ -34,6 +41,8 @@ module RosettAi
|
|
|
34
41
|
self >= other
|
|
35
42
|
end
|
|
36
43
|
|
|
44
|
+
# Return the human-readable tier name.
|
|
45
|
+
# @return [String]
|
|
37
46
|
def to_s
|
|
38
47
|
name.to_s.capitalize
|
|
39
48
|
end
|
|
@@ -34,13 +34,16 @@ module RosettAi
|
|
|
34
34
|
# :priority, :description
|
|
35
35
|
# @param behaviour_name [String] source behaviour name
|
|
36
36
|
# @param behaviour_version [String] source behaviour version
|
|
37
|
+
# @param contextual_rules [Array<Hash>] rules without extractable regex patterns;
|
|
38
|
+
# listed in header for visibility but not enforced at hook time
|
|
37
39
|
# @return [String] complete Ruby hook script
|
|
38
|
-
def generate(rules, behaviour_name:, behaviour_version:)
|
|
40
|
+
def generate(rules, behaviour_name:, behaviour_version:, contextual_rules: [])
|
|
39
41
|
timestamp = Time.now.utc.iso8601
|
|
40
42
|
parts = []
|
|
41
43
|
parts << shebang_and_magic
|
|
42
44
|
parts << yard_documentation(rules)
|
|
43
|
-
parts << traceability_header(behaviour_name, behaviour_version, rules, timestamp
|
|
45
|
+
parts << traceability_header(behaviour_name, behaviour_version, rules, timestamp,
|
|
46
|
+
contextual_rules)
|
|
44
47
|
parts << ai_client_instructions
|
|
45
48
|
parts << rule_constant(rules)
|
|
46
49
|
parts << enforcement_body
|
|
@@ -83,9 +86,11 @@ module RosettAi
|
|
|
83
86
|
# @param behaviour_version [String]
|
|
84
87
|
# @param rules [Array<Hash>]
|
|
85
88
|
# @param timestamp [String]
|
|
89
|
+
# @param contextual_rules [Array<Hash>]
|
|
86
90
|
# @return [String]
|
|
87
|
-
def traceability_header(behaviour_name, behaviour_version, rules, timestamp
|
|
88
|
-
|
|
91
|
+
def traceability_header(behaviour_name, behaviour_version, rules, timestamp,
|
|
92
|
+
contextual_rules = [])
|
|
93
|
+
header = <<~RUBY
|
|
89
94
|
# --- Traceability ---
|
|
90
95
|
# Source behaviour: #{behaviour_name}
|
|
91
96
|
# Behaviour version: #{behaviour_version}
|
|
@@ -94,6 +99,24 @@ module RosettAi
|
|
|
94
99
|
# Rule count: #{rules.size}
|
|
95
100
|
# Rule IDs: #{rules.map { |r| r[:rule_id] }.join(', ')}
|
|
96
101
|
RUBY
|
|
102
|
+
header + contextual_warning(contextual_rules)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Generates a contextual rules warning section for rules that cannot be
|
|
106
|
+
# regex-enforced. Listed for visibility; not enforced at hook time.
|
|
107
|
+
#
|
|
108
|
+
# @param contextual_rules [Array<Hash>]
|
|
109
|
+
# @return [String]
|
|
110
|
+
def contextual_warning(contextual_rules)
|
|
111
|
+
return '' if contextual_rules.empty?
|
|
112
|
+
|
|
113
|
+
lines = contextual_rules.map do |r|
|
|
114
|
+
"# #{r[:behaviour]}/#{r[:rule_id]} (P#{r[:priority]})"
|
|
115
|
+
end
|
|
116
|
+
<<~RUBY
|
|
117
|
+
# Contextual rules (no regex pattern — human-reviewed only):
|
|
118
|
+
#{lines.join("\n")}
|
|
119
|
+
RUBY
|
|
97
120
|
end
|
|
98
121
|
|
|
99
122
|
# @return [String]
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
module RosettAi
|
|
7
7
|
module Mcp
|
|
8
|
+
# Rule enforcement pipeline for MCP operations.
|
|
8
9
|
module Enforcement
|
|
9
10
|
# Validates enforcement blocks in behaviour rules.
|
|
10
11
|
#
|
|
@@ -27,7 +28,9 @@ module RosettAi
|
|
|
27
28
|
# @author hugo
|
|
28
29
|
# @author claude
|
|
29
30
|
class Validator
|
|
31
|
+
# @return [Array] Set of permitted type values.
|
|
30
32
|
VALID_TYPES = ['enforceable', 'advisory', 'informational'].freeze
|
|
33
|
+
# @return [Array] Set of permitted action values.
|
|
31
34
|
VALID_ACTIONS = ['block', 'warn', 'log'].freeze
|
|
32
35
|
|
|
33
36
|
# Patterns that match everything or nearly everything — unsafe for hooks.
|
|
@@ -44,6 +47,8 @@ module RosettAi
|
|
|
44
47
|
/\A\(\.\+\)\z/ # (.+)
|
|
45
48
|
].freeze
|
|
46
49
|
|
|
50
|
+
# Struct holding rule context for enforcement validation.
|
|
51
|
+
#
|
|
47
52
|
# @!attribute [r] behaviour
|
|
48
53
|
# @return [String] behaviour name for error messages
|
|
49
54
|
# @!attribute [r] rule_id
|
|
@@ -148,7 +153,7 @@ module RosettAi
|
|
|
148
153
|
# @param prefix [String] error message prefix
|
|
149
154
|
# @return [Array<String>]
|
|
150
155
|
def check_pattern(pattern, prefix)
|
|
151
|
-
return ["#{prefix}: pattern missing or empty"] if
|
|
156
|
+
return ["#{prefix}: pattern missing or empty"] if blank?(pattern.to_s)
|
|
152
157
|
|
|
153
158
|
Regexp.new(pattern)
|
|
154
159
|
return ["#{prefix}: pattern '#{pattern}' is degenerate (matches everything)"] if degenerate?(pattern)
|
|
@@ -170,17 +175,32 @@ module RosettAi
|
|
|
170
175
|
end
|
|
171
176
|
|
|
172
177
|
# Validates the action field.
|
|
178
|
+
# A nil/absent action is allowed — priority-based default applies.
|
|
173
179
|
#
|
|
174
180
|
# @param action [String, nil]
|
|
175
181
|
# @param prefix [String] error message prefix
|
|
176
182
|
# @return [Array<String>]
|
|
177
183
|
def check_action(action, prefix)
|
|
184
|
+
return [] if action.to_s.strip.empty?
|
|
178
185
|
return [] if VALID_ACTIONS.include?(action)
|
|
179
186
|
|
|
180
187
|
allowed = VALID_ACTIONS.join(', ')
|
|
181
188
|
["#{prefix}: action '#{action}' invalid (must be one of: #{allowed})"]
|
|
182
189
|
end
|
|
183
190
|
|
|
191
|
+
# Derives action from priority when none is explicitly set.
|
|
192
|
+
# Priority >= 80 → block; priority < 80 → warn.
|
|
193
|
+
#
|
|
194
|
+
# @param enforcement [Hash]
|
|
195
|
+
# @param priority [Integer]
|
|
196
|
+
# @return [String]
|
|
197
|
+
def derive_action(enforcement, priority)
|
|
198
|
+
action = enforcement['action'].to_s.strip
|
|
199
|
+
return action unless action.empty?
|
|
200
|
+
|
|
201
|
+
priority.to_i >= 80 ? 'block' : 'warn'
|
|
202
|
+
end
|
|
203
|
+
|
|
184
204
|
# Tests whether a string is blank (nil, empty, or whitespace-only).
|
|
185
205
|
#
|
|
186
206
|
# @param value [String]
|
|
@@ -204,10 +224,11 @@ module RosettAi
|
|
|
204
224
|
# @param ctx [RuleContext]
|
|
205
225
|
# @return [Hash]
|
|
206
226
|
def build_valid_entry(rule, enforcement, ctx)
|
|
227
|
+
priority = rule['priority'] || 0
|
|
207
228
|
{ rule_id: ctx.rule_id, behaviour: ctx.behaviour, type: 'enforceable',
|
|
208
229
|
pattern: enforcement['pattern'], applies_to: enforcement['applies_to'],
|
|
209
|
-
action: enforcement
|
|
210
|
-
priority:
|
|
230
|
+
action: derive_action(enforcement, priority), message: enforcement['message'],
|
|
231
|
+
priority: priority, description: rule['description'].to_s.strip }
|
|
211
232
|
end
|
|
212
233
|
end
|
|
213
234
|
end
|
|
@@ -13,6 +13,7 @@ module RosettAi
|
|
|
13
13
|
# @author hugo
|
|
14
14
|
# @author claude
|
|
15
15
|
module Governance
|
|
16
|
+
# @return [Array] Registered MCP tool implementation classes.
|
|
16
17
|
TOOL_CLASSES = [
|
|
17
18
|
Tools::ValidateTool,
|
|
18
19
|
Tools::CompileTool,
|
|
@@ -49,6 +50,7 @@ module RosettAi
|
|
|
49
50
|
Tools::SchemaGetTool
|
|
50
51
|
].freeze
|
|
51
52
|
|
|
53
|
+
# @return [Array] Registered MCP resource implementation classes.
|
|
52
54
|
RESOURCE_CLASSES = [
|
|
53
55
|
Resources::BehaviourResource,
|
|
54
56
|
Resources::DesignResource,
|
|
@@ -59,6 +61,7 @@ module RosettAi
|
|
|
59
61
|
Resources::HooksResource
|
|
60
62
|
].freeze
|
|
61
63
|
|
|
64
|
+
# @return [Array] Registered MCP prompt implementation classes.
|
|
62
65
|
PROMPT_CLASSES = [
|
|
63
66
|
Prompts::ValidationPrompt,
|
|
64
67
|
Prompts::CompilationPrompt,
|
|
@@ -66,6 +69,7 @@ module RosettAi
|
|
|
66
69
|
Prompts::DiagnosticsPrompt
|
|
67
70
|
].freeze
|
|
68
71
|
|
|
72
|
+
# @return [Array] Parameter types passed as keyword arguments.
|
|
69
73
|
KEYWORD_PARAM_TYPES = [:keyreq, :key].freeze
|
|
70
74
|
|
|
71
75
|
module_function
|
|
@@ -125,6 +129,11 @@ module RosettAi
|
|
|
125
129
|
end
|
|
126
130
|
end
|
|
127
131
|
|
|
132
|
+
# Look up the MCP resource handler for a URI.
|
|
133
|
+
#
|
|
134
|
+
# @param resources [Array] registered resource instances
|
|
135
|
+
# @param uri [String] the resource URI to match
|
|
136
|
+
# @return [Object, nil] the matching resource, or nil
|
|
128
137
|
def find_resource_for_uri(resources, uri)
|
|
129
138
|
resources.find { |r| resource_matches_uri?(r, uri) }
|
|
130
139
|
end
|
|
@@ -46,6 +46,7 @@ module RosettAi
|
|
|
46
46
|
class AuthConfig
|
|
47
47
|
attr_accessor :type, :key_source, :keyfile_path, :api_key_env
|
|
48
48
|
|
|
49
|
+
# @return [String] Default keyfile name constant.
|
|
49
50
|
DEFAULT_KEYFILE_NAME = 'rosett-ai-mcp-keys.yml'
|
|
50
51
|
|
|
51
52
|
def initialize
|
|
@@ -64,6 +65,10 @@ module RosettAi
|
|
|
64
65
|
File.exist?(File.expand_path(@keyfile_path)) ? 'keyfile' : 'env'
|
|
65
66
|
end
|
|
66
67
|
|
|
68
|
+
# Apply authentication configuration from a hash.
|
|
69
|
+
#
|
|
70
|
+
# @param hash [Hash] configuration values
|
|
71
|
+
# @return [void]
|
|
67
72
|
def apply(hash)
|
|
68
73
|
return unless hash.is_a?(Hash)
|
|
69
74
|
|
|
@@ -84,6 +89,10 @@ module RosettAi
|
|
|
84
89
|
@key_path = nil
|
|
85
90
|
end
|
|
86
91
|
|
|
92
|
+
# Apply TLS configuration from a hash.
|
|
93
|
+
#
|
|
94
|
+
# @param hash [Hash] configuration values
|
|
95
|
+
# @return [void]
|
|
87
96
|
def apply(hash)
|
|
88
97
|
return unless hash.is_a?(Hash)
|
|
89
98
|
|
|
@@ -95,6 +104,7 @@ module RosettAi
|
|
|
95
104
|
|
|
96
105
|
# Origin validation sub-configuration.
|
|
97
106
|
class OriginConfig
|
|
107
|
+
# @return [Array] Default allowed origins for origin validation.
|
|
98
108
|
DEFAULT_ORIGINS = ['http://localhost:*', 'http://127.0.0.1:*'].freeze
|
|
99
109
|
|
|
100
110
|
attr_accessor :allowed_origins, :strict_mode
|
|
@@ -104,6 +114,10 @@ module RosettAi
|
|
|
104
114
|
@strict_mode = false
|
|
105
115
|
end
|
|
106
116
|
|
|
117
|
+
# Apply origin validation configuration from a hash.
|
|
118
|
+
#
|
|
119
|
+
# @param hash [Hash] configuration values
|
|
120
|
+
# @return [void]
|
|
107
121
|
def apply(hash)
|
|
108
122
|
return unless hash.is_a?(Hash)
|
|
109
123
|
|
|
@@ -122,6 +136,10 @@ module RosettAi
|
|
|
122
136
|
@authenticated_rpm = 300
|
|
123
137
|
end
|
|
124
138
|
|
|
139
|
+
# Apply rate limit configuration from a hash.
|
|
140
|
+
#
|
|
141
|
+
# @param hash [Hash] configuration values
|
|
142
|
+
# @return [void]
|
|
125
143
|
def apply(hash)
|
|
126
144
|
return unless hash.is_a?(Hash)
|
|
127
145
|
|
|
@@ -143,6 +161,10 @@ module RosettAi
|
|
|
143
161
|
@max_age = 86_400
|
|
144
162
|
end
|
|
145
163
|
|
|
164
|
+
# Apply CORS configuration from a hash.
|
|
165
|
+
#
|
|
166
|
+
# @param hash [Hash] configuration values
|
|
167
|
+
# @return [void]
|
|
146
168
|
def apply(hash)
|
|
147
169
|
return unless hash.is_a?(Hash)
|
|
148
170
|
|
|
@@ -16,7 +16,9 @@ module RosettAi
|
|
|
16
16
|
# @author hugo
|
|
17
17
|
# @author claude
|
|
18
18
|
module KeyHasher
|
|
19
|
+
# @return [Integer] Number of random bytes used for key salting.
|
|
19
20
|
SALT_BYTES = 16
|
|
21
|
+
# @return [String] Prefix for hashed API key identifiers.
|
|
20
22
|
KEY_PREFIX = 'nncc_'
|
|
21
23
|
|
|
22
24
|
module_function
|
|
@@ -53,8 +55,8 @@ module RosettAi
|
|
|
53
55
|
|
|
54
56
|
# Constant-time string comparison to prevent timing attacks.
|
|
55
57
|
#
|
|
56
|
-
# @param
|
|
57
|
-
# @param
|
|
58
|
+
# @param a_str [String] first string
|
|
59
|
+
# @param b_str [String] second string
|
|
58
60
|
# @return [Boolean] true if strings match
|
|
59
61
|
def secure_compare(a_str, b_str)
|
|
60
62
|
return false unless a_str.bytesize == b_str.bytesize
|
|
@@ -14,9 +14,13 @@ module RosettAi
|
|
|
14
14
|
# @author hugo
|
|
15
15
|
# @author claude
|
|
16
16
|
class Keyfile
|
|
17
|
+
# @return [String] Current version of the rosett-ai gem.
|
|
17
18
|
VERSION = '1.0'
|
|
19
|
+
# @return [Object] Maximum number of permissions per key.
|
|
18
20
|
MAX_PERMISSIONS = 0o600
|
|
21
|
+
# @return [String] Default filename for the MCP keyfile.
|
|
19
22
|
DEFAULT_FILENAME = 'rosett-ai-mcp-keys.yml'
|
|
23
|
+
# @return [Integer] Days before expiry to show warnings.
|
|
20
24
|
EXPIRY_WARNING_DAYS = 7
|
|
21
25
|
|
|
22
26
|
# @param path [String] path to the keyfile
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
module RosettAi
|
|
7
7
|
module Mcp
|
|
8
|
+
# HTTP middleware: CORS, rate limiting, origin validation.
|
|
8
9
|
module Middleware
|
|
9
10
|
# Rack middleware for CORS header handling and preflight.
|
|
10
11
|
#
|
|
@@ -17,8 +18,11 @@ module RosettAi
|
|
|
17
18
|
# @param app [#call] the next Rack application
|
|
18
19
|
# @param config [#origins, #methods, #headers, #max_age] CORS config
|
|
19
20
|
DEFAULT_METHODS = ['POST', 'GET', 'DELETE'].freeze
|
|
21
|
+
# @return [Array] Default CORS headers.
|
|
20
22
|
DEFAULT_HEADERS = ['Content-Type', 'Authorization', 'Accept', 'Mcp-Session-Id'].freeze
|
|
23
|
+
# @return [Object] Default CORS preflight cache duration in seconds.
|
|
21
24
|
DEFAULT_MAX_AGE = 86_400
|
|
25
|
+
# @return [Array] Configuration field names for CORS middleware.
|
|
22
26
|
CONFIG_FIELDS = [:origins, :methods, :headers, :max_age].freeze
|
|
23
27
|
|
|
24
28
|
def initialize(app, config: nil)
|
|
@@ -15,6 +15,7 @@ module RosettAi
|
|
|
15
15
|
# @author hugo
|
|
16
16
|
# @author claude
|
|
17
17
|
class OriginValidation
|
|
18
|
+
# @return [Array] Default allowed origins for origin validation.
|
|
18
19
|
DEFAULT_ORIGINS = ['http://localhost:*', 'http://127.0.0.1:*'].freeze
|
|
19
20
|
|
|
20
21
|
# @param app [#call] the next Rack application
|
|
@@ -15,9 +15,12 @@ module RosettAi
|
|
|
15
15
|
# @author hugo
|
|
16
16
|
# @author claude
|
|
17
17
|
class RateLimit
|
|
18
|
+
# @return [Integer] Default rate limit for unauthenticated requests per minute.
|
|
18
19
|
DEFAULT_UNAUTH_RPM = 60
|
|
20
|
+
# @return [Integer] Default rate limit for authenticated requests per minute.
|
|
19
21
|
DEFAULT_AUTH_RPM = 300
|
|
20
22
|
BUCKET_WINDOW = 60 # seconds
|
|
23
|
+
# @return [Integer] Interval between rate limit bucket cleanup sweeps.
|
|
21
24
|
CLEANUP_INTERVAL = 100
|
|
22
25
|
|
|
23
26
|
# @param app [#call] the next Rack application
|
|
@@ -14,7 +14,9 @@ module RosettAi
|
|
|
14
14
|
# @author hugo
|
|
15
15
|
# @author claude
|
|
16
16
|
class CompilationPrompt
|
|
17
|
+
# @return [String] MCP prompt identifier string.
|
|
17
18
|
PROMPT_NAME = 'rai_compilation_workflow'
|
|
19
|
+
# @return [String] Human-readable description of this tool.
|
|
18
20
|
DESCRIPTION = 'Compile rai behaviours and review output'
|
|
19
21
|
|
|
20
22
|
# Generates the compilation prompt messages.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
module RosettAi
|
|
7
7
|
module Mcp
|
|
8
|
+
# MCP prompt implementations for guided workflows.
|
|
8
9
|
module Prompts
|
|
9
10
|
# MCP prompt: compliance workflow.
|
|
10
11
|
#
|
|
@@ -14,7 +15,9 @@ module RosettAi
|
|
|
14
15
|
# @author hugo
|
|
15
16
|
# @author claude
|
|
16
17
|
class CompliancePrompt
|
|
18
|
+
# @return [String] MCP prompt identifier string.
|
|
17
19
|
PROMPT_NAME = 'rai_compliance_workflow'
|
|
20
|
+
# @return [String] Human-readable description of this tool.
|
|
18
21
|
DESCRIPTION = 'Run compliance checks and interpret results'
|
|
19
22
|
|
|
20
23
|
# Generates the compliance prompt messages.
|
|
@@ -14,7 +14,9 @@ module RosettAi
|
|
|
14
14
|
# @author hugo
|
|
15
15
|
# @author claude
|
|
16
16
|
class DiagnosticsPrompt
|
|
17
|
+
# @return [String] MCP prompt identifier string.
|
|
17
18
|
PROMPT_NAME = 'rai_diagnostics_workflow'
|
|
19
|
+
# @return [String] Human-readable description of this tool.
|
|
18
20
|
DESCRIPTION = 'Run diagnostics and troubleshoot issues'
|
|
19
21
|
|
|
20
22
|
# Generates the diagnostics prompt messages.
|
|
@@ -14,7 +14,9 @@ module RosettAi
|
|
|
14
14
|
# @author hugo
|
|
15
15
|
# @author claude
|
|
16
16
|
class ValidationPrompt
|
|
17
|
+
# @return [String] MCP prompt identifier string.
|
|
17
18
|
PROMPT_NAME = 'rai_validation_workflow'
|
|
19
|
+
# @return [String] Human-readable description of this tool.
|
|
18
20
|
DESCRIPTION = 'Validate rai configuration and suggest fixes'
|
|
19
21
|
|
|
20
22
|
# Generates the validation prompt messages.
|
|
@@ -18,8 +18,10 @@ module RosettAi
|
|
|
18
18
|
# @author hugo
|
|
19
19
|
# @author claude
|
|
20
20
|
class BehaviourResource
|
|
21
|
+
# @return [String] URI prefix for MCP resource discovery.
|
|
21
22
|
URI_PREFIX = 'rosett-ai://behaviour/'
|
|
22
23
|
|
|
24
|
+
# @return [Hash] Directory names for each configuration tier.
|
|
23
25
|
TIER_DIRS = {
|
|
24
26
|
'project' => -> { RosettAi.conf_root.join('conf', 'behaviour') },
|
|
25
27
|
'xdg' => -> { RosettAi.paths.rai_conf_dir.join('behaviour') },
|
|
@@ -13,7 +13,9 @@ module RosettAi
|
|
|
13
13
|
# @author hugo
|
|
14
14
|
# @author claude
|
|
15
15
|
class ConfigResource
|
|
16
|
+
# @return [String] URI prefix for MCP resource discovery.
|
|
16
17
|
URI_PREFIX = 'rosett-ai://config/'
|
|
18
|
+
# @return [Array] Supported configuration scope names.
|
|
17
19
|
SCOPES = ['managed', 'user', 'project', 'local'].freeze
|
|
18
20
|
|
|
19
21
|
# Lists available config resources.
|