reis-mobile 0.3.5 → 0.4.0
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +33 -0
- package/README.md +186 -172
- package/THIRD_PARTY_NOTICES.md +224 -4
- package/agents/android-architect.md +89 -0
- package/agents/android-performance-engineer.md +92 -0
- package/agents/android-test-engineer.md +97 -0
- package/agents/flutter-test-engineer.md +2 -0
- package/agents/ios-architect.md +93 -0
- package/agents/ios-performance-engineer.md +92 -0
- package/agents/ios-test-engineer.md +95 -0
- package/agents/lead-mobile.md +10 -1
- package/agents/mobile-staff-engineer.md +1 -1
- package/agents/rn-architect.md +94 -0
- package/agents/rn-performance-engineer.md +92 -0
- package/agents/rn-test-engineer.md +98 -0
- package/bin/reis-mobile.mjs +83 -33
- package/commands/debate.md +10 -1
- package/commands/debug.md +60 -0
- package/commands/reis-mobile.md +7 -2
- package/core/config/project.mjs +59 -0
- package/core/install/codex-plugin.mjs +66 -0
- package/core/install/init.mjs +46 -0
- package/core/registry/frontmatter.mjs +15 -4
- package/core/registry/registry.mjs +21 -1
- package/core/router/intents.mjs +2 -0
- package/core/router/router.mjs +10 -5
- package/package.json +1 -1
- package/skills/android-adaptive/SKILL.md +304 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/container-behavior.md +112 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/get-started.md +69 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/index.md +81 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/item-behavior.md +170 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/container-properties.md +415 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/get-started.md +51 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/index.md +73 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/item-properties.md +170 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/layouts/adaptive/mediaquery/index.md +333 -0
- package/skills/android-adaptive/references/android/develop/ui/compose/tooling/debug.md +114 -0
- package/skills/android-adaptive/references/android/guide/navigation/navigation-3/recipes/material-listdetail.md +141 -0
- package/skills/android-agp-9-upgrade/SKILL.md +106 -0
- package/skills/android-agp-9-upgrade/references/android/build/migrate-to-built-in-kotlin.md +416 -0
- package/skills/android-agp-9-upgrade/references/android/build/releases/agp-9-0-0-release-notes.md +554 -0
- package/skills/android-agp-9-upgrade/references/buildconfig.md +54 -0
- package/skills/android-agp-9-upgrade/references/ksp-kapt.md +39 -0
- package/skills/android-agp-9-upgrade/references/paparazzi-gradle-9.md +30 -0
- package/skills/android-agp-9-upgrade/references/recipes.md +62 -0
- package/skills/android-appfunctions/SKILL.md +74 -0
- package/skills/android-appfunctions/references/adb-interaction-testing.md +95 -0
- package/skills/android-appfunctions/references/context.md +26 -0
- package/skills/android-appfunctions/references/feature-discovery-analysis.md +71 -0
- package/skills/android-appfunctions/references/implementation-configuration.md +282 -0
- package/skills/android-appfunctions/references/kdoc-refinement-optimization.md +75 -0
- package/skills/android-appfunctions/references/migrate-to-service-entry-point.md +226 -0
- package/skills/android-camerax/SKILL.md +135 -0
- package/skills/android-camerax/references/camera1-to-camerax.md +198 -0
- package/skills/android-camerax/references/camera2-to-camerax.md +193 -0
- package/skills/android-camerax/references/expert-blueprints.md +58 -0
- package/skills/android-camerax/references/foldables.md +83 -0
- package/skills/android-camerax/references/immutability.md +60 -0
- package/skills/android-camerax/references/low-light.md +124 -0
- package/skills/android-camerax/references/mlkit-spatial.md +75 -0
- package/skills/android-camerax/references/modern-apis.md +42 -0
- package/skills/android-camerax/references/testing.md +69 -0
- package/skills/android-camerax/references/thermals.md +85 -0
- package/skills/android-camerax/references/wear-os.md +76 -0
- package/skills/android-camerax/references/xr.md +54 -0
- package/skills/android-cli/SKILL.md +474 -0
- package/skills/android-cli/references/interact.md +113 -0
- package/skills/android-cli/references/journeys.md +120 -0
- package/skills/android-code-review/SKILL.md +58 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/SKILL.md +340 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/design/ui/ai-glasses/guides/interaction/inputs.md +67 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/access-hardware-projected-context.md +388 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/buttons.md +139 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/cards.md +148 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/focus.md +107 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/icons.md +90 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/text.md +69 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer/title-chips.md +82 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/android/develop/xr/jetpack-xr-sdk/request-hardware-permissions.md +213 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/button-samples-source.md +176 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/button-source.md +203 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/card-samples-source.md +296 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/card-source.md +515 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/deptheffect-source.md +224 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/deptheffectlevels-source.md +105 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/glimmersansflextypography-source.md +270 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/glimmertheme-source.md +182 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/icon-source.md +388 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/iconbutton-source.md +126 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/iconsizes-source.md +78 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/list-source.md +27 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/listitem-source.md +272 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/liststate-source.md +427 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/material-hct-source.md +217 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/projectedcontext-source.md +265 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/stack-source.md +368 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/stackitemscope-source.md +440 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/stackstate-source.md +325 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/surface-source.md +1211 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/titlechip-samples-source.md +101 -0
- package/skills/android-display-glasses-with-jetpack-compose-glimmer/references/titlechip-source.md +131 -0
- package/skills/android-edge-to-edge/SKILL.md +429 -0
- package/skills/android-engage-sdk-integration/SKILL.md +130 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/faq.md +439 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/food.md +1149 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/healthandfitness.md +1055 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/listen.md +1050 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/otherverticals.md +1301 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/read.md +910 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/shopping.md +1224 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/social.md +719 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/travel.md +1413 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/tv/continue-watching/index.md +19 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/tv/entitlements.md +353 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/tv/getting-started.md +202 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/tv/recommendations.md +471 -0
- package/skills/android-engage-sdk-integration/references/android/guide/playcore/engage/watch.md +1081 -0
- package/skills/android-engage-sdk-integration/references/clusters.md +154 -0
- package/skills/android-engage-sdk-integration/references/common.md +519 -0
- package/skills/android-engage-sdk-integration/references/patterns.md +527 -0
- package/skills/android-engage-sdk-integration/references/requests.md +260 -0
- package/skills/android-engage-sdk-integration/references/schemas/food.md +509 -0
- package/skills/android-engage-sdk-integration/references/schemas/listen.md +842 -0
- package/skills/android-engage-sdk-integration/references/schemas/other.md +220 -0
- package/skills/android-engage-sdk-integration/references/schemas/read.md +412 -0
- package/skills/android-engage-sdk-integration/references/schemas/shopping.md +357 -0
- package/skills/android-engage-sdk-integration/references/schemas/social.md +228 -0
- package/skills/android-engage-sdk-integration/references/schemas/travel.md +923 -0
- package/skills/android-engage-sdk-integration/references/schemas/tv.md +1226 -0
- package/skills/android-engage-sdk-integration/references/schemas/watch.md +1137 -0
- package/skills/android-engage-sdk-integration/references/troubleshooting.md +39 -0
- package/skills/android-gradle-build-debug/SKILL.md +71 -0
- package/skills/android-intent-security/SKILL.md +550 -0
- package/skills/android-leanback-to-compose-tv-migration/SKILL.md +743 -0
- package/skills/android-leanback-to-compose-tv-migration/references/android/training/tv/get-started/navigation.md +372 -0
- package/skills/android-leanback-to-compose-tv-migration/references/android/training/tv/playback/compose/browse.md +243 -0
- package/skills/android-leanback-to-compose-tv-migration/references/android/training/tv/playback/compose/index.md +153 -0
- package/skills/android-media3-cast-integration/SKILL.md +236 -0
- package/skills/android-media3-cast-integration/references/android/media/media3/cast/create-castplayer.md +390 -0
- package/skills/android-media3-cast-integration/references/android/media/media3/cast/customize-castoptions.md +93 -0
- package/skills/android-media3-cast-integration/references/android/media/media3/cast/index.md +21 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/SKILL.md +127 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/analysis-of-the-project-and-layout.md +42 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/android/develop/ui/compose/designsystems/migrate-xml-theme-to-compose.md +171 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/android/develop/ui/compose/migrate/interoperability-apis/compose-in-views.md +299 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/android/develop/ui/compose/migrate/interoperability-apis/views-in-compose.md +286 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/android/develop/ui/compose/setup-compose-dependencies-and-compiler.md +197 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/identify-optimal-xml-candidate.md +31 -0
- package/skills/android-migrate-xml-views-to-jetpack-compose/references/xml-layout-migration.md +86 -0
- package/skills/android-ml-kit-genai-prompt-api/SKILL.md +124 -0
- package/skills/android-ml-kit-genai-prompt-api/references/get-started.md +272 -0
- package/skills/android-ml-kit-genai-prompt-api/references/prefix-caching.md +146 -0
- package/skills/android-ml-kit-genai-prompt-api/references/prompt-design.md +55 -0
- package/skills/android-ml-kit-genai-prompt-api/references/prompt-optimization.md +74 -0
- package/skills/android-ml-kit-genai-prompt-api/references/structured-output.md +219 -0
- package/skills/android-ml-kit-genai-prompt-api/references/system-instructions.md +71 -0
- package/skills/android-navigation-3/SKILL.md +122 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/index.md +51 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/migration-guide.md +670 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/animations.md +147 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/basic.md +89 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/basicdsl.md +85 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/basicsaveable.md +90 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/bottomsheet.md +195 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/common-ui.md +200 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/conditional-transitions.md +182 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/conditional.md +230 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/deeplinks-custommatcher.md +176 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/deeplinks-staticuri.md +140 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/deeplinks-syntheticbackstack.md +184 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/dialog.md +107 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/lifecycle-owner.md +185 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/material-listdetail.md +141 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/material-supportingpane.md +145 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/modular-hilt.md +283 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/modular-koin.md +287 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/multiple-backstacks.md +468 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/passingarguments.md +371 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/results-event.md +273 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/results-state.md +266 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/scenes-listdetail.md +435 -0
- package/skills/android-navigation-3/references/android/guide/navigation/navigation-3/recipes/scenes-twopane.md +244 -0
- package/skills/android-navigation-3/references/android/guide/navigation/type-safe-destinations.md +129 -0
- package/skills/android-navigation-event/SKILL.md +312 -0
- package/skills/android-navigation-event/references/android/guide/navigation/navigation-event/dispatcher.md +134 -0
- package/skills/android-navigation-event/references/android/guide/navigation/navigation-event/handle-back.md +217 -0
- package/skills/android-navigation-event/references/android/guide/navigation/navigation-event/index.md +83 -0
- package/skills/android-navigation-event/references/android/guide/navigation/navigation-event/setup.md +32 -0
- package/skills/android-play-billing-library-version-upgrade/SKILL.md +96 -0
- package/skills/android-play-billing-library-version-upgrade/references/android/google/play/billing/release-notes.md +1240 -0
- package/skills/android-play-billing-library-version-upgrade/references/migration-logic.md +78 -0
- package/skills/android-play-billing-library-version-upgrade/references/version-checklist.md +54 -0
- package/skills/android-play-policy-insights/SKILL.md +172 -0
- package/skills/android-play-policy-insights/resources/common_mandates.md +100 -0
- package/skills/android-play-policy-insights/resources/compliance_report_template.md +59 -0
- package/skills/android-play-policy-insights/resources/critic.md +86 -0
- package/skills/android-play-policy-insights/resources/goal_data_safety.md +212 -0
- package/skills/android-play-policy-insights/resources/goal_permissions_and_apis.md +459 -0
- package/skills/android-play-policy-insights/resources/goal_user_account.md +106 -0
- package/skills/android-play-policy-insights/resources/policies.json +321 -0
- package/skills/android-play-policy-insights/resources/scanner_config.json +843 -0
- package/skills/android-play-policy-insights/scripts/generate_report.py +860 -0
- package/skills/android-play-policy-insights/scripts/orchestrator.py +1313 -0
- package/skills/android-play-policy-insights/scripts/play_store_scraper.py +410 -0
- package/skills/android-play-policy-insights/scripts/scanner.py +261 -0
- package/skills/android-play-policy-insights/scripts/template_engine.py +243 -0
- package/skills/android-profiler/SKILL.md +60 -0
- package/skills/android-profiler/analysis/analysis_orchestrator.md +32 -0
- package/skills/android-profiler/analysis/workflows/perfetto-sql/perfetto_sql.md +28 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/perfetto_trace_analysis.md +121 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/guiding_principles.md +51 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/domain_hints_template.md +7 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_cpu.md +56 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_graphics.md +51 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_io.md +46 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_ipc.md +41 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_memory.md +55 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/hints/subsystems/hints_power.md +33 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/per_candidate_analysis.md +172 -0
- package/skills/android-profiler/analysis/workflows/perfetto-trace-analysis/references/triage.md +94 -0
- package/skills/android-profiler/recording/recording_orchestrator.md +36 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/perfetto_trace_recording.md +148 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/app_jank.pftxt +43 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/cpu_profile.pftxt +35 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/java_heap_dump.pftxt +21 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/long_background.pftxt +37 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/memory_counters.pftxt +45 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/native_heap.pftxt +21 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/example-configs/sched_cpu.pftxt +33 -0
- package/skills/android-profiler/recording/workflows/perfetto-trace-recording/references/trace_config_reference.md +102 -0
- package/skills/android-profiler/references/env_setup.md +15 -0
- package/skills/android-profiler/references/perfetto/setup.md +29 -0
- package/skills/android-profiler/references/perfetto/sql.md +327 -0
- package/skills/android-r8-analyzer/SKILL.md +72 -0
- package/skills/android-r8-analyzer/references/CONFIGURATION-ANALYZER.md +287 -0
- package/skills/android-r8-analyzer/references/CONFIGURATION.md +44 -0
- package/skills/android-r8-analyzer/references/KEEP-RULES-IMPACT-HIERARCHY.md +83 -0
- package/skills/android-r8-analyzer/references/REDUNDANT-RULES.md +222 -0
- package/skills/android-r8-analyzer/references/REFLECTION-GUIDE.md +139 -0
- package/skills/android-r8-analyzer/references/REPORT_FORMAT.md +51 -0
- package/skills/android-r8-analyzer/references/android/topic/performance/app-optimization/enable-app-optimization.md +252 -0
- package/skills/android-r8-analyzer/references/android/training/testing/other-components/ui-automator.md +312 -0
- package/skills/android-restore-credentials/SKILL.md +359 -0
- package/skills/android-restore-credentials/references/android/guide/topics/manifest/application-element.md +832 -0
- package/skills/android-restore-credentials/references/android/identity/passkeys/create-passkeys.md +327 -0
- package/skills/android-restore-credentials/references/android/identity/passkeys/sign-in-with-passkeys.md +219 -0
- package/skills/android-styles/SKILL.md +229 -0
- package/skills/android-styles/references/android/develop/ui/compose/designsystems/custom.md +459 -0
- package/skills/android-styles/references/android/develop/ui/compose/styles/fundamentals.md +421 -0
- package/skills/android-styles/references/android/develop/ui/compose/styles/state-animations.md +461 -0
- package/skills/android-styles/references/android/develop/ui/compose/styles/styles-vs-modifiers.md +48 -0
- package/skills/android-styles/references/android/develop/ui/compose/styles/theming.md +269 -0
- package/skills/android-verified-email/SKILL.md +432 -0
- package/skills/android-verified-email/references/android/identity/credential-manager/index.md +67 -0
- package/skills/android-verified-email/references/android/identity/digital-credentials/credential-verifier.md +166 -0
- package/skills/android-verified-email/references/android/identity/digital-credentials/email-verification-implementation.md +313 -0
- package/skills/android-verified-email/references/android/identity/digital-credentials/email-verification.md +158 -0
- package/skills/android-verified-email/references/android/identity/digital-credentials/index.md +112 -0
- package/skills/android-verified-email/references/android/identity/passkeys/create-passkeys.md +327 -0
- package/skills/android-verified-email/references/android/identity/sign-in/credential-manager-webview.md +84 -0
- package/skills/android-wear-compose-m3/SKILL.md +365 -0
- package/skills/android-wear-compose-m3/references/android/training/wearables/compose/migrate-to-material3.md +677 -0
- package/skills/android-wear-compose-m3/references/foundation/AmbientModeSample.kt.md +123 -0
- package/skills/android-wear-compose-m3/references/foundation/AmbientModeSample.kt.md.txt +123 -0
- package/skills/android-wear-compose-m3/references/foundation/CurvedWorldSample.kt.md +430 -0
- package/skills/android-wear-compose-m3/references/foundation/CurvedWorldSample.kt.md.txt +430 -0
- package/skills/android-wear-compose-m3/references/foundation/ExpandableSample.kt.md +99 -0
- package/skills/android-wear-compose-m3/references/foundation/ExpandableSample.kt.md.txt +99 -0
- package/skills/android-wear-compose-m3/references/foundation/HierarchicalFocusSample.kt.md +141 -0
- package/skills/android-wear-compose-m3/references/foundation/HierarchicalFocusSample.kt.md.txt +141 -0
- package/skills/android-wear-compose-m3/references/foundation/PagerSamples.kt.md +56 -0
- package/skills/android-wear-compose-m3/references/foundation/PagerSamples.kt.md.txt +56 -0
- package/skills/android-wear-compose-m3/references/foundation/RotarySamples.kt.md +153 -0
- package/skills/android-wear-compose-m3/references/foundation/RotarySamples.kt.md.txt +153 -0
- package/skills/android-wear-compose-m3/references/foundation/ScalingLazyColumnSample.kt.md +131 -0
- package/skills/android-wear-compose-m3/references/foundation/ScalingLazyColumnSample.kt.md.txt +131 -0
- package/skills/android-wear-compose-m3/references/foundation/SwipeToDismissBoxSample.kt.md +169 -0
- package/skills/android-wear-compose-m3/references/foundation/SwipeToDismissBoxSample.kt.md.txt +169 -0
- package/skills/android-wear-compose-m3/references/foundation/SwipeToRevealSample.kt.md +282 -0
- package/skills/android-wear-compose-m3/references/foundation/SwipeToRevealSample.kt.md.txt +282 -0
- package/skills/android-wear-compose-m3/references/foundation/TransformingLazyColumnSample.kt.md +335 -0
- package/skills/android-wear-compose-m3/references/foundation/TransformingLazyColumnSample.kt.md.txt +335 -0
- package/skills/android-wear-compose-m3/references/material3/AlertDialogSample.kt.md +377 -0
- package/skills/android-wear-compose-m3/references/material3/AlertDialogSample.kt.md.txt +377 -0
- package/skills/android-wear-compose-m3/references/material3/AnimatedTextSample.kt.md +165 -0
- package/skills/android-wear-compose-m3/references/material3/AnimatedTextSample.kt.md.txt +165 -0
- package/skills/android-wear-compose-m3/references/material3/ButtonGroupSample.kt.md +91 -0
- package/skills/android-wear-compose-m3/references/material3/ButtonGroupSample.kt.md.txt +91 -0
- package/skills/android-wear-compose-m3/references/material3/ButtonSample.kt.md +496 -0
- package/skills/android-wear-compose-m3/references/material3/ButtonSample.kt.md.txt +496 -0
- package/skills/android-wear-compose-m3/references/material3/CardSample.kt.md +470 -0
- package/skills/android-wear-compose-m3/references/material3/CardSample.kt.md.txt +470 -0
- package/skills/android-wear-compose-m3/references/material3/CheckboxButtonSample.kt.md +67 -0
- package/skills/android-wear-compose-m3/references/material3/CheckboxButtonSample.kt.md.txt +67 -0
- package/skills/android-wear-compose-m3/references/material3/ConfirmationDialogSample.kt.md +162 -0
- package/skills/android-wear-compose-m3/references/material3/ConfirmationDialogSample.kt.md.txt +162 -0
- package/skills/android-wear-compose-m3/references/material3/CurvedTextSamples.kt.md +78 -0
- package/skills/android-wear-compose-m3/references/material3/CurvedTextSamples.kt.md.txt +78 -0
- package/skills/android-wear-compose-m3/references/material3/DatePickerSample.kt.md +131 -0
- package/skills/android-wear-compose-m3/references/material3/DatePickerSample.kt.md.txt +131 -0
- package/skills/android-wear-compose-m3/references/material3/DynamicColorSchemeSample.kt.md +74 -0
- package/skills/android-wear-compose-m3/references/material3/DynamicColorSchemeSample.kt.md.txt +74 -0
- package/skills/android-wear-compose-m3/references/material3/EdgeButtonSample.kt.md +63 -0
- package/skills/android-wear-compose-m3/references/material3/EdgeButtonSample.kt.md.txt +63 -0
- package/skills/android-wear-compose-m3/references/material3/FadingExpandingLabelSample.kt.md +60 -0
- package/skills/android-wear-compose-m3/references/material3/FadingExpandingLabelSample.kt.md.txt +60 -0
- package/skills/android-wear-compose-m3/references/material3/IconButtonSample.kt.md +125 -0
- package/skills/android-wear-compose-m3/references/material3/IconButtonSample.kt.md.txt +125 -0
- package/skills/android-wear-compose-m3/references/material3/IconToggleButtonSample.kt.md +116 -0
- package/skills/android-wear-compose-m3/references/material3/IconToggleButtonSample.kt.md.txt +116 -0
- package/skills/android-wear-compose-m3/references/material3/LevelIndicatorSample.kt.md +68 -0
- package/skills/android-wear-compose-m3/references/material3/LevelIndicatorSample.kt.md.txt +68 -0
- package/skills/android-wear-compose-m3/references/material3/LinearProgressIndicatorSample.kt.md +50 -0
- package/skills/android-wear-compose-m3/references/material3/LinearProgressIndicatorSample.kt.md.txt +50 -0
- package/skills/android-wear-compose-m3/references/material3/ListHeaderSample.kt.md +177 -0
- package/skills/android-wear-compose-m3/references/material3/ListHeaderSample.kt.md.txt +177 -0
- package/skills/android-wear-compose-m3/references/material3/OneHandedGestureSamples.kt.md +651 -0
- package/skills/android-wear-compose-m3/references/material3/OneHandedGestureSamples.kt.md.txt +651 -0
- package/skills/android-wear-compose-m3/references/material3/OpenOnPhoneDialogSample.kt.md +57 -0
- package/skills/android-wear-compose-m3/references/material3/OpenOnPhoneDialogSample.kt.md.txt +57 -0
- package/skills/android-wear-compose-m3/references/material3/PageIndicatorSample.kt.md +110 -0
- package/skills/android-wear-compose-m3/references/material3/PageIndicatorSample.kt.md.txt +110 -0
- package/skills/android-wear-compose-m3/references/material3/PagerScaffoldSample.kt.md +204 -0
- package/skills/android-wear-compose-m3/references/material3/PagerScaffoldSample.kt.md.txt +204 -0
- package/skills/android-wear-compose-m3/references/material3/PickerGroupSample.kt.md +139 -0
- package/skills/android-wear-compose-m3/references/material3/PickerGroupSample.kt.md.txt +139 -0
- package/skills/android-wear-compose-m3/references/material3/PickerSample.kt.md +111 -0
- package/skills/android-wear-compose-m3/references/material3/PickerSample.kt.md.txt +111 -0
- package/skills/android-wear-compose-m3/references/material3/PlaceholderSample.kt.md +184 -0
- package/skills/android-wear-compose-m3/references/material3/PlaceholderSample.kt.md.txt +184 -0
- package/skills/android-wear-compose-m3/references/material3/ProgressIndicatorSample.kt.md +263 -0
- package/skills/android-wear-compose-m3/references/material3/ProgressIndicatorSample.kt.md.txt +263 -0
- package/skills/android-wear-compose-m3/references/material3/RadioButtonSample.kt.md +105 -0
- package/skills/android-wear-compose-m3/references/material3/RadioButtonSample.kt.md.txt +105 -0
- package/skills/android-wear-compose-m3/references/material3/ScaffoldSample.kt.md +146 -0
- package/skills/android-wear-compose-m3/references/material3/ScaffoldSample.kt.md.txt +146 -0
- package/skills/android-wear-compose-m3/references/material3/ScrollAwaySample.kt.md +97 -0
- package/skills/android-wear-compose-m3/references/material3/ScrollAwaySample.kt.md.txt +97 -0
- package/skills/android-wear-compose-m3/references/material3/ScrollIndicatorSample.kt.md +66 -0
- package/skills/android-wear-compose-m3/references/material3/ScrollIndicatorSample.kt.md.txt +66 -0
- package/skills/android-wear-compose-m3/references/material3/SliderSample.kt.md +86 -0
- package/skills/android-wear-compose-m3/references/material3/SliderSample.kt.md.txt +86 -0
- package/skills/android-wear-compose-m3/references/material3/StepperSample.kt.md +148 -0
- package/skills/android-wear-compose-m3/references/material3/StepperSample.kt.md.txt +148 -0
- package/skills/android-wear-compose-m3/references/material3/SurfaceTransformationSample.kt.md +166 -0
- package/skills/android-wear-compose-m3/references/material3/SurfaceTransformationSample.kt.md.txt +166 -0
- package/skills/android-wear-compose-m3/references/material3/SwipeToDismissBoxSample.kt.md +172 -0
- package/skills/android-wear-compose-m3/references/material3/SwipeToDismissBoxSample.kt.md.txt +172 -0
- package/skills/android-wear-compose-m3/references/material3/SwipeToRevealSample.kt.md +367 -0
- package/skills/android-wear-compose-m3/references/material3/SwipeToRevealSample.kt.md.txt +367 -0
- package/skills/android-wear-compose-m3/references/material3/SwitchButtonSample.kt.md +66 -0
- package/skills/android-wear-compose-m3/references/material3/SwitchButtonSample.kt.md.txt +66 -0
- package/skills/android-wear-compose-m3/references/material3/TextButtonSample.kt.md +115 -0
- package/skills/android-wear-compose-m3/references/material3/TextButtonSample.kt.md.txt +115 -0
- package/skills/android-wear-compose-m3/references/material3/TextToggleButtonSample.kt.md +71 -0
- package/skills/android-wear-compose-m3/references/material3/TextToggleButtonSample.kt.md.txt +71 -0
- package/skills/android-wear-compose-m3/references/material3/TimePickerSample.kt.md +151 -0
- package/skills/android-wear-compose-m3/references/material3/TimePickerSample.kt.md.txt +151 -0
- package/skills/android-wear-compose-m3/references/material3/TimeTextSample.kt.md +65 -0
- package/skills/android-wear-compose-m3/references/material3/TimeTextSample.kt.md.txt +65 -0
- package/skills/android-wear-compose-m3/references/material3/TransformationSpecSample.kt.md +246 -0
- package/skills/android-wear-compose-m3/references/material3/TransformationSpecSample.kt.md.txt +246 -0
- package/skills/android-wear-compose-m3/references/material3/TransformingLazyColumnNotificationsSample.kt.md +89 -0
- package/skills/android-wear-compose-m3/references/material3/TransformingLazyColumnNotificationsSample.kt.md.txt +89 -0
- package/skills/android-wear-compose-m3/references/material3/TransformingLazyColumnSample.kt.md +309 -0
- package/skills/android-wear-compose-m3/references/material3/TransformingLazyColumnSample.kt.md.txt +309 -0
- package/skills/android-wear-compose-m3/references/navigation3/SwipeDismissableSceneStrategySample.kt.md +205 -0
- package/skills/android-wear-compose-m3/references/navigation3/SwipeDismissableSceneStrategySample.kt.md.txt +205 -0
- package/skills/{architecture-feature-first → flutter-architecture-feature-first}/SKILL.md +1 -1
- package/skills/{bloc → flutter-bloc}/SKILL.md +1 -1
- package/skills/flutter-build-debug/SKILL.md +66 -0
- package/skills/{code-review → flutter-code-review}/SKILL.md +1 -1
- package/skills/{dart-3-updates → flutter-dart-3-updates}/SKILL.md +1 -1
- package/skills/{dart-fix-runtime-errors → flutter-dart-fix-runtime-errors}/SKILL.md +1 -1
- package/skills/{dart-resolve-package-conflicts → flutter-dart-resolve-package-conflicts}/SKILL.md +1 -1
- package/skills/{dart-run-static-analysis → flutter-dart-run-static-analysis}/SKILL.md +1 -1
- package/skills/{dart-use-pattern-matching → flutter-dart-use-pattern-matching}/SKILL.md +1 -1
- package/skills/{effective-dart → flutter-effective-dart}/SKILL.md +1 -1
- package/skills/{provider → flutter-provider}/SKILL.md +1 -1
- package/skills/{riverpod → flutter-riverpod}/SKILL.md +1 -1
- package/skills/ios-cocoapods-debug/SKILL.md +65 -0
- package/skills/ios-code-review/SKILL.md +56 -0
- package/skills/ios-xcode-build-debug/SKILL.md +66 -0
- package/skills/{detect-mobile-stack → mobile-detect-stack}/SKILL.md +1 -1
- package/skills/mobile-firebase/SKILL.md +54 -0
- package/skills/mobile-firebase/references/android/ai-logic.md +31 -0
- package/skills/mobile-firebase/references/android/analytics.md +33 -0
- package/skills/mobile-firebase/references/android/app-check.md +36 -0
- package/skills/mobile-firebase/references/android/auth.md +44 -0
- package/skills/mobile-firebase/references/android/crashlytics.md +31 -0
- package/skills/mobile-firebase/references/android/firestore.md +44 -0
- package/skills/mobile-firebase/references/android/functions.md +33 -0
- package/skills/mobile-firebase/references/android/in-app-messaging.md +28 -0
- package/skills/mobile-firebase/references/android/messaging.md +41 -0
- package/skills/mobile-firebase/references/android/realtime-database.md +50 -0
- package/skills/mobile-firebase/references/android/remote-config.md +43 -0
- package/skills/mobile-firebase/references/android/sql-connect.md +31 -0
- package/skills/mobile-firebase/references/android/storage.md +39 -0
- package/skills/mobile-firebase/references/android.md +30 -0
- package/skills/{firebase-ai/SKILL.md → mobile-firebase/references/flutter/ai-logic.md} +2 -8
- package/skills/{firebase-analytics/SKILL.md → mobile-firebase/references/flutter/analytics.md} +2 -8
- package/skills/{firebase-app-check/SKILL.md → mobile-firebase/references/flutter/app-check.md} +2 -8
- package/skills/{firebase-auth/SKILL.md → mobile-firebase/references/flutter/auth.md} +2 -8
- package/skills/{firebase-crashlytics/SKILL.md → mobile-firebase/references/flutter/crashlytics.md} +2 -8
- package/skills/{firebase-cloud-firestore/SKILL.md → mobile-firebase/references/flutter/firestore.md} +2 -8
- package/skills/{firebase-cloud-functions/SKILL.md → mobile-firebase/references/flutter/functions.md} +2 -8
- package/skills/{firebase-in-app-messaging/SKILL.md → mobile-firebase/references/flutter/in-app-messaging.md} +2 -8
- package/skills/{firebase-messaging/SKILL.md → mobile-firebase/references/flutter/messaging.md} +2 -8
- package/skills/{firebase-database/SKILL.md → mobile-firebase/references/flutter/realtime-database.md} +2 -8
- package/skills/{firebase-remote-config/SKILL.md → mobile-firebase/references/flutter/remote-config.md} +2 -8
- package/skills/{flutterfire-configure/SKILL.md → mobile-firebase/references/flutter/setup-flutterfire.md} +1 -8
- package/skills/{firebase-data-connect/SKILL.md → mobile-firebase/references/flutter/sql-connect.md} +2 -8
- package/skills/{firebase-storage/SKILL.md → mobile-firebase/references/flutter/storage.md} +2 -8
- package/skills/mobile-firebase/references/flutter.md +36 -0
- package/skills/mobile-firebase/references/ios/ai-logic.md +30 -0
- package/skills/mobile-firebase/references/ios/analytics.md +33 -0
- package/skills/mobile-firebase/references/ios/app-check.md +36 -0
- package/skills/mobile-firebase/references/ios/auth.md +48 -0
- package/skills/mobile-firebase/references/ios/crashlytics.md +34 -0
- package/skills/mobile-firebase/references/ios/firestore.md +53 -0
- package/skills/mobile-firebase/references/ios/functions.md +35 -0
- package/skills/mobile-firebase/references/ios/in-app-messaging.md +26 -0
- package/skills/mobile-firebase/references/ios/messaging.md +45 -0
- package/skills/mobile-firebase/references/ios/realtime-database.md +49 -0
- package/skills/mobile-firebase/references/ios/remote-config.md +44 -0
- package/skills/mobile-firebase/references/ios/sql-connect.md +33 -0
- package/skills/mobile-firebase/references/ios/storage.md +36 -0
- package/skills/mobile-firebase/references/ios.md +28 -0
- package/skills/mobile-firebase/references/react-native/ai-logic.md +32 -0
- package/skills/mobile-firebase/references/react-native/analytics.md +43 -0
- package/skills/mobile-firebase/references/react-native/app-check.md +35 -0
- package/skills/mobile-firebase/references/react-native/auth.md +50 -0
- package/skills/mobile-firebase/references/react-native/crashlytics.md +36 -0
- package/skills/mobile-firebase/references/react-native/firestore.md +45 -0
- package/skills/mobile-firebase/references/react-native/functions.md +28 -0
- package/skills/mobile-firebase/references/react-native/in-app-messaging.md +27 -0
- package/skills/mobile-firebase/references/react-native/messaging.md +46 -0
- package/skills/mobile-firebase/references/react-native/realtime-database.md +46 -0
- package/skills/mobile-firebase/references/react-native/remote-config.md +32 -0
- package/skills/mobile-firebase/references/react-native/sql-connect.md +11 -0
- package/skills/mobile-firebase/references/react-native/storage.md +30 -0
- package/skills/mobile-firebase/references/react-native.md +29 -0
- package/skills/mobile-test/SKILL.md +63 -0
- package/skills/mobile-test/references/android/setup/GUIDE.md +183 -0
- package/skills/mobile-test/references/android/setup/references/android/develop/ui/compose/testing/common-patterns.md +181 -0
- package/skills/mobile-test/references/android/setup/references/android/studio/preview/compose-screenshot-testing.md +255 -0
- package/skills/mobile-test/references/android/setup/references/android/training/dependency-injection/hilt-testing.md +447 -0
- package/skills/mobile-test/references/android.md +83 -0
- package/skills/{dart-collect-coverage/SKILL.md → mobile-test/references/flutter/coverage.md} +2 -11
- package/skills/{dart-generate-test-mocks/SKILL.md → mobile-test/references/flutter/generate-mocks.md} +2 -11
- package/skills/{flutter-add-integration-test/SKILL.md → mobile-test/references/flutter/integration-tests.md} +2 -11
- package/skills/{dart-migrate-to-checks-package/SKILL.md → mobile-test/references/flutter/migrate-to-checks.md} +2 -13
- package/skills/{mockito/SKILL.md → mobile-test/references/flutter/mockito.md} +1 -8
- package/skills/{mocktail/SKILL.md → mobile-test/references/flutter/mocktail.md} +1 -8
- package/skills/{patrol-e2e-testing/SKILL.md → mobile-test/references/flutter/patrol.md} +1 -8
- package/skills/{testing/SKILL.md → mobile-test/references/flutter/testing-guidelines.md} +1 -8
- package/skills/{dart-add-unit-test/SKILL.md → mobile-test/references/flutter/unit-tests.md} +2 -11
- package/skills/{flutter-add-widget-test/SKILL.md → mobile-test/references/flutter/widget-tests.md} +2 -11
- package/skills/mobile-test/references/flutter.md +44 -0
- package/skills/mobile-test/references/ios.md +79 -0
- package/skills/mobile-test/references/react-native.md +62 -0
- /package/skills/{dart-use-pattern-matching → flutter-dart-use-pattern-matching}/examples/json_patterns.dart +0 -0
package/bin/reis-mobile.mjs
CHANGED
|
@@ -4,10 +4,11 @@ import { join } from 'node:path';
|
|
|
4
4
|
import { parseArgs } from 'node:util';
|
|
5
5
|
|
|
6
6
|
import { LANGUAGES, configPath, removeConfig, resolveLanguage, saveLanguage } from '../core/config/language.mjs';
|
|
7
|
+
import { resolveProjectDir } from '../core/config/project.mjs';
|
|
7
8
|
import { collectReviewContext } from '../core/context/context-engine.mjs';
|
|
8
9
|
import { detectStack } from '../core/detection/stack-detector.mjs';
|
|
9
10
|
import { runDoctor } from '../core/diagnostics/doctor.mjs';
|
|
10
|
-
import {
|
|
11
|
+
import { runInit } from '../core/install/init.mjs';
|
|
11
12
|
import { PLUGIN_ROOT } from '../core/paths.mjs';
|
|
12
13
|
import { loadRegistry, validateRegistry } from '../core/registry/registry.mjs';
|
|
13
14
|
import { INTENT_IDS } from '../core/router/intents.mjs';
|
|
@@ -18,24 +19,25 @@ const USAGE = `reis-mobile — AI agents for mobile engineering
|
|
|
18
19
|
Usage: reis-mobile <command> [options]
|
|
19
20
|
|
|
20
21
|
Commands:
|
|
21
|
-
init [en|pt] Install the reis-mobile plugin into Claude Code, optionally setting the language
|
|
22
|
+
init [en|pt] Install the reis-mobile plugin into Claude Code and Codex, optionally setting the language
|
|
22
23
|
lang [en|pt] Show or set the language the /reis-mobile commands answer in
|
|
23
24
|
detect Detect the mobile stack of a project
|
|
24
25
|
doctor Diagnose the environment for the detected stack
|
|
25
26
|
route <prompt...> Show which intent, agent and skills a prompt resolves to
|
|
26
27
|
review [prompt...] Route a code review and collect the git context for it
|
|
28
|
+
debug [problem...] Route a build or runtime failure and report the toolchain it runs on
|
|
27
29
|
agents | skills | stacks List registered components
|
|
28
30
|
validate Validate the plugin's agents, skills and stacks
|
|
29
31
|
|
|
30
32
|
Options:
|
|
31
|
-
--dir <path> Project directory (default: current directory)
|
|
33
|
+
--dir <path> Project directory (default: current directory, or "app" in .reis-mobile/config.yaml)
|
|
32
34
|
--intent <id> Force an intent (${INTENT_IDS.join(', ')})
|
|
33
35
|
--base <ref> review: compare <ref>...HEAD instead of the working tree
|
|
34
36
|
--all doctor: check every tool, not only the relevant ones
|
|
35
37
|
--strict doctor: exit with code 1 when there are warnings
|
|
36
38
|
--local init: install the plugin from this installation instead of GitHub
|
|
37
|
-
--scope <scope> init: user (default), project or local
|
|
38
|
-
--uninstall init: remove the plugin
|
|
39
|
+
--scope <scope> init: Claude Code scope, user (default), project or local
|
|
40
|
+
--uninstall init: remove the plugin and its marketplace from Claude Code and Codex, and the saved language
|
|
39
41
|
--lang <en|pt> Override the saved language for this run
|
|
40
42
|
--json Machine-readable output
|
|
41
43
|
-v, --version Print the version
|
|
@@ -63,6 +65,7 @@ const COMMANDS = {
|
|
|
63
65
|
doctor: commandDoctor,
|
|
64
66
|
route: commandRoute,
|
|
65
67
|
review: commandReview,
|
|
68
|
+
debug: commandDebug,
|
|
66
69
|
agents: (options) => commandList('agents', options),
|
|
67
70
|
skills: (options) => commandList('skills', options),
|
|
68
71
|
stacks: (options) => commandList('stacks', options),
|
|
@@ -88,31 +91,46 @@ async function main(argv) {
|
|
|
88
91
|
console.error(`Unknown command "${name}".\n\n${USAGE}`);
|
|
89
92
|
return 1;
|
|
90
93
|
}
|
|
91
|
-
|
|
94
|
+
const dir = options.dir ?? process.cwd();
|
|
95
|
+
// Commands that analyze a project honor `app:` from .reis-mobile/config.yaml.
|
|
96
|
+
const project = PROJECT_COMMANDS.has(name) ? resolveProjectDir(dir) : { projectDir: dir, config: null, warnings: [] };
|
|
97
|
+
for (const warning of project.warnings) console.error(`! ${warning}`);
|
|
98
|
+
|
|
99
|
+
return (await command({ ...options, dir: project.projectDir, project, prompt: rest.join(' ') })) ?? 0;
|
|
92
100
|
}
|
|
93
101
|
|
|
102
|
+
const PROJECT_COMMANDS = new Set(['detect', 'doctor', 'route', 'review', 'debug']);
|
|
103
|
+
|
|
94
104
|
async function commandInit({ local, scope, uninstall, lang, prompt }) {
|
|
95
|
-
// The installers pass the language through REIS_MOBILE_LANG.
|
|
96
105
|
const requested = lang ?? (prompt || process.env.REIS_MOBILE_LANG || undefined);
|
|
97
|
-
// Validate before touching Claude Code, so a typo does not leave a half-done install.
|
|
106
|
+
// Validate before touching Claude Code or Codex, so a typo does not leave a half-done install.
|
|
98
107
|
if (requested && !uninstall) await resolveLanguage({ flag: requested, env: {} });
|
|
99
108
|
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
const { ok, results } = runInit({ uninstall, scope, ...(local && { source: PLUGIN_ROOT }) });
|
|
110
|
+
|
|
111
|
+
console.log('');
|
|
112
|
+
for (const result of results) {
|
|
113
|
+
if (result.skipped) console.log(`- ${result.name.padEnd(12)}not found, skipped`);
|
|
114
|
+
else if (result.ok) console.log(`✓ ${result.name.padEnd(12)}${uninstall ? 'removed' : 'installed'}`);
|
|
115
|
+
else console.error(`✗ ${result.name.padEnd(12)}${result.failedStep} failed (exit ${result.status})`);
|
|
116
|
+
}
|
|
103
117
|
|
|
104
|
-
if (!result.
|
|
105
|
-
console.error(
|
|
118
|
+
if (!results.some((result) => !result.skipped)) {
|
|
119
|
+
console.error('\nNeither Claude Code nor Codex was found in PATH. Install one of them and run `reis-mobile init` again.');
|
|
106
120
|
return 1;
|
|
107
121
|
}
|
|
108
122
|
if (uninstall) {
|
|
109
123
|
await removeConfig();
|
|
110
|
-
console.log('
|
|
111
|
-
return 0;
|
|
124
|
+
console.log(`✓ ${'Language'.padEnd(12)}saved setting removed`);
|
|
125
|
+
return ok ? 0 : 1;
|
|
112
126
|
}
|
|
113
|
-
if (requested
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
if (requested && results.some((result) => result.ok)) {
|
|
128
|
+
console.log(`✓ ${'Language'.padEnd(12)}${await saveLanguage(requested)} (${configPath()})`);
|
|
129
|
+
}
|
|
130
|
+
if (results.some((result) => result.ok)) {
|
|
131
|
+
console.log('\nRestart Claude Code or Codex. In Claude Code, run /reis-mobile:doctor.');
|
|
132
|
+
}
|
|
133
|
+
return ok ? 0 : 1;
|
|
116
134
|
}
|
|
117
135
|
|
|
118
136
|
async function commandLang({ prompt, json }) {
|
|
@@ -128,10 +146,12 @@ async function commandLang({ prompt, json }) {
|
|
|
128
146
|
return 0;
|
|
129
147
|
}
|
|
130
148
|
|
|
131
|
-
async function commandDetect({ dir, json, lang }) {
|
|
149
|
+
async function commandDetect({ dir, project, json, lang }) {
|
|
132
150
|
const detection = await detectStack(dir);
|
|
133
151
|
const language = await resolveLanguage({ flag: lang });
|
|
134
|
-
if (json) return print({ ...detection, language });
|
|
152
|
+
if (json) return print({ ...detection, language, projectConfig: project.config?.path ?? null });
|
|
153
|
+
|
|
154
|
+
printProject(project);
|
|
135
155
|
|
|
136
156
|
console.log(`Stack ${detection.stack}${detection.variant ? ` (${detection.variant})` : ''}`);
|
|
137
157
|
console.log(`Languages ${detection.languages.join(', ') || '-'}`);
|
|
@@ -143,47 +163,54 @@ async function commandDetect({ dir, json, lang }) {
|
|
|
143
163
|
return detection.stack === 'unknown' ? 2 : 0;
|
|
144
164
|
}
|
|
145
165
|
|
|
146
|
-
async function commandDoctor({ dir, all, strict, json, lang }) {
|
|
166
|
+
async function commandDoctor({ dir, project, all, strict, json, lang }) {
|
|
147
167
|
const report = await runDoctor({ projectDir: dir, all });
|
|
148
168
|
const language = await resolveLanguage({ flag: lang });
|
|
149
169
|
if (json) {
|
|
150
|
-
print({ ...report, language });
|
|
170
|
+
print({ ...report, language, projectConfig: project.config?.path ?? null });
|
|
151
171
|
} else {
|
|
152
172
|
console.log('reis-mobile doctor\n');
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (!checks.length) continue;
|
|
156
|
-
console.log(`${title}\n${'-'.repeat(title.length)}`);
|
|
157
|
-
for (const check of checks) console.log(`${check.label.padEnd(16)}${SYMBOLS[check.status]} ${check.detail ?? ''}`.trimEnd());
|
|
158
|
-
console.log('');
|
|
159
|
-
}
|
|
173
|
+
printProject(project);
|
|
174
|
+
printDoctorChecks(report);
|
|
160
175
|
console.log(report.warnings ? `${report.warnings} warning(s)` : 'No issues found');
|
|
161
176
|
printLanguage(language);
|
|
162
177
|
}
|
|
163
178
|
return strict && report.warnings ? 1 : 0;
|
|
164
179
|
}
|
|
165
180
|
|
|
181
|
+
function printDoctorChecks(report) {
|
|
182
|
+
for (const [section, title] of [['environment', 'Environment'], ['project', 'Project'], ['integrations', 'Integrations']]) {
|
|
183
|
+
const checks = report.checks.filter((check) => check.section === section);
|
|
184
|
+
if (!checks.length) continue;
|
|
185
|
+
console.log(`${title}\n${'-'.repeat(title.length)}`);
|
|
186
|
+
for (const check of checks) console.log(`${check.label.padEnd(16)}${SYMBOLS[check.status]} ${check.detail ?? ''}`.trimEnd());
|
|
187
|
+
console.log('');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
166
191
|
const SYMBOLS = { ok: '✓', warning: '✗', info: '-', skipped: '-' };
|
|
167
192
|
|
|
168
|
-
async function commandRoute({ dir, intent, prompt, json, lang }) {
|
|
193
|
+
async function commandRoute({ dir, project, intent, prompt, json, lang }) {
|
|
169
194
|
if (!prompt && !intent) {
|
|
170
195
|
console.error('route needs a prompt or --intent.');
|
|
171
196
|
return 1;
|
|
172
197
|
}
|
|
173
198
|
const result = await route({ prompt, intent, projectDir: dir });
|
|
174
199
|
const language = await resolveLanguage({ flag: lang });
|
|
175
|
-
if (json) return print({ ...summarizeRoute(result), language });
|
|
200
|
+
if (json) return print({ ...summarizeRoute(result), language, projectConfig: project.config?.path ?? null });
|
|
201
|
+
printProject(project);
|
|
176
202
|
printRoute(result);
|
|
177
203
|
printLanguage(language);
|
|
178
204
|
return 0;
|
|
179
205
|
}
|
|
180
206
|
|
|
181
|
-
async function commandReview({ dir, base, prompt, json, lang }) {
|
|
207
|
+
async function commandReview({ dir, project, base, prompt, json, lang }) {
|
|
182
208
|
const result = await route({ prompt, intent: 'review', projectDir: dir });
|
|
183
209
|
const context = collectReviewContext({ projectDir: dir, base });
|
|
184
210
|
const language = await resolveLanguage({ flag: lang });
|
|
185
|
-
if (json) return print({ ...summarizeRoute(result), language, context });
|
|
211
|
+
if (json) return print({ ...summarizeRoute(result), language, projectConfig: project.config?.path ?? null, context });
|
|
186
212
|
|
|
213
|
+
printProject(project);
|
|
187
214
|
printRoute(result);
|
|
188
215
|
printLanguage(language);
|
|
189
216
|
console.log(`\nContext ${context.mode}${context.base ? ` (${context.base}...HEAD)` : ''}`);
|
|
@@ -193,6 +220,24 @@ async function commandReview({ dir, base, prompt, json, lang }) {
|
|
|
193
220
|
return 0;
|
|
194
221
|
}
|
|
195
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Routes a failure to the debug agent and skills, and adds the doctor report: most build
|
|
225
|
+
* failures are toolchain mismatches (JDK, Gradle, Xcode, CocoaPods), which the report shows.
|
|
226
|
+
*/
|
|
227
|
+
async function commandDebug({ dir, project, prompt, json, lang }) {
|
|
228
|
+
const result = await route({ prompt, intent: 'debug', projectDir: dir });
|
|
229
|
+
const doctor = await runDoctor({ projectDir: dir });
|
|
230
|
+
const language = await resolveLanguage({ flag: lang });
|
|
231
|
+
if (json) return print({ ...summarizeRoute(result), language, projectConfig: project.config?.path ?? null, doctor });
|
|
232
|
+
|
|
233
|
+
printProject(project);
|
|
234
|
+
printRoute(result);
|
|
235
|
+
printLanguage(language);
|
|
236
|
+
console.log('');
|
|
237
|
+
printDoctorChecks(doctor);
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
196
241
|
async function commandList(kind, { json }) {
|
|
197
242
|
const registry = await loadRegistry();
|
|
198
243
|
const items = registry[kind];
|
|
@@ -235,6 +280,11 @@ function printRoute(result) {
|
|
|
235
280
|
for (const warning of result.warnings) console.log(`! ${warning}`);
|
|
236
281
|
}
|
|
237
282
|
|
|
283
|
+
/** Only printed when .reis-mobile/config.yaml moved the command to another folder. */
|
|
284
|
+
function printProject({ projectDir, config }) {
|
|
285
|
+
if (config?.data.app !== undefined) console.log(`Project ${projectDir} (app from ${config.path})`);
|
|
286
|
+
}
|
|
287
|
+
|
|
238
288
|
/** `-` means no saved language: the commands follow the language of the request. */
|
|
239
289
|
function printLanguage(language) {
|
|
240
290
|
console.log(`Language ${language ?? '-'}`);
|
package/commands/debate.md
CHANGED
|
@@ -39,6 +39,15 @@ Choose **three** agents whose priorities genuinely conflict on the question. A d
|
|
|
39
39
|
| `reis-mobile:flutter-architect` | Layer boundaries, modularization, long-term maintenance cost | `opus` |
|
|
40
40
|
| `reis-mobile:flutter-performance-engineer` | Frames, rebuilds, memory, startup time — hostile to indirection | `sonnet` |
|
|
41
41
|
| `reis-mobile:flutter-test-engineer` | Testability, injection seams, coverage cost | `sonnet` |
|
|
42
|
+
| `reis-mobile:android-architect` | Native Android layers, Gradle modularization, long-term maintenance cost | `opus` |
|
|
43
|
+
| `reis-mobile:android-performance-engineer` | Recomposition, ANRs, startup, memory — hostile to indirection | `sonnet` |
|
|
44
|
+
| `reis-mobile:android-test-engineer` | Testability, injected dispatchers and fakes, coverage cost | `sonnet` |
|
|
45
|
+
| `reis-mobile:ios-architect` | Native iOS structure, packages, concurrency isolation | `opus` |
|
|
46
|
+
| `reis-mobile:ios-performance-engineer` | Hangs, view updates, launch time, retain cycles | `sonnet` |
|
|
47
|
+
| `reis-mobile:ios-test-engineer` | Testability, protocol seams, coverage cost | `sonnet` |
|
|
48
|
+
| `reis-mobile:rn-architect` | Feature boundaries, server vs client state, native module isolation | `opus` |
|
|
49
|
+
| `reis-mobile:rn-performance-engineer` | Re-renders, lists, JavaScript thread, startup | `sonnet` |
|
|
50
|
+
| `reis-mobile:rn-test-engineer` | Testability through the UI, mocks at boundaries, coverage cost | `sonnet` |
|
|
42
51
|
| `reis-mobile:plugin-native-expert` | Flutter–native boundary, platform channels, lifecycle | `opus` |
|
|
43
52
|
| `reis-mobile:mobile-staff-engineer` | Build, release, migration, cross-platform trade-offs | `opus` |
|
|
44
53
|
| `reis-mobile:mobile-code-reviewer` | Concrete risk in the code that already exists | `sonnet` |
|
|
@@ -49,7 +58,7 @@ Automatic selection must end with **at least two different models** among the pa
|
|
|
49
58
|
|
|
50
59
|
Selection rules:
|
|
51
60
|
|
|
52
|
-
- The detected stack rules. The `flutter-*` agents only join Flutter projects
|
|
61
|
+
- The detected stack rules. The `flutter-*` agents only join Flutter projects, `android-*` native Android, `ios-*` native iOS and `rn-*` React Native. Pick the architect, performance and test specialists of the detected stack first; `mobile-staff-engineer` and `mobile-code-reviewer` fit any stack.
|
|
53
62
|
- Without native code in the project, do not call `plugin-native-expert`.
|
|
54
63
|
- `--agents` overrides the automatic choice, but not the models: each agent keeps the one from the table. Unknown name: warn and stop.
|
|
55
64
|
- `reis-mobile:lead-mobile` never debates — it moderates in step 7, always on `opus`, because synthesizing conflicting positions is the heaviest work in the flow.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Mobile debugging — routes a build or runtime failure (Gradle, Xcode, CocoaPods, Flutter) to the right agent and skills, finds the cause with evidence and proposes the fix
|
|
3
|
+
argument-hint: "<error message, failing command or description of the problem>"
|
|
4
|
+
allowed-tools: ["Bash(node:*)", "Bash(git:*)", "Bash(flutter:*)", "Bash(dart:*)", "Bash(./gradlew:*)", "Bash(xcodebuild:*)", "Bash(pod:*)", "Bash(java:*)", "Read", "Grep", "Glob"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# reis-mobile debug
|
|
8
|
+
|
|
9
|
+
Arguments received: `$ARGUMENTS`
|
|
10
|
+
|
|
11
|
+
The arguments are the problem: an error message, the command that fails, or a description. Without them, ask the user for the failing command and its full output, and stop. A debug session without the actual error guesses; one with it verifies.
|
|
12
|
+
|
|
13
|
+
## 1. Route and gather the toolchain
|
|
14
|
+
|
|
15
|
+
Run via Bash, with correct quoting:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/reis-mobile.mjs" debug --dir "$PWD" -- "<problem>"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The output reports:
|
|
22
|
+
|
|
23
|
+
- `Project`, when `.reis-mobile/config.yaml` points the command at an app folder;
|
|
24
|
+
- `Intent`, `Stack`, `focus` and `area` (`gradle`, `xcode`, `cocoapods`, `signing`, `pub`...);
|
|
25
|
+
- `Agent` and `Skills`, in priority order;
|
|
26
|
+
- `Language`, the language to answer in (see **Language**);
|
|
27
|
+
- the doctor checks: installed tools and their versions, lock files, Gradle wrapper, iOS deployment target.
|
|
28
|
+
|
|
29
|
+
If the command fails, show the error to the user and stop.
|
|
30
|
+
|
|
31
|
+
## Language
|
|
32
|
+
|
|
33
|
+
The CLI output has a `Language` line. Write everything the user reads in that language: `en` is English, `pt` is Brazilian Portuguese. With `-`, use the language of the user's request. Code, identifiers, file paths, commands and quoted tool output stay as they are.
|
|
34
|
+
|
|
35
|
+
## 2. Load the instructions
|
|
36
|
+
|
|
37
|
+
Read with the Read tool, in this order:
|
|
38
|
+
|
|
39
|
+
1. `${CLAUDE_PLUGIN_ROOT}/agents/<Agent>.md`;
|
|
40
|
+
2. `${CLAUDE_PLUGIN_ROOT}/skills/<skill>/SKILL.md` for each listed skill. The first skills are the most specific to the stack and area; read them all, since a failure often crosses layers (a Flutter build that fails inside Gradle).
|
|
41
|
+
|
|
42
|
+
## 3. Diagnose
|
|
43
|
+
|
|
44
|
+
Follow the agent's process and the skills' checklists:
|
|
45
|
+
|
|
46
|
+
1. **Find the first real error.** Build logs bury it under cascading failures. Quote the line that starts the failure, not the last `BUILD FAILED`.
|
|
47
|
+
2. **Read the files that decide the behavior** before forming a theory: build scripts, wrapper and lock files, manifests, `Info.plist`, `Podfile`, project settings. Compare versions against the doctor output — a mismatch between the JDK, Gradle, AGP, Kotlin, Xcode or CocoaPods is the most common cause.
|
|
48
|
+
3. **Reproduce when it is safe.** Read-only commands can run: `./gradlew --version`, `flutter --version`, `pod --version`, `xcodebuild -version`, `./gradlew :app:dependencies`. A build that only compiles (`./gradlew assembleDebug`, `flutter build apk --debug`) can run if the user already ran it or agrees, since it takes time and writes build outputs.
|
|
49
|
+
4. **Confirm the cause** with evidence at `file:line` or in the log. If two causes are plausible, say which evidence would separate them instead of picking one.
|
|
50
|
+
|
|
51
|
+
## 4. Propose, then wait
|
|
52
|
+
|
|
53
|
+
Answer with:
|
|
54
|
+
|
|
55
|
+
- **Cause:** one or two sentences, with the evidence.
|
|
56
|
+
- **Fix:** the minimal change, as a diff or the exact commands, in the order to apply them.
|
|
57
|
+
- **Why it works**, and what it changes beyond the error (a Gradle or Kotlin upgrade, a new minimum iOS version).
|
|
58
|
+
- **How to verify:** the command that failed, run again.
|
|
59
|
+
|
|
60
|
+
Do not edit files or run commands that change the project or the machine — `flutter clean`, `pod install`, `pod repo update`, deleting `DerivedData` or `~/.gradle` caches, dependency upgrades — until the user asks you to apply the fix. Once they do, apply it, run the verification command and report the result.
|
package/commands/reis-mobile.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: reis-mobile entry point — lists the commands or forwards to doctor, review, debate or the right agent from a free-form request
|
|
3
|
-
argument-hint: "[doctor | review | debate | free-form request]"
|
|
2
|
+
description: reis-mobile entry point — lists the commands or forwards to doctor, review, debug, debate or the right agent from a free-form request
|
|
3
|
+
argument-hint: "[doctor | review | debug | debate | free-form request]"
|
|
4
4
|
allowed-tools: ["Bash(node:*)", "Bash(git:*)", "Read", "Grep", "Glob"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -21,6 +21,7 @@ Reply only with this list. The only thing to run is `node "${CLAUDE_PLUGIN_ROOT}
|
|
|
21
21
|
```text
|
|
22
22
|
/reis-mobile:doctor Environment and project: SDKs, Xcode, CocoaPods, Gradle wrapper, lock files
|
|
23
23
|
/reis-mobile:review [--base <ref>] Code review of the changes (or the whole project)
|
|
24
|
+
/reis-mobile:debug <problem> Finds the cause of a build or runtime failure and proposes the fix
|
|
24
25
|
/reis-mobile:debate <question> Debate between the specialists, with a decision by lead-mobile
|
|
25
26
|
/reis-mobile <free-form request> Forwards the request to the agent and skills for the detected stack
|
|
26
27
|
```
|
|
@@ -36,6 +37,10 @@ When the language is `pt`, translate the descriptions and keep the commands as t
|
|
|
36
37
|
|
|
37
38
|
Read `${CLAUDE_PLUGIN_ROOT}/commands/review.md` and follow all of it, treating the rest of the arguments (without the word `review`) as `$ARGUMENTS`.
|
|
38
39
|
|
|
40
|
+
## `debug <problem>`
|
|
41
|
+
|
|
42
|
+
Read `${CLAUDE_PLUGIN_ROOT}/commands/debug.md` and follow all of it, treating the rest of the arguments (without the word `debug`) as `$ARGUMENTS`.
|
|
43
|
+
|
|
39
44
|
## `debate [options] <question>`
|
|
40
45
|
|
|
41
46
|
Read `${CLAUDE_PLUGIN_ROOT}/commands/debate.md` and follow all of it, treating the rest of the arguments (without the word `debate`) as `$ARGUMENTS`.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { parseYamlSubset } from '../registry/frontmatter.mjs';
|
|
5
|
+
|
|
6
|
+
export const PROJECT_CONFIG = join('.reis-mobile', 'config.yaml');
|
|
7
|
+
|
|
8
|
+
const KNOWN_KEYS = new Set(['app']);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Finds the nearest `.reis-mobile/config.yaml`, starting at `dir` and walking up, so a
|
|
12
|
+
* command run anywhere inside a monorepo sees the same settings.
|
|
13
|
+
*
|
|
14
|
+
* @returns {{ path: string, root: string, data: object } | null}
|
|
15
|
+
*/
|
|
16
|
+
export function findProjectConfig(dir) {
|
|
17
|
+
let current = resolve(dir);
|
|
18
|
+
for (;;) {
|
|
19
|
+
const path = join(current, PROJECT_CONFIG);
|
|
20
|
+
if (existsSync(path)) return { path, root: current, data: parseYamlSubset(readFileSync(path, 'utf8')) };
|
|
21
|
+
const parent = dirname(current);
|
|
22
|
+
if (parent === current) return null;
|
|
23
|
+
current = parent;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The directory commands should analyze. `app: apps/mobile` points a monorepo at its
|
|
29
|
+
* mobile app, relative to the folder that holds `.reis-mobile/`. A `dir` already inside
|
|
30
|
+
* the app is kept, so running from `apps/mobile/lib` still works.
|
|
31
|
+
*
|
|
32
|
+
* @returns {{ projectDir: string, config: object|null, warnings: string[] }}
|
|
33
|
+
*/
|
|
34
|
+
export function resolveProjectDir(dir) {
|
|
35
|
+
const requested = resolve(dir);
|
|
36
|
+
const config = findProjectConfig(requested);
|
|
37
|
+
if (!config) return { projectDir: requested, config: null, warnings: [] };
|
|
38
|
+
|
|
39
|
+
const warnings = Object.keys(config.data)
|
|
40
|
+
.filter((key) => !KNOWN_KEYS.has(key))
|
|
41
|
+
.map((key) => `${config.path}: unknown key "${key}" ignored`);
|
|
42
|
+
|
|
43
|
+
const { app } = config.data;
|
|
44
|
+
if (app === undefined) return { projectDir: requested, config, warnings };
|
|
45
|
+
if (typeof app !== 'string' || !app.trim() || isAbsolute(app)) {
|
|
46
|
+
throw new Error(`${config.path}: "app" must be a folder relative to ${config.root}, such as "apps/mobile"`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const appDir = resolve(config.root, app);
|
|
50
|
+
if (!existsSync(appDir) || !statSync(appDir).isDirectory()) {
|
|
51
|
+
throw new Error(`${config.path}: app folder "${app}" does not exist`);
|
|
52
|
+
}
|
|
53
|
+
return { projectDir: isInside(requested, appDir) ? requested : appDir, config, warnings };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isInside(child, parent) {
|
|
57
|
+
const path = relative(parent, child);
|
|
58
|
+
return path === '' || (!path.startsWith('..') && !isAbsolute(path));
|
|
59
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
import { LEGACY_PLUGIN_IDS, MARKETPLACE_NAME, MARKETPLACE_URL, PLUGIN_ID } from './claude-plugin.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Registers the reis-mobile marketplace and installs the plugin through the `codex` CLI.
|
|
7
|
+
*
|
|
8
|
+
* `marketplace add` and `plugin add` are idempotent in Codex. `marketplace upgrade` only
|
|
9
|
+
* accepts Git marketplaces, so it is skipped for a local `source`; it refreshes a snapshot
|
|
10
|
+
* that predates the latest release, which otherwise fails with "not found in marketplace".
|
|
11
|
+
*/
|
|
12
|
+
export function installCodexPlugin({ source = MARKETPLACE_URL, run = runCodex, list = listCodexPlugins } = {}) {
|
|
13
|
+
const result = runSteps(run, [
|
|
14
|
+
['plugin', 'marketplace', 'add', source],
|
|
15
|
+
...(isGitSource(source) ? [['plugin', 'marketplace', 'upgrade', MARKETPLACE_NAME]] : []),
|
|
16
|
+
['plugin', 'add', PLUGIN_ID],
|
|
17
|
+
]);
|
|
18
|
+
if (!result.ok) return result;
|
|
19
|
+
const installed = list().plugins;
|
|
20
|
+
return runSteps(run, LEGACY_PLUGIN_IDS.filter((id) => installed.includes(id)).map((id) => ['plugin', 'remove', id]));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** `marketplace remove` fails when the marketplace is not configured, so it only runs when it is. */
|
|
24
|
+
export function uninstallCodexPlugin({ run = runCodex, list = listCodexPlugins } = {}) {
|
|
25
|
+
const { plugins, marketplaces } = list();
|
|
26
|
+
return runSteps(run, [
|
|
27
|
+
...[PLUGIN_ID, ...LEGACY_PLUGIN_IDS].filter((id) => plugins.includes(id)).map((id) => ['plugin', 'remove', id]),
|
|
28
|
+
...(marketplaces.includes(MARKETPLACE_NAME) ? [['plugin', 'marketplace', 'remove', MARKETPLACE_NAME]] : []),
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isGitSource(source) {
|
|
33
|
+
return /^(https?:\/\/|git@|ssh:\/\/)/.test(source);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function runSteps(run, steps) {
|
|
37
|
+
for (const args of steps) {
|
|
38
|
+
const status = run(args);
|
|
39
|
+
if (status !== 0) return { ok: false, failedStep: `codex ${args.join(' ')}`, status };
|
|
40
|
+
}
|
|
41
|
+
return { ok: true };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function runCodex(args) {
|
|
45
|
+
const result = spawnSync('codex', args, { stdio: 'inherit', shell: process.platform === 'win32' });
|
|
46
|
+
if (result.error) throw result.error;
|
|
47
|
+
return result.status ?? 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Installed plugin ids and configured marketplace names. Unreadable output means neither. */
|
|
51
|
+
function listCodexPlugins() {
|
|
52
|
+
return {
|
|
53
|
+
plugins: readJson(['plugin', 'list', '--json'], (data) => data.installed.map((plugin) => plugin.pluginId)),
|
|
54
|
+
marketplaces: readJson(['plugin', 'marketplace', 'list', '--json'], (data) => data.marketplaces.map((marketplace) => marketplace.name)),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function readJson(args, pick) {
|
|
59
|
+
const result = spawnSync('codex', args, { encoding: 'utf8', shell: process.platform === 'win32' });
|
|
60
|
+
if (result.status !== 0) return [];
|
|
61
|
+
try {
|
|
62
|
+
return pick(JSON.parse(result.stdout));
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
import { installClaudePlugin, uninstallClaudePlugin } from './claude-plugin.mjs';
|
|
4
|
+
import { installCodexPlugin, uninstallCodexPlugin } from './codex-plugin.mjs';
|
|
5
|
+
|
|
6
|
+
/** Every tool `reis-mobile init` registers the plugin in, when its CLI is on the PATH. */
|
|
7
|
+
export const TARGETS = [
|
|
8
|
+
{
|
|
9
|
+
id: 'claude',
|
|
10
|
+
name: 'Claude Code',
|
|
11
|
+
bin: 'claude',
|
|
12
|
+
install: ({ source, scope }) => installClaudePlugin({ source, scope }),
|
|
13
|
+
uninstall: ({ scope }) => uninstallClaudePlugin({ scope }),
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 'codex',
|
|
17
|
+
name: 'Codex',
|
|
18
|
+
bin: 'codex',
|
|
19
|
+
install: ({ source }) => installCodexPlugin({ source }),
|
|
20
|
+
uninstall: () => uninstallCodexPlugin(),
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Installs (or removes) the plugin in each tool that is available, and never stops at the
|
|
26
|
+
* first failure: one broken tool must not keep the plugin out of the other.
|
|
27
|
+
*
|
|
28
|
+
* Returns one entry per target: `skipped` when its CLI is missing, otherwise `ok` plus the
|
|
29
|
+
* failing step. `ok` is false overall when a tool failed or none was found.
|
|
30
|
+
*/
|
|
31
|
+
export function runInit({ uninstall = false, source, scope = 'user', targets = TARGETS, exists = commandExists } = {}) {
|
|
32
|
+
const results = targets.map((target) => {
|
|
33
|
+
if (!exists(target.bin)) return { id: target.id, name: target.name, skipped: true };
|
|
34
|
+
const options = { scope, ...(source && { source }) };
|
|
35
|
+
const result = uninstall ? target.uninstall(options) : target.install(options);
|
|
36
|
+
return { id: target.id, name: target.name, ...result };
|
|
37
|
+
});
|
|
38
|
+
const ran = results.filter((result) => !result.skipped);
|
|
39
|
+
return { ok: ran.length > 0 && ran.every((result) => result.ok), results };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function commandExists(bin) {
|
|
43
|
+
const result = spawnSync(bin, ['--version'], { stdio: 'ignore', shell: process.platform === 'win32' });
|
|
44
|
+
// Through a Windows shell a missing command is exit code 1 (cmd) instead of ENOENT.
|
|
45
|
+
return !result.error && !(process.platform === 'win32' && result.status !== 0);
|
|
46
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// Minimal YAML frontmatter parser, dependency-free on purpose: the plugin must run
|
|
2
2
|
// straight from the Claude Code plugin cache without `npm install`.
|
|
3
3
|
//
|
|
4
|
-
// Supported subset: `key: scalar
|
|
5
|
-
//
|
|
6
|
-
// the `metadata:` block of
|
|
4
|
+
// Supported subset: `key: scalar` (continued on indented lines, as YAML folds plain
|
|
5
|
+
// scalars), `key: [a, b]`, block lists (`key:` followed by ` - item` lines) and block
|
|
6
|
+
// scalars (`key: |`, `|-`, `>`, `>-`). Nested maps, such as the `metadata:` block of
|
|
7
|
+
// upstream skills, are skipped.
|
|
7
8
|
|
|
8
9
|
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)([\s\S]*)$/;
|
|
9
10
|
const BLOCK_SCALAR = /^([|>])([+-]?)$/;
|
|
@@ -14,10 +15,12 @@ export function parseFrontmatter(source) {
|
|
|
14
15
|
return { data: parseYamlSubset(match[1]), body: match[2] };
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
/** Parses the same YAML subset outside frontmatter, for `.reis-mobile/config.yaml`. */
|
|
19
|
+
export function parseYamlSubset(text) {
|
|
18
20
|
const data = {};
|
|
19
21
|
const lines = text.split(/\r?\n/);
|
|
20
22
|
let listKey = null;
|
|
23
|
+
let plainKey = null;
|
|
21
24
|
|
|
22
25
|
for (let index = 0; index < lines.length; index++) {
|
|
23
26
|
const line = lines[index];
|
|
@@ -29,11 +32,17 @@ function parseYamlSubset(text) {
|
|
|
29
32
|
continue;
|
|
30
33
|
}
|
|
31
34
|
|
|
35
|
+
if (plainKey && /^\s+\S/.test(line)) {
|
|
36
|
+
data[plainKey] = `${data[plainKey]} ${line.trim()}`;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
const pair = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(line);
|
|
33
41
|
if (!pair) continue;
|
|
34
42
|
|
|
35
43
|
const [, key, value] = pair;
|
|
36
44
|
listKey = null;
|
|
45
|
+
plainKey = null;
|
|
37
46
|
const block = BLOCK_SCALAR.exec(value);
|
|
38
47
|
|
|
39
48
|
if (block) {
|
|
@@ -47,6 +56,8 @@ function parseYamlSubset(text) {
|
|
|
47
56
|
listKey = key;
|
|
48
57
|
} else {
|
|
49
58
|
data[key] = parseValue(value);
|
|
59
|
+
// Only an unquoted scalar can continue on the next lines.
|
|
60
|
+
if (typeof data[key] === 'string' && !/^["'[]/.test(value)) plainKey = key;
|
|
50
61
|
}
|
|
51
62
|
}
|
|
52
63
|
return data;
|
|
@@ -3,11 +3,21 @@ import { basename, join } from 'node:path';
|
|
|
3
3
|
|
|
4
4
|
import { DETECTABLE_STACKS } from '../detection/stack-detector.mjs';
|
|
5
5
|
import { PLUGIN_ROOT } from '../paths.mjs';
|
|
6
|
-
import { INTENT_IDS } from '../router/intents.mjs';
|
|
6
|
+
import { AREA_IDS, INTENT_IDS } from '../router/intents.mjs';
|
|
7
7
|
import { parseFrontmatter } from './frontmatter.mjs';
|
|
8
8
|
|
|
9
9
|
export const ANY_STACK = '*';
|
|
10
10
|
|
|
11
|
+
/** Every skill name starts with the prefix of the first stack it declares. */
|
|
12
|
+
export const SKILL_PREFIXES = {
|
|
13
|
+
[ANY_STACK]: ['mobile-'],
|
|
14
|
+
flutter: ['flutter-'],
|
|
15
|
+
android: ['android-'],
|
|
16
|
+
ios: ['ios-'],
|
|
17
|
+
'react-native': ['rn-'],
|
|
18
|
+
'kotlin-multiplatform': ['kmp-'],
|
|
19
|
+
};
|
|
20
|
+
|
|
11
21
|
/**
|
|
12
22
|
* Loads stacks (`stacks/<id>/stack.json`), agents (`agents/<name>.md`) and skills
|
|
13
23
|
* (`skills/<name>/SKILL.md`). Routing metadata lives in the same frontmatter Claude Code
|
|
@@ -68,6 +78,8 @@ function toComponent(kind, path, fileName, source) {
|
|
|
68
78
|
description: data.description,
|
|
69
79
|
intents: asList(data.intents),
|
|
70
80
|
stacks: asList(data.stacks),
|
|
81
|
+
// Optional: the build areas (gradle, xcode, cocoapods...) a skill is specific to.
|
|
82
|
+
areas: asList(data.areas),
|
|
71
83
|
// `routing: manual` marks helpers that Claude invokes by description only.
|
|
72
84
|
routed: data.routing !== 'manual',
|
|
73
85
|
// Third-party components declare where they came from (see THIRD_PARTY_NOTICES.md).
|
|
@@ -107,9 +119,17 @@ export function validateRegistry({ stacks, agents, skills }) {
|
|
|
107
119
|
|
|
108
120
|
if (component.source && !component.license) errors.push(`${label}: "source" requires "license"`);
|
|
109
121
|
|
|
122
|
+
const prefixes = component.kind === 'skill' ? SKILL_PREFIXES[component.stacks[0]] : undefined;
|
|
123
|
+
if (prefixes && component.name && !prefixes.some((prefix) => component.name.startsWith(prefix))) {
|
|
124
|
+
errors.push(`${label}: skill name must start with "${prefixes.join('" or "')}" for stack "${component.stacks[0]}"`);
|
|
125
|
+
}
|
|
126
|
+
|
|
110
127
|
for (const intent of component.intents) {
|
|
111
128
|
if (!INTENT_IDS.includes(intent)) errors.push(`${label}: unknown intent "${intent}"`);
|
|
112
129
|
}
|
|
130
|
+
for (const area of component.areas) {
|
|
131
|
+
if (!AREA_IDS.includes(area)) errors.push(`${label}: unknown area "${area}"`);
|
|
132
|
+
}
|
|
113
133
|
for (const stack of component.stacks) {
|
|
114
134
|
if (stack !== ANY_STACK && !stackIds.has(stack)) errors.push(`${label}: unknown stack "${stack}"`);
|
|
115
135
|
}
|
package/core/router/intents.mjs
CHANGED
|
@@ -80,6 +80,8 @@ export const AREAS = [
|
|
|
80
80
|
['pub', ['pub get', 'pubspec', 'version solving']],
|
|
81
81
|
];
|
|
82
82
|
|
|
83
|
+
export const AREA_IDS = AREAS.map(([id]) => id);
|
|
84
|
+
|
|
83
85
|
// Areas that only exist on one native platform, used to focus cross-platform projects.
|
|
84
86
|
export const AREA_PLATFORM = {
|
|
85
87
|
gradle: 'android',
|