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,289 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: desktop_integration
|
|
3
|
+
domain: ui
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
status: implemented
|
|
6
|
+
priority: 3
|
|
7
|
+
author: hugo
|
|
8
|
+
created_at: "2026-02-24"
|
|
9
|
+
modified_at: "2026-03-16"
|
|
10
|
+
modified_by: claude
|
|
11
|
+
depends_on:
|
|
12
|
+
- architecture
|
|
13
|
+
- ui_framework
|
|
14
|
+
- accessibility
|
|
15
|
+
- i18n
|
|
16
|
+
- security
|
|
17
|
+
- error_handling
|
|
18
|
+
|
|
19
|
+
intent: |
|
|
20
|
+
Define how rosett-ai integrates with Linux desktop environments via a D-Bus
|
|
21
|
+
session bus service (be.neatnerds.rosettai) and optional desktop-specific
|
|
22
|
+
frontends. The D-Bus service is the central IPC layer — all desktop
|
|
23
|
+
variants (GTK4 standalone app, KDE KCM plugin, CLI tools, tiling WM
|
|
24
|
+
scripts) consume the same D-Bus API. Includes system tray presence via
|
|
25
|
+
StatusNotifierItem and global hotkey registration via XDG GlobalShortcuts
|
|
26
|
+
portal.
|
|
27
|
+
|
|
28
|
+
The D-Bus service is implemented in Ruby using the ruby-dbus gem. It
|
|
29
|
+
exposes interfaces for configuration management, focus monitoring, and
|
|
30
|
+
automatic context switching. The service auto-activates via a standard
|
|
31
|
+
D-Bus .service file — no manual startup required. Rosett-AI core remains
|
|
32
|
+
fully functional without D-Bus (CLI/TUI degraded mode).
|
|
33
|
+
|
|
34
|
+
Focus monitoring uses compositor-specific adapters (GNOME D-Bus
|
|
35
|
+
extension, KWin D-Bus scripting, i3ipc gem, Hyprland socket2) that
|
|
36
|
+
feed into a unified FocusChanged D-Bus signal. This enables automatic
|
|
37
|
+
context switching when the user changes application focus.
|
|
38
|
+
|
|
39
|
+
Phased implementation:
|
|
40
|
+
|
|
41
|
+
Phase 1 — D-Bus Service Foundation:
|
|
42
|
+
be.neatnerds.rosettai D-Bus service (ruby-dbus)
|
|
43
|
+
StatusNotifierItem for system tray
|
|
44
|
+
FocusMonitor with compositor adapters
|
|
45
|
+
GlobalShortcuts portal registration
|
|
46
|
+
CLI command: bin/raictl --dbus-service
|
|
47
|
+
|
|
48
|
+
Phase 2 — GTK4 Desktop App (rosett-ai-gtk4):
|
|
49
|
+
Standalone libadwaita app consuming D-Bus service
|
|
50
|
+
AdwPreferencesDialog for settings
|
|
51
|
+
GNOME HIG compliance
|
|
52
|
+
Dogtail integration tests
|
|
53
|
+
.desktop file with DBusActivatable=true
|
|
54
|
+
|
|
55
|
+
Phase 3 — KDE KCM Module (rosett-ai-kde):
|
|
56
|
+
C++/QML thin shim consuming D-Bus service via QtDBus
|
|
57
|
+
KCMUtils.SimpleKCM + Kirigami.FormLayout
|
|
58
|
+
KDE HIG compliance
|
|
59
|
+
Spix / Dogtail integration tests
|
|
60
|
+
|
|
61
|
+
This design governs D-Bus IPC, compositor adapters, and desktop service
|
|
62
|
+
architecture. Pluggable GUI gem packaging and plugin lifecycle management
|
|
63
|
+
is governed by gui_plugins.yml. Accessibility requirements are governed
|
|
64
|
+
by accessibility.yml. Error handling follows error_handling.yml.
|
|
65
|
+
|
|
66
|
+
constraints:
|
|
67
|
+
- "D-Bus session bus is the sole IPC mechanism between rosett-ai backend and desktop frontends"
|
|
68
|
+
- "The D-Bus service is implemented in Ruby using ruby-dbus gem — no C/C++ daemon"
|
|
69
|
+
- "D-Bus service auto-activates via .service file — no manual startup required"
|
|
70
|
+
- "Rosett-AI core package must remain functional without D-Bus (CLI/TUI degraded mode)"
|
|
71
|
+
- "GNOME frontend is a standalone libadwaita app (no gnome-control-center plugin — impossible)"
|
|
72
|
+
- "KDE frontend is a KCM plugin (C++/QML thin shim) consuming the D-Bus service"
|
|
73
|
+
- "StatusNotifierItem is implemented in the D-Bus service itself — no GUI dependency for tray"
|
|
74
|
+
- "Global hotkeys use org.freedesktop.portal.GlobalShortcuts where available;
|
|
75
|
+
compositor-specific config as documented fallback"
|
|
76
|
+
- "All D-Bus interfaces provide introspection XML"
|
|
77
|
+
- "Security constraints from security.yml apply to all D-Bus method handlers"
|
|
78
|
+
- "Follow reverse-DNS naming — bus name be.neatnerds.rosettai, object path /be/neatnerds/rosett-ai"
|
|
79
|
+
- "This design governs D-Bus IPC, compositor adapters, and desktop service
|
|
80
|
+
architecture. Pluggable GUI gem packaging is governed by gui_plugins.yml"
|
|
81
|
+
|
|
82
|
+
acceptance_criteria:
|
|
83
|
+
- "be.neatnerds.rosettai service starts on D-Bus session bus via bin/raictl --dbus-service"
|
|
84
|
+
- "Service auto-activates when any client calls a method (via .service file)"
|
|
85
|
+
- "busctl --user introspect be.neatnerds.rosettai /be/neatnerds/rosett-ai shows all interfaces"
|
|
86
|
+
- "GTK4 app communicates exclusively via D-Bus (no direct Ruby API calls)"
|
|
87
|
+
- "KDE KCM communicates exclusively via D-Bus (via QtDBus)"
|
|
88
|
+
- "CLI command bin/raictl dbus status shows service state"
|
|
89
|
+
- "StatusNotifierItem appears in KDE Plasma system tray and Waybar without GTK4 app running"
|
|
90
|
+
- "bin/raictl --dbus-service gracefully degrades if D-Bus session bus unavailable"
|
|
91
|
+
- "Focus monitor detects compositor type and subscribes to focus events"
|
|
92
|
+
- "FocusChanged signal emitted on D-Bus when active window changes"
|
|
93
|
+
- "Global hotkey registration succeeds on KDE Plasma via GlobalShortcuts portal"
|
|
94
|
+
- "Exit code 0 on success, 1 on D-Bus connection failure, 5 on missing ruby-dbus dependency"
|
|
95
|
+
- "TTY-aware output: formatted status when interactive, JSON when piped"
|
|
96
|
+
|
|
97
|
+
examples:
|
|
98
|
+
- scenario: "D-Bus service on sway — user runs sway, installs Rosett-AI core only"
|
|
99
|
+
expected: |
|
|
100
|
+
bin/raictl compile works via CLI. D-Bus service auto-activates when
|
|
101
|
+
Waybar's SNI module queries the tray. Tray icon appears. Focus monitor
|
|
102
|
+
uses i3ipc adapter for sway IPC socket.
|
|
103
|
+
not: "Service crashes because no GNOME/KDE present. Tray requires GTK4 app."
|
|
104
|
+
- scenario: "GTK4 app on GNOME — user installs rosett-ai + rosett-ai-gtk4"
|
|
105
|
+
expected: |
|
|
106
|
+
Launches via desktop file. App connects to be.neatnerds.rosettai via
|
|
107
|
+
GDBus. All operations go through D-Bus. Settings use
|
|
108
|
+
AdwPreferencesDialog with instant-apply pattern.
|
|
109
|
+
not: "GTK4 app imports Ruby Rosett-AI modules directly. Uses OK/Apply buttons."
|
|
110
|
+
- scenario: "Focus-based context switching — user has VS Code and Firefox open"
|
|
111
|
+
expected: |
|
|
112
|
+
User switches to Firefox. Focus monitor detects app_id change, emits
|
|
113
|
+
FocusChanged('firefox', ...). Manager loads browser memory profile.
|
|
114
|
+
ContextChanged signal emitted on D-Bus.
|
|
115
|
+
not: "Polling loop checks focus every N seconds. Context switch requires manual action."
|
|
116
|
+
- scenario: "Hotkey triggers compile — user presses configured hotkey"
|
|
117
|
+
expected: |
|
|
118
|
+
GlobalShortcuts portal delivers event to D-Bus service. Service runs
|
|
119
|
+
compile. Notification sent via org.freedesktop.Notifications.
|
|
120
|
+
not: "rosett-ai grabs keyboard input directly. Hotkey only works under specific compositor."
|
|
121
|
+
|
|
122
|
+
anti_patterns:
|
|
123
|
+
- "QProcess/subprocess calls from GUI to Rosett-AI CLI (bypasses D-Bus)"
|
|
124
|
+
- "Polling for focus changes instead of event-driven subscription"
|
|
125
|
+
- "Implementing SNI in the GTK4 app instead of the D-Bus service"
|
|
126
|
+
- "Assuming GlobalShortcuts portal is available on all compositors"
|
|
127
|
+
- "Business logic in KCM C++/QML layer or GTK4 UI layer"
|
|
128
|
+
- "Hardcoded compositor detection instead of environment variable + D-Bus name probing"
|
|
129
|
+
|
|
130
|
+
gui_notes: |
|
|
131
|
+
Document interactions (cross-references):
|
|
132
|
+
|
|
133
|
+
1. gui_plugins.yml: desktop_integration provides D-Bus service and
|
|
134
|
+
compositor adapters. gui_plugins governs pluggable GUI gem packaging,
|
|
135
|
+
plugin lifecycle management, and PackageManager abstraction.
|
|
136
|
+
|
|
137
|
+
2. accessibility.yml: desktop integration implements EN 301 549
|
|
138
|
+
requirements for D-Bus service responses, SNI tray, and focus
|
|
139
|
+
announcements.
|
|
140
|
+
|
|
141
|
+
3. security.yml: all D-Bus method handlers follow security constraints.
|
|
142
|
+
No secret exposure via D-Bus properties or signals.
|
|
143
|
+
|
|
144
|
+
4. error_handling.yml: D-Bus method errors map to structured error
|
|
145
|
+
hierarchy. Exit codes for dbus status command.
|
|
146
|
+
|
|
147
|
+
5. ui_framework.yml: TUI is the primary interface. Desktop integration
|
|
148
|
+
adds D-Bus IPC layer for optional GUI frontends.
|
|
149
|
+
|
|
150
|
+
6. i18n.yml: D-Bus service status messages and error responses are
|
|
151
|
+
localised via gettext.
|
|
152
|
+
|
|
153
|
+
D-Bus Interfaces:
|
|
154
|
+
|
|
155
|
+
be.neatnerds.rosettai.Manager:
|
|
156
|
+
Methods:
|
|
157
|
+
Compile() -> s # Run compilation, return status
|
|
158
|
+
SwitchContext(s context_name) # Switch AI context by name
|
|
159
|
+
GetStatus() -> a{sv} # Return service status as dict
|
|
160
|
+
Properties:
|
|
161
|
+
Version: s (read) # Service version string
|
|
162
|
+
Signals:
|
|
163
|
+
ContextChanged(s context_name) # Emitted after context switch
|
|
164
|
+
|
|
165
|
+
be.neatnerds.rosettai.FocusMonitor:
|
|
166
|
+
Methods:
|
|
167
|
+
GetCurrentFocus() -> (ss) # Return (app_id, window_title)
|
|
168
|
+
Signals:
|
|
169
|
+
FocusChanged(s app_id, s title) # Emitted on active window change
|
|
170
|
+
|
|
171
|
+
org.kde.StatusNotifierItem:
|
|
172
|
+
Standard SNI interface for system tray icon. Implemented in the D-Bus
|
|
173
|
+
service itself — no GTK4 or Qt6 dependency. Consumed by KDE Plasma
|
|
174
|
+
system tray, Waybar, swaybar, and other SNI-capable panels.
|
|
175
|
+
|
|
176
|
+
org.freedesktop.portal.GlobalShortcuts:
|
|
177
|
+
Consumer (not provider). The D-Bus service registers hotkey bindings
|
|
178
|
+
via the XDG GlobalShortcuts portal. Specific key bindings are
|
|
179
|
+
user-configurable — not hardcoded. Fallback: compositor-specific
|
|
180
|
+
config documentation (sway bindsym, Hyprland bind, etc.).
|
|
181
|
+
|
|
182
|
+
D-Bus Service File (/usr/share/dbus-1/services/be.neatnerds.rosettai.service):
|
|
183
|
+
[D-BUS Service]
|
|
184
|
+
Name=be.neatnerds.rosettai
|
|
185
|
+
Exec=/usr/bin/raictl --dbus-service
|
|
186
|
+
|
|
187
|
+
Compositor Detection (auto):
|
|
188
|
+
1. HYPRLAND_INSTANCE_SIGNATURE → :hyprland
|
|
189
|
+
2. SWAYSOCK → :sway
|
|
190
|
+
3. I3SOCK → :i3
|
|
191
|
+
4. D-Bus name org.gnome.Shell active → :gnome
|
|
192
|
+
5. D-Bus name org.kde.KWin active → :kwin
|
|
193
|
+
6. DISPLAY set, WAYLAND_DISPLAY unset → :x11
|
|
194
|
+
7. else → :unknown
|
|
195
|
+
|
|
196
|
+
Focus Adapter Mapping:
|
|
197
|
+
:gnome → GNOME Shell extension D-Bus interface
|
|
198
|
+
:kwin → KWin D-Bus scripting API (org.kde.KWin)
|
|
199
|
+
:sway → i3ipc gem (window::focus event)
|
|
200
|
+
:i3 → i3ipc gem (window::focus event)
|
|
201
|
+
:hyprland → Hyprland IPC socket2 (activewindow>> event)
|
|
202
|
+
:x11 → _NET_ACTIVE_WINDOW property change (xprop)
|
|
203
|
+
:unknown → no focus monitoring (degraded mode)
|
|
204
|
+
|
|
205
|
+
interactions:
|
|
206
|
+
- action: "View rosett-ai status"
|
|
207
|
+
tui: "bin/raictl status"
|
|
208
|
+
gtk4: "Preferences dialog status page"
|
|
209
|
+
qt6: "KCM panel status section"
|
|
210
|
+
- action: "Switch AI context"
|
|
211
|
+
tui: "bin/raictl context switch <name>"
|
|
212
|
+
gtk4: "Tray menu context submenu"
|
|
213
|
+
qt6: "KCM dropdown or tray menu"
|
|
214
|
+
- action: "Trigger compile"
|
|
215
|
+
tui: "bin/raictl compile"
|
|
216
|
+
gtk4: "Hotkey or tray action"
|
|
217
|
+
qt6: "KCM button or hotkey"
|
|
218
|
+
- action: "View D-Bus service state"
|
|
219
|
+
tui: "bin/raictl dbus status"
|
|
220
|
+
gtk4: "Status indicator in preferences"
|
|
221
|
+
qt6: "KCM status widget"
|
|
222
|
+
|
|
223
|
+
accessibility:
|
|
224
|
+
roles:
|
|
225
|
+
- element: "tray_menu"
|
|
226
|
+
role: "menu"
|
|
227
|
+
label: "Rosett-AI tray menu"
|
|
228
|
+
description: "System tray context menu for quick actions"
|
|
229
|
+
- element: "preferences_dialog"
|
|
230
|
+
role: "dialog"
|
|
231
|
+
label: "Rosett-AI preferences"
|
|
232
|
+
description: "Configuration dialog (GTK4: AdwPreferencesDialog)"
|
|
233
|
+
- element: "focus_indicator"
|
|
234
|
+
role: "status"
|
|
235
|
+
label: "Current focus application"
|
|
236
|
+
description: "Shows which application currently has focus"
|
|
237
|
+
- element: "context_selector"
|
|
238
|
+
role: "listbox"
|
|
239
|
+
label: "AI context selector"
|
|
240
|
+
description: "Dropdown or list for switching AI context"
|
|
241
|
+
keyboard:
|
|
242
|
+
- key: "Menu key or right-click"
|
|
243
|
+
action: "Open tray context menu"
|
|
244
|
+
- key: "Arrow keys"
|
|
245
|
+
action: "Navigate tray menu items"
|
|
246
|
+
- key: "Enter"
|
|
247
|
+
action: "Activate selected tray menu item"
|
|
248
|
+
- key: "Escape"
|
|
249
|
+
action: "Close tray menu or preferences dialog"
|
|
250
|
+
announcements:
|
|
251
|
+
- event: "context_switch"
|
|
252
|
+
announce: "Context switched to <name>"
|
|
253
|
+
priority: "polite"
|
|
254
|
+
- event: "compile_complete"
|
|
255
|
+
announce: "Compilation completed successfully"
|
|
256
|
+
priority: "polite"
|
|
257
|
+
- event: "compile_error"
|
|
258
|
+
announce: "Compilation failed: <error>"
|
|
259
|
+
priority: "assertive"
|
|
260
|
+
- event: "service_unavailable"
|
|
261
|
+
announce: "D-Bus service unavailable — running in degraded mode"
|
|
262
|
+
priority: "assertive"
|
|
263
|
+
- event: "focus_change"
|
|
264
|
+
announce: "Focus changed to <app_id>"
|
|
265
|
+
priority: "polite"
|
|
266
|
+
|
|
267
|
+
preferences:
|
|
268
|
+
language: ruby
|
|
269
|
+
patterns:
|
|
270
|
+
- "Adapter pattern for compositor-specific focus monitors"
|
|
271
|
+
- "Event-driven subscription (not polling)"
|
|
272
|
+
- "Graceful degradation when D-Bus unavailable"
|
|
273
|
+
- "Reverse-DNS naming (be.neatnerds.rosettai)"
|
|
274
|
+
testing: rspec with D-Bus service unit tests, compositor adapter mock
|
|
275
|
+
scenarios, focus monitor event subscription, SNI interface validation,
|
|
276
|
+
graceful degradation tests, and dogtail integration tests for GUI variants
|
|
277
|
+
gems:
|
|
278
|
+
- ruby-dbus
|
|
279
|
+
- i3ipc (sway/i3 focus adapter)
|
|
280
|
+
- gtk4 (rosett-ai-gtk4 package only)
|
|
281
|
+
- adwaita (rosett-ai-gtk4 package only)
|
|
282
|
+
kde_build:
|
|
283
|
+
- cmake
|
|
284
|
+
- extra-cmake-modules
|
|
285
|
+
- kf6-kcmutils
|
|
286
|
+
- kf6-ki18n
|
|
287
|
+
- kf6-kcoreaddons
|
|
288
|
+
- qt6-base-dev
|
|
289
|
+
- qt6-declarative-dev
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: distribution
|
|
3
|
+
domain: ci
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
status: implemented
|
|
6
|
+
priority: 5
|
|
7
|
+
author: claude
|
|
8
|
+
created_at: "2026-02-22"
|
|
9
|
+
modified_at: "2026-03-16"
|
|
10
|
+
modified_by: claude
|
|
11
|
+
depends_on:
|
|
12
|
+
- ci_pipeline
|
|
13
|
+
- release_management
|
|
14
|
+
- documentation
|
|
15
|
+
- security
|
|
16
|
+
- error_handling
|
|
17
|
+
|
|
18
|
+
intent: |
|
|
19
|
+
Define how built packages reach end users through a self-hosted,
|
|
20
|
+
multi-format repository backed by Pulp (pulpproject.org).
|
|
21
|
+
|
|
22
|
+
The build pipeline (P1 ci_pipeline) already produces .deb packages, and
|
|
23
|
+
the release process (P5 release_management) creates versioned tags. This
|
|
24
|
+
document closes the gap: how does a tagged release become an installable
|
|
25
|
+
package for users — and how does that scale to multiple distributions and
|
|
26
|
+
operating systems?
|
|
27
|
+
|
|
28
|
+
Without distribution:
|
|
29
|
+
- Users must manually download .deb files from GitLab releases
|
|
30
|
+
- No automatic security updates via apt upgrade / dnf upgrade
|
|
31
|
+
- No GPG verification of package authenticity
|
|
32
|
+
- No separation between stable and development channels
|
|
33
|
+
- Adding RPM or other formats requires standing up a new tool each time
|
|
34
|
+
|
|
35
|
+
With distribution:
|
|
36
|
+
- Users add the NeatNerds repo once, then 'apt install rosett-ai' or 'dnf install rosett-ai'
|
|
37
|
+
- Security updates arrive via the native package manager
|
|
38
|
+
- Every package is GPG-signed and verifiable
|
|
39
|
+
- Stable and unstable channels serve different audiences
|
|
40
|
+
- New formats (RPM, generic, container, Homebrew tap) are added as Pulp
|
|
41
|
+
plugins without replacing the core infrastructure
|
|
42
|
+
|
|
43
|
+
Why Pulp over aptly:
|
|
44
|
+
- aptly is Debian-only. Pulp supports DEB, RPM, Python, Container, Ansible,
|
|
45
|
+
and generic file repositories via its plugin architecture
|
|
46
|
+
- Pulp is used in production by Microsoft (packages.microsoft.com) and
|
|
47
|
+
Red Hat (Satellite/Katello)
|
|
48
|
+
- Adding RPM support later is 'pulp_rpm plugin install', not 'deploy a
|
|
49
|
+
second repository server'
|
|
50
|
+
- Pulp's REST API is CI-friendly for automated publishing
|
|
51
|
+
|
|
52
|
+
Deployment phases:
|
|
53
|
+
Phase 1 — DEB only (Debian Bookworm, amd64 + arm64). Pulp with pulp_deb.
|
|
54
|
+
Phase 2 — Add RPM (Fedora/RHEL). Install pulp_rpm plugin, add CI matrix.
|
|
55
|
+
Phase 3 — Generic files (AppImage, standalone tarballs). Install pulp_file.
|
|
56
|
+
|
|
57
|
+
Phase 1 is the scope of this design document. Phases 2-3 are noted in
|
|
58
|
+
constraints and acceptance criteria to ensure Phase 1 decisions do not
|
|
59
|
+
block them.
|
|
60
|
+
|
|
61
|
+
CI/CD recipes are documented as reusable pipeline patterns: multi-format
|
|
62
|
+
builds (DEB for amd64 and arm64 in parallel), release automation (tag →
|
|
63
|
+
build → sign → publish → smoke test), and integration test recipes (install
|
|
64
|
+
package in clean container, verify rosett-ai version, verify rai doctor passes).
|
|
65
|
+
These recipes are documented in doc/CI_CD_RECIPES.md and implemented as
|
|
66
|
+
CI job templates in the shared ci-components repository.
|
|
67
|
+
|
|
68
|
+
Distribution complements release management (release_management.yml):
|
|
69
|
+
release management creates versioned tags and changelogs, distribution
|
|
70
|
+
delivers the built packages to end users via native package managers.
|
|
71
|
+
The handoff point is the CI tag event — release creates the tag,
|
|
72
|
+
distribution publishes the artifact.
|
|
73
|
+
|
|
74
|
+
constraints:
|
|
75
|
+
- Package repository managed by Pulp 3 (pulpproject.org) with OCI container deployment
|
|
76
|
+
- DEB support via pulp_deb plugin (Phase 1)
|
|
77
|
+
- RPM support via pulp_rpm plugin MUST NOT be blocked by Phase 1 infrastructure decisions (Phase 2 readiness)
|
|
78
|
+
- Generic file support via pulp_file MUST NOT be blocked (Phase 3 readiness)
|
|
79
|
+
- All packages are GPG-signed using repository-level detached signing (InRelease for DEB, repomd.xml.asc for RPM)
|
|
80
|
+
- GPG signing key uses Ed25519 or RSA-4096 with SHA256+ digest (SHA1 rejected by apt after Feb 2026)
|
|
81
|
+
- CI publishes packages only on annotated tag push events (never on branch commits to stable)
|
|
82
|
+
- Two distribution channels — stable (tagged releases) and unstable (main branch builds)
|
|
83
|
+
- The GPG public key is distributed via HTTPS from the repository server
|
|
84
|
+
- Repository configuration documented in INSTALL.md
|
|
85
|
+
- Package publishing is idempotent — re-publishing the same version is a no-op, not an error
|
|
86
|
+
- The private GPG signing key is stored as a CI/CD variable (protected, masked) — never in the repository
|
|
87
|
+
- Repository serves amd64 and arm64 architectures (DEB Phase 1); x86_64 and aarch64 (RPM Phase 2)
|
|
88
|
+
- HTTPS only for repository access (no plain HTTP)
|
|
89
|
+
- Pulp deployment uses the official OCI images (pulp/pulp-minimal or pulp/pulp)
|
|
90
|
+
- Pulp API access from CI uses token authentication (not username/password)
|
|
91
|
+
- Repository metadata is generated by Pulp (never manually crafted)
|
|
92
|
+
- Infrastructure configuration is reproducible (container compose file versioned in a separate ops repository)
|
|
93
|
+
- "doc/CI_CD_RECIPES.md must document reusable pipeline patterns for
|
|
94
|
+
multi-format builds, release automation, and integration testing"
|
|
95
|
+
- "CI/CD recipes must be engine-agnostic — applicable to any engine that
|
|
96
|
+
produces a distributable artifact"
|
|
97
|
+
- "This design governs package distribution (delivering built packages to
|
|
98
|
+
users). Release management (versioning, tagging, changelogs) is governed
|
|
99
|
+
by release_management.yml. Package building is governed by ci_pipeline.yml.
|
|
100
|
+
The CI tag event is the handoff point between release and distribution"
|
|
101
|
+
|
|
102
|
+
acceptance_criteria:
|
|
103
|
+
- A GitLab CI job deploy:publish runs on tag push and publishes the .deb to the Pulp DEB repository
|
|
104
|
+
- apt install rosett-ai works after adding the NeatNerds repository and GPG key
|
|
105
|
+
- apt upgrade picks up new rosett-ai versions when published to stable
|
|
106
|
+
- Repository serves signed InRelease files verifiable by apt
|
|
107
|
+
- CI job uses Pulp REST API (via pulp-cli or curl) to upload package and trigger publication
|
|
108
|
+
- GPG public key downloadable via HTTPS at a documented URL
|
|
109
|
+
- INSTALL.md contains copy-pasteable commands for repository setup (DEB)
|
|
110
|
+
- Stable channel only receives packages from annotated tags matching v*.*.*
|
|
111
|
+
- Unstable channel receives packages from main branch CI builds (latest commit)
|
|
112
|
+
- Repository supports both amd64 and arm64 packages in the same DEB distribution
|
|
113
|
+
- Pulp container deployment is defined in a docker-compose.yml (or podman equivalent)
|
|
114
|
+
- pulp_rpm plugin can be added to the running Pulp instance without rebuilding (Phase 2 readiness)
|
|
115
|
+
- A CI smoke test verifies the published package is installable in a clean Debian container
|
|
116
|
+
- "CI publish job exits 0 on success, 1 on upload failure, 2 on
|
|
117
|
+
authentication failure, 3 on package validation failure"
|
|
118
|
+
- "doc/CI_CD_RECIPES.md documents multi-format build, release automation,
|
|
119
|
+
and integration test pipeline patterns"
|
|
120
|
+
|
|
121
|
+
examples:
|
|
122
|
+
- scenario: "CI publishes v0.2.0 after tag push"
|
|
123
|
+
expected: |
|
|
124
|
+
1. Developer pushes tag v0.2.0
|
|
125
|
+
2. CI pipeline triggers on tag event
|
|
126
|
+
3. build:package jobs produce rosett-ai_0.2.0_amd64.deb and rosett-ai_0.2.0_arm64.deb
|
|
127
|
+
4. deploy:publish job authenticates to Pulp API via token
|
|
128
|
+
5. Job uploads .deb artifacts to Pulp content endpoint
|
|
129
|
+
6. Job adds packages to the 'stable' DEB repository
|
|
130
|
+
7. Job triggers Pulp publication (regenerates InRelease, Packages.gz)
|
|
131
|
+
8. Users see update via 'apt update && apt list --upgradable'
|
|
132
|
+
not: |
|
|
133
|
+
Publishing happens on every commit. Publishing overwrites existing
|
|
134
|
+
version without warning. Publishing uses unsigned repository.
|
|
135
|
+
CI SSHes directly to a server (use API instead).
|
|
136
|
+
|
|
137
|
+
- scenario: "User adds NeatNerds APT repository for the first time"
|
|
138
|
+
expected: |
|
|
139
|
+
# Commands from INSTALL.md:
|
|
140
|
+
curl -fsSL https://repo.neatnerds.be/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/neatnerds.gpg
|
|
141
|
+
echo "deb [signed-by=/usr/share/keyrings/neatnerds.gpg] https://repo.neatnerds.be/stable bookworm main" \
|
|
142
|
+
| sudo tee /etc/apt/sources.list.d/neatnerds.list
|
|
143
|
+
sudo apt update
|
|
144
|
+
sudo apt install rosett-ai
|
|
145
|
+
raictl version # → rai version 0.2.0
|
|
146
|
+
not: |
|
|
147
|
+
Using deprecated apt-key add. Downloading GPG key over HTTP.
|
|
148
|
+
Using unsigned repository. Instructions that don't work on copy-paste.
|
|
149
|
+
|
|
150
|
+
- scenario: "Attempting to publish without API credentials"
|
|
151
|
+
expected: |
|
|
152
|
+
CI job fails with clear error: "Pulp API token not configured.
|
|
153
|
+
Set CI variable PULP_API_TOKEN (protected, masked)."
|
|
154
|
+
No package is published. Pipeline status: failed.
|
|
155
|
+
not: |
|
|
156
|
+
Publish unsigned package to repository. Silently skip authentication.
|
|
157
|
+
Fall back to anonymous upload.
|
|
158
|
+
|
|
159
|
+
- scenario: "Phase 2 — adding RPM support"
|
|
160
|
+
expected: |
|
|
161
|
+
1. Ops installs pulp_rpm plugin into the running Pulp container
|
|
162
|
+
2. CI matrix adds Fedora/RHEL build jobs producing .rpm files
|
|
163
|
+
3. deploy:publish job extended with RPM upload path
|
|
164
|
+
4. Users on Fedora: dnf config-manager --add-repo https://repo.neatnerds.be/stable/rpm
|
|
165
|
+
5. Same GPG key, same server, same CI pipeline structure
|
|
166
|
+
not: |
|
|
167
|
+
Standing up a second repository server. Migrating from Pulp to
|
|
168
|
+
another tool. Changing the DEB pipeline to accommodate RPM.
|
|
169
|
+
|
|
170
|
+
anti_patterns:
|
|
171
|
+
- Publishing packages on every commit (stable channel is for releases only)
|
|
172
|
+
- Using apt-key add (deprecated since Debian 11, removed in Debian 12)
|
|
173
|
+
- Distributing GPG key over plain HTTP (MITM risk)
|
|
174
|
+
- Storing GPG private key in the git repository
|
|
175
|
+
- Using SHA1-based GPG keys (rejected by apt after Feb 2026)
|
|
176
|
+
- Manual package uploading to the repository server (must be CI-automated)
|
|
177
|
+
- Mixing stable and unstable packages in the same repository component
|
|
178
|
+
- Publishing without verifying the package installs correctly (smoke test)
|
|
179
|
+
- Using aptly or other Debian-only tools that block future RPM/generic expansion
|
|
180
|
+
- SSHing to the repository server from CI (use Pulp REST API instead)
|
|
181
|
+
- Running Pulp on bare metal without containerisation (reproducibility risk)
|
|
182
|
+
- Crafting repository metadata manually instead of letting Pulp generate it
|
|
183
|
+
#
|
|
184
|
+
gui_notes: |
|
|
185
|
+
Document interactions (cross-references):
|
|
186
|
+
|
|
187
|
+
1. release_management.yml: release creates versioned tags and changelogs.
|
|
188
|
+
Distribution publishes the built packages. Tag event is the handoff.
|
|
189
|
+
|
|
190
|
+
2. ci_pipeline.yml: CI builds the packages. Distribution publishes them.
|
|
191
|
+
The publish job runs after the build job in the same pipeline.
|
|
192
|
+
|
|
193
|
+
3. security.yml: GPG signing, HTTPS transport, token authentication,
|
|
194
|
+
private key storage as CI/CD variable.
|
|
195
|
+
|
|
196
|
+
4. documentation.yml: INSTALL.md contains repository setup instructions
|
|
197
|
+
that must be kept in sync with distribution changes.
|
|
198
|
+
|
|
199
|
+
5. error_handling.yml: CI job exit codes follow structured error conventions.
|
|
200
|
+
#
|
|
201
|
+
preferences:
|
|
202
|
+
language: bash
|
|
203
|
+
patterns:
|
|
204
|
+
- "Immutable releases (publish once, never overwrite)"
|
|
205
|
+
- "Signed artifacts (GPG-signed packages and repository metadata)"
|
|
206
|
+
- "Infrastructure as code (container compose versioned in ops repo)"
|
|
207
|
+
- "Plugin architecture (Pulp plugins for format expansion)"
|
|
208
|
+
tools:
|
|
209
|
+
repository: pulp (pulpproject.org)
|
|
210
|
+
plugins_phase1: pulp_deb
|
|
211
|
+
plugins_phase2: pulp_rpm
|
|
212
|
+
plugins_phase3: pulp_file
|
|
213
|
+
signing: gpg (Ed25519 or RSA-4096, SHA256+)
|
|
214
|
+
transport: pulp REST API over HTTPS
|
|
215
|
+
deployment: OCI containers (docker-compose or podman)
|
|
216
|
+
ci: gitlab-ci with protected variables
|