rosett-ai 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.ai-provenance.yml +119 -0
- data/.debride_whitelist +186 -0
- data/.fasterer.yml +29 -0
- data/.mdl_style.rb +10 -0
- data/.mdlrc +3 -0
- data/.mutant.yml +49 -0
- data/.namespace-allowlist +42 -0
- data/.reek.yml +1040 -0
- data/.rosett-ai/config.yml +3 -0
- data/.rspec +5 -0
- data/.rubocop.yml +380 -0
- data/.ruby-version +1 -0
- data/.yamllint +51 -0
- data/.yardopts +12 -0
- data/AI-DISCLOSURE.md +48 -0
- data/CHANGELOG.md +519 -0
- data/CLAUDE.md +141 -0
- data/CONTRIBUTING.md +734 -0
- data/INSTALL.md +154 -0
- data/LICENSE +674 -0
- data/LICENSE.md +675 -0
- data/QUICKSTART.md +73 -0
- data/README.md +366 -0
- data/Rakefile +200 -0
- data/SECURITY.md +114 -0
- data/bin/rai +1 -0
- data/cliff.toml +52 -0
- data/conf/adopt_redactions.yml +8 -0
- data/conf/behaviour/.gitkeep +0 -0
- data/conf/compliance/cra_rules.yml +25 -0
- data/conf/compliance/license_rules.yml +20 -0
- data/conf/design/aaif_alignment.yml +181 -0
- data/conf/design/ab_testing.yml +172 -0
- data/conf/design/accessibility.yml +84 -0
- data/conf/design/ai_authorship.yml +210 -0
- data/conf/design/ai_provenance.yml +224 -0
- data/conf/design/ai_tool_configuration.yml +207 -0
- data/conf/design/architecture.yml +139 -0
- data/conf/design/autocompletion.yml +115 -0
- data/conf/design/backward_compatibility.yml +112 -0
- data/conf/design/behaviour_composition.yml +246 -0
- data/conf/design/build_rake_extraction.yml +57 -0
- data/conf/design/ci_pipeline.yml +100 -0
- data/conf/design/claude_code_configuration.yml +157 -0
- data/conf/design/compiler.yml +128 -0
- data/conf/design/comply.yml +153 -0
- data/conf/design/content_packs.yml +84 -0
- data/conf/design/desktop_integration.yml +289 -0
- data/conf/design/distribution.yml +216 -0
- data/conf/design/doctor.yml +184 -0
- data/conf/design/documentation.yml +152 -0
- data/conf/design/engine_architecture.yml +257 -0
- data/conf/design/error_handling.yml +103 -0
- data/conf/design/feature_flags.yml +142 -0
- data/conf/design/git_hooks.yml +165 -0
- data/conf/design/gui_plugins.yml +475 -0
- data/conf/design/i18n.yml +84 -0
- data/conf/design/integration_testing.yml +56 -0
- data/conf/design/licensing_system.yml +88 -0
- data/conf/design/lifecycle_management.yml +208 -0
- data/conf/design/mcp_integration.yml +207 -0
- data/conf/design/mcp_settings.yml +126 -0
- data/conf/design/migration.yml +56 -0
- data/conf/design/monitoring_observability.yml +194 -0
- data/conf/design/namespace_cleanup.yml +145 -0
- data/conf/design/plugin_test_segregation.yml +145 -0
- data/conf/design/policy_management.yml +229 -0
- data/conf/design/project_management.yml +183 -0
- data/conf/design/rai_mcp_asset_discovery.yml +164 -0
- data/conf/design/rai_mcp_server.yml +605 -0
- data/conf/design/release_management.yml +117 -0
- data/conf/design/retrofit.yml +199 -0
- data/conf/design/retrospective_analyzer.yml +79 -0
- data/conf/design/scope_hierarchy.yml +352 -0
- data/conf/design/security.yml +115 -0
- data/conf/design/session_retrospective.yml +85 -0
- data/conf/design/smart_ui_feedback.yml +89 -0
- data/conf/design/structured_logging.yml +148 -0
- data/conf/design/styles.yml +123 -0
- data/conf/design/test_peer_review.yml +89 -0
- data/conf/design/testing.yml +136 -0
- data/conf/design/threat_model.yml +108 -0
- data/conf/design/ui_framework.yml +111 -0
- data/conf/design/usage_optimization.yml +122 -0
- data/conf/design/version_management.yml +60 -0
- data/conf/design/workflow.yml +227 -0
- data/conf/mcp/server_defaults.yml +42 -0
- data/conf/mcp/trust.yml +21 -0
- data/conf/packaging/core.yml +12 -0
- data/conf/packaging/gtk4.yml +11 -0
- data/conf/packaging/qt6.yml +11 -0
- data/conf/policy/default_deny_list.yml +197 -0
- data/conf/review/cli-command-audit.yml +857 -0
- data/conf/review/design-docs.yml +1064 -0
- data/conf/review/design-questionnaire.yml +153 -0
- data/conf/review/questionnaire.yml +146 -0
- data/conf/review/rosett-ai-core.yml +2919 -0
- data/conf/schemas/ai_config_schema.json +73 -0
- data/conf/schemas/behaviour_schema.json +132 -0
- data/conf/schemas/compliance_rule_schema.json +63 -0
- data/conf/schemas/content_pack_manifest_schema.json +51 -0
- data/conf/schemas/design_schema.json +210 -0
- data/conf/schemas/engine_manifest_schema.json +144 -0
- data/conf/schemas/lockfile_schema.json +74 -0
- data/conf/schemas/mcp_server_schema.json +48 -0
- data/conf/schemas/packaging_schema.json +70 -0
- data/conf/schemas/policy_schema.json +85 -0
- data/conf/schemas/provenance_schema.json +84 -0
- data/conf/schemas/rai_config_schema.json +56 -0
- data/conf/schemas/rai_project_schema.json +20 -0
- data/conf/schemas/scope_hierarchy_schema.json +49 -0
- data/conf/schemas/target_schema.json +67 -0
- data/conf/schemas/tooling_schema.json +65 -0
- data/conf/schemas/workflow_schema.json +112 -0
- data/conf/targets/agents_md.yml +17 -0
- data/conf/targets/claude.yml +12 -0
- data/conf/tooling/tools.yml +58 -0
- data/dist/rosett-ai-mcp.service +48 -0
- data/dist/rosett-ai-mcp.yml.default +45 -0
- data/doc/AAIF_POSITIONING.md +58 -0
- data/doc/ADOPT.md +224 -0
- data/doc/AI_PROVENANCE.md +139 -0
- data/doc/ARCHITECTURE.md +920 -0
- data/doc/BEHAVIOUR.md +409 -0
- data/doc/BUILD.md +138 -0
- data/doc/CI_CD_RECIPES.md +171 -0
- data/doc/CLAUDE_SESSIONS_MOVED.md +16 -0
- data/doc/COMMAND_ANALYSIS.md +229 -0
- data/doc/CONFIGURATION.md +281 -0
- data/doc/DESIGN_AUDIT.md +235 -0
- data/doc/DESIGN_PEER_REVIEW.md +771 -0
- data/doc/DESKTOP.md +447 -0
- data/doc/ENGINES.md +567 -0
- data/doc/ENGINE_DEVELOPMENT_GUIDE.md +417 -0
- data/doc/FEATURE_AUDIT.md +218 -0
- data/doc/IMPLEMENTATION_PLAN.md +669 -0
- data/doc/INCIDENT_REPORT_2026-02-02.md +251 -0
- data/doc/MIGRATION_GUIDE.md +88 -0
- data/doc/PACKAGING.md +232 -0
- data/doc/PROJECT_DASHBOARD.md +153 -0
- data/doc/PULP_DEPLOYMENT.md +164 -0
- data/doc/QUALITY_FIX_SUMMARY.md +110 -0
- data/doc/QUICK_START.md +162 -0
- data/doc/REEK_CONFIGURATION.md +166 -0
- data/doc/REFERENCE.md +253 -0
- data/doc/REFERENCES.md +324 -0
- data/doc/SECURITY_REVIEW_CHECKLIST.md +72 -0
- data/doc/SESSION_2026-02-28_GTK4_HARDENING.md +359 -0
- data/doc/SETUP.md +202 -0
- data/doc/TEST_PEER_REVIEW.md +152 -0
- data/doc/THREAT_MODEL.md +230 -0
- data/doc/USAGE.md +545 -0
- data/doc/USER_MANUAL.md +585 -0
- data/doc/ai_test_review_checklist.md +110 -0
- data/doc/changes/2026-02-18-packaging-fpm.md +155 -0
- data/doc/changes/2026-02-19-testing-infrastructure.md +221 -0
- data/doc/changes/2026-02-20-security-implementation.md +281 -0
- data/doc/changes/2026-02-20-styles-implementation.md +220 -0
- data/doc/changes/2026-02-21-architecture-completion.md +95 -0
- data/doc/changes/2026-02-21-architecture-ui-layer.md +253 -0
- data/doc/changes/2026-02-21-cc-config-implementation.md +108 -0
- data/doc/changes/2026-02-21-ci-pipeline-implementation.md +214 -0
- data/doc/changes/2026-02-21-compiler-multi-target-pipeline.md +241 -0
- data/doc/changes/2026-02-21-config-design-show-commands.md +61 -0
- data/doc/changes/2026-02-21-design-implementation-overview.md +455 -0
- data/doc/changes/2026-02-21-lifecycle-management.md +196 -0
- data/doc/changes/2026-02-21-path-resolver.md +128 -0
- data/doc/changes/2026-02-24-ci-tmpdir-mutant-fetch.md +45 -0
- data/doc/changes/2026-03-01-ci-bundler-strategy.md +120 -0
- data/doc/changes/2026-03-20-security-hardening-phase2.md +163 -0
- data/doc/context/SESSION-HANDOFF.md +69 -0
- data/doc/context/ai-engine-usage-trends-2026.md +80 -0
- data/doc/context/plan-pluggable-engines.md +590 -0
- data/doc/decisions/001-flog-deferred.md +32 -0
- data/doc/decisions/002-path-resolution-strategy.md +158 -0
- data/doc/decisions/003-ui-adapter-selection.md +193 -0
- data/doc/decisions/004-design-document-validation.md +179 -0
- data/doc/decisions/005-package-splitting-strategy.md +200 -0
- data/doc/decisions/006-multi-engine-architecture.md +147 -0
- data/doc/decisions/007-engine-agnostic-pivot.md +219 -0
- data/doc/decisions/008-ci-bundler-strategy.md +129 -0
- data/doc/decisions/009-core-only-v1-release.md +60 -0
- data/doc/decisions/010-engine-debian-packaging.md +66 -0
- data/doc/decisions/011-context-aware-cli.md +71 -0
- data/doc/dependency_decisions.yml +247 -0
- data/doc/issues/001-wrapper-missing-environment-variables.md +197 -0
- data/doc/issues/002-embedded-ruby-wrong-prefix.md +217 -0
- data/doc/issues/003-smoke-test-false-positive.md +127 -0
- data/doc/issues/004-market-research-design-updates.md +109 -0
- data/doc/issues/005-compile-scope-coexistence.md +161 -0
- data/doc/locales/.gitkeep +0 -0
- data/doc/man/rai.1.ronn +505 -0
- data/doc/operations/packaging.md +133 -0
- data/doc/operations/rosett-ai-release.md +65 -0
- data/doc/reference/error-catalog.md +107 -0
- 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 +4 -0
- data/doc/reference/src/bibliography.bib +79 -0
- data/doc/reference/src/main.tex +1288 -0
- data/doc/reference/src/structure.tex +303 -0
- data/doc/rosett-ai-bookmarks.html +301 -0
- data/kitchen.yml +46 -0
- data/lib/rosett_ai/adopter/executor_resolver.rb +77 -0
- data/lib/rosett_ai/adopter/local_analysis_collector.rb +154 -0
- data/lib/rosett_ai/adopter/rule_adopter.rb +254 -0
- data/lib/rosett_ai/ai_config/config_compiler.rb +111 -0
- data/lib/rosett_ai/ai_config/context_window.rb +55 -0
- data/lib/rosett_ai/ai_config/cost_controls.rb +44 -0
- data/lib/rosett_ai/ai_config/fallback_chain.rb +64 -0
- data/lib/rosett_ai/ai_config/model_router.rb +121 -0
- data/lib/rosett_ai/ai_config/validator.rb +45 -0
- data/lib/rosett_ai/authorship/attribution_compiler.rb +99 -0
- data/lib/rosett_ai/authorship/disclosure_policy.rb +81 -0
- data/lib/rosett_ai/authorship/review_validator.rb +39 -0
- data/lib/rosett_ai/authorship/trailer_generator.rb +88 -0
- data/lib/rosett_ai/backup/compressor.rb +180 -0
- data/lib/rosett_ai/backup/destination.rb +91 -0
- data/lib/rosett_ai/behaviour/manager.rb +156 -0
- data/lib/rosett_ai/compiler/backend.rb +86 -0
- data/lib/rosett_ai/compiler/backends/agents_md_backend.rb +80 -0
- data/lib/rosett_ai/compiler/backends/claude_backend.rb +88 -0
- data/lib/rosett_ai/compiler/backends/generic_backend.rb +15 -0
- data/lib/rosett_ai/compiler/behaviour_compiler.rb +40 -0
- data/lib/rosett_ai/compiler/capability_checker.rb +104 -0
- data/lib/rosett_ai/compiler/compilation_pipeline.rb +361 -0
- data/lib/rosett_ai/compiler/compiled_output.rb +39 -0
- data/lib/rosett_ai/compiler/locale_compiler.rb +250 -0
- data/lib/rosett_ai/compiler/target_profile.rb +112 -0
- data/lib/rosett_ai/completion/generator.rb +101 -0
- data/lib/rosett_ai/completion/shells/bash_generator.rb +126 -0
- data/lib/rosett_ai/completion/shells/fish_generator.rb +78 -0
- data/lib/rosett_ai/completion/shells/zsh_generator.rb +126 -0
- data/lib/rosett_ai/comply/checkers/cra_checker.rb +102 -0
- data/lib/rosett_ai/comply/checkers/license_checker.rb +85 -0
- data/lib/rosett_ai/comply/checkers/spdx_header_checker.rb +98 -0
- data/lib/rosett_ai/comply/reporter.rb +113 -0
- data/lib/rosett_ai/comply/runner.rb +50 -0
- data/lib/rosett_ai/composition/circular_dependency_detector.rb +56 -0
- data/lib/rosett_ai/composition/composer.rb +158 -0
- data/lib/rosett_ai/composition/composition_result.rb +64 -0
- data/lib/rosett_ai/composition/conflict_detector.rb +53 -0
- data/lib/rosett_ai/composition/lockfile.rb +103 -0
- data/lib/rosett_ai/composition/merge_strategy.rb +131 -0
- data/lib/rosett_ai/composition/priority_sorter.rb +29 -0
- data/lib/rosett_ai/composition/scope_resolver.rb +55 -0
- data/lib/rosett_ai/config/compile_result.rb +37 -0
- data/lib/rosett_ai/config/compiler.rb +13 -0
- data/lib/rosett_ai/config/domain_transformer.rb +13 -0
- data/lib/rosett_ai/config/key_map.rb +13 -0
- data/lib/rosett_ai/config/masking_secret_resolver.rb +40 -0
- data/lib/rosett_ai/config/scope_router.rb +13 -0
- data/lib/rosett_ai/config/secret_resolver.rb +125 -0
- data/lib/rosett_ai/configuration.rb +119 -0
- data/lib/rosett_ai/content/content_client.rb +60 -0
- data/lib/rosett_ai/content/pack_installer.rb +117 -0
- data/lib/rosett_ai/content/pack_manifest.rb +50 -0
- data/lib/rosett_ai/content/pack_registry.rb +68 -0
- data/lib/rosett_ai/content_packs/manager.rb +50 -0
- data/lib/rosett_ai/dbus/compositor_detector.rb +77 -0
- data/lib/rosett_ai/dbus/focus_adapters/base.rb +59 -0
- data/lib/rosett_ai/dbus/focus_adapters/gnome_adapter.rb +172 -0
- data/lib/rosett_ai/dbus/focus_adapters/hyprland_adapter.rb +77 -0
- data/lib/rosett_ai/dbus/focus_adapters/i3_adapter.rb +65 -0
- data/lib/rosett_ai/dbus/focus_adapters/kwin_adapter.rb +103 -0
- data/lib/rosett_ai/dbus/focus_adapters/x11_adapter.rb +105 -0
- data/lib/rosett_ai/dbus/focus_monitor_interface.rb +103 -0
- data/lib/rosett_ai/dbus/manager_interface.rb +213 -0
- data/lib/rosett_ai/dbus/plugin_manager_interface.rb +169 -0
- data/lib/rosett_ai/dbus/rate_limiter.rb +89 -0
- data/lib/rosett_ai/dbus/service.rb +121 -0
- data/lib/rosett_ai/dbus/status_notifier_interface.rb +79 -0
- data/lib/rosett_ai/deprecation.rb +79 -0
- data/lib/rosett_ai/desktop/dbus_client.rb +259 -0
- data/lib/rosett_ai/desktop/gtk4_app.rb +371 -0
- data/lib/rosett_ai/desktop/gtk4_preferences.rb +331 -0
- data/lib/rosett_ai/desktop/gui_logger.rb +236 -0
- data/lib/rosett_ai/doctor/check.rb +92 -0
- data/lib/rosett_ai/doctor/checks/cache_health_check.rb +50 -0
- data/lib/rosett_ai/doctor/checks/dbus_availability_check.rb +39 -0
- data/lib/rosett_ai/doctor/checks/engine_detection_check.rb +46 -0
- data/lib/rosett_ai/doctor/checks/file_permission_check.rb +44 -0
- data/lib/rosett_ai/doctor/checks/gem_dependency_check.rb +55 -0
- data/lib/rosett_ai/doctor/checks/ruby_version_check.rb +50 -0
- data/lib/rosett_ai/doctor/checks/stale_config_nncc_check.rb +57 -0
- data/lib/rosett_ai/doctor/checks/stale_home_nncc_check.rb +59 -0
- data/lib/rosett_ai/doctor.rb +81 -0
- data/lib/rosett_ai/documentation/reference_compiler.rb +122 -0
- data/lib/rosett_ai/documentation/translator.rb +62 -0
- data/lib/rosett_ai/engines/base_config_compiler.rb +203 -0
- data/lib/rosett_ai/engines/detector.rb +63 -0
- data/lib/rosett_ai/engines/registry.rb +50 -0
- data/lib/rosett_ai/error_handler.rb +139 -0
- data/lib/rosett_ai/exit_codes.rb +76 -0
- data/lib/rosett_ai/feature_flags.rb +102 -0
- data/lib/rosett_ai/formatting.rb +33 -0
- data/lib/rosett_ai/gem_consistency_checker.rb +199 -0
- data/lib/rosett_ai/git_hooks/chain_detector.rb +86 -0
- data/lib/rosett_ai/git_hooks/installer.rb +175 -0
- data/lib/rosett_ai/git_hooks/script_generator.rb +125 -0
- data/lib/rosett_ai/gitlab/validators/supplementary_gitlab_ci_yaml_validator.rb +79 -0
- data/lib/rosett_ai/i18n/locale_resolver.rb +46 -0
- data/lib/rosett_ai/i18n/utf8_checker.rb +32 -0
- data/lib/rosett_ai/init/config_file_writer.rb +24 -0
- data/lib/rosett_ai/init/directory_builder.rb +38 -0
- data/lib/rosett_ai/init/file_copier.rb +95 -0
- data/lib/rosett_ai/init/global_initializer.rb +28 -0
- data/lib/rosett_ai/init/local_initializer.rb +27 -0
- data/lib/rosett_ai/init/mcp_registrar.rb +109 -0
- data/lib/rosett_ai/init/project_initializer.rb +38 -0
- data/lib/rosett_ai/licensing/license_key.rb +139 -0
- data/lib/rosett_ai/licensing/license_store.rb +64 -0
- data/lib/rosett_ai/licensing/license_validator.rb +60 -0
- data/lib/rosett_ai/licensing/tier.rb +42 -0
- data/lib/rosett_ai/mcp/admin/auditor.rb +88 -0
- data/lib/rosett_ai/mcp/admin/health_checker.rb +81 -0
- data/lib/rosett_ai/mcp/admin/registry.rb +100 -0
- data/lib/rosett_ai/mcp/admin/schema_validator.rb +63 -0
- data/lib/rosett_ai/mcp/enforcement/.gitkeep +0 -0
- data/lib/rosett_ai/mcp/enforcement/hook_generator.rb +197 -0
- data/lib/rosett_ai/mcp/enforcement/validator.rb +215 -0
- data/lib/rosett_ai/mcp/governance.rb +160 -0
- data/lib/rosett_ai/mcp/http_security_config.rb +158 -0
- data/lib/rosett_ai/mcp/instructions.rb +266 -0
- data/lib/rosett_ai/mcp/key_hasher.rb +66 -0
- data/lib/rosett_ai/mcp/keyfile.rb +221 -0
- data/lib/rosett_ai/mcp/middleware/authentication.rb +146 -0
- data/lib/rosett_ai/mcp/middleware/content_type.rb +56 -0
- data/lib/rosett_ai/mcp/middleware/cors.rb +83 -0
- data/lib/rosett_ai/mcp/middleware/origin_validation.rb +73 -0
- data/lib/rosett_ai/mcp/middleware/rate_limit.rb +106 -0
- data/lib/rosett_ai/mcp/middleware/request_size.rb +51 -0
- data/lib/rosett_ai/mcp/plugins.rb +143 -0
- data/lib/rosett_ai/mcp/prompts/compilation_prompt.rb +40 -0
- data/lib/rosett_ai/mcp/prompts/compliance_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/prompts/diagnostics_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/prompts/validation_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/resources/behaviour_resource.rb +127 -0
- data/lib/rosett_ai/mcp/resources/config_resource.rb +72 -0
- data/lib/rosett_ai/mcp/resources/design_resource.rb +58 -0
- data/lib/rosett_ai/mcp/resources/hooks_resource.rb +74 -0
- data/lib/rosett_ai/mcp/resources/provenance_resource.rb +51 -0
- data/lib/rosett_ai/mcp/resources/rules_resource.rb +60 -0
- data/lib/rosett_ai/mcp/resources/schema_resource.rb +72 -0
- data/lib/rosett_ai/mcp/response_helper.rb +46 -0
- data/lib/rosett_ai/mcp/security_logger.rb +60 -0
- data/lib/rosett_ai/mcp/server.rb +212 -0
- data/lib/rosett_ai/mcp/settings/server_installer.rb +112 -0
- data/lib/rosett_ai/mcp/settings/trust_manager.rb +142 -0
- data/lib/rosett_ai/mcp/tools/adopt_tool.rb +70 -0
- data/lib/rosett_ai/mcp/tools/backup_tool.rb +64 -0
- data/lib/rosett_ai/mcp/tools/behaviour_display_tool.rb +72 -0
- data/lib/rosett_ai/mcp/tools/behaviour_list_tool.rb +56 -0
- data/lib/rosett_ai/mcp/tools/behaviour_manage_tool.rb +114 -0
- data/lib/rosett_ai/mcp/tools/behaviour_show_tool.rb +62 -0
- data/lib/rosett_ai/mcp/tools/compile_status_tool.rb +122 -0
- data/lib/rosett_ai/mcp/tools/compile_tool.rb +191 -0
- data/lib/rosett_ai/mcp/tools/comply_tool.rb +79 -0
- data/lib/rosett_ai/mcp/tools/config_compile_tool.rb +71 -0
- data/lib/rosett_ai/mcp/tools/config_status_tool.rb +79 -0
- data/lib/rosett_ai/mcp/tools/content_tool.rb +78 -0
- data/lib/rosett_ai/mcp/tools/context_query_tool.rb +156 -0
- data/lib/rosett_ai/mcp/tools/design_list_tool.rb +57 -0
- data/lib/rosett_ai/mcp/tools/design_show_tool.rb +69 -0
- data/lib/rosett_ai/mcp/tools/doctor_tool.rb +62 -0
- data/lib/rosett_ai/mcp/tools/documentation_status_tool.rb +45 -0
- data/lib/rosett_ai/mcp/tools/engines_tool.rb +84 -0
- data/lib/rosett_ai/mcp/tools/hook_install_tool.rb +190 -0
- data/lib/rosett_ai/mcp/tools/hook_preview_tool.rb +173 -0
- data/lib/rosett_ai/mcp/tools/hooks_status_tool.rb +84 -0
- data/lib/rosett_ai/mcp/tools/init_tool.rb +87 -0
- data/lib/rosett_ai/mcp/tools/license_status_tool.rb +44 -0
- data/lib/rosett_ai/mcp/tools/project_tool.rb +117 -0
- data/lib/rosett_ai/mcp/tools/provenance_tool.rb +97 -0
- data/lib/rosett_ai/mcp/tools/provenance_write_tool.rb +40 -0
- data/lib/rosett_ai/mcp/tools/retrofit_tool.rb +81 -0
- data/lib/rosett_ai/mcp/tools/rule_search_tool.rb +163 -0
- data/lib/rosett_ai/mcp/tools/schema_get_tool.rb +94 -0
- data/lib/rosett_ai/mcp/tools/tooling_tool.rb +86 -0
- data/lib/rosett_ai/mcp/tools/validate_tool.rb +105 -0
- data/lib/rosett_ai/mcp/tools/workflow_execute_tool.rb +74 -0
- data/lib/rosett_ai/mcp/tools/workflow_tool.rb +78 -0
- data/lib/rosett_ai/migration/detector.rb +117 -0
- data/lib/rosett_ai/migration/nncc_config_migrator.rb +94 -0
- data/lib/rosett_ai/migration/nncc_project_migrator.rb +90 -0
- data/lib/rosett_ai/migration/xdg_migrator.rb +123 -0
- data/lib/rosett_ai/package_manager/apt.rb +108 -0
- data/lib/rosett_ai/package_manager/base.rb +68 -0
- data/lib/rosett_ai/package_manager/gem_backend.rb +90 -0
- data/lib/rosett_ai/packaging/variant_config.rb +92 -0
- data/lib/rosett_ai/path_resolver.rb +115 -0
- data/lib/rosett_ai/plugins/contract.rb +43 -0
- data/lib/rosett_ai/plugins/engine_contract.rb +60 -0
- data/lib/rosett_ai/plugins/gui_contract.rb +74 -0
- data/lib/rosett_ai/plugins/mcp_contract.rb +48 -0
- data/lib/rosett_ai/plugins/registry.rb +150 -0
- data/lib/rosett_ai/policy/auditor.rb +41 -0
- data/lib/rosett_ai/policy/deny_list.rb +71 -0
- data/lib/rosett_ai/policy/opt_out_scanner.rb +37 -0
- data/lib/rosett_ai/policy/policy_compiler.rb +84 -0
- data/lib/rosett_ai/policy/protected_files.rb +47 -0
- data/lib/rosett_ai/policy/tier_hierarchy.rb +48 -0
- data/lib/rosett_ai/policy/validator.rb +35 -0
- data/lib/rosett_ai/profiler.rb +79 -0
- data/lib/rosett_ai/project/drift_detector.rb +126 -0
- data/lib/rosett_ai/project/manager.rb +115 -0
- data/lib/rosett_ai/project/sync_manager.rb +138 -0
- data/lib/rosett_ai/project/template_applier.rb +105 -0
- data/lib/rosett_ai/project_context.rb +82 -0
- data/lib/rosett_ai/provenance/entry.rb +63 -0
- data/lib/rosett_ai/provenance/file_source.rb +32 -0
- data/lib/rosett_ai/provenance/source.rb +62 -0
- data/lib/rosett_ai/provenance/store.rb +153 -0
- data/lib/rosett_ai/provenance/tracker.rb +62 -0
- data/lib/rosett_ai/provenance/trailer_generator.rb +43 -0
- data/lib/rosett_ai/provenance/validator.rb +45 -0
- data/lib/rosett_ai/quorum/collector.rb +59 -0
- data/lib/rosett_ai/quorum/comparator.rb +81 -0
- data/lib/rosett_ai/quorum/dispatcher.rb +57 -0
- data/lib/rosett_ai/quorum/strategies/adopt.rb +56 -0
- data/lib/rosett_ai/rai_config.rb +107 -0
- data/lib/rosett_ai/retrofit/base_parser.rb +66 -0
- data/lib/rosett_ai/retrofit/engine.rb +171 -0
- data/lib/rosett_ai/retrofit/parsers/agents_md_parser.rb +50 -0
- data/lib/rosett_ai/retrofit/parsers/claude_parser.rb +69 -0
- data/lib/rosett_ai/retrofit/parsers/cursor_parser.rb +82 -0
- data/lib/rosett_ai/retrofit/round_trip_validator.rb +65 -0
- data/lib/rosett_ai/retrofit/scanner.rb +47 -0
- data/lib/rosett_ai/retrofit/secret_detector.rb +87 -0
- data/lib/rosett_ai/secrets_resolver.rb +71 -0
- data/lib/rosett_ai/smart_feedback/suggester.rb +83 -0
- data/lib/rosett_ai/smart_feedback/thor_middleware.rb +84 -0
- data/lib/rosett_ai/structured_logger.rb +110 -0
- data/lib/rosett_ai/telemetry/json_lines_writer.rb +50 -0
- data/lib/rosett_ai/telemetry/log_rotator.rb +67 -0
- data/lib/rosett_ai/telemetry/provider.rb +26 -0
- data/lib/rosett_ai/telemetry/reporter.rb +144 -0
- data/lib/rosett_ai/telemetry.rb +47 -0
- data/lib/rosett_ai/text_sanitizer.rb +62 -0
- data/lib/rosett_ai/thor/cli.rb +269 -0
- data/lib/rosett_ai/thor/tasks/adopt.rb +250 -0
- data/lib/rosett_ai/thor/tasks/backup.rb +420 -0
- data/lib/rosett_ai/thor/tasks/behaviour.rb +474 -0
- data/lib/rosett_ai/thor/tasks/build.rb +1162 -0
- data/lib/rosett_ai/thor/tasks/compile.rb +415 -0
- data/lib/rosett_ai/thor/tasks/completion.rb +123 -0
- data/lib/rosett_ai/thor/tasks/comply.rb +82 -0
- data/lib/rosett_ai/thor/tasks/config.rb +265 -0
- data/lib/rosett_ai/thor/tasks/content.rb +193 -0
- data/lib/rosett_ai/thor/tasks/dbus.rb +321 -0
- data/lib/rosett_ai/thor/tasks/design.rb +258 -0
- data/lib/rosett_ai/thor/tasks/desktop.rb +129 -0
- data/lib/rosett_ai/thor/tasks/doctor.rb +127 -0
- data/lib/rosett_ai/thor/tasks/documentation.rb +321 -0
- data/lib/rosett_ai/thor/tasks/engines.rb +167 -0
- data/lib/rosett_ai/thor/tasks/hooks.rb +219 -0
- data/lib/rosett_ai/thor/tasks/init.rb +259 -0
- data/lib/rosett_ai/thor/tasks/license.rb +120 -0
- data/lib/rosett_ai/thor/tasks/mcp.rb +535 -0
- data/lib/rosett_ai/thor/tasks/migrate.rb +121 -0
- data/lib/rosett_ai/thor/tasks/plugins.rb +157 -0
- data/lib/rosett_ai/thor/tasks/project.rb +260 -0
- data/lib/rosett_ai/thor/tasks/provenance.rb +195 -0
- data/lib/rosett_ai/thor/tasks/release.rb +314 -0
- data/lib/rosett_ai/thor/tasks/retrofit.rb +90 -0
- data/lib/rosett_ai/thor/tasks/tooling.rb +308 -0
- data/lib/rosett_ai/thor/tasks/validate.rb +108 -0
- data/lib/rosett_ai/thor/tasks/workflow.rb +196 -0
- data/lib/rosett_ai/tooling/ci_yaml_validator.rb +37 -0
- data/lib/rosett_ai/tooling/version_checker.rb +35 -0
- data/lib/rosett_ai/ui/accessible_tui.rb +61 -0
- data/lib/rosett_ai/ui/base.rb +46 -0
- data/lib/rosett_ai/ui/gtk4.rb +98 -0
- data/lib/rosett_ai/ui/kde.rb +40 -0
- data/lib/rosett_ai/ui/qt6.rb +40 -0
- data/lib/rosett_ai/ui/registry.rb +60 -0
- data/lib/rosett_ai/ui/tty_helper.rb +74 -0
- data/lib/rosett_ai/ui/tui.rb +59 -0
- data/lib/rosett_ai/validators/behaviour_validator.rb +20 -0
- data/lib/rosett_ai/validators/design_validator.rb +17 -0
- data/lib/rosett_ai/validators/schema_validator.rb +84 -0
- data/lib/rosett_ai/validators/tooling_validator.rb +17 -0
- data/lib/rosett_ai/version.rb +8 -0
- data/lib/rosett_ai/version_consistency_checker.rb +129 -0
- data/lib/rosett_ai/workflow/audit_log.rb +86 -0
- data/lib/rosett_ai/workflow/engine.rb +142 -0
- data/lib/rosett_ai/workflow/manager.rb +82 -0
- data/lib/rosett_ai/workflow/schema_validator.rb +71 -0
- data/lib/rosett_ai/workflow/step_runner.rb +61 -0
- data/lib/rosett_ai/workflow/steps/prompt_step.rb +62 -0
- data/lib/rosett_ai/workflow/steps/rai_step.rb +74 -0
- data/lib/rosett_ai/workflow/steps/shell_step.rb +53 -0
- data/lib/rosett_ai/yaml_loader.rb +78 -0
- data/lib/rosett_ai.rb +221 -0
- data/lib/rubocop/cop/rosett_ai/shell_interpolation.rb +54 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_const_get.rb +60 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_send.rb +50 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_yaml_load.rb +40 -0
- data/lib/rubocop/rosett_ai.rb +9 -0
- data/lib/scripts/generated/docker_hub_tags.rb +126 -0
- data/locales/.gitkeep +0 -0
- data/locales/ar.yml +579 -0
- data/locales/en.yml +571 -0
- data/locales/fr.yml +567 -0
- data/packaging/build-engine-deb.sh +81 -0
- data/packaging/scripts/postinst +17 -0
- data/packaging/scripts/postrm +19 -0
- data/packaging/scripts/prerm +10 -0
- data/packaging/wrapper.sh.template +38 -0
- data/rosett-ai.gemspec +63 -0
- data/rules/.gitkeep +0 -0
- data/scripts/publish/pulp_upload.sh +123 -0
- data/settings.json +29 -0
- data/share/applications/be.neatnerds.rosettai.desktop +29 -0
- data/share/dbus-1/interfaces/be.neatnerds.rosettai.xml +103 -0
- data/share/dbus-1/services/be.neatnerds.rosettai.service +3 -0
- data/share/templates/behaviour/criticalthinking.yml +69 -0
- metadata +810 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
require 'dbus'
|
|
7
|
+
|
|
8
|
+
module RosettAi
|
|
9
|
+
module DBus
|
|
10
|
+
# D-Bus StatusNotifierItem interface for system tray presence.
|
|
11
|
+
#
|
|
12
|
+
# Implements org.kde.StatusNotifierItem, the freedesktop standard
|
|
13
|
+
# for system tray icons on Linux. Supports KDE, GNOME (via extension),
|
|
14
|
+
# and Xfce status notifier hosts.
|
|
15
|
+
#
|
|
16
|
+
# Degrades gracefully if no StatusNotifierHost is available.
|
|
17
|
+
class StatusNotifierInterface < ::DBus::Object
|
|
18
|
+
INTERFACE = 'org.kde.StatusNotifierItem'
|
|
19
|
+
|
|
20
|
+
CATEGORY = 'ApplicationStatus'
|
|
21
|
+
ICON_NAME = 'rosett-ai-symbolic'
|
|
22
|
+
APP_ID = 'be.neatnerds.rosettai'
|
|
23
|
+
|
|
24
|
+
dbus_interface INTERFACE do
|
|
25
|
+
dbus_method :Activate, 'in x:i, in y:i' do |_x, _y|
|
|
26
|
+
activate
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
dbus_method :ContextMenu, 'in x:i, in y:i' do |_x, _y|
|
|
30
|
+
context_menu
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
dbus_attr_reader :id, 's'
|
|
34
|
+
dbus_attr_reader :category, 's'
|
|
35
|
+
dbus_attr_reader :status, 's'
|
|
36
|
+
dbus_attr_reader :title, 's'
|
|
37
|
+
dbus_attr_reader :icon_name, 's'
|
|
38
|
+
dbus_attr_reader :tool_tip, '(sa(iiay)ss)'
|
|
39
|
+
|
|
40
|
+
dbus_signal :NewStatus, 'status:s'
|
|
41
|
+
dbus_signal :NewTitle
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize(path)
|
|
45
|
+
super
|
|
46
|
+
@current_status = 'Active'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def id = APP_ID
|
|
50
|
+
def category = CATEGORY
|
|
51
|
+
def status = @current_status
|
|
52
|
+
def title = "rai #{RosettAi::VERSION}"
|
|
53
|
+
def icon_name = ICON_NAME
|
|
54
|
+
|
|
55
|
+
# ToolTip is a struct: (icon_name, icon_pixmap[], title, body)
|
|
56
|
+
def tool_tip
|
|
57
|
+
[ICON_NAME, [], "rai #{RosettAi::VERSION}", 'NeatNerds Code Companion']
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Update displayed status and emit signal.
|
|
61
|
+
#
|
|
62
|
+
# @param new_status [String] one of 'Passive', 'Active', 'NeedsAttention'
|
|
63
|
+
def update_status(new_status)
|
|
64
|
+
@current_status = new_status
|
|
65
|
+
NewStatus(new_status)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def activate
|
|
71
|
+
RosettAi.logger.info('StatusNotifierItem activated')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def context_menu
|
|
75
|
+
RosettAi.logger.info('StatusNotifierItem context menu requested')
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
require 'rainbow'
|
|
7
|
+
|
|
8
|
+
module RosettAi
|
|
9
|
+
# Structured deprecation warning system.
|
|
10
|
+
#
|
|
11
|
+
# Emits formatted warnings to stderr when deprecated features are used,
|
|
12
|
+
# including the version where deprecation started and the planned removal
|
|
13
|
+
# version. Warnings are deduplicated per session to avoid noise.
|
|
14
|
+
#
|
|
15
|
+
# @author hugo
|
|
16
|
+
# @author claude
|
|
17
|
+
# @see conf/design/backward_compatibility.yml
|
|
18
|
+
module Deprecation
|
|
19
|
+
@warned = {}
|
|
20
|
+
@mutex = Mutex.new
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
# Emit a deprecation warning for a feature.
|
|
24
|
+
#
|
|
25
|
+
# Deduplicates by feature name — a second call for the same feature
|
|
26
|
+
# within the same process is silently ignored.
|
|
27
|
+
#
|
|
28
|
+
# @param feature [String] the deprecated feature name (e.g. "--target")
|
|
29
|
+
# @param replacement [String] the replacement (e.g. "--engine")
|
|
30
|
+
# @param since [String] version when deprecation started (e.g. "1.1.0")
|
|
31
|
+
# @param removal [String] version when feature will be removed (e.g. "2.0.0")
|
|
32
|
+
# @param stderr [IO] output stream for warnings (default: $stderr)
|
|
33
|
+
# @return [void]
|
|
34
|
+
def warn_deprecated(feature:, replacement:, since:, removal:, stderr: $stderr)
|
|
35
|
+
return if already_warned?(feature)
|
|
36
|
+
|
|
37
|
+
mark_warned(feature)
|
|
38
|
+
message = format_message(feature: feature, replacement: replacement, since: since, removal: removal)
|
|
39
|
+
formatted = tty?(stderr) ? Rainbow(message).yellow : message
|
|
40
|
+
stderr.puts formatted
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Check whether a feature has already been warned in this session.
|
|
44
|
+
#
|
|
45
|
+
# @param feature [String]
|
|
46
|
+
# @return [Boolean]
|
|
47
|
+
def already_warned?(feature)
|
|
48
|
+
@mutex.synchronize { @warned.key?(feature) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Reset all warned state. Intended for test isolation.
|
|
52
|
+
#
|
|
53
|
+
# @return [void]
|
|
54
|
+
def reset!
|
|
55
|
+
@mutex.synchronize { @warned = {} }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def mark_warned(feature)
|
|
61
|
+
@mutex.synchronize { @warned[feature] = true }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def format_message(feature:, replacement:, since:, removal:)
|
|
65
|
+
::I18n.t(
|
|
66
|
+
'rosett_ai.deprecation.warning',
|
|
67
|
+
feature: feature,
|
|
68
|
+
replacement: replacement,
|
|
69
|
+
since: since,
|
|
70
|
+
removal: removal
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def tty?(io)
|
|
75
|
+
io.respond_to?(:tty?) && io.tty?
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
require 'dbus'
|
|
7
|
+
require_relative 'gui_logger'
|
|
8
|
+
|
|
9
|
+
module RosettAi
|
|
10
|
+
module Desktop
|
|
11
|
+
# D-Bus client for communicating with be.neatnerds.rosettai service.
|
|
12
|
+
#
|
|
13
|
+
# SAFETY: This client is designed to NEVER raise exceptions to callers.
|
|
14
|
+
# All methods return safe default values on failure. This is critical
|
|
15
|
+
# for GUI stability - a D-Bus failure should never crash the app.
|
|
16
|
+
#
|
|
17
|
+
# All GTK4/Qt6 desktop apps use this client instead of calling
|
|
18
|
+
# Ruby Rosett-AI modules directly. This ensures the D-Bus service is
|
|
19
|
+
# the single source of truth.
|
|
20
|
+
class DbusClient
|
|
21
|
+
BUS_NAME = 'be.neatnerds.rosettai'
|
|
22
|
+
OBJECT_PATH = '/be/neatnerds/rosett-ai'
|
|
23
|
+
MANAGER_IFACE = 'be.neatnerds.rosettai.Manager'
|
|
24
|
+
FOCUS_IFACE = 'be.neatnerds.rosettai.FocusMonitor'
|
|
25
|
+
|
|
26
|
+
# Default safe return values
|
|
27
|
+
SAFE_STATUS = { 'error' => 'Service not available', 'version' => 'unknown' }.freeze
|
|
28
|
+
SAFE_FOCUS = ['', ''].freeze
|
|
29
|
+
SAFE_COMPILE_RESULT = 'Error: D-Bus service not available'
|
|
30
|
+
|
|
31
|
+
attr_reader :bus, :last_error
|
|
32
|
+
|
|
33
|
+
def initialize
|
|
34
|
+
@bus = nil
|
|
35
|
+
@object = nil
|
|
36
|
+
@connected = false
|
|
37
|
+
@last_error = nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Connect to the D-Bus session bus and get service proxy.
|
|
41
|
+
#
|
|
42
|
+
# @return [Boolean] true if connected successfully
|
|
43
|
+
def connect
|
|
44
|
+
return true if @connected
|
|
45
|
+
|
|
46
|
+
GuiLogger.dbus_call(:connect, bus_name: BUS_NAME)
|
|
47
|
+
@last_error = nil
|
|
48
|
+
@bus = ::DBus::SessionBus.instance
|
|
49
|
+
service = @bus.service(BUS_NAME)
|
|
50
|
+
@object = service.object(OBJECT_PATH)
|
|
51
|
+
@object.introspect
|
|
52
|
+
@connected = true
|
|
53
|
+
GuiLogger.dbus_call(:connect, status: :success)
|
|
54
|
+
true
|
|
55
|
+
rescue ::DBus::Error => e
|
|
56
|
+
@last_error = e.message
|
|
57
|
+
log_error('D-Bus connection failed', e)
|
|
58
|
+
@connected = false
|
|
59
|
+
false
|
|
60
|
+
rescue StandardError => e
|
|
61
|
+
@last_error = e.message
|
|
62
|
+
log_error('Unexpected error during D-Bus connection', e)
|
|
63
|
+
@connected = false
|
|
64
|
+
false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Check if connected to D-Bus service.
|
|
68
|
+
#
|
|
69
|
+
# @return [Boolean]
|
|
70
|
+
def connected?
|
|
71
|
+
@connected
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Check if the D-Bus service is available.
|
|
75
|
+
# SAFETY: Never raises, returns false on any error.
|
|
76
|
+
#
|
|
77
|
+
# @return [Boolean]
|
|
78
|
+
def service_available?
|
|
79
|
+
return false unless connect
|
|
80
|
+
|
|
81
|
+
@bus.service(BUS_NAME).exists?
|
|
82
|
+
rescue StandardError => e
|
|
83
|
+
log_error('Service availability check failed', e)
|
|
84
|
+
false
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Get service status from Manager interface.
|
|
88
|
+
# SAFETY: Never raises, returns safe default hash on error.
|
|
89
|
+
#
|
|
90
|
+
# @return [Hash] status dictionary
|
|
91
|
+
def status
|
|
92
|
+
return SAFE_STATUS.dup unless safe_connect
|
|
93
|
+
|
|
94
|
+
@object.default_iface = MANAGER_IFACE
|
|
95
|
+
result = @object.GetStatus
|
|
96
|
+
result.is_a?(Array) ? result.first : SAFE_STATUS.dup
|
|
97
|
+
rescue StandardError => e
|
|
98
|
+
log_error('GetStatus failed', e)
|
|
99
|
+
SAFE_STATUS.merge('error' => e.message)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Run compilation via D-Bus.
|
|
103
|
+
# SAFETY: Never raises, returns error string on failure.
|
|
104
|
+
#
|
|
105
|
+
# @return [String] compilation result or error message
|
|
106
|
+
def compile
|
|
107
|
+
GuiLogger.dbus_call(:compile, interface: MANAGER_IFACE)
|
|
108
|
+
return SAFE_COMPILE_RESULT unless safe_connect
|
|
109
|
+
|
|
110
|
+
@object.default_iface = MANAGER_IFACE
|
|
111
|
+
result = @object.Compile
|
|
112
|
+
output = result.is_a?(Array) ? result.first : result.to_s
|
|
113
|
+
GuiLogger.dbus_call(:compile, status: :success, result_length: output.length)
|
|
114
|
+
output
|
|
115
|
+
rescue StandardError => e
|
|
116
|
+
log_error('Compile failed', e)
|
|
117
|
+
"Error: #{e.message}"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Switch AI context.
|
|
121
|
+
# SAFETY: Never raises, returns false on failure.
|
|
122
|
+
#
|
|
123
|
+
# @param context_name [String] name of context to switch to
|
|
124
|
+
# @return [Boolean] true if successful
|
|
125
|
+
def switch_context(context_name)
|
|
126
|
+
return false unless safe_connect
|
|
127
|
+
|
|
128
|
+
@object.default_iface = MANAGER_IFACE
|
|
129
|
+
@object.SwitchContext(context_name)
|
|
130
|
+
true
|
|
131
|
+
rescue StandardError => e
|
|
132
|
+
log_error('SwitchContext failed', e)
|
|
133
|
+
false
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Get current focus from FocusMonitor interface.
|
|
137
|
+
# SAFETY: Never raises, returns empty array on failure.
|
|
138
|
+
#
|
|
139
|
+
# @return [Array<String>] [app_id, window_title]
|
|
140
|
+
def current_focus
|
|
141
|
+
return SAFE_FOCUS.dup unless safe_connect
|
|
142
|
+
|
|
143
|
+
@object.default_iface = FOCUS_IFACE
|
|
144
|
+
result = @object.GetCurrentFocus
|
|
145
|
+
result.is_a?(Array) && result.size >= 2 ? result : SAFE_FOCUS.dup
|
|
146
|
+
rescue StandardError => e
|
|
147
|
+
log_error('GetCurrentFocus failed', e)
|
|
148
|
+
SAFE_FOCUS.dup
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Subscribe to FocusChanged signal.
|
|
152
|
+
# SAFETY: Never raises, silently fails if service unavailable.
|
|
153
|
+
#
|
|
154
|
+
# @yield [app_id, title] called when focus changes
|
|
155
|
+
# @return [Boolean] true if subscription succeeded
|
|
156
|
+
def on_focus_changed(&block)
|
|
157
|
+
return false unless safe_connect
|
|
158
|
+
return false unless block
|
|
159
|
+
|
|
160
|
+
@object.default_iface = FOCUS_IFACE
|
|
161
|
+
@object.on_signal('FocusChanged', &block)
|
|
162
|
+
true
|
|
163
|
+
rescue StandardError => e
|
|
164
|
+
log_error('FocusChanged subscription failed', e)
|
|
165
|
+
false
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Subscribe to ContextChanged signal.
|
|
169
|
+
# SAFETY: Never raises, silently fails if service unavailable.
|
|
170
|
+
#
|
|
171
|
+
# @yield [context_name] called when context changes
|
|
172
|
+
# @return [Boolean] true if subscription succeeded
|
|
173
|
+
def on_context_changed(&block)
|
|
174
|
+
return false unless safe_connect
|
|
175
|
+
return false unless block
|
|
176
|
+
|
|
177
|
+
@object.default_iface = MANAGER_IFACE
|
|
178
|
+
@object.on_signal('ContextChanged', &block)
|
|
179
|
+
true
|
|
180
|
+
rescue StandardError => e
|
|
181
|
+
log_error('ContextChanged subscription failed', e)
|
|
182
|
+
false
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# List available engines from D-Bus service.
|
|
186
|
+
# SAFETY: Never raises, returns empty array on failure.
|
|
187
|
+
#
|
|
188
|
+
# @return [Array<Hash>] engine hashes with :name and :display_name keys
|
|
189
|
+
def list_engines
|
|
190
|
+
return [] unless safe_connect
|
|
191
|
+
|
|
192
|
+
@object.default_iface = MANAGER_IFACE
|
|
193
|
+
result = @object.ListEngines
|
|
194
|
+
tuples = result.is_a?(Array) ? result.first : []
|
|
195
|
+
(tuples || []).map { |name, display| { name: name, display_name: display } }
|
|
196
|
+
rescue StandardError => e
|
|
197
|
+
log_error('ListEngines failed', e)
|
|
198
|
+
[]
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Update a configuration key via D-Bus.
|
|
202
|
+
# SAFETY: Never raises, returns false on failure.
|
|
203
|
+
#
|
|
204
|
+
# @param key [String] configuration key (e.g. 'default_engine')
|
|
205
|
+
# @param value [String] new value
|
|
206
|
+
# @return [Boolean] true if successful
|
|
207
|
+
def set_config(key, value)
|
|
208
|
+
return false unless safe_connect
|
|
209
|
+
|
|
210
|
+
@object.default_iface = MANAGER_IFACE
|
|
211
|
+
result = @object.SetConfig(key, value.to_s)
|
|
212
|
+
output = result.is_a?(Array) ? result.first : result.to_s
|
|
213
|
+
!output.start_with?('Error:')
|
|
214
|
+
rescue StandardError => e
|
|
215
|
+
log_error('SetConfig failed', e)
|
|
216
|
+
false
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Disconnect from D-Bus.
|
|
220
|
+
# SAFETY: Never raises.
|
|
221
|
+
def disconnect
|
|
222
|
+
@connected = false
|
|
223
|
+
@object = nil
|
|
224
|
+
@bus = nil
|
|
225
|
+
@last_error = nil
|
|
226
|
+
rescue StandardError => e
|
|
227
|
+
log_error('Disconnect failed', e)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
private
|
|
231
|
+
|
|
232
|
+
# Safe connect that never raises.
|
|
233
|
+
#
|
|
234
|
+
# @return [Boolean] true if connected
|
|
235
|
+
def safe_connect
|
|
236
|
+
connect
|
|
237
|
+
rescue StandardError => e
|
|
238
|
+
log_error('Safe connect failed', e)
|
|
239
|
+
false
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Log error without raising.
|
|
243
|
+
#
|
|
244
|
+
# @param context [String] what operation failed
|
|
245
|
+
# @param error [Exception] the error
|
|
246
|
+
def log_error(context, error)
|
|
247
|
+
@last_error = error.message
|
|
248
|
+
GuiLogger.error(context, error, component: 'DbusClient')
|
|
249
|
+
|
|
250
|
+
return unless defined?(RosettAi.logger) && RosettAi.logger
|
|
251
|
+
|
|
252
|
+
RosettAi.logger.debug("[DbusClient] #{context}: #{error.class} - #{error.message}")
|
|
253
|
+
rescue StandardError
|
|
254
|
+
# Never let logging itself cause issues
|
|
255
|
+
nil
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|