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,321 @@
|
|
|
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 'json'
|
|
7
|
+
require 'thor'
|
|
8
|
+
require 'rainbow'
|
|
9
|
+
require 'terminal-table'
|
|
10
|
+
|
|
11
|
+
module RosettAi
|
|
12
|
+
module Thor
|
|
13
|
+
module Tasks
|
|
14
|
+
# Thor task for D-Bus service management.
|
|
15
|
+
#
|
|
16
|
+
# Exit codes:
|
|
17
|
+
# 0 — success
|
|
18
|
+
# 1 — D-Bus connection failure
|
|
19
|
+
# 5 — missing ruby-dbus dependency
|
|
20
|
+
#
|
|
21
|
+
# @author hugo
|
|
22
|
+
# @author claude
|
|
23
|
+
class DBus < ::Thor
|
|
24
|
+
EXIT_SUCCESS = 0
|
|
25
|
+
EXIT_DBUS_FAILURE = 1
|
|
26
|
+
EXIT_MISSING_DEPENDENCY = 5
|
|
27
|
+
|
|
28
|
+
ENV_VARS = [
|
|
29
|
+
'SWAYSOCK', 'I3SOCK', 'HYPRLAND_INSTANCE_SIGNATURE', 'DISPLAY', 'WAYLAND_DISPLAY', 'XDG_RUNTIME_DIR', 'XDG_SESSION_TYPE'
|
|
30
|
+
].freeze
|
|
31
|
+
|
|
32
|
+
ADAPTER_MAP = {
|
|
33
|
+
sway: 'I3Adapter (i3ipc)',
|
|
34
|
+
i3: 'I3Adapter (i3ipc)',
|
|
35
|
+
hyprland: 'HyprlandAdapter (socket2)',
|
|
36
|
+
gnome: 'GnomeAdapter (Shell D-Bus)',
|
|
37
|
+
kwin: 'KwinAdapter (KWin D-Bus)',
|
|
38
|
+
x11: 'X11Adapter (xprop)'
|
|
39
|
+
}.freeze
|
|
40
|
+
|
|
41
|
+
desc 'status', 'Show D-Bus service status'
|
|
42
|
+
long_desc <<~LONGDESC
|
|
43
|
+
Checks if the be.neatnerds.rosettai D-Bus service is running and displays status.
|
|
44
|
+
Output format depends on TTY detection (table or JSON).
|
|
45
|
+
|
|
46
|
+
Exit codes:
|
|
47
|
+
0: success
|
|
48
|
+
1: D-Bus connection failure
|
|
49
|
+
5: missing ruby-dbus gem
|
|
50
|
+
|
|
51
|
+
EXAMPLES
|
|
52
|
+
|
|
53
|
+
raictl dbus status
|
|
54
|
+
|
|
55
|
+
Related commands: raictl dbus start, rai dbus detect
|
|
56
|
+
LONGDESC
|
|
57
|
+
def status
|
|
58
|
+
require_desktop_gems!
|
|
59
|
+
check_dbus_availability
|
|
60
|
+
|
|
61
|
+
if service_running?
|
|
62
|
+
print_running_status
|
|
63
|
+
else
|
|
64
|
+
print_not_running
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
desc 'start', 'Start the D-Bus service (foreground)'
|
|
69
|
+
long_desc <<~LONGDESC
|
|
70
|
+
Starts the be.neatnerds.rosettai D-Bus service for focus tracking and IPC.
|
|
71
|
+
By default runs in foreground. Use --daemonize to run as background daemon.
|
|
72
|
+
|
|
73
|
+
Flags:
|
|
74
|
+
--daemonize, -d: Run as daemon (background)
|
|
75
|
+
|
|
76
|
+
Exit codes:
|
|
77
|
+
0: success
|
|
78
|
+
1: D-Bus connection failure or service already running
|
|
79
|
+
5: missing ruby-dbus gem
|
|
80
|
+
|
|
81
|
+
EXAMPLES
|
|
82
|
+
|
|
83
|
+
raictl dbus start
|
|
84
|
+
raictl dbus start --daemonize
|
|
85
|
+
|
|
86
|
+
Related commands: raictl dbus status, rai dbus stop
|
|
87
|
+
LONGDESC
|
|
88
|
+
method_option :daemonize,
|
|
89
|
+
type: :boolean,
|
|
90
|
+
default: false,
|
|
91
|
+
aliases: '-d',
|
|
92
|
+
desc: 'Run as daemon (background)'
|
|
93
|
+
def start
|
|
94
|
+
require_desktop_gems!
|
|
95
|
+
check_dbus_availability
|
|
96
|
+
|
|
97
|
+
if service_running?
|
|
98
|
+
warn Rainbow(t('already_running')).yellow
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if options[:daemonize]
|
|
103
|
+
start_daemon
|
|
104
|
+
else
|
|
105
|
+
start_foreground
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
desc 'stop', 'Stop the D-Bus service'
|
|
110
|
+
long_desc <<~LONGDESC
|
|
111
|
+
Stops the running be.neatnerds.rosettai D-Bus service via D-Bus shutdown signal.
|
|
112
|
+
|
|
113
|
+
Exit codes:
|
|
114
|
+
0: success
|
|
115
|
+
1: D-Bus connection failure
|
|
116
|
+
5: missing ruby-dbus gem
|
|
117
|
+
|
|
118
|
+
EXAMPLES
|
|
119
|
+
|
|
120
|
+
raictl dbus stop
|
|
121
|
+
|
|
122
|
+
Related commands: raictl dbus start, rai dbus status
|
|
123
|
+
LONGDESC
|
|
124
|
+
def stop
|
|
125
|
+
require_desktop_gems!
|
|
126
|
+
unless service_running?
|
|
127
|
+
warn Rainbow(t('not_running')).yellow
|
|
128
|
+
return
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
stop_via_dbus
|
|
132
|
+
warn Rainbow(t('stopped')).green
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
desc 'detect', 'Detect compositor and show focus adapter'
|
|
136
|
+
long_desc <<~LONGDESC
|
|
137
|
+
Detects the running compositor (Sway, i3, Hyprland, GNOME, KWin, X11) and displays
|
|
138
|
+
the corresponding focus tracking adapter. Shows environment variables used for detection.
|
|
139
|
+
|
|
140
|
+
Output format depends on TTY detection (table or JSON).
|
|
141
|
+
|
|
142
|
+
EXAMPLES
|
|
143
|
+
|
|
144
|
+
raictl dbus detect
|
|
145
|
+
|
|
146
|
+
Related commands: raictl dbus status, rai dbus start
|
|
147
|
+
LONGDESC
|
|
148
|
+
def detect
|
|
149
|
+
require_desktop_gems!
|
|
150
|
+
compositor = RosettAi::DBus::CompositorDetector.detect
|
|
151
|
+
|
|
152
|
+
if tty_output?
|
|
153
|
+
print_detect_tty(compositor)
|
|
154
|
+
else
|
|
155
|
+
print_detect_json(compositor)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
private
|
|
160
|
+
|
|
161
|
+
def t(key, **)
|
|
162
|
+
::I18n.t("rosett_ai.cli.dbus.#{key}", **)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def tty_output?
|
|
166
|
+
$stdout.tty?
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def require_desktop_gems!
|
|
170
|
+
require 'dbus'
|
|
171
|
+
rescue LoadError
|
|
172
|
+
warn Rainbow(::I18n.t('rosett_ai.cli.dbus.missing_dependency',
|
|
173
|
+
default: 'Desktop features require the ruby-dbus gem. ' \
|
|
174
|
+
'Install with: apt install rosett-ai-gtk4')).red
|
|
175
|
+
exit EXIT_MISSING_DEPENDENCY
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def check_dbus_availability
|
|
179
|
+
return if RosettAi::DBus::Service.dbus_available?
|
|
180
|
+
|
|
181
|
+
warn Rainbow(t('bus_unavailable')).red
|
|
182
|
+
warn t('bus_unavailable_hint')
|
|
183
|
+
exit EXIT_DBUS_FAILURE
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def service_running?
|
|
187
|
+
bus = ::DBus::SessionBus.instance
|
|
188
|
+
bus.service(RosettAi::DBus::Service::BUS_NAME).exists?
|
|
189
|
+
rescue ::DBus::Error
|
|
190
|
+
false
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def print_not_running
|
|
194
|
+
if tty_output?
|
|
195
|
+
warn Rainbow(t('not_running')).yellow
|
|
196
|
+
warn t('start_hint', command: 'bin/raictl dbus start')
|
|
197
|
+
else
|
|
198
|
+
puts JSON.generate(running: false)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# -- TTY vs JSON branching
|
|
203
|
+
def print_running_status
|
|
204
|
+
status_data = fetch_service_status
|
|
205
|
+
return unless status_data
|
|
206
|
+
|
|
207
|
+
if tty_output?
|
|
208
|
+
print_status_table(status_data)
|
|
209
|
+
else
|
|
210
|
+
puts JSON.generate(status_data)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def fetch_service_status
|
|
215
|
+
bus = ::DBus::SessionBus.instance
|
|
216
|
+
service = bus.service(RosettAi::DBus::Service::BUS_NAME)
|
|
217
|
+
object = service.object(RosettAi::DBus::Service::OBJECT_PATH)
|
|
218
|
+
object.introspect
|
|
219
|
+
object.default_iface = 'be.neatnerds.rosettai.Manager'
|
|
220
|
+
object.GetStatus.first
|
|
221
|
+
rescue ::DBus::Error => e
|
|
222
|
+
warn Rainbow(t('error_querying', message: e.message)).red
|
|
223
|
+
nil
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def print_status_table(status_data)
|
|
227
|
+
puts Rainbow(t('status_title')).bright
|
|
228
|
+
puts
|
|
229
|
+
|
|
230
|
+
rows = status_data.map { |k, v| [k, v.to_s] }
|
|
231
|
+
table = ::Terminal::Table.new(
|
|
232
|
+
headings: [t('property'), t('value')],
|
|
233
|
+
rows: rows,
|
|
234
|
+
style: { border: :unicode_round }
|
|
235
|
+
)
|
|
236
|
+
puts table
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def stop_via_dbus
|
|
240
|
+
bus = ::DBus::SessionBus.instance
|
|
241
|
+
service = bus.service(RosettAi::DBus::Service::BUS_NAME)
|
|
242
|
+
object = service.object(RosettAi::DBus::Service::OBJECT_PATH)
|
|
243
|
+
object.introspect
|
|
244
|
+
object.default_iface = 'be.neatnerds.rosettai.Manager'
|
|
245
|
+
object.Shutdown
|
|
246
|
+
rescue ::DBus::Error => e
|
|
247
|
+
warn Rainbow("Error stopping service: #{e.message}").red
|
|
248
|
+
exit EXIT_DBUS_FAILURE
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def start_foreground
|
|
252
|
+
warn Rainbow(t('starting')).cyan
|
|
253
|
+
warn t('press_ctrl_c')
|
|
254
|
+
$stderr.puts
|
|
255
|
+
|
|
256
|
+
service = RosettAi::DBus::Service.new
|
|
257
|
+
unless service.start
|
|
258
|
+
warn Rainbow(t('start_failed')).red
|
|
259
|
+
exit EXIT_DBUS_FAILURE
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
service.run
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def start_daemon
|
|
266
|
+
pid = fork do
|
|
267
|
+
Process.daemon(true, false)
|
|
268
|
+
service = RosettAi::DBus::Service.new
|
|
269
|
+
service.start && service.run
|
|
270
|
+
end
|
|
271
|
+
Process.detach(pid)
|
|
272
|
+
warn Rainbow(t('started_background', pid: pid)).green
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def adapter_for(compositor)
|
|
276
|
+
ADAPTER_MAP.fetch(compositor, nil)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def print_detect_tty(compositor)
|
|
280
|
+
adapter_name = adapter_for(compositor)
|
|
281
|
+
|
|
282
|
+
puts Rainbow(t('detect_title')).bright
|
|
283
|
+
puts
|
|
284
|
+
puts " #{t('detected')}: #{Rainbow(compositor.to_s).cyan}"
|
|
285
|
+
puts " #{t('adapter')}: #{adapter_name ? Rainbow(adapter_name).green : Rainbow(t('adapter_none')).yellow}"
|
|
286
|
+
puts
|
|
287
|
+
|
|
288
|
+
print_environment_table
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def print_detect_json(compositor)
|
|
292
|
+
env_data = ENV_VARS.to_h do |var|
|
|
293
|
+
[var, ENV.fetch(var, nil)]
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
puts JSON.generate(
|
|
297
|
+
compositor: compositor.to_s,
|
|
298
|
+
adapter: adapter_for(compositor),
|
|
299
|
+
environment: env_data
|
|
300
|
+
)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def print_environment_table
|
|
304
|
+
rows = ENV_VARS.map do |var|
|
|
305
|
+
value = ENV.fetch(var, nil)
|
|
306
|
+
[var, value ? Rainbow(value).cyan : Rainbow(t('not_set')).faint]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
puts Rainbow(t('env_title')).bright
|
|
310
|
+
puts
|
|
311
|
+
table = ::Terminal::Table.new(
|
|
312
|
+
headings: [t('variable'), t('value')],
|
|
313
|
+
rows: rows,
|
|
314
|
+
style: { border: :unicode_round }
|
|
315
|
+
)
|
|
316
|
+
puts table
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
@@ -0,0 +1,258 @@
|
|
|
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 'thor'
|
|
7
|
+
require 'rainbow'
|
|
8
|
+
require 'terminal-table'
|
|
9
|
+
|
|
10
|
+
module RosettAi
|
|
11
|
+
module Thor
|
|
12
|
+
module Tasks
|
|
13
|
+
# Thor tasks for design document management
|
|
14
|
+
class Design < ::Thor
|
|
15
|
+
desc 'validate [NAME]', 'Validate design document(s) against the design schema'
|
|
16
|
+
long_desc <<~LONGDESC
|
|
17
|
+
Validates design document(s) against JSON schema. If NAME is provided, validates
|
|
18
|
+
only that document; otherwise validates all design documents.
|
|
19
|
+
|
|
20
|
+
Exit codes: 1 if any validation fails
|
|
21
|
+
|
|
22
|
+
EXAMPLES
|
|
23
|
+
|
|
24
|
+
raictl design validate
|
|
25
|
+
raictl design validate architecture
|
|
26
|
+
|
|
27
|
+
Related commands: raictl design list, rai design show
|
|
28
|
+
LONGDESC
|
|
29
|
+
def validate(name = nil)
|
|
30
|
+
name = RosettAi::TextSanitizer.normalize_nfc(name) if name
|
|
31
|
+
files = files_to_validate(name)
|
|
32
|
+
return puts Rainbow(t('no_documents')).yellow if files.empty?
|
|
33
|
+
|
|
34
|
+
all_valid = validate_files(files)
|
|
35
|
+
raise ::Thor::Error, t('validation_failed') unless all_valid
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc 'show NAME', 'Display a design document summary'
|
|
39
|
+
long_desc <<~LONGDESC
|
|
40
|
+
Displays formatted design document with metadata, intent, constraints, and acceptance criteria.
|
|
41
|
+
By default shows essential sections only. Use --full to include examples and preferences.
|
|
42
|
+
|
|
43
|
+
Flags:
|
|
44
|
+
--full: Show all sections including examples, anti-patterns, and preferences
|
|
45
|
+
|
|
46
|
+
EXAMPLES
|
|
47
|
+
|
|
48
|
+
raictl design show architecture
|
|
49
|
+
raictl design show security --full
|
|
50
|
+
|
|
51
|
+
Related commands: raictl design list, rai design validate
|
|
52
|
+
LONGDESC
|
|
53
|
+
method_option :full, type: :boolean, default: false,
|
|
54
|
+
desc: 'Show all sections including examples and preferences'
|
|
55
|
+
|
|
56
|
+
def show(name)
|
|
57
|
+
name = RosettAi::TextSanitizer.normalize_nfc(name)
|
|
58
|
+
file_path = find_design_file(name)
|
|
59
|
+
raise ::Thor::Error, Rainbow(t('not_found', name: name)).red unless file_path
|
|
60
|
+
|
|
61
|
+
data = RosettAi::YamlLoader.load_file(file_path)
|
|
62
|
+
raise ::Thor::Error, Rainbow(t('empty_file', path: file_path)).red if data.nil?
|
|
63
|
+
|
|
64
|
+
sanitized = RosettAi::TextSanitizer.sanitize_for_display(data)
|
|
65
|
+
|
|
66
|
+
print_design_header(sanitized)
|
|
67
|
+
print_section(t('intent'), sanitized['intent'])
|
|
68
|
+
print_numbered_section(t('constraints'), sanitized['constraints'])
|
|
69
|
+
print_numbered_section(t('acceptance_criteria'), sanitized['acceptance_criteria'])
|
|
70
|
+
print_dependencies(sanitized['depends_on'])
|
|
71
|
+
|
|
72
|
+
return unless options[:full]
|
|
73
|
+
|
|
74
|
+
print_examples(sanitized['examples'])
|
|
75
|
+
print_numbered_section(t('anti_patterns'), sanitized['anti_patterns'])
|
|
76
|
+
print_preferences(sanitized['preferences'])
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
desc 'list', 'List all design documents'
|
|
80
|
+
long_desc <<~LONGDESC
|
|
81
|
+
Lists all design documents in a table with name, version, status, domain, and priority.
|
|
82
|
+
Results are sorted by priority then name.
|
|
83
|
+
|
|
84
|
+
EXAMPLES
|
|
85
|
+
|
|
86
|
+
raictl design list
|
|
87
|
+
|
|
88
|
+
Related commands: raictl design show, rai design validate
|
|
89
|
+
LONGDESC
|
|
90
|
+
def list
|
|
91
|
+
files = design_files
|
|
92
|
+
if files.empty?
|
|
93
|
+
puts Rainbow(t('no_documents_found')).yellow
|
|
94
|
+
return
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
print_design_list(files)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def t(key, **)
|
|
103
|
+
::I18n.t("rosett_ai.cli.design.#{key}", **)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def design_path
|
|
107
|
+
RosettAi.conf_root.join('conf', 'design')
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def design_files
|
|
111
|
+
Dir.glob(design_path.join('*.yml'))
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def find_design_file(name)
|
|
115
|
+
path = design_path.join("#{name}.yml")
|
|
116
|
+
path.exist? ? path.to_s : nil
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def files_to_validate(name)
|
|
120
|
+
return design_files unless name
|
|
121
|
+
|
|
122
|
+
file = find_design_file(name)
|
|
123
|
+
unless file
|
|
124
|
+
puts Rainbow(t('not_found', name: name)).red
|
|
125
|
+
return []
|
|
126
|
+
end
|
|
127
|
+
[file]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def validate_files(files)
|
|
131
|
+
validator = RosettAi::Validators::DesignValidator.new
|
|
132
|
+
files.all? { |file| file_valid?(validator, file) }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def file_valid?(validator, file)
|
|
136
|
+
basename = File.basename(file)
|
|
137
|
+
if validator.valid?(file)
|
|
138
|
+
puts "#{Rainbow(t('valid')).green} #{basename}"
|
|
139
|
+
true
|
|
140
|
+
else
|
|
141
|
+
display_validation_errors(basename, validator.errors)
|
|
142
|
+
false
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def display_validation_errors(basename, errors)
|
|
147
|
+
puts "#{Rainbow(t('invalid')).red} #{basename}"
|
|
148
|
+
errors.each { |err| puts " #{err}" }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def print_design_header(data)
|
|
152
|
+
rows = [
|
|
153
|
+
[t('name'), data['name']],
|
|
154
|
+
[t('design_version'), data['version']],
|
|
155
|
+
[t('status'), format_status(data['status'])],
|
|
156
|
+
[t('domain'), data['domain']],
|
|
157
|
+
[t('priority'), data['priority']],
|
|
158
|
+
['Author', data['author']],
|
|
159
|
+
['Created', data['created_at']],
|
|
160
|
+
['Modified', data['modified_at']],
|
|
161
|
+
['Modified By', data['modified_by']]
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
table = ::Terminal::Table.new(
|
|
165
|
+
title: Rainbow(data['name'] || 'Design Document').bright,
|
|
166
|
+
rows: rows,
|
|
167
|
+
style: { border: :unicode_round }
|
|
168
|
+
)
|
|
169
|
+
puts table
|
|
170
|
+
puts
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def print_section(title, content)
|
|
174
|
+
return unless content
|
|
175
|
+
|
|
176
|
+
puts Rainbow(title).bright.underline
|
|
177
|
+
puts content.to_s.strip
|
|
178
|
+
puts
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def print_numbered_section(title, items)
|
|
182
|
+
return unless items.is_a?(Array) && !items.empty?
|
|
183
|
+
|
|
184
|
+
puts Rainbow(title).bright.underline
|
|
185
|
+
items.each_with_index do |item, index|
|
|
186
|
+
puts " #{index + 1}. #{item}"
|
|
187
|
+
end
|
|
188
|
+
puts
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def print_dependencies(deps)
|
|
192
|
+
return unless deps.is_a?(Array) && !deps.empty?
|
|
193
|
+
|
|
194
|
+
puts Rainbow(t('dependencies')).bright.underline
|
|
195
|
+
deps.each { |dep| puts " - #{dep}" }
|
|
196
|
+
puts
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def print_examples(examples)
|
|
200
|
+
return unless examples.is_a?(Array) && !examples.empty?
|
|
201
|
+
|
|
202
|
+
puts Rainbow(t('examples')).bright.underline
|
|
203
|
+
examples.each do |example|
|
|
204
|
+
puts " #{Rainbow(t('scenario')).cyan} #{example['scenario']}"
|
|
205
|
+
puts " #{Rainbow(t('expected')).green} #{example['expected']&.strip}"
|
|
206
|
+
puts " #{Rainbow(t('not_expected')).red} #{example['not']&.strip}" if example['not']
|
|
207
|
+
puts
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def print_preferences(prefs)
|
|
212
|
+
return unless prefs.is_a?(Hash) && !prefs.empty?
|
|
213
|
+
|
|
214
|
+
puts Rainbow(t('preferences')).bright.underline
|
|
215
|
+
prefs.each do |key, value|
|
|
216
|
+
formatted = value.is_a?(Array) ? value.join(', ') : value.to_s
|
|
217
|
+
puts " #{key}: #{formatted}"
|
|
218
|
+
end
|
|
219
|
+
puts
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def print_design_list(files)
|
|
223
|
+
rows = files.map { |file| build_design_list_row(file) }
|
|
224
|
+
rows.sort_by! { |row| [row[4].to_i, row[0].to_s] }
|
|
225
|
+
|
|
226
|
+
table = ::Terminal::Table.new(
|
|
227
|
+
title: Rainbow(t('title')).bright,
|
|
228
|
+
headings: [t('name'), t('design_version'), t('status'), t('domain'), t('priority')],
|
|
229
|
+
rows: rows,
|
|
230
|
+
style: { border: :unicode_round }
|
|
231
|
+
)
|
|
232
|
+
puts table
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def build_design_list_row(file)
|
|
236
|
+
data = RosettAi::YamlLoader.load_file(file)
|
|
237
|
+
[
|
|
238
|
+
data['name'],
|
|
239
|
+
data['version'],
|
|
240
|
+
format_status(data['status']),
|
|
241
|
+
data['domain'],
|
|
242
|
+
data['priority']
|
|
243
|
+
]
|
|
244
|
+
rescue StandardError
|
|
245
|
+
[File.basename(file, '.yml'), '-', Rainbow('error').red, '-', '-']
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def format_status(status)
|
|
249
|
+
case status
|
|
250
|
+
when 'approved' then Rainbow(status).green
|
|
251
|
+
when 'draft' then Rainbow(status).yellow
|
|
252
|
+
else status.to_s
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
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 'json'
|
|
7
|
+
require 'thor'
|
|
8
|
+
require 'rainbow'
|
|
9
|
+
|
|
10
|
+
module RosettAi
|
|
11
|
+
module Thor
|
|
12
|
+
module Tasks
|
|
13
|
+
# Thor task for launching desktop applications.
|
|
14
|
+
#
|
|
15
|
+
# @author hugo
|
|
16
|
+
# @author claude
|
|
17
|
+
class Desktop < ::Thor
|
|
18
|
+
desc 'gtk4', 'Launch the GTK4/Adwaita desktop application'
|
|
19
|
+
long_desc <<~LONGDESC
|
|
20
|
+
Launches the GTK4/Adwaita desktop GUI for Rosett-AI. Requires rosett-ai-gtk4 package.
|
|
21
|
+
|
|
22
|
+
Exit codes:
|
|
23
|
+
0: success
|
|
24
|
+
1: GTK4 not available or missing dependencies
|
|
25
|
+
|
|
26
|
+
EXAMPLES
|
|
27
|
+
|
|
28
|
+
raictl desktop gtk4
|
|
29
|
+
|
|
30
|
+
Related commands: raictl desktop status, rai dbus start
|
|
31
|
+
LONGDESC
|
|
32
|
+
def gtk4
|
|
33
|
+
require_desktop_gems!
|
|
34
|
+
unless RosettAi::Desktop::Gtk4App.available?
|
|
35
|
+
msg = "#{t('unavailable')}\n#{t('install_adwaita')}\n#{t('install_pkg')}"
|
|
36
|
+
raise ::Thor::Error, msg
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
app = RosettAi::Desktop::Gtk4App.new
|
|
40
|
+
exit_code = app.run(ARGV)
|
|
41
|
+
exit exit_code
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc 'status', 'Show desktop integration status'
|
|
45
|
+
long_desc <<~LONGDESC
|
|
46
|
+
Shows availability status of GTK4 application and D-Bus service.
|
|
47
|
+
Output format depends on TTY detection (table or JSON).
|
|
48
|
+
|
|
49
|
+
EXAMPLES
|
|
50
|
+
|
|
51
|
+
raictl desktop status
|
|
52
|
+
|
|
53
|
+
Related commands: raictl desktop gtk4, rai dbus status
|
|
54
|
+
LONGDESC
|
|
55
|
+
def status
|
|
56
|
+
require_desktop_gems!
|
|
57
|
+
gtk4_available = RosettAi::Desktop::Gtk4App.available?
|
|
58
|
+
dbus_running = check_dbus_service
|
|
59
|
+
|
|
60
|
+
if tty_output?
|
|
61
|
+
print_status_tty(gtk4_available, dbus_running)
|
|
62
|
+
else
|
|
63
|
+
print_status_json(gtk4_available, dbus_running)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def t(key, **)
|
|
70
|
+
::I18n.t("rosett_ai.cli.desktop.#{key}", **)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def tty_output?
|
|
74
|
+
$stdout.tty?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def require_desktop_gems!
|
|
78
|
+
require 'dbus'
|
|
79
|
+
rescue LoadError
|
|
80
|
+
raise ::Thor::Error, ::I18n.t('rosett_ai.cli.dbus.missing_dependency',
|
|
81
|
+
default: 'Desktop features require the ruby-dbus gem. ' \
|
|
82
|
+
'Install with: apt install rosett-ai-gtk4')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def check_dbus_service
|
|
86
|
+
client = RosettAi::Desktop::DbusClient.new
|
|
87
|
+
client.service_available?
|
|
88
|
+
rescue StandardError
|
|
89
|
+
false
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# -- user-facing display logic
|
|
93
|
+
def print_status_tty(gtk4_available, dbus_running)
|
|
94
|
+
puts Rainbow(t('status_title')).bright
|
|
95
|
+
puts
|
|
96
|
+
|
|
97
|
+
gtk4_label = gtk4_available ? t('available') : t('not_installed')
|
|
98
|
+
gtk4_color = gtk4_available ? :green : :yellow
|
|
99
|
+
puts " #{t('gtk4_label')}: #{Rainbow(gtk4_label).color(gtk4_color)}"
|
|
100
|
+
|
|
101
|
+
dbus_label = dbus_running ? t('running') : t('not_running')
|
|
102
|
+
dbus_color = dbus_running ? :green : :yellow
|
|
103
|
+
puts " #{t('dbus_label')}: #{Rainbow(dbus_label).color(dbus_color)}"
|
|
104
|
+
puts
|
|
105
|
+
|
|
106
|
+
unless gtk4_available
|
|
107
|
+
puts Rainbow(t('to_enable_gtk4')).cyan
|
|
108
|
+
puts " #{t('install_adwaita')}"
|
|
109
|
+
puts " #{t('install_pkg')}"
|
|
110
|
+
puts
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
return if dbus_running
|
|
114
|
+
|
|
115
|
+
puts Rainbow(t('to_start_dbus')).cyan
|
|
116
|
+
puts ' bin/raictl dbus start'
|
|
117
|
+
puts
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def print_status_json(gtk4_available, dbus_running)
|
|
121
|
+
puts JSON.generate(
|
|
122
|
+
gtk4: { available: gtk4_available },
|
|
123
|
+
dbus: { running: dbus_running }
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|