[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-ionic-cordova-plugin-migrator":3,"mdc--qn9q9m-key":40,"related-repo-ionic-cordova-plugin-migrator":4187,"related-org-ionic-cordova-plugin-migrator":4225},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":30,"repoUrl":31,"updatedAt":32,"license":33,"forks":34,"topics":35,"repo":36,"sourceUrl":38,"mdContent":39},"cordova-plugin-migrator","migrate Cordova projects to Capacitor","End-to-end Cordova-to-Capacitor migration orchestrator. Analyzes the Cordova plugin (plugin.xml, native iOS\u002FAndroid source, JS bridge, hooks, third-party dependencies), produces a structured migration plan as YAML conforming to capacitor-plugin-generator's input contract, invokes the generator skill in structured mode at a user checkpoint, then consolidates intermediate notes into a single MIGRATION.md. Use when the user says \"migrate this cordova plugin\", \"convert cordova to capacitor\", \"assess migration feasibility\", \"what blocks this migration\", \"port this cordova plugin to capacitor\", or \"estimate the effort to migrate\". Do not use for generating new Capacitor plugins from scratch (use capacitor-plugin-generator instead), debugging runtime issues in an already-migrated plugin, or migrating an entire Cordova application; scope is plugin-level only.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"ionic","Ionic","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fionic.png","ionic-team",[13,17,20,23,26,29],{"name":14,"slug":15,"type":16},"Android","android","tag",{"name":18,"slug":19,"type":16},"iOS","ios",{"name":21,"slug":22,"type":16},"Mobile","mobile",{"name":24,"slug":25,"type":16},"Capacitor","capacitor",{"name":27,"slug":28,"type":16},"Migration","migration",{"name":9,"slug":8,"type":16},14,"https:\u002F\u002Fgithub.com\u002Fionic-team\u002Fcapacitor-skills","2026-07-12T07:37:43.055071",null,1,[],{"repoUrl":31,"stars":30,"forks":34,"topics":37,"description":33},[],"https:\u002F\u002Fgithub.com\u002Fionic-team\u002Fcapacitor-skills\u002Ftree\u002FHEAD\u002Fskills\u002Fcordova-plugin-migrator","---\nname: cordova-plugin-migrator\ndescription: >-\n  End-to-end Cordova-to-Capacitor migration orchestrator. Analyzes the\n  Cordova plugin (plugin.xml, native iOS\u002FAndroid source, JS bridge,\n  hooks, third-party dependencies), produces a structured migration plan\n  as YAML conforming to capacitor-plugin-generator's input contract,\n  invokes the generator skill in structured mode at a user checkpoint,\n  then consolidates intermediate notes into a single MIGRATION.md. Use\n  when the user says \"migrate this cordova plugin\", \"convert cordova to\n  capacitor\", \"assess migration feasibility\", \"what blocks this\n  migration\", \"port this cordova plugin to capacitor\", or \"estimate the\n  effort to migrate\". Do not use for generating new Capacitor plugins\n  from scratch (use capacitor-plugin-generator instead), debugging\n  runtime issues in an already-migrated plugin, or migrating an entire\n  Cordova application; scope is plugin-level only.\nmetadata:\n  author: ionic\n  source: https:\u002F\u002Fgithub.com\u002Fionic-team\u002Fcapacitor-skills\n---\n\n# Cordova Plugin Migrator\n\nEnd-to-end orchestrator that takes a Cordova plugin source tree and\nproduces a candidate Capacitor plugin plus a consolidated `MIGRATION.md`,\nvia a single skill invocation. Internally it analyzes the Cordova plugin,\nemits a structured YAML plan conforming to\n`capacitor-plugin-generator\u002Freferences\u002Finput-contract.md`, hits a user\ncheckpoint, then invokes the `capacitor-plugin-generator` skill in\nstructured mode with that plan. This skill never re-implements what the\ngenerator already does; the generator owns scaffolding and native code\nemission.\n\n## When to Use This Skill\n\n✅ **Use this skill when:**\n\n- Migrating an existing Cordova plugin to Capacitor.\n- Assessing migration complexity, effort, and blockers before committing.\n- Producing the structured handoff YAML for `capacitor-plugin-generator`.\n- Comparing the official Cordova API to an existing or planned Capacitor API.\n- Auditing a Cordova plugin's hooks, native dependencies, or `\u003Cconfig-file>`\n  modifications for portability.\n\n❌ **Do NOT use this skill for:**\n\n- Generating a Capacitor plugin scaffold or implementation, pass the plan to\n  `capacitor-plugin-generator`.\n- Designing a brand-new plugin without prior Cordova source.\n- Migrating entire Cordova apps. Scope is plugin-level only.\n- Debugging runtime issues in an already-migrated plugin.\n- Publishing or releasing the resulting Capacitor plugin.\n\n## Prerequisites\n\n| Requirement | Use |\n| --- | --- |\n| Cordova plugin source (local clone or accessible repo) | Read `plugin.xml`, native source, and JS bridge. |\n| Node.js LTS and npm | Inspect dependencies, run scripts referenced by hooks. |\n| `capacitor-plugin-generator` skill | Receives the YAML plan this skill produces. |\n| `capacitor-plugin-generator\u002Freferences\u002Finput-contract.md` | Authoritative shape for the handoff YAML. |\n| Read access to the official Capacitor equivalent (if any) | Reuse wire-format names and types when porting a plugin that already exists in Capacitor. |\n| Xcode and Android Studio (optional) | Confirm SDK availability for detected native dependencies. |\n\n## Agent Behavior\n\n- Run as an orchestrator. Phases 1–10 analyze the Cordova source and\n  produce a YAML plan; Phase 11 invokes `capacitor-plugin-generator` via\n  the Skill tool, passing the plan in structured mode; Phase 12\n  consolidates documentation. Do not emit native Capacitor code from\n  this skill. The generator owns that.\n- Read `capacitor-plugin-generator\u002Freferences\u002Finput-contract.md` before\n  producing YAML. The generator's contract is authoritative; do not invent\n  fields or rename existing ones.\n- Resolve the plugin's identity from `plugin.xml` first: id, name, version,\n  declared platforms, declared frameworks, hooks, and config-file targets.\n- Inspect every native dependency declaration before asserting platform\n  support. Mirror what `plugin.xml` actually says, not what the README claims.\n- Classify each `\u003Chook>` into Tier 1 (Capacitor hooks), Tier 2 (npm\n  scripts\u002Fmanual steps), or Tier 3 (blocker) using the rules in\n  `references\u002Fhooks-migration.md`. A single Tier 3 hook is enough to block\n  generator handoff.\n- When an official Capacitor equivalent exists (`@capacitor\u002F\u003Cname>` or a\n  Capawesome\u002Fcommunity port), read its `definitions.ts` and native source.\n  Reuse its wire-format strings, enum values, method names, and event names\n  verbatim. Do not invent parallel APIs that \"look similar.\"\n- Detect hybrid plugins. If `package.json` already declares `scripts.capacitor:*`\n  hooks, the plugin is partially Capacitor-aware. Record the existing hooks\n  as Tier 1 \"already converted\" and ask the user whether to reuse, rewrite,\n  or merge them. Do not silently drop them.\n- A JS method whose Cordova-side argument is a stringified JSON blob\n  (`JSON.parse` \u002F `Gson.fromJson` \u002F `JSONObject(args.getString(0))` in the\n  native handler) must be mapped to a strongly-typed TypeScript interface in\n  `api.types`, not a `string` parameter. Capture the interface shape from\n  the native parsing site.\n- When the Cordova native source uses runtime permission APIs\n  (`cordova.requestPermission`, `requestPermissions(...)`,\n  `AVCaptureDevice.requestAccess`, `PHPhotoLibrary.requestAuthorization`,\n  `CLLocationManager` delegates, `CNContactStore.requestAccess`, etc.), add\n  `checkPermissions()` and `requestPermissions()` methods to the YAML\n  **even if the Cordova JS surface did not expose them**. Capacitor's\n  convention is explicit permission methods, and the official equivalent\n  (if any) almost always exposes them.\n- When the Cordova native source extracts metadata in helper classes\n  (`ExifHelper`, `MimeTypeHelper`, `ImageMetadata`, etc.) and includes it\n  in the response payload, capture those fields in the corresponding\n  `api.types` interface, even if the Cordova JS docs did not document\n  them. Read the native code, not the README.\n- When mirroring an official Capacitor equivalent, sanity-check the\n  official's native LOC against the Cordova source's native LOC. If the\n  official is more than 3× larger, add a `migration.notes` entry warning\n  the reviewer that a literal port will leave behavior the official\n  handles (e.g., iOS `CHHapticEngine` for duration-accurate vibration,\n  Android `VibrationEffect` patterns for impact \u002F notification) on the\n  floor. The generator's SDK-adapter rule may or may not catch this.\n- Distinguish three downstream destinations when emitting setup notes:\n  1. **Plugin's own packaging.** Gradle `implementation '...'` lines,\n     CocoaPods `s.dependency '...'` lines, custom Maven repo URLs,\n     `s.weak_framework`, `s.vendored_frameworks`, AndroidManifest\n     `\u003Cuses-permission>` \u002F `\u003Cmeta-data>` \u002F `\u003Cqueries>` entries, and\n     `@CapacitorPlugin(permissions = [...])` declarations all belong\n     in the plugin's own `android\u002Fbuild.gradle`, `.podspec`,\n     `android\u002Fsrc\u002Fmain\u002FAndroidManifest.xml`, or annotations. Gradle's\n     manifest merger and CocoaPods transitively propagate these to\n     consumers, so no host-app step and no `MIGRATION.md` entry is\n     required.\n  2. **Host-app build configuration.** Items that cannot live in the\n     plugin package and must be applied to the consuming app: Info.plist\n     privacy strings (`NSCameraUsageDescription`,\n     `NSLocationWhenInUseUsageDescription`, etc.), iOS capabilities and\n     entitlements (Apple Pay merchant ID, `aps-environment`,\n     `com.apple.security.application-groups`), and any other manifest\n     mutation that must live on the host app rather than the plugin.\n     Record under `migration.notes` and document in `MIGRATION.md` with\n     copy-paste-ready snippets per platform.\n  3. **Consumer runtime config \u002F code.** Apple Developer-side credential\n     provisioning, host-app-supplied JSON config values (merchant\n     numbers, API keys), and consumer JS call-site migration (callback\n     → Promise, positional → named). No tool can automate these because\n     the inputs are the consumer's own data.\n\n  Record each `plugin.xml` directive under one of those three buckets\n  in `migration.notes`. Never write a `MIGRATION.md` step that asks\n  consumers to add `implementation '...'` for a dep the plugin should\n  bundle. See `references\u002Fdependency-migration.md` \"Ownership Model\"\n  for the dep-specific table.\n\n- When the Cordova plugin used `\u003Cpreference name=\"VAR\" default=\"...\">`\n  install-time placeholders inside `\u003Cconfig-file target=\"*-Info.plist\">`\n  entries (Apple Pay merchant config, OAuth client IDs, analytics keys,\n  etc.), detect it and recommend the **runtime config JSON file**\n  pattern in `migration.warnings`: a `PluginConfig.json` consumed by a\n  hybrid `capacitor:sync:after` script that copies the file into native\n  projects at build time. The Cordova plugin may already ship this\n  script (look for it in `hooks\u002Fcapacitor*.js`); if so, reuse it.\n  Otherwise propose a one-screen template. This pattern keeps consumer\n  values out of static plist \u002F manifest entries entirely.\n- Detect SPM markers in `plugin.xml`: `\u003Cplatform name=\"ios\" package=\"swift\">`\n  and `\u003Cpod ... nospm=\"true\">` indicate the Cordova plugin already ships a\n  sibling `Package.swift`. When present: (a) read that `Package.swift` and\n  lift its dependencies into the YAML's `dependencies.ios.spm`, (b) move\n  any pod **without** `nospm=\"true\"` to `dependencies.ios.cocoapods`,\n  (c) add a `migration.notes` entry that the generated Capacitor plugin\n  must ship both `Package.swift` and `.podspec` (Capacitor 8 supports\n  both, and SPM is the default for new plugins). See\n  `references\u002Fdependency-migration.md` \"Swift Package Manager (SPM)\" for\n  the schema.\n- Default output mode is Mode B (side-by-side directory). Switch to Mode A\n  (in-place with `.cordova-archive\u002F`) only when the user explicitly asks and\n  the source is in a writable working copy.\n- Stop and request user input when blockers, Tier 3 hooks, unresolvable\n  proprietary SDKs, or missing source files would force you to guess. Do not\n  emit a YAML plan that hides the gap.\n- Distinguish between resolvable warnings (documented manual steps) and\n  blockers (cannot be auto-migrated). Both go in the plan; only blockers stop\n  handoff.\n- A vendored binary checked into the Cordova plugin's tree (e.g.,\n  `src\u002Fios\u002Fframeworks\u002FFoo.xcframework`) is **not** a blocker on its own. Carry\n  the binary forward and record its path under\n  `migration.source_files.ios` (or `.android`). Treat as blocker only when\n  the binary requires runtime credentials the user does not have or fails\n  AndroidX \u002F 64-bit \u002F simulator requirements.\n- Report what was actually inspected. Cite file paths and line numbers when\n  flagging blockers or unsupported patterns.\n- Compare iOS and Android findings against each other before declaring\n  Phase 9. If one platform exposes a method the other does not, surface the\n  mismatch in `migration.warnings` so the generator can pick a strategy\n  (mirror both, expose conditionally, or drop). Do not silently emit a\n  contract that only one platform can fulfil.\n- Default response shape is **architecture and plan**, not code. Do not\n  include full before\u002Fafter code blocks unless the user explicitly asks for\n  \"show me the code\" or \"deep dive\". Per-method one-line mappings in\n  `migration.cordova_to_capacitor_map` are not \"code\" in this sense, they\n  are part of the plan.\n- Quote every value in `migration.cordova_to_capacitor_map` and any other\n  YAML string that contains JS syntax (`(`, `)`, `{`, `}`, `:`, `[`, `]`).\n  Unquoted JS expressions like `Foo.bar({ x: 1 })` are unparseable YAML and\n  the generator will reject the plan at load time.\n- Invoke the generator only after the Phase 10 user checkpoint\n  approves. If the user rejects, halts, or has unanswered blockers,\n  stop. Never invoke the generator with a YAML that has non-empty\n  `migration.blockers` or non-empty `migration.hooks.tier_3`.\n- When `odc_target: true`, Phase 11 splits into two sequential sub-phases\n  (11a and 11b). Phase 11a invokes `build-actions-generator`; Phase 11b\n  invokes `capacitor-plugin-generator`. See `references\u002Fusing-plugin-generator.md`\n  \"ODC Path\" for the full sequence. Build actions are written to the Capacitor\n  plugin folder. Hooks and migration notes that are fully covered by build\n  actions must be excluded from the YAML passed to the generator (Phase 11b),\n  to avoid the generator emitting redundant Capacitor hook scripts for\n  config-level work already handled by build actions.\n\n## Procedures\n\n### Phase 1: Determine the Task and Output Mode\n\nConfirm the user has a Cordova plugin to migrate. **If the user wants a\nbrand-new Capacitor plugin from scratch with no Cordova source to\nconvert**, stop here and redirect to `capacitor-plugin-generator`\ndirectly, this skill has nothing to add.\n\nOtherwise, pick the output mode:\n\n- **Mode B (default, side-by-side)**, generator scaffolds a new\n  Capacitor plugin into a sibling directory of the Cordova repo. The\n  Cordova repo is never touched.\n- **Mode A (opt-in, in-place)**, generator scaffolds into a temp\n  directory. After Phase 11 succeeds, Phase 12 relocates the generator's\n  output into the Cordova repo root and moves the original Cordova\n  source under `.cordova-archive\u002F`. Preserves the original repo's npm\n  package name and git history. Requires explicit user opt-in and a\n  clean writable git working copy.\n\nSee `references\u002Foutput-modes.md` for layouts, pre-flight checks, and\nthe exact relocation sequence.\n\n**ODC confirmation:** Check whether the user mentioned ODC or OutSystems\nDeveloper Cloud anywhere in the request. If yes, set `odc_target: true` and\nproceed. If not, ask: *\"Will this Capacitor plugin be consumed by an ODC\n(OutSystems Developer Cloud) app? If yes, build actions will be generated\nalongside the Capacitor plugin to handle native configuration in MABS.\"*\nRecord the answer as `odc_target: true\u002Ffalse` for use in Phase 11.\n\n### Phase 2: Read `plugin.xml`\n\nA typical Cordova plugin layout:\n\n```\nmy-plugin\u002F\n├── plugin.xml           # Plugin manifest and configuration\n├── package.json         # NPM metadata (and any capacitor:* scripts)\n├── www\u002F                 # JavaScript bridge\n├── src\u002F\n│   ├── ios\u002F             # CDVPlugin subclasses (.h\u002F.m\u002F.swift)\n│   └── android\u002F         # CordovaPlugin subclasses (.java\u002F.kt)\n└── hooks\u002F               # Optional lifecycle scripts\n```\n\nOpen `plugin.xml`. Extract: plugin id, name, version, declared platforms\n(`\u003Cplatform name=\"...\">`), `\u003Csource-file>`\u002F`\u003Cheader-file>` mappings,\n`\u003Cframework>` entries, `\u003Cpodspec>` blocks, `\u003Cconfig-file>` targets,\n`\u003Cedit-config>` targets, `\u003Chook>` declarations, `\u003Cdependency>` entries,\n`\u003Cpreference>` tags, and `\u003Cjs-module>` exposure (`clobbers` \u002F `merges` \u002F\n`runs`). Record file paths and line numbers for every blocker candidate.\n\n### Phase 3: Analyze Native Dependencies\n\nApply `references\u002Fdependency-migration.md`. For each `\u003Cframework>` and\n`\u003Cpodspec>` pod, decide: direct migration, version update, alternative\nlibrary, or blocker. For each Android Gradle coord, check AndroidX vs Support\nLibrary and Capacitor's minimum compile SDK. Record manual installation steps\nrequired after migration.\n\n### Phase 4: Analyze Hooks\n\nApply the three-tier rule in `references\u002Fhooks-migration.md`:\n\n- **Tier 1**, convertible to a Capacitor plugin npm hook\n  (`capacitor:{sync,copy,update}:{before,after}`,\n  `capacitor:{android,ios}:add:{before,after}`).\n- **Tier 2**, convertible to an npm lifecycle script (`postinstall`,\n  `preuninstall`) or a documented manual step.\n- **Tier 3**, interactive prompts, plugin.xml\u002Fconfig.xml mutation, Cordova\n  CLI internals, or anything else with no Capacitor equivalent.\n\nRead each referenced script. Do not classify on filename alone.\n\n### Phase 5: Analyze the JavaScript Bridge\n\nApply `references\u002Fapi-mappings.md`. From `www\u002F*.js`, list every public method,\nits positional argument shape, whether it uses success\u002Ferror callbacks or\nreturns a promise, and whether `exec()` is paired with a `cordova.exec()`\naction name. Map each method to a Capacitor `methodName(options): Promise\u003CR>`\nsignature.\n\n### Phase 6: Analyze iOS Implementation\n\nApply `references\u002Fapi-mappings.md`. From `src\u002Fios\u002F*.{h,m,swift}`, identify the\n`CDVPlugin` subclass, each method matching a JS action, argument extraction\nfrom `command.arguments`, response construction (`CDVPluginResult`), permission\nflows, and any system frameworks or SDK adapters used. Note where Objective-C\nmust be modernized to Swift.\n\n### Phase 7: Analyze Android Implementation\n\nApply `references\u002Fapi-mappings.md`. From `src\u002Fandroid\u002F**\u002F*.{java,kt}`,\nidentify the `CordovaPlugin` subclass, the `execute()` router, action\nstrings, argument extraction (`args.getString(i)`), response paths\n(`CallbackContext.success\u002Ferror`), permission flows, and any Activity Result\npatterns. Note where Java must be modernized to Kotlin.\n\n### Phase 8: Assess Complexity\n\nApply `references\u002Fcomplexity-assessment.md`. Score the plugin on method count,\nLOC, dependency footprint, hook tier mix, language modernization, blocker\ncount, and Capacitor-equivalent reuse. Output one of: `simple`, `moderate`,\n`complex`, `blocked`. `blocked` means the user must resolve issues before\ngenerator handoff.\n\n### Phase 9: Produce the Migration YAML\n\nApply `references\u002Fusing-plugin-generator.md`. Build the YAML against the\ngenerator's `references\u002Finput-contract.md`, base block (`plugin`,\n`platforms`, `api`, `permissions`, `dependencies`) plus the optional\n`migration:` block (`source`, `complexity`, `output_mode`, `blockers`,\n`warnings`, `language_modernization`, `source_files`, `hooks`,\n`cordova_to_capacitor_map`). Pin wire-format strings to the official\nCapacitor equivalent when one exists.\n\n### Phase 10: User Checkpoint\n\nPresent a short human summary alongside the YAML: complexity, blockers,\nwarnings, manual setup, recommended output mode, and any Capacitor\nequivalent being mirrored. Stop and wait for confirmation if blockers or\nTier 3 hooks are non-empty.\n\n### Phase 11: Invoke Downstream Skills\n\nThe downstream invocation path depends on whether ODC was confirmed in Phase 1.\n\n**Non-ODC path:** Apply `references\u002Fusing-plugin-generator.md`. Invoke\n`capacitor-plugin-generator` via the Skill tool in structured mode with the\nPhase 9 YAML. The generator runs its own playbook; this skill does not\nre-inspect Cordova source. For **Complex** plugins use **incremental mode**\n(one platform at a time with user checkpoints). If the generator rejects the\nYAML, return to Phase 9 and fix it — never hand-edit generator output.\n\n**ODC path:** Follow the two-sub-phase sequence in\n`references\u002Fusing-plugin-generator.md` \"ODC Path\":\n\n- **Phase 11a** — Invoke `build-actions-generator` with the Phase 9 YAML\n  and the Cordova plugin path; wait for `build-actions\u002F` output. Note which\n  hooks\u002Felements it covered.\n- **Phase 11b** — Remove build-action-covered items from\n  `migration.hooks.tier_1` (or mark `status: handled_by_build_actions`); add\n  a `migration.notes` entry documenting this. Then invoke\n  `capacitor-plugin-generator` with the annotated YAML (standard or incremental\n  per complexity).\n\n### Phase 12: Post-Migration Cleanup\n\nApply `references\u002Fpost-migration-cleanup.md`. After the generator produces a\nworking scaffold, consolidate intermediate notes into a single `MIGRATION.md`\nat the plugin root, archive or remove the original Cordova source per the\nchosen output mode, and update the README with the consumer-facing breaking\nchanges (callbacks → promises, positional → named arguments, manual native\nsetup).\n\nCross-check that every `migration.notes` and `migration.warnings`\nentry is bucketed (plugin packaging \u002F host-app build configuration \u002F\nconsumer runtime config) per the Agent Behavior rule. The\n`MIGRATION.md` should list only items that fall in buckets 2 or 3.\nPlugin-packaging items are transparent to consumers and do not belong\nin the migration trail.\n\n## Best Practices\n\n### DO\n\n- ✅ Read `plugin.xml` first and ground every claim in actual XML, source\n  paths, or hook script content. Cite line numbers for blockers.\n- ✅ Treat the generator's input contract as authoritative. Build the YAML\n  against `capacitor-plugin-generator\u002Freferences\u002Finput-contract.md`.\n- ✅ Reuse wire-format strings from an official Capacitor equivalent when one\n  exists. Mirror enum casing, event names, and method names exactly.\n- ✅ Classify hooks by reading the referenced script, not by filename.\n- ✅ Default to Mode B (side-by-side). Move to Mode A only on explicit user\n  opt-in with a writable working copy.\n- ✅ Stop at the Phase 10 checkpoint if blockers or Tier 3 hooks exist.\n- ✅ Capture both blockers and warnings; only blockers stop handoff.\n- ✅ Note manual native setup steps consumers will need after migration\n  (Info.plist keys, AndroidManifest entries, Podfile \u002F Gradle additions).\n\n### DON'T\n\n- ❌ Emit native Capacitor code (Swift, Kotlin, Java, TypeScript) from\n  this skill. The generator owns code emission.\n- ❌ Invent YAML fields or rename ones the generator already defines.\n- ❌ Re-derive wire-format strings from human-friendly names when an\n  official Capacitor equivalent exists. Read its `definitions.ts`.\n- ❌ Classify a hook as Tier 1\u002F2 without opening the referenced script.\n- ❌ Emit a YAML plan that lists `complexity: simple` while hiding a\n  proprietary AAR or interactive setup hook.\n- ❌ Add Capacitor-version-specific guidance here, the generator skill owns\n  generator-side rules (name parity, Java filename, `notifyListeners`\n  visibility, etc.). Reference, don't duplicate.\n- ❌ Invoke the generator silently. Phase 10 is a mandatory user\n  checkpoint; do not skip it.\n- ❌ Invoke the generator with blockers or Tier 3 hooks unresolved.\n- ❌ Commit, push, or publish generator output from this skill.\n\n## Error Handling\n\n| Symptom | Fix |\n| --- | --- |\n| `plugin.xml` missing or malformed | Stop. Ask for the canonical plugin source. Do not infer a contract from README marketing copy. |\n| Source files referenced by `plugin.xml` are not present on disk | Stop. Report missing files by path. The plan is incomplete without them; do not proceed to Phase 9. |\n| Hooks reference scripts that cannot be opened or are obfuscated | Classify as Tier 3 and add to `migration.blockers` with the script path. Do not guess based on the hook type. |\n| Plugin declares `\u003Cframework>` for a private\u002Fproprietary AAR or `.framework` requiring runtime credentials the user does not have | Record as a blocker. Note vendor contact requirement. Do not silently swap for a public alternative. |\n| Plugin vendors a binary in-tree (e.g., `src\u002Fios\u002Fframeworks\u002FFoo.xcframework`, `src\u002Fandroid\u002Flibs\u002FFoo.aar`) but it is publicly distributed | Not a blocker. Carry the binary forward and record its path under `migration.source_files.{ios,android}`. The generator copies it into the Capacitor plugin's `ios\u002F` or `android\u002Flibs\u002F` directory. |\n| Plugin pulls Android deps from a custom Maven repository (Azure DevOps, JFrog, etc.) | Record the URL under `migration.dependencies.android.maven_repos`. Warning, not blocker, when the URL is reachable without auth. Blocker when auth is required and credentials are not provided. |\n| Plugin uses Support Library (`android.support.*`) coordinates | Record as a blocker unless Jetifier acceptance is confirmed by the user. Capacitor expects AndroidX. |\n| Cordova plugin has an official Capacitor equivalent (`@capacitor\u002F\u003Cname>`) | Read the equivalent's `definitions.ts` and native source. Pin method names, enum values, event names, and error codes in the YAML. Add the equivalent's package as `migration.notes` for the reviewer. |\n| Plugin declares both `\u003Chook>` entries and `package.json` `scripts.capacitor:*` entries (hybrid plugin) | The Capacitor scripts already exist. Record them as Tier 1 \"already converted\" hooks. Ask the user whether to reuse, rewrite, or merge them with any newly migrated Cordova hooks. |\n| Plugin uses `\u003Cconfig-file>` to mutate `AndroidManifest.xml` with `\u003Cuses-permission>`, `\u003Cmeta-data>`, `\u003Cqueries>`, or `\u003Cprovider>` | **Goes in the plugin's own `android\u002Fsrc\u002Fmain\u002FAndroidManifest.xml`**, Gradle manifest merger merges into the host app automatically. No host-app step. Record under `migration.notes` for the generator to emit. |\n| Plugin uses `\u003Cconfig-file>` to mutate `Info.plist` with an Apple-required privacy string (`NSCameraUsageDescription`, `NSLocationWhenInUseUsageDescription`, `NSMicrophoneUsageDescription`, etc.) | **Host-app Info.plist**, Apple App Store requires these on the host app's plist, not the plugin's. Record under `migration.notes` and document a copy-paste snippet in `MIGRATION.md`. |\n| Plugin uses `\u003Cconfig-file>` to mutate `Info.plist` with consumer-specific values (Apple Pay merchant ID, OAuth client ID, analytics key) via `$VAR` install-time placeholders | **Runtime config JSON file** pattern is strongly preferred: a `\u003CPlugin>Configuration.json` consumed by a hybrid `capacitor:sync:after` script. Reuse an existing script from the Cordova plugin if present, else propose a one-screen template. Keeps consumer-specific values out of the plist entirely. |\n| Plugin uses `\u003Cconfig-file>` to mutate entitlements plists (`*-Debug.plist`, `*-Release.plist`, `*-Entitlements.plist`) for capabilities like `com.apple.developer.in-app-payments`, `aps-environment`, `com.apple.security.application-groups` | **Host-app capability + entitlement.** Record under `migration.notes`; document the exact Xcode capability the consumer must enable (Apple Pay, Push Notifications, App Groups, etc.) and the entitlement value in `MIGRATION.md`. |\n| Plugin declares `\u003Cframework>` with `weak=\"true\"` for iOS | **Plugin's own podspec.** Record in `dependencies.ios.system_frameworks` and add a `migration.notes` line so the generator emits `s.weak_framework` instead of `s.framework`. No host-app step. |\n| Plugin uses `\u003Cedit-config>` with `mode=\"merge\"` to add an `android:requestLegacyExternalStorage` or similar attribute to the host `\u003Capplication>` element | **Host-app AndroidManifest** if the attribute applies to the host app; otherwise plugin's own AndroidManifest. Record in `migration.notes` with the exact attribute and parent so `MIGRATION.md` can include a copy-paste snippet. |\n| Plugin uses `\u003Cjs-module runs=\"true\">` | Add to `migration.warnings`. Recommend an explicit `initialize()` method or constructor-side init in the web layer. |\n| Plugin has multiple `\u003Cjs-module>` entries with multiple `\u003Cclobbers>` targets (e.g., constants module + main module) | Collapse into a single `registerPlugin()` registration. Export constants from `definitions.ts` next to the plugin interface. Capacitor has no analog to multi-clobber. |\n| Plugin includes Android resource files via `\u003Csource-file target-dir=\"res\u002F...\">` | Record under `migration.source_files.android` with the destination `res\u002F` subpath. The generator copies them into `android\u002Fsrc\u002Fmain\u002Fres\u002F\u003Csubpath>\u002F`. Common for `FileProvider` paths and themes. |\n| Plugin uses `\u003Cpreference name=\"...\" default=\"...\">` with install-time variable substitution (`${VAR}` in plugin.xml) referenced inside `\u003Cconfig-file target=\"*-Info.plist\">` or `AndroidManifest.xml` | Prefer the **runtime config JSON file** pattern (consumer drops their values into a `\u003CPlugin>Configuration.json` consumed by a hybrid `capacitor:sync:after` script). Reuse an existing script from the Cordova plugin if present. Fallback: `capacitor.config.json` runtime config under `plugins.\u003CPluginJSName>`. |\n| Plugin uses `\u003Cpreference name=\"ANDROIDX_CORE_VERSION\" default=\"1.18.0\">` (or similar build-time-only version pins) referenced inside the plugin's own `build.gradle` | **Plugin's own build.gradle**, pin the version literally in the generated Gradle file. No host-app step, no runtime config. Consumer never sees this. |\n| Plugin's native handler parses a stringified JSON blob (`Gson.fromJson`, `JSONObject(args.getString(0))`) | Map the parsed shape to a strongly-typed `api.types` interface, never `string`. Capture the schema from the native parsing site (Kotlin data class or Swift struct). |\n| One JS method dispatches to multiple `cordova.exec()` action names based on `typeof param` (e.g., `vibrate(num)` vs `vibrate([...])`) | Split into multiple typed Capacitor methods, `vibrate({ duration })`, `vibrateWithPattern({ pattern, repeat })`, `cancelVibration()`. Record the split in `migration.cordova_to_capacitor_map` and add to `migration.warnings` as a consumer-facing breaking change. |\n| Generator rejects YAML with \"bad indentation\" or \"mapping entry\" parse error | A `cordova_to_capacitor_map` entry contains unquoted JS syntax (`(`, `{`, `:`, etc.). Quote every `cordova:` and `capacitor:` value as a YAML string. The plan must be re-emitted; the generator cannot load it as-is. |\n| Cordova native source requests runtime permissions but the Cordova JS surface has no permission methods | Add `checkPermissions()` (`Promise\u003CPermissionStatus>`) and `requestPermissions(options?)` (`Promise\u003CPermissionStatus>`) to `api.methods`, and a `PermissionStatus` interface to `api.types`. Without these the migrated plugin will violate Capacitor convention and consumers will expect them. |\n| Cordova native source has a helper class for metadata extraction (`ExifHelper`, `MimeTypeHelper`, etc.) but the Cordova JS docs don't list the resulting fields | Read the native response-construction site. Add the metadata fields (typically `exif?: any`, `mimeType?`, `size?`) to the result type. The Cordova JS docs frequently understate what the native side actually returns. |\n| Official Capacitor equivalent's native source is more than 3× the LOC of the Cordova source | Add a `migration.notes` entry warning the reviewer that a literal port will leave platform-specific behavior unimplemented (e.g., iOS `CHHapticEngine` over `AudioServicesPlaySystemSound`, Android pattern-based haptics over single-shot vibration). Recommend reviewing whether to retarget consumers to the official package. |\n| Cordova plugin.xml has `\u003Cplatform name=\"ios\" package=\"swift\">` or any `\u003Cpod ... nospm=\"true\">` | Plugin already ships SPM support alongside CocoaPods. Lift its `Package.swift` dependencies into `dependencies.ios.spm`; lift only pods without `nospm=\"true\"` into `dependencies.ios.cocoapods`. Capacitor port must ship both `Package.swift` and `.podspec`. |\n| Plugin declares `\u003Cdependency>` on another Cordova plugin | Resolve the dependency target separately. If it lacks a Capacitor equivalent or migration plan, treat as blocker for the current plugin. |\n| Plugin's iOS source is Objective-C only | Record `migration.language_modernization.ios: { from: objective_c, to: swift }`. Note bridging headers consumers may still need. |\n| Plugin's Android source is Java only | Record `migration.language_modernization.android: { from: java, to: kotlin }`. The generator will still produce Java if the user asks, but Kotlin is the default recommendation. |\n| YAML rejected by the generator | Re-read `capacitor-plugin-generator\u002Freferences\u002Finput-contract.md`. Fix the YAML in this skill, not in the generator. Do not work around the contract. |\n| Generator flags missing wire-format strings | Re-read the official Capacitor equivalent's `definitions.ts`. Update `api.types` values verbatim. Do not \"translate\" from the human-friendly names. |\n| User requests Mode A but the working copy is not under version control or is read-only | Refuse Mode A. Recommend Mode B. Recovery from a botched in-place move without VCS is manual. |\n| Plugin advertises features the source does not implement | Trust the source. Record the advertised-but-unimplemented features under `migration.warnings`. Do not fabricate API methods to match documentation. |\n| Hook classified as Tier 1 by filename but actually interactive | Read the script source, not just the `\u003Chook>` `name` attribute. Anything that prompts via stdin, opens a TTY, or shells to `read` \u002F `prompt` is Tier 3. |\n| Dep marked \"direct migration\" but the pod \u002F Gradle artifact is abandoned | Cross-check the latest release date and Swift \u002F AndroidX compatibility before marking as direct. Anything not updated in 3+ years moves to \"replace\" or \"blocker\". |\n| Complexity assessed \"Simple\" but plugin has 15+ public API methods | Always count public API methods. Any plugin with more than 10 public methods is at least Moderate, regardless of other signals. |\n| Blocker missed during analysis | Always scan `plugin.xml` for `\u003Cconfig-file>`, `\u003Cedit-config>`, `\u003Cjs-module runs=\"true\">`, `\u003Chook>`, and `\u003Cdependency>`, these are the non-negotiable blocker candidates. Re-scan before Phase 9 if anything in the YAML looks too tidy. |\n| Generator re-reads Cordova source during Phase 11 | The YAML plan is incomplete. Re-validate against `capacitor-plugin-generator\u002Freferences\u002Finput-contract.md`; include JS API signatures, native method mappings, permissions, dependencies, and blockers inline so the generator never has to look at the Cordova tree. |\n| User halts at checkpoint due to a blocker they will not accept | Document the blocker in `MIGRATION.md` and stop. Do not invoke the generator. Capture the rejection reason so the next attempt can address it. |\n| Complex plugin overwhelms generator context on a single invocation | Use **incremental mode**: invoke the generator once per platform (web → iOS → Android → final) with user checkpoints between each, not once for the whole plugin. See `references\u002Fusing-plugin-generator.md`. |\n| Mode A relocation conflicts with files in the Cordova repo (top-level name collision) | Halt the chain. Either resolve manually with the user (rename, delete, or move conflicting files), or fall back to Mode B by re-running Phase 11 against a sibling directory. |\n\n## Related Skills\n\n- `capacitor-plugin-generator` *(required downstream dependency)*:\n  Phase 11 invokes this skill via the Skill tool in structured mode\n  with the YAML plan produced in Phase 9. The generator's\n  `references\u002Finput-contract.md` is the authoritative shape for handoff.\n  This skill conforms and cites it but does not duplicate any\n  generator-side rules.\n- `build-actions-generator` *(optional downstream dependency, ODC path only)*:\n  Phase 11a invokes this skill when `odc_target: true`. It generates\n  `buildAction.json` for the Capacitor plugin's `build-actions\u002F` directory,\n  covering config-level native setup (manifest, plist, Gradle deps,\n  entitlements) so the generator does not need to emit Capacitor hook\n  equivalents for those items.\n\n## References\n\n- `references\u002Foutput-modes.md`: Mode A (in-place with `.cordova-archive\u002F`) vs Mode B (side-by-side) directory layouts and `git mv` patterns.\n- `references\u002Funsupported-patterns.md`: `\u003Cconfig-file>`, `\u003Cedit-config>`, `\u003Chook>`, `\u003Cjs-module runs>`, preferences, permissions, and per-pattern blocker thresholds.\n- `references\u002Fdependency-migration.md`: CocoaPods, SPM, system frameworks, Gradle coordinates, AAR\u002FJAR, custom Maven repos, and per-dependency blocker thresholds.\n- `references\u002Fhooks-migration.md`: Three-tier hook classification (Tier 1 Capacitor hooks, Tier 2 npm scripts, Tier 3 blocker) with script analysis workflow.\n- `references\u002Fapi-mappings.md`: JavaScript bridge, iOS (`CDVPlugin` → `CAPPlugin`), Android (`CordovaPlugin` → `Plugin`), and plugin.xml → package.json conversion.\n- `references\u002Fmigration-patterns.md`: Callback → Promise, permission handling, multi-platform configuration, and consistent error handling across platforms.\n- `references\u002Fcomplexity-assessment.md`: Scoring rubric for `simple` \u002F `moderate` \u002F `complex` \u002F `blocked` and the inputs that move a plugin between buckets.\n- `references\u002Fusing-plugin-generator.md`: Building the YAML against `capacitor-plugin-generator\u002Freferences\u002Finput-contract.md`, the `migration:` optional block, and the Phase 11 invocation pattern (standard vs incremental mode).\n- `references\u002Fpost-migration-cleanup.md`: Consolidating intermediate notes into `MIGRATION.md`, the Mode A relocation flow, archiving Cordova source, updating README, and the consumer-facing breaking-change checklist.\n- `references\u002Fexample-analysis.md`: Full worked example end-to-end, plugin.xml read, dependency analysis, hooks classification, YAML output, and generator handoff.\n",{"data":41,"body":43},{"name":4,"description":6,"metadata":42},{"author":8,"source":31},{"type":44,"children":45},"root",[46,54,85,92,103,148,158,192,198,320,326,1218,1224,1231,1250,1255,1285,1298,1331,1342,1347,1359,1480,1486,1512,1518,1529,1592,1597,1603,1647,1653,1695,1701,1751,1757,1805,1811,1938,1944,1949,1955,1960,1998,2015,2083,2089,2108,2133,2139,2145,2201,2207,2277,2283,3890,3896,3960,3966],{"type":47,"tag":48,"props":49,"children":50},"element","h1",{"id":4},[51],{"type":52,"value":53},"text","Cordova Plugin Migrator",{"type":47,"tag":55,"props":56,"children":57},"p",{},[58,60,67,69,75,77,83],{"type":52,"value":59},"End-to-end orchestrator that takes a Cordova plugin source tree and\nproduces a candidate Capacitor plugin plus a consolidated ",{"type":47,"tag":61,"props":62,"children":64},"code",{"className":63},[],[65],{"type":52,"value":66},"MIGRATION.md",{"type":52,"value":68},",\nvia a single skill invocation. Internally it analyzes the Cordova plugin,\nemits a structured YAML plan conforming to\n",{"type":47,"tag":61,"props":70,"children":72},{"className":71},[],[73],{"type":52,"value":74},"capacitor-plugin-generator\u002Freferences\u002Finput-contract.md",{"type":52,"value":76},", hits a user\ncheckpoint, then invokes the ",{"type":47,"tag":61,"props":78,"children":80},{"className":79},[],[81],{"type":52,"value":82},"capacitor-plugin-generator",{"type":52,"value":84}," skill in\nstructured mode with that plan. This skill never re-implements what the\ngenerator already does; the generator owns scaffolding and native code\nemission.",{"type":47,"tag":86,"props":87,"children":89},"h2",{"id":88},"when-to-use-this-skill",[90],{"type":52,"value":91},"When to Use This Skill",{"type":47,"tag":55,"props":93,"children":94},{},[95,97],{"type":52,"value":96},"✅ ",{"type":47,"tag":98,"props":99,"children":100},"strong",{},[101],{"type":52,"value":102},"Use this skill when:",{"type":47,"tag":104,"props":105,"children":106},"ul",{},[107,113,118,130,135],{"type":47,"tag":108,"props":109,"children":110},"li",{},[111],{"type":52,"value":112},"Migrating an existing Cordova plugin to Capacitor.",{"type":47,"tag":108,"props":114,"children":115},{},[116],{"type":52,"value":117},"Assessing migration complexity, effort, and blockers before committing.",{"type":47,"tag":108,"props":119,"children":120},{},[121,123,128],{"type":52,"value":122},"Producing the structured handoff YAML for ",{"type":47,"tag":61,"props":124,"children":126},{"className":125},[],[127],{"type":52,"value":82},{"type":52,"value":129},".",{"type":47,"tag":108,"props":131,"children":132},{},[133],{"type":52,"value":134},"Comparing the official Cordova API to an existing or planned Capacitor API.",{"type":47,"tag":108,"props":136,"children":137},{},[138,140,146],{"type":52,"value":139},"Auditing a Cordova plugin's hooks, native dependencies, or ",{"type":47,"tag":61,"props":141,"children":143},{"className":142},[],[144],{"type":52,"value":145},"\u003Cconfig-file>",{"type":52,"value":147},"\nmodifications for portability.",{"type":47,"tag":55,"props":149,"children":150},{},[151,153],{"type":52,"value":152},"❌ ",{"type":47,"tag":98,"props":154,"children":155},{},[156],{"type":52,"value":157},"Do NOT use this skill for:",{"type":47,"tag":104,"props":159,"children":160},{},[161,172,177,182,187],{"type":47,"tag":108,"props":162,"children":163},{},[164,166,171],{"type":52,"value":165},"Generating a Capacitor plugin scaffold or implementation, pass the plan to\n",{"type":47,"tag":61,"props":167,"children":169},{"className":168},[],[170],{"type":52,"value":82},{"type":52,"value":129},{"type":47,"tag":108,"props":173,"children":174},{},[175],{"type":52,"value":176},"Designing a brand-new plugin without prior Cordova source.",{"type":47,"tag":108,"props":178,"children":179},{},[180],{"type":52,"value":181},"Migrating entire Cordova apps. Scope is plugin-level only.",{"type":47,"tag":108,"props":183,"children":184},{},[185],{"type":52,"value":186},"Debugging runtime issues in an already-migrated plugin.",{"type":47,"tag":108,"props":188,"children":189},{},[190],{"type":52,"value":191},"Publishing or releasing the resulting Capacitor plugin.",{"type":47,"tag":86,"props":193,"children":195},{"id":194},"prerequisites",[196],{"type":52,"value":197},"Prerequisites",{"type":47,"tag":199,"props":200,"children":201},"table",{},[202,221],{"type":47,"tag":203,"props":204,"children":205},"thead",{},[206],{"type":47,"tag":207,"props":208,"children":209},"tr",{},[210,216],{"type":47,"tag":211,"props":212,"children":213},"th",{},[214],{"type":52,"value":215},"Requirement",{"type":47,"tag":211,"props":217,"children":218},{},[219],{"type":52,"value":220},"Use",{"type":47,"tag":222,"props":223,"children":224},"tbody",{},[225,247,260,278,294,307],{"type":47,"tag":207,"props":226,"children":227},{},[228,234],{"type":47,"tag":229,"props":230,"children":231},"td",{},[232],{"type":52,"value":233},"Cordova plugin source (local clone or accessible repo)",{"type":47,"tag":229,"props":235,"children":236},{},[237,239,245],{"type":52,"value":238},"Read ",{"type":47,"tag":61,"props":240,"children":242},{"className":241},[],[243],{"type":52,"value":244},"plugin.xml",{"type":52,"value":246},", native source, and JS bridge.",{"type":47,"tag":207,"props":248,"children":249},{},[250,255],{"type":47,"tag":229,"props":251,"children":252},{},[253],{"type":52,"value":254},"Node.js LTS and npm",{"type":47,"tag":229,"props":256,"children":257},{},[258],{"type":52,"value":259},"Inspect dependencies, run scripts referenced by hooks.",{"type":47,"tag":207,"props":261,"children":262},{},[263,273],{"type":47,"tag":229,"props":264,"children":265},{},[266,271],{"type":47,"tag":61,"props":267,"children":269},{"className":268},[],[270],{"type":52,"value":82},{"type":52,"value":272}," skill",{"type":47,"tag":229,"props":274,"children":275},{},[276],{"type":52,"value":277},"Receives the YAML plan this skill produces.",{"type":47,"tag":207,"props":279,"children":280},{},[281,289],{"type":47,"tag":229,"props":282,"children":283},{},[284],{"type":47,"tag":61,"props":285,"children":287},{"className":286},[],[288],{"type":52,"value":74},{"type":47,"tag":229,"props":290,"children":291},{},[292],{"type":52,"value":293},"Authoritative shape for the handoff YAML.",{"type":47,"tag":207,"props":295,"children":296},{},[297,302],{"type":47,"tag":229,"props":298,"children":299},{},[300],{"type":52,"value":301},"Read access to the official Capacitor equivalent (if any)",{"type":47,"tag":229,"props":303,"children":304},{},[305],{"type":52,"value":306},"Reuse wire-format names and types when porting a plugin that already exists in Capacitor.",{"type":47,"tag":207,"props":308,"children":309},{},[310,315],{"type":47,"tag":229,"props":311,"children":312},{},[313],{"type":52,"value":314},"Xcode and Android Studio (optional)",{"type":47,"tag":229,"props":316,"children":317},{},[318],{"type":52,"value":319},"Confirm SDK availability for detected native dependencies.",{"type":47,"tag":86,"props":321,"children":323},{"id":322},"agent-behavior",[324],{"type":52,"value":325},"Agent Behavior",{"type":47,"tag":104,"props":327,"children":328},{},[329,341,352,364,376,397,418,439,483,557,591,620,835,895,996,1009,1014,1019,1055,1060,1072,1092,1162,1182],{"type":47,"tag":108,"props":330,"children":331},{},[332,334,339],{"type":52,"value":333},"Run as an orchestrator. Phases 1–10 analyze the Cordova source and\nproduce a YAML plan; Phase 11 invokes ",{"type":47,"tag":61,"props":335,"children":337},{"className":336},[],[338],{"type":52,"value":82},{"type":52,"value":340}," via\nthe Skill tool, passing the plan in structured mode; Phase 12\nconsolidates documentation. Do not emit native Capacitor code from\nthis skill. The generator owns that.",{"type":47,"tag":108,"props":342,"children":343},{},[344,345,350],{"type":52,"value":238},{"type":47,"tag":61,"props":346,"children":348},{"className":347},[],[349],{"type":52,"value":74},{"type":52,"value":351}," before\nproducing YAML. The generator's contract is authoritative; do not invent\nfields or rename existing ones.",{"type":47,"tag":108,"props":353,"children":354},{},[355,357,362],{"type":52,"value":356},"Resolve the plugin's identity from ",{"type":47,"tag":61,"props":358,"children":360},{"className":359},[],[361],{"type":52,"value":244},{"type":52,"value":363}," first: id, name, version,\ndeclared platforms, declared frameworks, hooks, and config-file targets.",{"type":47,"tag":108,"props":365,"children":366},{},[367,369,374],{"type":52,"value":368},"Inspect every native dependency declaration before asserting platform\nsupport. Mirror what ",{"type":47,"tag":61,"props":370,"children":372},{"className":371},[],[373],{"type":52,"value":244},{"type":52,"value":375}," actually says, not what the README claims.",{"type":47,"tag":108,"props":377,"children":378},{},[379,381,387,389,395],{"type":52,"value":380},"Classify each ",{"type":47,"tag":61,"props":382,"children":384},{"className":383},[],[385],{"type":52,"value":386},"\u003Chook>",{"type":52,"value":388}," into Tier 1 (Capacitor hooks), Tier 2 (npm\nscripts\u002Fmanual steps), or Tier 3 (blocker) using the rules in\n",{"type":47,"tag":61,"props":390,"children":392},{"className":391},[],[393],{"type":52,"value":394},"references\u002Fhooks-migration.md",{"type":52,"value":396},". A single Tier 3 hook is enough to block\ngenerator handoff.",{"type":47,"tag":108,"props":398,"children":399},{},[400,402,408,410,416],{"type":52,"value":401},"When an official Capacitor equivalent exists (",{"type":47,"tag":61,"props":403,"children":405},{"className":404},[],[406],{"type":52,"value":407},"@capacitor\u002F\u003Cname>",{"type":52,"value":409}," or a\nCapawesome\u002Fcommunity port), read its ",{"type":47,"tag":61,"props":411,"children":413},{"className":412},[],[414],{"type":52,"value":415},"definitions.ts",{"type":52,"value":417}," and native source.\nReuse its wire-format strings, enum values, method names, and event names\nverbatim. Do not invent parallel APIs that \"look similar.\"",{"type":47,"tag":108,"props":419,"children":420},{},[421,423,429,431,437],{"type":52,"value":422},"Detect hybrid plugins. If ",{"type":47,"tag":61,"props":424,"children":426},{"className":425},[],[427],{"type":52,"value":428},"package.json",{"type":52,"value":430}," already declares ",{"type":47,"tag":61,"props":432,"children":434},{"className":433},[],[435],{"type":52,"value":436},"scripts.capacitor:*",{"type":52,"value":438},"\nhooks, the plugin is partially Capacitor-aware. Record the existing hooks\nas Tier 1 \"already converted\" and ask the user whether to reuse, rewrite,\nor merge them. Do not silently drop them.",{"type":47,"tag":108,"props":440,"children":441},{},[442,444,450,452,458,459,465,467,473,475,481],{"type":52,"value":443},"A JS method whose Cordova-side argument is a stringified JSON blob\n(",{"type":47,"tag":61,"props":445,"children":447},{"className":446},[],[448],{"type":52,"value":449},"JSON.parse",{"type":52,"value":451}," \u002F ",{"type":47,"tag":61,"props":453,"children":455},{"className":454},[],[456],{"type":52,"value":457},"Gson.fromJson",{"type":52,"value":451},{"type":47,"tag":61,"props":460,"children":462},{"className":461},[],[463],{"type":52,"value":464},"JSONObject(args.getString(0))",{"type":52,"value":466}," in the\nnative handler) must be mapped to a strongly-typed TypeScript interface in\n",{"type":47,"tag":61,"props":468,"children":470},{"className":469},[],[471],{"type":52,"value":472},"api.types",{"type":52,"value":474},", not a ",{"type":47,"tag":61,"props":476,"children":478},{"className":477},[],[479],{"type":52,"value":480},"string",{"type":52,"value":482}," parameter. Capture the interface shape from\nthe native parsing site.",{"type":47,"tag":108,"props":484,"children":485},{},[486,488,494,496,502,504,510,511,517,518,524,526,532,534,540,542,548,550,555],{"type":52,"value":487},"When the Cordova native source uses runtime permission APIs\n(",{"type":47,"tag":61,"props":489,"children":491},{"className":490},[],[492],{"type":52,"value":493},"cordova.requestPermission",{"type":52,"value":495},", ",{"type":47,"tag":61,"props":497,"children":499},{"className":498},[],[500],{"type":52,"value":501},"requestPermissions(...)",{"type":52,"value":503},",\n",{"type":47,"tag":61,"props":505,"children":507},{"className":506},[],[508],{"type":52,"value":509},"AVCaptureDevice.requestAccess",{"type":52,"value":495},{"type":47,"tag":61,"props":512,"children":514},{"className":513},[],[515],{"type":52,"value":516},"PHPhotoLibrary.requestAuthorization",{"type":52,"value":503},{"type":47,"tag":61,"props":519,"children":521},{"className":520},[],[522],{"type":52,"value":523},"CLLocationManager",{"type":52,"value":525}," delegates, ",{"type":47,"tag":61,"props":527,"children":529},{"className":528},[],[530],{"type":52,"value":531},"CNContactStore.requestAccess",{"type":52,"value":533},", etc.), add\n",{"type":47,"tag":61,"props":535,"children":537},{"className":536},[],[538],{"type":52,"value":539},"checkPermissions()",{"type":52,"value":541}," and ",{"type":47,"tag":61,"props":543,"children":545},{"className":544},[],[546],{"type":52,"value":547},"requestPermissions()",{"type":52,"value":549}," methods to the YAML\n",{"type":47,"tag":98,"props":551,"children":552},{},[553],{"type":52,"value":554},"even if the Cordova JS surface did not expose them",{"type":52,"value":556},". Capacitor's\nconvention is explicit permission methods, and the official equivalent\n(if any) almost always exposes them.",{"type":47,"tag":108,"props":558,"children":559},{},[560,562,568,569,575,576,582,584,589],{"type":52,"value":561},"When the Cordova native source extracts metadata in helper classes\n(",{"type":47,"tag":61,"props":563,"children":565},{"className":564},[],[566],{"type":52,"value":567},"ExifHelper",{"type":52,"value":495},{"type":47,"tag":61,"props":570,"children":572},{"className":571},[],[573],{"type":52,"value":574},"MimeTypeHelper",{"type":52,"value":495},{"type":47,"tag":61,"props":577,"children":579},{"className":578},[],[580],{"type":52,"value":581},"ImageMetadata",{"type":52,"value":583},", etc.) and includes it\nin the response payload, capture those fields in the corresponding\n",{"type":47,"tag":61,"props":585,"children":587},{"className":586},[],[588],{"type":52,"value":472},{"type":52,"value":590}," interface, even if the Cordova JS docs did not document\nthem. Read the native code, not the README.",{"type":47,"tag":108,"props":592,"children":593},{},[594,596,602,604,610,612,618],{"type":52,"value":595},"When mirroring an official Capacitor equivalent, sanity-check the\nofficial's native LOC against the Cordova source's native LOC. If the\nofficial is more than 3× larger, add a ",{"type":47,"tag":61,"props":597,"children":599},{"className":598},[],[600],{"type":52,"value":601},"migration.notes",{"type":52,"value":603}," entry warning\nthe reviewer that a literal port will leave behavior the official\nhandles (e.g., iOS ",{"type":47,"tag":61,"props":605,"children":607},{"className":606},[],[608],{"type":52,"value":609},"CHHapticEngine",{"type":52,"value":611}," for duration-accurate vibration,\nAndroid ",{"type":47,"tag":61,"props":613,"children":615},{"className":614},[],[616],{"type":52,"value":617},"VibrationEffect",{"type":52,"value":619}," patterns for impact \u002F notification) on the\nfloor. The generator's SDK-adapter rule may or may not catch this.",{"type":47,"tag":108,"props":621,"children":622},{},[623,625,793,797,799,804,806,811,813,818,820,825,827,833],{"type":52,"value":624},"Distinguish three downstream destinations when emitting setup notes:",{"type":47,"tag":626,"props":627,"children":628},"ol",{},[629,729,783],{"type":47,"tag":108,"props":630,"children":631},{},[632,637,639,645,647,653,655,661,662,668,670,676,677,683,684,690,692,698,700,706,707,713,714,720,722,727],{"type":47,"tag":98,"props":633,"children":634},{},[635],{"type":52,"value":636},"Plugin's own packaging.",{"type":52,"value":638}," Gradle ",{"type":47,"tag":61,"props":640,"children":642},{"className":641},[],[643],{"type":52,"value":644},"implementation '...'",{"type":52,"value":646}," lines,\nCocoaPods ",{"type":47,"tag":61,"props":648,"children":650},{"className":649},[],[651],{"type":52,"value":652},"s.dependency '...'",{"type":52,"value":654}," lines, custom Maven repo URLs,\n",{"type":47,"tag":61,"props":656,"children":658},{"className":657},[],[659],{"type":52,"value":660},"s.weak_framework",{"type":52,"value":495},{"type":47,"tag":61,"props":663,"children":665},{"className":664},[],[666],{"type":52,"value":667},"s.vendored_frameworks",{"type":52,"value":669},", AndroidManifest\n",{"type":47,"tag":61,"props":671,"children":673},{"className":672},[],[674],{"type":52,"value":675},"\u003Cuses-permission>",{"type":52,"value":451},{"type":47,"tag":61,"props":678,"children":680},{"className":679},[],[681],{"type":52,"value":682},"\u003Cmeta-data>",{"type":52,"value":451},{"type":47,"tag":61,"props":685,"children":687},{"className":686},[],[688],{"type":52,"value":689},"\u003Cqueries>",{"type":52,"value":691}," entries, and\n",{"type":47,"tag":61,"props":693,"children":695},{"className":694},[],[696],{"type":52,"value":697},"@CapacitorPlugin(permissions = [...])",{"type":52,"value":699}," declarations all belong\nin the plugin's own ",{"type":47,"tag":61,"props":701,"children":703},{"className":702},[],[704],{"type":52,"value":705},"android\u002Fbuild.gradle",{"type":52,"value":495},{"type":47,"tag":61,"props":708,"children":710},{"className":709},[],[711],{"type":52,"value":712},".podspec",{"type":52,"value":503},{"type":47,"tag":61,"props":715,"children":717},{"className":716},[],[718],{"type":52,"value":719},"android\u002Fsrc\u002Fmain\u002FAndroidManifest.xml",{"type":52,"value":721},", or annotations. Gradle's\nmanifest merger and CocoaPods transitively propagate these to\nconsumers, so no host-app step and no ",{"type":47,"tag":61,"props":723,"children":725},{"className":724},[],[726],{"type":52,"value":66},{"type":52,"value":728}," entry is\nrequired.",{"type":47,"tag":108,"props":730,"children":731},{},[732,737,739,745,746,752,754,760,761,767,769,774,776,781],{"type":47,"tag":98,"props":733,"children":734},{},[735],{"type":52,"value":736},"Host-app build configuration.",{"type":52,"value":738}," Items that cannot live in the\nplugin package and must be applied to the consuming app: Info.plist\nprivacy strings (",{"type":47,"tag":61,"props":740,"children":742},{"className":741},[],[743],{"type":52,"value":744},"NSCameraUsageDescription",{"type":52,"value":503},{"type":47,"tag":61,"props":747,"children":749},{"className":748},[],[750],{"type":52,"value":751},"NSLocationWhenInUseUsageDescription",{"type":52,"value":753},", etc.), iOS capabilities and\nentitlements (Apple Pay merchant ID, ",{"type":47,"tag":61,"props":755,"children":757},{"className":756},[],[758],{"type":52,"value":759},"aps-environment",{"type":52,"value":503},{"type":47,"tag":61,"props":762,"children":764},{"className":763},[],[765],{"type":52,"value":766},"com.apple.security.application-groups",{"type":52,"value":768},"), and any other manifest\nmutation that must live on the host app rather than the plugin.\nRecord under ",{"type":47,"tag":61,"props":770,"children":772},{"className":771},[],[773],{"type":52,"value":601},{"type":52,"value":775}," and document in ",{"type":47,"tag":61,"props":777,"children":779},{"className":778},[],[780],{"type":52,"value":66},{"type":52,"value":782}," with\ncopy-paste-ready snippets per platform.",{"type":47,"tag":108,"props":784,"children":785},{},[786,791],{"type":47,"tag":98,"props":787,"children":788},{},[789],{"type":52,"value":790},"Consumer runtime config \u002F code.",{"type":52,"value":792}," Apple Developer-side credential\nprovisioning, host-app-supplied JSON config values (merchant\nnumbers, API keys), and consumer JS call-site migration (callback\n→ Promise, positional → named). No tool can automate these because\nthe inputs are the consumer's own data.",{"type":47,"tag":794,"props":795,"children":796},"br",{},[],{"type":52,"value":798},"Record each ",{"type":47,"tag":61,"props":800,"children":802},{"className":801},[],[803],{"type":52,"value":244},{"type":52,"value":805}," directive under one of those three buckets\nin ",{"type":47,"tag":61,"props":807,"children":809},{"className":808},[],[810],{"type":52,"value":601},{"type":52,"value":812},". Never write a ",{"type":47,"tag":61,"props":814,"children":816},{"className":815},[],[817],{"type":52,"value":66},{"type":52,"value":819}," step that asks\nconsumers to add ",{"type":47,"tag":61,"props":821,"children":823},{"className":822},[],[824],{"type":52,"value":644},{"type":52,"value":826}," for a dep the plugin should\nbundle. See ",{"type":47,"tag":61,"props":828,"children":830},{"className":829},[],[831],{"type":52,"value":832},"references\u002Fdependency-migration.md",{"type":52,"value":834}," \"Ownership Model\"\nfor the dep-specific table.",{"type":47,"tag":108,"props":836,"children":837},{},[838,840,846,848,854,856,861,863,869,871,877,879,885,887,893],{"type":52,"value":839},"When the Cordova plugin used ",{"type":47,"tag":61,"props":841,"children":843},{"className":842},[],[844],{"type":52,"value":845},"\u003Cpreference name=\"VAR\" default=\"...\">",{"type":52,"value":847},"\ninstall-time placeholders inside ",{"type":47,"tag":61,"props":849,"children":851},{"className":850},[],[852],{"type":52,"value":853},"\u003Cconfig-file target=\"*-Info.plist\">",{"type":52,"value":855},"\nentries (Apple Pay merchant config, OAuth client IDs, analytics keys,\netc.), detect it and recommend the ",{"type":47,"tag":98,"props":857,"children":858},{},[859],{"type":52,"value":860},"runtime config JSON file",{"type":52,"value":862},"\npattern in ",{"type":47,"tag":61,"props":864,"children":866},{"className":865},[],[867],{"type":52,"value":868},"migration.warnings",{"type":52,"value":870},": a ",{"type":47,"tag":61,"props":872,"children":874},{"className":873},[],[875],{"type":52,"value":876},"PluginConfig.json",{"type":52,"value":878}," consumed by a\nhybrid ",{"type":47,"tag":61,"props":880,"children":882},{"className":881},[],[883],{"type":52,"value":884},"capacitor:sync:after",{"type":52,"value":886}," script that copies the file into native\nprojects at build time. The Cordova plugin may already ship this\nscript (look for it in ",{"type":47,"tag":61,"props":888,"children":890},{"className":889},[],[891],{"type":52,"value":892},"hooks\u002Fcapacitor*.js",{"type":52,"value":894},"); if so, reuse it.\nOtherwise propose a one-screen template. This pattern keeps consumer\nvalues out of static plist \u002F manifest entries entirely.",{"type":47,"tag":108,"props":896,"children":897},{},[898,900,905,907,913,915,921,923,929,931,936,938,944,946,951,953,959,961,967,969,974,976,981,982,987,989,994],{"type":52,"value":899},"Detect SPM markers in ",{"type":47,"tag":61,"props":901,"children":903},{"className":902},[],[904],{"type":52,"value":244},{"type":52,"value":906},": ",{"type":47,"tag":61,"props":908,"children":910},{"className":909},[],[911],{"type":52,"value":912},"\u003Cplatform name=\"ios\" package=\"swift\">",{"type":52,"value":914},"\nand ",{"type":47,"tag":61,"props":916,"children":918},{"className":917},[],[919],{"type":52,"value":920},"\u003Cpod ... nospm=\"true\">",{"type":52,"value":922}," indicate the Cordova plugin already ships a\nsibling ",{"type":47,"tag":61,"props":924,"children":926},{"className":925},[],[927],{"type":52,"value":928},"Package.swift",{"type":52,"value":930},". When present: (a) read that ",{"type":47,"tag":61,"props":932,"children":934},{"className":933},[],[935],{"type":52,"value":928},{"type":52,"value":937}," and\nlift its dependencies into the YAML's ",{"type":47,"tag":61,"props":939,"children":941},{"className":940},[],[942],{"type":52,"value":943},"dependencies.ios.spm",{"type":52,"value":945},", (b) move\nany pod ",{"type":47,"tag":98,"props":947,"children":948},{},[949],{"type":52,"value":950},"without",{"type":52,"value":952}," ",{"type":47,"tag":61,"props":954,"children":956},{"className":955},[],[957],{"type":52,"value":958},"nospm=\"true\"",{"type":52,"value":960}," to ",{"type":47,"tag":61,"props":962,"children":964},{"className":963},[],[965],{"type":52,"value":966},"dependencies.ios.cocoapods",{"type":52,"value":968},",\n(c) add a ",{"type":47,"tag":61,"props":970,"children":972},{"className":971},[],[973],{"type":52,"value":601},{"type":52,"value":975}," entry that the generated Capacitor plugin\nmust ship both ",{"type":47,"tag":61,"props":977,"children":979},{"className":978},[],[980],{"type":52,"value":928},{"type":52,"value":541},{"type":47,"tag":61,"props":983,"children":985},{"className":984},[],[986],{"type":52,"value":712},{"type":52,"value":988}," (Capacitor 8 supports\nboth, and SPM is the default for new plugins). See\n",{"type":47,"tag":61,"props":990,"children":992},{"className":991},[],[993],{"type":52,"value":832},{"type":52,"value":995}," \"Swift Package Manager (SPM)\" for\nthe schema.",{"type":47,"tag":108,"props":997,"children":998},{},[999,1001,1007],{"type":52,"value":1000},"Default output mode is Mode B (side-by-side directory). Switch to Mode A\n(in-place with ",{"type":47,"tag":61,"props":1002,"children":1004},{"className":1003},[],[1005],{"type":52,"value":1006},".cordova-archive\u002F",{"type":52,"value":1008},") only when the user explicitly asks and\nthe source is in a writable working copy.",{"type":47,"tag":108,"props":1010,"children":1011},{},[1012],{"type":52,"value":1013},"Stop and request user input when blockers, Tier 3 hooks, unresolvable\nproprietary SDKs, or missing source files would force you to guess. Do not\nemit a YAML plan that hides the gap.",{"type":47,"tag":108,"props":1015,"children":1016},{},[1017],{"type":52,"value":1018},"Distinguish between resolvable warnings (documented manual steps) and\nblockers (cannot be auto-migrated). Both go in the plan; only blockers stop\nhandoff.",{"type":47,"tag":108,"props":1020,"children":1021},{},[1022,1024,1030,1032,1037,1039,1045,1047,1053],{"type":52,"value":1023},"A vendored binary checked into the Cordova plugin's tree (e.g.,\n",{"type":47,"tag":61,"props":1025,"children":1027},{"className":1026},[],[1028],{"type":52,"value":1029},"src\u002Fios\u002Fframeworks\u002FFoo.xcframework",{"type":52,"value":1031},") is ",{"type":47,"tag":98,"props":1033,"children":1034},{},[1035],{"type":52,"value":1036},"not",{"type":52,"value":1038}," a blocker on its own. Carry\nthe binary forward and record its path under\n",{"type":47,"tag":61,"props":1040,"children":1042},{"className":1041},[],[1043],{"type":52,"value":1044},"migration.source_files.ios",{"type":52,"value":1046}," (or ",{"type":47,"tag":61,"props":1048,"children":1050},{"className":1049},[],[1051],{"type":52,"value":1052},".android",{"type":52,"value":1054},"). Treat as blocker only when\nthe binary requires runtime credentials the user does not have or fails\nAndroidX \u002F 64-bit \u002F simulator requirements.",{"type":47,"tag":108,"props":1056,"children":1057},{},[1058],{"type":52,"value":1059},"Report what was actually inspected. Cite file paths and line numbers when\nflagging blockers or unsupported patterns.",{"type":47,"tag":108,"props":1061,"children":1062},{},[1063,1065,1070],{"type":52,"value":1064},"Compare iOS and Android findings against each other before declaring\nPhase 9. If one platform exposes a method the other does not, surface the\nmismatch in ",{"type":47,"tag":61,"props":1066,"children":1068},{"className":1067},[],[1069],{"type":52,"value":868},{"type":52,"value":1071}," so the generator can pick a strategy\n(mirror both, expose conditionally, or drop). Do not silently emit a\ncontract that only one platform can fulfil.",{"type":47,"tag":108,"props":1073,"children":1074},{},[1075,1077,1082,1084,1090],{"type":52,"value":1076},"Default response shape is ",{"type":47,"tag":98,"props":1078,"children":1079},{},[1080],{"type":52,"value":1081},"architecture and plan",{"type":52,"value":1083},", not code. Do not\ninclude full before\u002Fafter code blocks unless the user explicitly asks for\n\"show me the code\" or \"deep dive\". Per-method one-line mappings in\n",{"type":47,"tag":61,"props":1085,"children":1087},{"className":1086},[],[1088],{"type":52,"value":1089},"migration.cordova_to_capacitor_map",{"type":52,"value":1091}," are not \"code\" in this sense, they\nare part of the plan.",{"type":47,"tag":108,"props":1093,"children":1094},{},[1095,1097,1102,1104,1110,1111,1117,1118,1124,1125,1131,1132,1138,1139,1145,1146,1152,1154,1160],{"type":52,"value":1096},"Quote every value in ",{"type":47,"tag":61,"props":1098,"children":1100},{"className":1099},[],[1101],{"type":52,"value":1089},{"type":52,"value":1103}," and any other\nYAML string that contains JS syntax (",{"type":47,"tag":61,"props":1105,"children":1107},{"className":1106},[],[1108],{"type":52,"value":1109},"(",{"type":52,"value":495},{"type":47,"tag":61,"props":1112,"children":1114},{"className":1113},[],[1115],{"type":52,"value":1116},")",{"type":52,"value":495},{"type":47,"tag":61,"props":1119,"children":1121},{"className":1120},[],[1122],{"type":52,"value":1123},"{",{"type":52,"value":495},{"type":47,"tag":61,"props":1126,"children":1128},{"className":1127},[],[1129],{"type":52,"value":1130},"}",{"type":52,"value":495},{"type":47,"tag":61,"props":1133,"children":1135},{"className":1134},[],[1136],{"type":52,"value":1137},":",{"type":52,"value":495},{"type":47,"tag":61,"props":1140,"children":1142},{"className":1141},[],[1143],{"type":52,"value":1144},"[",{"type":52,"value":495},{"type":47,"tag":61,"props":1147,"children":1149},{"className":1148},[],[1150],{"type":52,"value":1151},"]",{"type":52,"value":1153},").\nUnquoted JS expressions like ",{"type":47,"tag":61,"props":1155,"children":1157},{"className":1156},[],[1158],{"type":52,"value":1159},"Foo.bar({ x: 1 })",{"type":52,"value":1161}," are unparseable YAML and\nthe generator will reject the plan at load time.",{"type":47,"tag":108,"props":1163,"children":1164},{},[1165,1167,1173,1175,1181],{"type":52,"value":1166},"Invoke the generator only after the Phase 10 user checkpoint\napproves. If the user rejects, halts, or has unanswered blockers,\nstop. Never invoke the generator with a YAML that has non-empty\n",{"type":47,"tag":61,"props":1168,"children":1170},{"className":1169},[],[1171],{"type":52,"value":1172},"migration.blockers",{"type":52,"value":1174}," or non-empty ",{"type":47,"tag":61,"props":1176,"children":1178},{"className":1177},[],[1179],{"type":52,"value":1180},"migration.hooks.tier_3",{"type":52,"value":129},{"type":47,"tag":108,"props":1183,"children":1184},{},[1185,1187,1193,1195,1201,1203,1208,1210,1216],{"type":52,"value":1186},"When ",{"type":47,"tag":61,"props":1188,"children":1190},{"className":1189},[],[1191],{"type":52,"value":1192},"odc_target: true",{"type":52,"value":1194},", Phase 11 splits into two sequential sub-phases\n(11a and 11b). Phase 11a invokes ",{"type":47,"tag":61,"props":1196,"children":1198},{"className":1197},[],[1199],{"type":52,"value":1200},"build-actions-generator",{"type":52,"value":1202},"; Phase 11b\ninvokes ",{"type":47,"tag":61,"props":1204,"children":1206},{"className":1205},[],[1207],{"type":52,"value":82},{"type":52,"value":1209},". See ",{"type":47,"tag":61,"props":1211,"children":1213},{"className":1212},[],[1214],{"type":52,"value":1215},"references\u002Fusing-plugin-generator.md",{"type":52,"value":1217},"\n\"ODC Path\" for the full sequence. Build actions are written to the Capacitor\nplugin folder. Hooks and migration notes that are fully covered by build\nactions must be excluded from the YAML passed to the generator (Phase 11b),\nto avoid the generator emitting redundant Capacitor hook scripts for\nconfig-level work already handled by build actions.",{"type":47,"tag":86,"props":1219,"children":1221},{"id":1220},"procedures",[1222],{"type":52,"value":1223},"Procedures",{"type":47,"tag":1225,"props":1226,"children":1228},"h3",{"id":1227},"phase-1-determine-the-task-and-output-mode",[1229],{"type":52,"value":1230},"Phase 1: Determine the Task and Output Mode",{"type":47,"tag":55,"props":1232,"children":1233},{},[1234,1236,1241,1243,1248],{"type":52,"value":1235},"Confirm the user has a Cordova plugin to migrate. ",{"type":47,"tag":98,"props":1237,"children":1238},{},[1239],{"type":52,"value":1240},"If the user wants a\nbrand-new Capacitor plugin from scratch with no Cordova source to\nconvert",{"type":52,"value":1242},", stop here and redirect to ",{"type":47,"tag":61,"props":1244,"children":1246},{"className":1245},[],[1247],{"type":52,"value":82},{"type":52,"value":1249},"\ndirectly, this skill has nothing to add.",{"type":47,"tag":55,"props":1251,"children":1252},{},[1253],{"type":52,"value":1254},"Otherwise, pick the output mode:",{"type":47,"tag":104,"props":1256,"children":1257},{},[1258,1268],{"type":47,"tag":108,"props":1259,"children":1260},{},[1261,1266],{"type":47,"tag":98,"props":1262,"children":1263},{},[1264],{"type":52,"value":1265},"Mode B (default, side-by-side)",{"type":52,"value":1267},", generator scaffolds a new\nCapacitor plugin into a sibling directory of the Cordova repo. The\nCordova repo is never touched.",{"type":47,"tag":108,"props":1269,"children":1270},{},[1271,1276,1278,1283],{"type":47,"tag":98,"props":1272,"children":1273},{},[1274],{"type":52,"value":1275},"Mode A (opt-in, in-place)",{"type":52,"value":1277},", generator scaffolds into a temp\ndirectory. After Phase 11 succeeds, Phase 12 relocates the generator's\noutput into the Cordova repo root and moves the original Cordova\nsource under ",{"type":47,"tag":61,"props":1279,"children":1281},{"className":1280},[],[1282],{"type":52,"value":1006},{"type":52,"value":1284},". Preserves the original repo's npm\npackage name and git history. Requires explicit user opt-in and a\nclean writable git working copy.",{"type":47,"tag":55,"props":1286,"children":1287},{},[1288,1290,1296],{"type":52,"value":1289},"See ",{"type":47,"tag":61,"props":1291,"children":1293},{"className":1292},[],[1294],{"type":52,"value":1295},"references\u002Foutput-modes.md",{"type":52,"value":1297}," for layouts, pre-flight checks, and\nthe exact relocation sequence.",{"type":47,"tag":55,"props":1299,"children":1300},{},[1301,1306,1308,1313,1315,1321,1323,1329],{"type":47,"tag":98,"props":1302,"children":1303},{},[1304],{"type":52,"value":1305},"ODC confirmation:",{"type":52,"value":1307}," Check whether the user mentioned ODC or OutSystems\nDeveloper Cloud anywhere in the request. If yes, set ",{"type":47,"tag":61,"props":1309,"children":1311},{"className":1310},[],[1312],{"type":52,"value":1192},{"type":52,"value":1314}," and\nproceed. If not, ask: ",{"type":47,"tag":1316,"props":1317,"children":1318},"em",{},[1319],{"type":52,"value":1320},"\"Will this Capacitor plugin be consumed by an ODC\n(OutSystems Developer Cloud) app? If yes, build actions will be generated\nalongside the Capacitor plugin to handle native configuration in MABS.\"",{"type":52,"value":1322},"\nRecord the answer as ",{"type":47,"tag":61,"props":1324,"children":1326},{"className":1325},[],[1327],{"type":52,"value":1328},"odc_target: true\u002Ffalse",{"type":52,"value":1330}," for use in Phase 11.",{"type":47,"tag":1225,"props":1332,"children":1334},{"id":1333},"phase-2-read-pluginxml",[1335,1337],{"type":52,"value":1336},"Phase 2: Read ",{"type":47,"tag":61,"props":1338,"children":1340},{"className":1339},[],[1341],{"type":52,"value":244},{"type":47,"tag":55,"props":1343,"children":1344},{},[1345],{"type":52,"value":1346},"A typical Cordova plugin layout:",{"type":47,"tag":1348,"props":1349,"children":1353},"pre",{"className":1350,"code":1352,"language":52},[1351],"language-text","my-plugin\u002F\n├── plugin.xml           # Plugin manifest and configuration\n├── package.json         # NPM metadata (and any capacitor:* scripts)\n├── www\u002F                 # JavaScript bridge\n├── src\u002F\n│   ├── ios\u002F             # CDVPlugin subclasses (.h\u002F.m\u002F.swift)\n│   └── android\u002F         # CordovaPlugin subclasses (.java\u002F.kt)\n└── hooks\u002F               # Optional lifecycle scripts\n",[1354],{"type":47,"tag":61,"props":1355,"children":1357},{"__ignoreMap":1356},"",[1358],{"type":52,"value":1352},{"type":47,"tag":55,"props":1360,"children":1361},{},[1362,1364,1369,1371,1377,1379,1385,1387,1393,1395,1401,1403,1409,1411,1416,1418,1424,1426,1431,1433,1439,1441,1447,1449,1455,1457,1463,1464,1470,1472,1478],{"type":52,"value":1363},"Open ",{"type":47,"tag":61,"props":1365,"children":1367},{"className":1366},[],[1368],{"type":52,"value":244},{"type":52,"value":1370},". Extract: plugin id, name, version, declared platforms\n(",{"type":47,"tag":61,"props":1372,"children":1374},{"className":1373},[],[1375],{"type":52,"value":1376},"\u003Cplatform name=\"...\">",{"type":52,"value":1378},"), ",{"type":47,"tag":61,"props":1380,"children":1382},{"className":1381},[],[1383],{"type":52,"value":1384},"\u003Csource-file>",{"type":52,"value":1386},"\u002F",{"type":47,"tag":61,"props":1388,"children":1390},{"className":1389},[],[1391],{"type":52,"value":1392},"\u003Cheader-file>",{"type":52,"value":1394}," mappings,\n",{"type":47,"tag":61,"props":1396,"children":1398},{"className":1397},[],[1399],{"type":52,"value":1400},"\u003Cframework>",{"type":52,"value":1402}," entries, ",{"type":47,"tag":61,"props":1404,"children":1406},{"className":1405},[],[1407],{"type":52,"value":1408},"\u003Cpodspec>",{"type":52,"value":1410}," blocks, ",{"type":47,"tag":61,"props":1412,"children":1414},{"className":1413},[],[1415],{"type":52,"value":145},{"type":52,"value":1417}," targets,\n",{"type":47,"tag":61,"props":1419,"children":1421},{"className":1420},[],[1422],{"type":52,"value":1423},"\u003Cedit-config>",{"type":52,"value":1425}," targets, ",{"type":47,"tag":61,"props":1427,"children":1429},{"className":1428},[],[1430],{"type":52,"value":386},{"type":52,"value":1432}," declarations, ",{"type":47,"tag":61,"props":1434,"children":1436},{"className":1435},[],[1437],{"type":52,"value":1438},"\u003Cdependency>",{"type":52,"value":1440}," entries,\n",{"type":47,"tag":61,"props":1442,"children":1444},{"className":1443},[],[1445],{"type":52,"value":1446},"\u003Cpreference>",{"type":52,"value":1448}," tags, and ",{"type":47,"tag":61,"props":1450,"children":1452},{"className":1451},[],[1453],{"type":52,"value":1454},"\u003Cjs-module>",{"type":52,"value":1456}," exposure (",{"type":47,"tag":61,"props":1458,"children":1460},{"className":1459},[],[1461],{"type":52,"value":1462},"clobbers",{"type":52,"value":451},{"type":47,"tag":61,"props":1465,"children":1467},{"className":1466},[],[1468],{"type":52,"value":1469},"merges",{"type":52,"value":1471}," \u002F\n",{"type":47,"tag":61,"props":1473,"children":1475},{"className":1474},[],[1476],{"type":52,"value":1477},"runs",{"type":52,"value":1479},"). Record file paths and line numbers for every blocker candidate.",{"type":47,"tag":1225,"props":1481,"children":1483},{"id":1482},"phase-3-analyze-native-dependencies",[1484],{"type":52,"value":1485},"Phase 3: Analyze Native Dependencies",{"type":47,"tag":55,"props":1487,"children":1488},{},[1489,1491,1496,1498,1503,1505,1510],{"type":52,"value":1490},"Apply ",{"type":47,"tag":61,"props":1492,"children":1494},{"className":1493},[],[1495],{"type":52,"value":832},{"type":52,"value":1497},". For each ",{"type":47,"tag":61,"props":1499,"children":1501},{"className":1500},[],[1502],{"type":52,"value":1400},{"type":52,"value":1504}," and\n",{"type":47,"tag":61,"props":1506,"children":1508},{"className":1507},[],[1509],{"type":52,"value":1408},{"type":52,"value":1511}," pod, decide: direct migration, version update, alternative\nlibrary, or blocker. For each Android Gradle coord, check AndroidX vs Support\nLibrary and Capacitor's minimum compile SDK. Record manual installation steps\nrequired after migration.",{"type":47,"tag":1225,"props":1513,"children":1515},{"id":1514},"phase-4-analyze-hooks",[1516],{"type":52,"value":1517},"Phase 4: Analyze Hooks",{"type":47,"tag":55,"props":1519,"children":1520},{},[1521,1523,1528],{"type":52,"value":1522},"Apply the three-tier rule in ",{"type":47,"tag":61,"props":1524,"children":1526},{"className":1525},[],[1527],{"type":52,"value":394},{"type":52,"value":1137},{"type":47,"tag":104,"props":1530,"children":1531},{},[1532,1557,1582],{"type":47,"tag":108,"props":1533,"children":1534},{},[1535,1540,1542,1548,1549,1555],{"type":47,"tag":98,"props":1536,"children":1537},{},[1538],{"type":52,"value":1539},"Tier 1",{"type":52,"value":1541},", convertible to a Capacitor plugin npm hook\n(",{"type":47,"tag":61,"props":1543,"children":1545},{"className":1544},[],[1546],{"type":52,"value":1547},"capacitor:{sync,copy,update}:{before,after}",{"type":52,"value":503},{"type":47,"tag":61,"props":1550,"children":1552},{"className":1551},[],[1553],{"type":52,"value":1554},"capacitor:{android,ios}:add:{before,after}",{"type":52,"value":1556},").",{"type":47,"tag":108,"props":1558,"children":1559},{},[1560,1565,1567,1573,1574,1580],{"type":47,"tag":98,"props":1561,"children":1562},{},[1563],{"type":52,"value":1564},"Tier 2",{"type":52,"value":1566},", convertible to an npm lifecycle script (",{"type":47,"tag":61,"props":1568,"children":1570},{"className":1569},[],[1571],{"type":52,"value":1572},"postinstall",{"type":52,"value":503},{"type":47,"tag":61,"props":1575,"children":1577},{"className":1576},[],[1578],{"type":52,"value":1579},"preuninstall",{"type":52,"value":1581},") or a documented manual step.",{"type":47,"tag":108,"props":1583,"children":1584},{},[1585,1590],{"type":47,"tag":98,"props":1586,"children":1587},{},[1588],{"type":52,"value":1589},"Tier 3",{"type":52,"value":1591},", interactive prompts, plugin.xml\u002Fconfig.xml mutation, Cordova\nCLI internals, or anything else with no Capacitor equivalent.",{"type":47,"tag":55,"props":1593,"children":1594},{},[1595],{"type":52,"value":1596},"Read each referenced script. Do not classify on filename alone.",{"type":47,"tag":1225,"props":1598,"children":1600},{"id":1599},"phase-5-analyze-the-javascript-bridge",[1601],{"type":52,"value":1602},"Phase 5: Analyze the JavaScript Bridge",{"type":47,"tag":55,"props":1604,"children":1605},{},[1606,1607,1613,1615,1621,1623,1629,1631,1637,1639,1645],{"type":52,"value":1490},{"type":47,"tag":61,"props":1608,"children":1610},{"className":1609},[],[1611],{"type":52,"value":1612},"references\u002Fapi-mappings.md",{"type":52,"value":1614},". From ",{"type":47,"tag":61,"props":1616,"children":1618},{"className":1617},[],[1619],{"type":52,"value":1620},"www\u002F*.js",{"type":52,"value":1622},", list every public method,\nits positional argument shape, whether it uses success\u002Ferror callbacks or\nreturns a promise, and whether ",{"type":47,"tag":61,"props":1624,"children":1626},{"className":1625},[],[1627],{"type":52,"value":1628},"exec()",{"type":52,"value":1630}," is paired with a ",{"type":47,"tag":61,"props":1632,"children":1634},{"className":1633},[],[1635],{"type":52,"value":1636},"cordova.exec()",{"type":52,"value":1638},"\naction name. Map each method to a Capacitor ",{"type":47,"tag":61,"props":1640,"children":1642},{"className":1641},[],[1643],{"type":52,"value":1644},"methodName(options): Promise\u003CR>",{"type":52,"value":1646},"\nsignature.",{"type":47,"tag":1225,"props":1648,"children":1650},{"id":1649},"phase-6-analyze-ios-implementation",[1651],{"type":52,"value":1652},"Phase 6: Analyze iOS Implementation",{"type":47,"tag":55,"props":1654,"children":1655},{},[1656,1657,1662,1663,1669,1671,1677,1679,1685,1687,1693],{"type":52,"value":1490},{"type":47,"tag":61,"props":1658,"children":1660},{"className":1659},[],[1661],{"type":52,"value":1612},{"type":52,"value":1614},{"type":47,"tag":61,"props":1664,"children":1666},{"className":1665},[],[1667],{"type":52,"value":1668},"src\u002Fios\u002F*.{h,m,swift}",{"type":52,"value":1670},", identify the\n",{"type":47,"tag":61,"props":1672,"children":1674},{"className":1673},[],[1675],{"type":52,"value":1676},"CDVPlugin",{"type":52,"value":1678}," subclass, each method matching a JS action, argument extraction\nfrom ",{"type":47,"tag":61,"props":1680,"children":1682},{"className":1681},[],[1683],{"type":52,"value":1684},"command.arguments",{"type":52,"value":1686},", response construction (",{"type":47,"tag":61,"props":1688,"children":1690},{"className":1689},[],[1691],{"type":52,"value":1692},"CDVPluginResult",{"type":52,"value":1694},"), permission\nflows, and any system frameworks or SDK adapters used. Note where Objective-C\nmust be modernized to Swift.",{"type":47,"tag":1225,"props":1696,"children":1698},{"id":1697},"phase-7-analyze-android-implementation",[1699],{"type":52,"value":1700},"Phase 7: Analyze Android Implementation",{"type":47,"tag":55,"props":1702,"children":1703},{},[1704,1705,1710,1711,1717,1719,1725,1727,1733,1735,1741,1743,1749],{"type":52,"value":1490},{"type":47,"tag":61,"props":1706,"children":1708},{"className":1707},[],[1709],{"type":52,"value":1612},{"type":52,"value":1614},{"type":47,"tag":61,"props":1712,"children":1714},{"className":1713},[],[1715],{"type":52,"value":1716},"src\u002Fandroid\u002F**\u002F*.{java,kt}",{"type":52,"value":1718},",\nidentify the ",{"type":47,"tag":61,"props":1720,"children":1722},{"className":1721},[],[1723],{"type":52,"value":1724},"CordovaPlugin",{"type":52,"value":1726}," subclass, the ",{"type":47,"tag":61,"props":1728,"children":1730},{"className":1729},[],[1731],{"type":52,"value":1732},"execute()",{"type":52,"value":1734}," router, action\nstrings, argument extraction (",{"type":47,"tag":61,"props":1736,"children":1738},{"className":1737},[],[1739],{"type":52,"value":1740},"args.getString(i)",{"type":52,"value":1742},"), response paths\n(",{"type":47,"tag":61,"props":1744,"children":1746},{"className":1745},[],[1747],{"type":52,"value":1748},"CallbackContext.success\u002Ferror",{"type":52,"value":1750},"), permission flows, and any Activity Result\npatterns. Note where Java must be modernized to Kotlin.",{"type":47,"tag":1225,"props":1752,"children":1754},{"id":1753},"phase-8-assess-complexity",[1755],{"type":52,"value":1756},"Phase 8: Assess Complexity",{"type":47,"tag":55,"props":1758,"children":1759},{},[1760,1761,1767,1769,1775,1776,1782,1783,1789,1790,1796,1798,1803],{"type":52,"value":1490},{"type":47,"tag":61,"props":1762,"children":1764},{"className":1763},[],[1765],{"type":52,"value":1766},"references\u002Fcomplexity-assessment.md",{"type":52,"value":1768},". Score the plugin on method count,\nLOC, dependency footprint, hook tier mix, language modernization, blocker\ncount, and Capacitor-equivalent reuse. Output one of: ",{"type":47,"tag":61,"props":1770,"children":1772},{"className":1771},[],[1773],{"type":52,"value":1774},"simple",{"type":52,"value":495},{"type":47,"tag":61,"props":1777,"children":1779},{"className":1778},[],[1780],{"type":52,"value":1781},"moderate",{"type":52,"value":503},{"type":47,"tag":61,"props":1784,"children":1786},{"className":1785},[],[1787],{"type":52,"value":1788},"complex",{"type":52,"value":495},{"type":47,"tag":61,"props":1791,"children":1793},{"className":1792},[],[1794],{"type":52,"value":1795},"blocked",{"type":52,"value":1797},". ",{"type":47,"tag":61,"props":1799,"children":1801},{"className":1800},[],[1802],{"type":52,"value":1795},{"type":52,"value":1804}," means the user must resolve issues before\ngenerator handoff.",{"type":47,"tag":1225,"props":1806,"children":1808},{"id":1807},"phase-9-produce-the-migration-yaml",[1809],{"type":52,"value":1810},"Phase 9: Produce the Migration YAML",{"type":47,"tag":55,"props":1812,"children":1813},{},[1814,1815,1820,1822,1828,1830,1836,1837,1843,1844,1850,1851,1857,1858,1864,1866,1872,1874,1880,1881,1887,1888,1894,1895,1901,1902,1908,1909,1915,1916,1922,1923,1929,1930,1936],{"type":52,"value":1490},{"type":47,"tag":61,"props":1816,"children":1818},{"className":1817},[],[1819],{"type":52,"value":1215},{"type":52,"value":1821},". Build the YAML against the\ngenerator's ",{"type":47,"tag":61,"props":1823,"children":1825},{"className":1824},[],[1826],{"type":52,"value":1827},"references\u002Finput-contract.md",{"type":52,"value":1829},", base block (",{"type":47,"tag":61,"props":1831,"children":1833},{"className":1832},[],[1834],{"type":52,"value":1835},"plugin",{"type":52,"value":503},{"type":47,"tag":61,"props":1838,"children":1840},{"className":1839},[],[1841],{"type":52,"value":1842},"platforms",{"type":52,"value":495},{"type":47,"tag":61,"props":1845,"children":1847},{"className":1846},[],[1848],{"type":52,"value":1849},"api",{"type":52,"value":495},{"type":47,"tag":61,"props":1852,"children":1854},{"className":1853},[],[1855],{"type":52,"value":1856},"permissions",{"type":52,"value":495},{"type":47,"tag":61,"props":1859,"children":1861},{"className":1860},[],[1862],{"type":52,"value":1863},"dependencies",{"type":52,"value":1865},") plus the optional\n",{"type":47,"tag":61,"props":1867,"children":1869},{"className":1868},[],[1870],{"type":52,"value":1871},"migration:",{"type":52,"value":1873}," block (",{"type":47,"tag":61,"props":1875,"children":1877},{"className":1876},[],[1878],{"type":52,"value":1879},"source",{"type":52,"value":495},{"type":47,"tag":61,"props":1882,"children":1884},{"className":1883},[],[1885],{"type":52,"value":1886},"complexity",{"type":52,"value":495},{"type":47,"tag":61,"props":1889,"children":1891},{"className":1890},[],[1892],{"type":52,"value":1893},"output_mode",{"type":52,"value":495},{"type":47,"tag":61,"props":1896,"children":1898},{"className":1897},[],[1899],{"type":52,"value":1900},"blockers",{"type":52,"value":503},{"type":47,"tag":61,"props":1903,"children":1905},{"className":1904},[],[1906],{"type":52,"value":1907},"warnings",{"type":52,"value":495},{"type":47,"tag":61,"props":1910,"children":1912},{"className":1911},[],[1913],{"type":52,"value":1914},"language_modernization",{"type":52,"value":495},{"type":47,"tag":61,"props":1917,"children":1919},{"className":1918},[],[1920],{"type":52,"value":1921},"source_files",{"type":52,"value":495},{"type":47,"tag":61,"props":1924,"children":1926},{"className":1925},[],[1927],{"type":52,"value":1928},"hooks",{"type":52,"value":503},{"type":47,"tag":61,"props":1931,"children":1933},{"className":1932},[],[1934],{"type":52,"value":1935},"cordova_to_capacitor_map",{"type":52,"value":1937},"). Pin wire-format strings to the official\nCapacitor equivalent when one exists.",{"type":47,"tag":1225,"props":1939,"children":1941},{"id":1940},"phase-10-user-checkpoint",[1942],{"type":52,"value":1943},"Phase 10: User Checkpoint",{"type":47,"tag":55,"props":1945,"children":1946},{},[1947],{"type":52,"value":1948},"Present a short human summary alongside the YAML: complexity, blockers,\nwarnings, manual setup, recommended output mode, and any Capacitor\nequivalent being mirrored. Stop and wait for confirmation if blockers or\nTier 3 hooks are non-empty.",{"type":47,"tag":1225,"props":1950,"children":1952},{"id":1951},"phase-11-invoke-downstream-skills",[1953],{"type":52,"value":1954},"Phase 11: Invoke Downstream Skills",{"type":47,"tag":55,"props":1956,"children":1957},{},[1958],{"type":52,"value":1959},"The downstream invocation path depends on whether ODC was confirmed in Phase 1.",{"type":47,"tag":55,"props":1961,"children":1962},{},[1963,1968,1970,1975,1977,1982,1984,1989,1991,1996],{"type":47,"tag":98,"props":1964,"children":1965},{},[1966],{"type":52,"value":1967},"Non-ODC path:",{"type":52,"value":1969}," Apply ",{"type":47,"tag":61,"props":1971,"children":1973},{"className":1972},[],[1974],{"type":52,"value":1215},{"type":52,"value":1976},". Invoke\n",{"type":47,"tag":61,"props":1978,"children":1980},{"className":1979},[],[1981],{"type":52,"value":82},{"type":52,"value":1983}," via the Skill tool in structured mode with the\nPhase 9 YAML. The generator runs its own playbook; this skill does not\nre-inspect Cordova source. For ",{"type":47,"tag":98,"props":1985,"children":1986},{},[1987],{"type":52,"value":1988},"Complex",{"type":52,"value":1990}," plugins use ",{"type":47,"tag":98,"props":1992,"children":1993},{},[1994],{"type":52,"value":1995},"incremental mode",{"type":52,"value":1997},"\n(one platform at a time with user checkpoints). If the generator rejects the\nYAML, return to Phase 9 and fix it — never hand-edit generator output.",{"type":47,"tag":55,"props":1999,"children":2000},{},[2001,2006,2008,2013],{"type":47,"tag":98,"props":2002,"children":2003},{},[2004],{"type":52,"value":2005},"ODC path:",{"type":52,"value":2007}," Follow the two-sub-phase sequence in\n",{"type":47,"tag":61,"props":2009,"children":2011},{"className":2010},[],[2012],{"type":52,"value":1215},{"type":52,"value":2014}," \"ODC Path\":",{"type":47,"tag":104,"props":2016,"children":2017},{},[2018,2043],{"type":47,"tag":108,"props":2019,"children":2020},{},[2021,2026,2028,2033,2035,2041],{"type":47,"tag":98,"props":2022,"children":2023},{},[2024],{"type":52,"value":2025},"Phase 11a",{"type":52,"value":2027}," — Invoke ",{"type":47,"tag":61,"props":2029,"children":2031},{"className":2030},[],[2032],{"type":52,"value":1200},{"type":52,"value":2034}," with the Phase 9 YAML\nand the Cordova plugin path; wait for ",{"type":47,"tag":61,"props":2036,"children":2038},{"className":2037},[],[2039],{"type":52,"value":2040},"build-actions\u002F",{"type":52,"value":2042}," output. Note which\nhooks\u002Felements it covered.",{"type":47,"tag":108,"props":2044,"children":2045},{},[2046,2051,2053,2059,2061,2067,2069,2074,2076,2081],{"type":47,"tag":98,"props":2047,"children":2048},{},[2049],{"type":52,"value":2050},"Phase 11b",{"type":52,"value":2052}," — Remove build-action-covered items from\n",{"type":47,"tag":61,"props":2054,"children":2056},{"className":2055},[],[2057],{"type":52,"value":2058},"migration.hooks.tier_1",{"type":52,"value":2060}," (or mark ",{"type":47,"tag":61,"props":2062,"children":2064},{"className":2063},[],[2065],{"type":52,"value":2066},"status: handled_by_build_actions",{"type":52,"value":2068},"); add\na ",{"type":47,"tag":61,"props":2070,"children":2072},{"className":2071},[],[2073],{"type":52,"value":601},{"type":52,"value":2075}," entry documenting this. Then invoke\n",{"type":47,"tag":61,"props":2077,"children":2079},{"className":2078},[],[2080],{"type":52,"value":82},{"type":52,"value":2082}," with the annotated YAML (standard or incremental\nper complexity).",{"type":47,"tag":1225,"props":2084,"children":2086},{"id":2085},"phase-12-post-migration-cleanup",[2087],{"type":52,"value":2088},"Phase 12: Post-Migration Cleanup",{"type":47,"tag":55,"props":2090,"children":2091},{},[2092,2093,2099,2101,2106],{"type":52,"value":1490},{"type":47,"tag":61,"props":2094,"children":2096},{"className":2095},[],[2097],{"type":52,"value":2098},"references\u002Fpost-migration-cleanup.md",{"type":52,"value":2100},". After the generator produces a\nworking scaffold, consolidate intermediate notes into a single ",{"type":47,"tag":61,"props":2102,"children":2104},{"className":2103},[],[2105],{"type":52,"value":66},{"type":52,"value":2107},"\nat the plugin root, archive or remove the original Cordova source per the\nchosen output mode, and update the README with the consumer-facing breaking\nchanges (callbacks → promises, positional → named arguments, manual native\nsetup).",{"type":47,"tag":55,"props":2109,"children":2110},{},[2111,2113,2118,2119,2124,2126,2131],{"type":52,"value":2112},"Cross-check that every ",{"type":47,"tag":61,"props":2114,"children":2116},{"className":2115},[],[2117],{"type":52,"value":601},{"type":52,"value":541},{"type":47,"tag":61,"props":2120,"children":2122},{"className":2121},[],[2123],{"type":52,"value":868},{"type":52,"value":2125},"\nentry is bucketed (plugin packaging \u002F host-app build configuration \u002F\nconsumer runtime config) per the Agent Behavior rule. The\n",{"type":47,"tag":61,"props":2127,"children":2129},{"className":2128},[],[2130],{"type":52,"value":66},{"type":52,"value":2132}," should list only items that fall in buckets 2 or 3.\nPlugin-packaging items are transparent to consumers and do not belong\nin the migration trail.",{"type":47,"tag":86,"props":2134,"children":2136},{"id":2135},"best-practices",[2137],{"type":52,"value":2138},"Best Practices",{"type":47,"tag":1225,"props":2140,"children":2142},{"id":2141},"do",[2143],{"type":52,"value":2144},"DO",{"type":47,"tag":104,"props":2146,"children":2147},{},[2148,2160,2171,2176,2181,2186,2191,2196],{"type":47,"tag":108,"props":2149,"children":2150},{},[2151,2153,2158],{"type":52,"value":2152},"✅ Read ",{"type":47,"tag":61,"props":2154,"children":2156},{"className":2155},[],[2157],{"type":52,"value":244},{"type":52,"value":2159}," first and ground every claim in actual XML, source\npaths, or hook script content. Cite line numbers for blockers.",{"type":47,"tag":108,"props":2161,"children":2162},{},[2163,2165,2170],{"type":52,"value":2164},"✅ Treat the generator's input contract as authoritative. Build the YAML\nagainst ",{"type":47,"tag":61,"props":2166,"children":2168},{"className":2167},[],[2169],{"type":52,"value":74},{"type":52,"value":129},{"type":47,"tag":108,"props":2172,"children":2173},{},[2174],{"type":52,"value":2175},"✅ Reuse wire-format strings from an official Capacitor equivalent when one\nexists. Mirror enum casing, event names, and method names exactly.",{"type":47,"tag":108,"props":2177,"children":2178},{},[2179],{"type":52,"value":2180},"✅ Classify hooks by reading the referenced script, not by filename.",{"type":47,"tag":108,"props":2182,"children":2183},{},[2184],{"type":52,"value":2185},"✅ Default to Mode B (side-by-side). Move to Mode A only on explicit user\nopt-in with a writable working copy.",{"type":47,"tag":108,"props":2187,"children":2188},{},[2189],{"type":52,"value":2190},"✅ Stop at the Phase 10 checkpoint if blockers or Tier 3 hooks exist.",{"type":47,"tag":108,"props":2192,"children":2193},{},[2194],{"type":52,"value":2195},"✅ Capture both blockers and warnings; only blockers stop handoff.",{"type":47,"tag":108,"props":2197,"children":2198},{},[2199],{"type":52,"value":2200},"✅ Note manual native setup steps consumers will need after migration\n(Info.plist keys, AndroidManifest entries, Podfile \u002F Gradle additions).",{"type":47,"tag":1225,"props":2202,"children":2204},{"id":2203},"dont",[2205],{"type":52,"value":2206},"DON'T",{"type":47,"tag":104,"props":2208,"children":2209},{},[2210,2215,2220,2231,2236,2249,2262,2267,2272],{"type":47,"tag":108,"props":2211,"children":2212},{},[2213],{"type":52,"value":2214},"❌ Emit native Capacitor code (Swift, Kotlin, Java, TypeScript) from\nthis skill. The generator owns code emission.",{"type":47,"tag":108,"props":2216,"children":2217},{},[2218],{"type":52,"value":2219},"❌ Invent YAML fields or rename ones the generator already defines.",{"type":47,"tag":108,"props":2221,"children":2222},{},[2223,2225,2230],{"type":52,"value":2224},"❌ Re-derive wire-format strings from human-friendly names when an\nofficial Capacitor equivalent exists. Read its ",{"type":47,"tag":61,"props":2226,"children":2228},{"className":2227},[],[2229],{"type":52,"value":415},{"type":52,"value":129},{"type":47,"tag":108,"props":2232,"children":2233},{},[2234],{"type":52,"value":2235},"❌ Classify a hook as Tier 1\u002F2 without opening the referenced script.",{"type":47,"tag":108,"props":2237,"children":2238},{},[2239,2241,2247],{"type":52,"value":2240},"❌ Emit a YAML plan that lists ",{"type":47,"tag":61,"props":2242,"children":2244},{"className":2243},[],[2245],{"type":52,"value":2246},"complexity: simple",{"type":52,"value":2248}," while hiding a\nproprietary AAR or interactive setup hook.",{"type":47,"tag":108,"props":2250,"children":2251},{},[2252,2254,2260],{"type":52,"value":2253},"❌ Add Capacitor-version-specific guidance here, the generator skill owns\ngenerator-side rules (name parity, Java filename, ",{"type":47,"tag":61,"props":2255,"children":2257},{"className":2256},[],[2258],{"type":52,"value":2259},"notifyListeners",{"type":52,"value":2261},"\nvisibility, etc.). Reference, don't duplicate.",{"type":47,"tag":108,"props":2263,"children":2264},{},[2265],{"type":52,"value":2266},"❌ Invoke the generator silently. Phase 10 is a mandatory user\ncheckpoint; do not skip it.",{"type":47,"tag":108,"props":2268,"children":2269},{},[2270],{"type":52,"value":2271},"❌ Invoke the generator with blockers or Tier 3 hooks unresolved.",{"type":47,"tag":108,"props":2273,"children":2274},{},[2275],{"type":52,"value":2276},"❌ Commit, push, or publish generator output from this skill.",{"type":47,"tag":86,"props":2278,"children":2280},{"id":2279},"error-handling",[2281],{"type":52,"value":2282},"Error Handling",{"type":47,"tag":199,"props":2284,"children":2285},{},[2286,2302],{"type":47,"tag":203,"props":2287,"children":2288},{},[2289],{"type":47,"tag":207,"props":2290,"children":2291},{},[2292,2297],{"type":47,"tag":211,"props":2293,"children":2294},{},[2295],{"type":52,"value":2296},"Symptom",{"type":47,"tag":211,"props":2298,"children":2299},{},[2300],{"type":52,"value":2301},"Fix",{"type":47,"tag":222,"props":2303,"children":2304},{},[2305,2323,2343,2363,2391,2442,2463,2484,2517,2550,2620,2684,2737,2814,2875,2936,2969,3012,3063,3136,3167,3206,3285,3339,3404,3452,3487,3552,3571,3592,3612,3632,3659,3672,3692,3734,3747,3760,3812,3832,3852,3877],{"type":47,"tag":207,"props":2306,"children":2307},{},[2308,2318],{"type":47,"tag":229,"props":2309,"children":2310},{},[2311,2316],{"type":47,"tag":61,"props":2312,"children":2314},{"className":2313},[],[2315],{"type":52,"value":244},{"type":52,"value":2317}," missing or malformed",{"type":47,"tag":229,"props":2319,"children":2320},{},[2321],{"type":52,"value":2322},"Stop. Ask for the canonical plugin source. Do not infer a contract from README marketing copy.",{"type":47,"tag":207,"props":2324,"children":2325},{},[2326,2338],{"type":47,"tag":229,"props":2327,"children":2328},{},[2329,2331,2336],{"type":52,"value":2330},"Source files referenced by ",{"type":47,"tag":61,"props":2332,"children":2334},{"className":2333},[],[2335],{"type":52,"value":244},{"type":52,"value":2337}," are not present on disk",{"type":47,"tag":229,"props":2339,"children":2340},{},[2341],{"type":52,"value":2342},"Stop. Report missing files by path. The plan is incomplete without them; do not proceed to Phase 9.",{"type":47,"tag":207,"props":2344,"children":2345},{},[2346,2351],{"type":47,"tag":229,"props":2347,"children":2348},{},[2349],{"type":52,"value":2350},"Hooks reference scripts that cannot be opened or are obfuscated",{"type":47,"tag":229,"props":2352,"children":2353},{},[2354,2356,2361],{"type":52,"value":2355},"Classify as Tier 3 and add to ",{"type":47,"tag":61,"props":2357,"children":2359},{"className":2358},[],[2360],{"type":52,"value":1172},{"type":52,"value":2362}," with the script path. Do not guess based on the hook type.",{"type":47,"tag":207,"props":2364,"children":2365},{},[2366,2386],{"type":47,"tag":229,"props":2367,"children":2368},{},[2369,2371,2376,2378,2384],{"type":52,"value":2370},"Plugin declares ",{"type":47,"tag":61,"props":2372,"children":2374},{"className":2373},[],[2375],{"type":52,"value":1400},{"type":52,"value":2377}," for a private\u002Fproprietary AAR or ",{"type":47,"tag":61,"props":2379,"children":2381},{"className":2380},[],[2382],{"type":52,"value":2383},".framework",{"type":52,"value":2385}," requiring runtime credentials the user does not have",{"type":47,"tag":229,"props":2387,"children":2388},{},[2389],{"type":52,"value":2390},"Record as a blocker. Note vendor contact requirement. Do not silently swap for a public alternative.",{"type":47,"tag":207,"props":2392,"children":2393},{},[2394,2413],{"type":47,"tag":229,"props":2395,"children":2396},{},[2397,2399,2404,2405,2411],{"type":52,"value":2398},"Plugin vendors a binary in-tree (e.g., ",{"type":47,"tag":61,"props":2400,"children":2402},{"className":2401},[],[2403],{"type":52,"value":1029},{"type":52,"value":495},{"type":47,"tag":61,"props":2406,"children":2408},{"className":2407},[],[2409],{"type":52,"value":2410},"src\u002Fandroid\u002Flibs\u002FFoo.aar",{"type":52,"value":2412},") but it is publicly distributed",{"type":47,"tag":229,"props":2414,"children":2415},{},[2416,2418,2424,2426,2432,2434,2440],{"type":52,"value":2417},"Not a blocker. Carry the binary forward and record its path under ",{"type":47,"tag":61,"props":2419,"children":2421},{"className":2420},[],[2422],{"type":52,"value":2423},"migration.source_files.{ios,android}",{"type":52,"value":2425},". The generator copies it into the Capacitor plugin's ",{"type":47,"tag":61,"props":2427,"children":2429},{"className":2428},[],[2430],{"type":52,"value":2431},"ios\u002F",{"type":52,"value":2433}," or ",{"type":47,"tag":61,"props":2435,"children":2437},{"className":2436},[],[2438],{"type":52,"value":2439},"android\u002Flibs\u002F",{"type":52,"value":2441}," directory.",{"type":47,"tag":207,"props":2443,"children":2444},{},[2445,2450],{"type":47,"tag":229,"props":2446,"children":2447},{},[2448],{"type":52,"value":2449},"Plugin pulls Android deps from a custom Maven repository (Azure DevOps, JFrog, etc.)",{"type":47,"tag":229,"props":2451,"children":2452},{},[2453,2455,2461],{"type":52,"value":2454},"Record the URL under ",{"type":47,"tag":61,"props":2456,"children":2458},{"className":2457},[],[2459],{"type":52,"value":2460},"migration.dependencies.android.maven_repos",{"type":52,"value":2462},". Warning, not blocker, when the URL is reachable without auth. Blocker when auth is required and credentials are not provided.",{"type":47,"tag":207,"props":2464,"children":2465},{},[2466,2479],{"type":47,"tag":229,"props":2467,"children":2468},{},[2469,2471,2477],{"type":52,"value":2470},"Plugin uses Support Library (",{"type":47,"tag":61,"props":2472,"children":2474},{"className":2473},[],[2475],{"type":52,"value":2476},"android.support.*",{"type":52,"value":2478},") coordinates",{"type":47,"tag":229,"props":2480,"children":2481},{},[2482],{"type":52,"value":2483},"Record as a blocker unless Jetifier acceptance is confirmed by the user. Capacitor expects AndroidX.",{"type":47,"tag":207,"props":2485,"children":2486},{},[2487,2498],{"type":47,"tag":229,"props":2488,"children":2489},{},[2490,2492,2497],{"type":52,"value":2491},"Cordova plugin has an official Capacitor equivalent (",{"type":47,"tag":61,"props":2493,"children":2495},{"className":2494},[],[2496],{"type":52,"value":407},{"type":52,"value":1116},{"type":47,"tag":229,"props":2499,"children":2500},{},[2501,2503,2508,2510,2515],{"type":52,"value":2502},"Read the equivalent's ",{"type":47,"tag":61,"props":2504,"children":2506},{"className":2505},[],[2507],{"type":52,"value":415},{"type":52,"value":2509}," and native source. Pin method names, enum values, event names, and error codes in the YAML. Add the equivalent's package as ",{"type":47,"tag":61,"props":2511,"children":2513},{"className":2512},[],[2514],{"type":52,"value":601},{"type":52,"value":2516}," for the reviewer.",{"type":47,"tag":207,"props":2518,"children":2519},{},[2520,2545],{"type":47,"tag":229,"props":2521,"children":2522},{},[2523,2525,2530,2532,2537,2538,2543],{"type":52,"value":2524},"Plugin declares both ",{"type":47,"tag":61,"props":2526,"children":2528},{"className":2527},[],[2529],{"type":52,"value":386},{"type":52,"value":2531}," entries and ",{"type":47,"tag":61,"props":2533,"children":2535},{"className":2534},[],[2536],{"type":52,"value":428},{"type":52,"value":952},{"type":47,"tag":61,"props":2539,"children":2541},{"className":2540},[],[2542],{"type":52,"value":436},{"type":52,"value":2544}," entries (hybrid plugin)",{"type":47,"tag":229,"props":2546,"children":2547},{},[2548],{"type":52,"value":2549},"The Capacitor scripts already exist. Record them as Tier 1 \"already converted\" hooks. Ask the user whether to reuse, rewrite, or merge them with any newly migrated Cordova hooks.",{"type":47,"tag":207,"props":2551,"children":2552},{},[2553,2598],{"type":47,"tag":229,"props":2554,"children":2555},{},[2556,2558,2563,2565,2571,2573,2578,2579,2584,2585,2590,2592],{"type":52,"value":2557},"Plugin uses ",{"type":47,"tag":61,"props":2559,"children":2561},{"className":2560},[],[2562],{"type":52,"value":145},{"type":52,"value":2564}," to mutate ",{"type":47,"tag":61,"props":2566,"children":2568},{"className":2567},[],[2569],{"type":52,"value":2570},"AndroidManifest.xml",{"type":52,"value":2572}," with ",{"type":47,"tag":61,"props":2574,"children":2576},{"className":2575},[],[2577],{"type":52,"value":675},{"type":52,"value":495},{"type":47,"tag":61,"props":2580,"children":2582},{"className":2581},[],[2583],{"type":52,"value":682},{"type":52,"value":495},{"type":47,"tag":61,"props":2586,"children":2588},{"className":2587},[],[2589],{"type":52,"value":689},{"type":52,"value":2591},", or ",{"type":47,"tag":61,"props":2593,"children":2595},{"className":2594},[],[2596],{"type":52,"value":2597},"\u003Cprovider>",{"type":47,"tag":229,"props":2599,"children":2600},{},[2601,2611,2613,2618],{"type":47,"tag":98,"props":2602,"children":2603},{},[2604,2606],{"type":52,"value":2605},"Goes in the plugin's own ",{"type":47,"tag":61,"props":2607,"children":2609},{"className":2608},[],[2610],{"type":52,"value":719},{"type":52,"value":2612},", Gradle manifest merger merges into the host app automatically. No host-app step. Record under ",{"type":47,"tag":61,"props":2614,"children":2616},{"className":2615},[],[2617],{"type":52,"value":601},{"type":52,"value":2619}," for the generator to emit.",{"type":47,"tag":207,"props":2621,"children":2622},{},[2623,2661],{"type":47,"tag":229,"props":2624,"children":2625},{},[2626,2627,2632,2633,2639,2641,2646,2647,2652,2653,2659],{"type":52,"value":2557},{"type":47,"tag":61,"props":2628,"children":2630},{"className":2629},[],[2631],{"type":52,"value":145},{"type":52,"value":2564},{"type":47,"tag":61,"props":2634,"children":2636},{"className":2635},[],[2637],{"type":52,"value":2638},"Info.plist",{"type":52,"value":2640}," with an Apple-required privacy string (",{"type":47,"tag":61,"props":2642,"children":2644},{"className":2643},[],[2645],{"type":52,"value":744},{"type":52,"value":495},{"type":47,"tag":61,"props":2648,"children":2650},{"className":2649},[],[2651],{"type":52,"value":751},{"type":52,"value":495},{"type":47,"tag":61,"props":2654,"children":2656},{"className":2655},[],[2657],{"type":52,"value":2658},"NSMicrophoneUsageDescription",{"type":52,"value":2660},", etc.)",{"type":47,"tag":229,"props":2662,"children":2663},{},[2664,2669,2671,2676,2678,2683],{"type":47,"tag":98,"props":2665,"children":2666},{},[2667],{"type":52,"value":2668},"Host-app Info.plist",{"type":52,"value":2670},", Apple App Store requires these on the host app's plist, not the plugin's. Record under ",{"type":47,"tag":61,"props":2672,"children":2674},{"className":2673},[],[2675],{"type":52,"value":601},{"type":52,"value":2677}," and document a copy-paste snippet in ",{"type":47,"tag":61,"props":2679,"children":2681},{"className":2680},[],[2682],{"type":52,"value":66},{"type":52,"value":129},{"type":47,"tag":207,"props":2685,"children":2686},{},[2687,2712],{"type":47,"tag":229,"props":2688,"children":2689},{},[2690,2691,2696,2697,2702,2704,2710],{"type":52,"value":2557},{"type":47,"tag":61,"props":2692,"children":2694},{"className":2693},[],[2695],{"type":52,"value":145},{"type":52,"value":2564},{"type":47,"tag":61,"props":2698,"children":2700},{"className":2699},[],[2701],{"type":52,"value":2638},{"type":52,"value":2703}," with consumer-specific values (Apple Pay merchant ID, OAuth client ID, analytics key) via ",{"type":47,"tag":61,"props":2705,"children":2707},{"className":2706},[],[2708],{"type":52,"value":2709},"$VAR",{"type":52,"value":2711}," install-time placeholders",{"type":47,"tag":229,"props":2713,"children":2714},{},[2715,2720,2722,2728,2730,2735],{"type":47,"tag":98,"props":2716,"children":2717},{},[2718],{"type":52,"value":2719},"Runtime config JSON file",{"type":52,"value":2721}," pattern is strongly preferred: a ",{"type":47,"tag":61,"props":2723,"children":2725},{"className":2724},[],[2726],{"type":52,"value":2727},"\u003CPlugin>Configuration.json",{"type":52,"value":2729}," consumed by a hybrid ",{"type":47,"tag":61,"props":2731,"children":2733},{"className":2732},[],[2734],{"type":52,"value":884},{"type":52,"value":2736}," script. Reuse an existing script from the Cordova plugin if present, else propose a one-screen template. Keeps consumer-specific values out of the plist entirely.",{"type":47,"tag":207,"props":2738,"children":2739},{},[2740,2791],{"type":47,"tag":229,"props":2741,"children":2742},{},[2743,2744,2749,2751,2757,2758,2764,2765,2771,2773,2779,2780,2785,2786],{"type":52,"value":2557},{"type":47,"tag":61,"props":2745,"children":2747},{"className":2746},[],[2748],{"type":52,"value":145},{"type":52,"value":2750}," to mutate entitlements plists (",{"type":47,"tag":61,"props":2752,"children":2754},{"className":2753},[],[2755],{"type":52,"value":2756},"*-Debug.plist",{"type":52,"value":495},{"type":47,"tag":61,"props":2759,"children":2761},{"className":2760},[],[2762],{"type":52,"value":2763},"*-Release.plist",{"type":52,"value":495},{"type":47,"tag":61,"props":2766,"children":2768},{"className":2767},[],[2769],{"type":52,"value":2770},"*-Entitlements.plist",{"type":52,"value":2772},") for capabilities like ",{"type":47,"tag":61,"props":2774,"children":2776},{"className":2775},[],[2777],{"type":52,"value":2778},"com.apple.developer.in-app-payments",{"type":52,"value":495},{"type":47,"tag":61,"props":2781,"children":2783},{"className":2782},[],[2784],{"type":52,"value":759},{"type":52,"value":495},{"type":47,"tag":61,"props":2787,"children":2789},{"className":2788},[],[2790],{"type":52,"value":766},{"type":47,"tag":229,"props":2792,"children":2793},{},[2794,2799,2801,2806,2808,2813],{"type":47,"tag":98,"props":2795,"children":2796},{},[2797],{"type":52,"value":2798},"Host-app capability + entitlement.",{"type":52,"value":2800}," Record under ",{"type":47,"tag":61,"props":2802,"children":2804},{"className":2803},[],[2805],{"type":52,"value":601},{"type":52,"value":2807},"; document the exact Xcode capability the consumer must enable (Apple Pay, Push Notifications, App Groups, etc.) and the entitlement value in ",{"type":47,"tag":61,"props":2809,"children":2811},{"className":2810},[],[2812],{"type":52,"value":66},{"type":52,"value":129},{"type":47,"tag":207,"props":2815,"children":2816},{},[2817,2835],{"type":47,"tag":229,"props":2818,"children":2819},{},[2820,2821,2826,2827,2833],{"type":52,"value":2370},{"type":47,"tag":61,"props":2822,"children":2824},{"className":2823},[],[2825],{"type":52,"value":1400},{"type":52,"value":2572},{"type":47,"tag":61,"props":2828,"children":2830},{"className":2829},[],[2831],{"type":52,"value":2832},"weak=\"true\"",{"type":52,"value":2834}," for iOS",{"type":47,"tag":229,"props":2836,"children":2837},{},[2838,2843,2845,2851,2853,2858,2860,2865,2867,2873],{"type":47,"tag":98,"props":2839,"children":2840},{},[2841],{"type":52,"value":2842},"Plugin's own podspec.",{"type":52,"value":2844}," Record in ",{"type":47,"tag":61,"props":2846,"children":2848},{"className":2847},[],[2849],{"type":52,"value":2850},"dependencies.ios.system_frameworks",{"type":52,"value":2852}," and add a ",{"type":47,"tag":61,"props":2854,"children":2856},{"className":2855},[],[2857],{"type":52,"value":601},{"type":52,"value":2859}," line so the generator emits ",{"type":47,"tag":61,"props":2861,"children":2863},{"className":2862},[],[2864],{"type":52,"value":660},{"type":52,"value":2866}," instead of ",{"type":47,"tag":61,"props":2868,"children":2870},{"className":2869},[],[2871],{"type":52,"value":2872},"s.framework",{"type":52,"value":2874},". No host-app step.",{"type":47,"tag":207,"props":2876,"children":2877},{},[2878,2912],{"type":47,"tag":229,"props":2879,"children":2880},{},[2881,2882,2887,2888,2894,2896,2902,2904,2910],{"type":52,"value":2557},{"type":47,"tag":61,"props":2883,"children":2885},{"className":2884},[],[2886],{"type":52,"value":1423},{"type":52,"value":2572},{"type":47,"tag":61,"props":2889,"children":2891},{"className":2890},[],[2892],{"type":52,"value":2893},"mode=\"merge\"",{"type":52,"value":2895}," to add an ",{"type":47,"tag":61,"props":2897,"children":2899},{"className":2898},[],[2900],{"type":52,"value":2901},"android:requestLegacyExternalStorage",{"type":52,"value":2903}," or similar attribute to the host ",{"type":47,"tag":61,"props":2905,"children":2907},{"className":2906},[],[2908],{"type":52,"value":2909},"\u003Capplication>",{"type":52,"value":2911}," element",{"type":47,"tag":229,"props":2913,"children":2914},{},[2915,2920,2922,2927,2929,2934],{"type":47,"tag":98,"props":2916,"children":2917},{},[2918],{"type":52,"value":2919},"Host-app AndroidManifest",{"type":52,"value":2921}," if the attribute applies to the host app; otherwise plugin's own AndroidManifest. Record in ",{"type":47,"tag":61,"props":2923,"children":2925},{"className":2924},[],[2926],{"type":52,"value":601},{"type":52,"value":2928}," with the exact attribute and parent so ",{"type":47,"tag":61,"props":2930,"children":2932},{"className":2931},[],[2933],{"type":52,"value":66},{"type":52,"value":2935}," can include a copy-paste snippet.",{"type":47,"tag":207,"props":2937,"children":2938},{},[2939,2949],{"type":47,"tag":229,"props":2940,"children":2941},{},[2942,2943],{"type":52,"value":2557},{"type":47,"tag":61,"props":2944,"children":2946},{"className":2945},[],[2947],{"type":52,"value":2948},"\u003Cjs-module runs=\"true\">",{"type":47,"tag":229,"props":2950,"children":2951},{},[2952,2954,2959,2961,2967],{"type":52,"value":2953},"Add to ",{"type":47,"tag":61,"props":2955,"children":2957},{"className":2956},[],[2958],{"type":52,"value":868},{"type":52,"value":2960},". Recommend an explicit ",{"type":47,"tag":61,"props":2962,"children":2964},{"className":2963},[],[2965],{"type":52,"value":2966},"initialize()",{"type":52,"value":2968}," method or constructor-side init in the web layer.",{"type":47,"tag":207,"props":2970,"children":2971},{},[2972,2992],{"type":47,"tag":229,"props":2973,"children":2974},{},[2975,2977,2982,2984,2990],{"type":52,"value":2976},"Plugin has multiple ",{"type":47,"tag":61,"props":2978,"children":2980},{"className":2979},[],[2981],{"type":52,"value":1454},{"type":52,"value":2983}," entries with multiple ",{"type":47,"tag":61,"props":2985,"children":2987},{"className":2986},[],[2988],{"type":52,"value":2989},"\u003Cclobbers>",{"type":52,"value":2991}," targets (e.g., constants module + main module)",{"type":47,"tag":229,"props":2993,"children":2994},{},[2995,2997,3003,3005,3010],{"type":52,"value":2996},"Collapse into a single ",{"type":47,"tag":61,"props":2998,"children":3000},{"className":2999},[],[3001],{"type":52,"value":3002},"registerPlugin()",{"type":52,"value":3004}," registration. Export constants from ",{"type":47,"tag":61,"props":3006,"children":3008},{"className":3007},[],[3009],{"type":52,"value":415},{"type":52,"value":3011}," next to the plugin interface. Capacitor has no analog to multi-clobber.",{"type":47,"tag":207,"props":3013,"children":3014},{},[3015,3026],{"type":47,"tag":229,"props":3016,"children":3017},{},[3018,3020],{"type":52,"value":3019},"Plugin includes Android resource files via ",{"type":47,"tag":61,"props":3021,"children":3023},{"className":3022},[],[3024],{"type":52,"value":3025},"\u003Csource-file target-dir=\"res\u002F...\">",{"type":47,"tag":229,"props":3027,"children":3028},{},[3029,3031,3037,3039,3045,3047,3053,3055,3061],{"type":52,"value":3030},"Record under ",{"type":47,"tag":61,"props":3032,"children":3034},{"className":3033},[],[3035],{"type":52,"value":3036},"migration.source_files.android",{"type":52,"value":3038}," with the destination ",{"type":47,"tag":61,"props":3040,"children":3042},{"className":3041},[],[3043],{"type":52,"value":3044},"res\u002F",{"type":52,"value":3046}," subpath. The generator copies them into ",{"type":47,"tag":61,"props":3048,"children":3050},{"className":3049},[],[3051],{"type":52,"value":3052},"android\u002Fsrc\u002Fmain\u002Fres\u002F\u003Csubpath>\u002F",{"type":52,"value":3054},". Common for ",{"type":47,"tag":61,"props":3056,"children":3058},{"className":3057},[],[3059],{"type":52,"value":3060},"FileProvider",{"type":52,"value":3062}," paths and themes.",{"type":47,"tag":207,"props":3064,"children":3065},{},[3066,3097],{"type":47,"tag":229,"props":3067,"children":3068},{},[3069,3070,3076,3078,3084,3086,3091,3092],{"type":52,"value":2557},{"type":47,"tag":61,"props":3071,"children":3073},{"className":3072},[],[3074],{"type":52,"value":3075},"\u003Cpreference name=\"...\" default=\"...\">",{"type":52,"value":3077}," with install-time variable substitution (",{"type":47,"tag":61,"props":3079,"children":3081},{"className":3080},[],[3082],{"type":52,"value":3083},"${VAR}",{"type":52,"value":3085}," in plugin.xml) referenced inside ",{"type":47,"tag":61,"props":3087,"children":3089},{"className":3088},[],[3090],{"type":52,"value":853},{"type":52,"value":2433},{"type":47,"tag":61,"props":3093,"children":3095},{"className":3094},[],[3096],{"type":52,"value":2570},{"type":47,"tag":229,"props":3098,"children":3099},{},[3100,3102,3106,3108,3113,3114,3119,3121,3127,3129,3135],{"type":52,"value":3101},"Prefer the ",{"type":47,"tag":98,"props":3103,"children":3104},{},[3105],{"type":52,"value":860},{"type":52,"value":3107}," pattern (consumer drops their values into a ",{"type":47,"tag":61,"props":3109,"children":3111},{"className":3110},[],[3112],{"type":52,"value":2727},{"type":52,"value":2729},{"type":47,"tag":61,"props":3115,"children":3117},{"className":3116},[],[3118],{"type":52,"value":884},{"type":52,"value":3120}," script). Reuse an existing script from the Cordova plugin if present. Fallback: ",{"type":47,"tag":61,"props":3122,"children":3124},{"className":3123},[],[3125],{"type":52,"value":3126},"capacitor.config.json",{"type":52,"value":3128}," runtime config under ",{"type":47,"tag":61,"props":3130,"children":3132},{"className":3131},[],[3133],{"type":52,"value":3134},"plugins.\u003CPluginJSName>",{"type":52,"value":129},{"type":47,"tag":207,"props":3137,"children":3138},{},[3139,3157],{"type":47,"tag":229,"props":3140,"children":3141},{},[3142,3143,3149,3151],{"type":52,"value":2557},{"type":47,"tag":61,"props":3144,"children":3146},{"className":3145},[],[3147],{"type":52,"value":3148},"\u003Cpreference name=\"ANDROIDX_CORE_VERSION\" default=\"1.18.0\">",{"type":52,"value":3150}," (or similar build-time-only version pins) referenced inside the plugin's own ",{"type":47,"tag":61,"props":3152,"children":3154},{"className":3153},[],[3155],{"type":52,"value":3156},"build.gradle",{"type":47,"tag":229,"props":3158,"children":3159},{},[3160,3165],{"type":47,"tag":98,"props":3161,"children":3162},{},[3163],{"type":52,"value":3164},"Plugin's own build.gradle",{"type":52,"value":3166},", pin the version literally in the generated Gradle file. No host-app step, no runtime config. Consumer never sees this.",{"type":47,"tag":207,"props":3168,"children":3169},{},[3170,3187],{"type":47,"tag":229,"props":3171,"children":3172},{},[3173,3175,3180,3181,3186],{"type":52,"value":3174},"Plugin's native handler parses a stringified JSON blob (",{"type":47,"tag":61,"props":3176,"children":3178},{"className":3177},[],[3179],{"type":52,"value":457},{"type":52,"value":495},{"type":47,"tag":61,"props":3182,"children":3184},{"className":3183},[],[3185],{"type":52,"value":464},{"type":52,"value":1116},{"type":47,"tag":229,"props":3188,"children":3189},{},[3190,3192,3197,3199,3204],{"type":52,"value":3191},"Map the parsed shape to a strongly-typed ",{"type":47,"tag":61,"props":3193,"children":3195},{"className":3194},[],[3196],{"type":52,"value":472},{"type":52,"value":3198}," interface, never ",{"type":47,"tag":61,"props":3200,"children":3202},{"className":3201},[],[3203],{"type":52,"value":480},{"type":52,"value":3205},". Capture the schema from the native parsing site (Kotlin data class or Swift struct).",{"type":47,"tag":207,"props":3207,"children":3208},{},[3209,3244],{"type":47,"tag":229,"props":3210,"children":3211},{},[3212,3214,3219,3221,3227,3229,3235,3237,3243],{"type":52,"value":3213},"One JS method dispatches to multiple ",{"type":47,"tag":61,"props":3215,"children":3217},{"className":3216},[],[3218],{"type":52,"value":1636},{"type":52,"value":3220}," action names based on ",{"type":47,"tag":61,"props":3222,"children":3224},{"className":3223},[],[3225],{"type":52,"value":3226},"typeof param",{"type":52,"value":3228}," (e.g., ",{"type":47,"tag":61,"props":3230,"children":3232},{"className":3231},[],[3233],{"type":52,"value":3234},"vibrate(num)",{"type":52,"value":3236}," vs ",{"type":47,"tag":61,"props":3238,"children":3240},{"className":3239},[],[3241],{"type":52,"value":3242},"vibrate([...])",{"type":52,"value":1116},{"type":47,"tag":229,"props":3245,"children":3246},{},[3247,3249,3255,3256,3262,3263,3269,3271,3276,3278,3283],{"type":52,"value":3248},"Split into multiple typed Capacitor methods, ",{"type":47,"tag":61,"props":3250,"children":3252},{"className":3251},[],[3253],{"type":52,"value":3254},"vibrate({ duration })",{"type":52,"value":495},{"type":47,"tag":61,"props":3257,"children":3259},{"className":3258},[],[3260],{"type":52,"value":3261},"vibrateWithPattern({ pattern, repeat })",{"type":52,"value":495},{"type":47,"tag":61,"props":3264,"children":3266},{"className":3265},[],[3267],{"type":52,"value":3268},"cancelVibration()",{"type":52,"value":3270},". Record the split in ",{"type":47,"tag":61,"props":3272,"children":3274},{"className":3273},[],[3275],{"type":52,"value":1089},{"type":52,"value":3277}," and add to ",{"type":47,"tag":61,"props":3279,"children":3281},{"className":3280},[],[3282],{"type":52,"value":868},{"type":52,"value":3284}," as a consumer-facing breaking change.",{"type":47,"tag":207,"props":3286,"children":3287},{},[3288,3293],{"type":47,"tag":229,"props":3289,"children":3290},{},[3291],{"type":52,"value":3292},"Generator rejects YAML with \"bad indentation\" or \"mapping entry\" parse error",{"type":47,"tag":229,"props":3294,"children":3295},{},[3296,3298,3303,3305,3310,3311,3316,3317,3322,3324,3330,3331,3337],{"type":52,"value":3297},"A ",{"type":47,"tag":61,"props":3299,"children":3301},{"className":3300},[],[3302],{"type":52,"value":1935},{"type":52,"value":3304}," entry contains unquoted JS syntax (",{"type":47,"tag":61,"props":3306,"children":3308},{"className":3307},[],[3309],{"type":52,"value":1109},{"type":52,"value":495},{"type":47,"tag":61,"props":3312,"children":3314},{"className":3313},[],[3315],{"type":52,"value":1123},{"type":52,"value":495},{"type":47,"tag":61,"props":3318,"children":3320},{"className":3319},[],[3321],{"type":52,"value":1137},{"type":52,"value":3323},", etc.). Quote every ",{"type":47,"tag":61,"props":3325,"children":3327},{"className":3326},[],[3328],{"type":52,"value":3329},"cordova:",{"type":52,"value":541},{"type":47,"tag":61,"props":3332,"children":3334},{"className":3333},[],[3335],{"type":52,"value":3336},"capacitor:",{"type":52,"value":3338}," value as a YAML string. The plan must be re-emitted; the generator cannot load it as-is.",{"type":47,"tag":207,"props":3340,"children":3341},{},[3342,3347],{"type":47,"tag":229,"props":3343,"children":3344},{},[3345],{"type":52,"value":3346},"Cordova native source requests runtime permissions but the Cordova JS surface has no permission methods",{"type":47,"tag":229,"props":3348,"children":3349},{},[3350,3352,3357,3359,3365,3367,3373,3374,3379,3381,3387,3389,3395,3397,3402],{"type":52,"value":3351},"Add ",{"type":47,"tag":61,"props":3353,"children":3355},{"className":3354},[],[3356],{"type":52,"value":539},{"type":52,"value":3358}," (",{"type":47,"tag":61,"props":3360,"children":3362},{"className":3361},[],[3363],{"type":52,"value":3364},"Promise\u003CPermissionStatus>",{"type":52,"value":3366},") and ",{"type":47,"tag":61,"props":3368,"children":3370},{"className":3369},[],[3371],{"type":52,"value":3372},"requestPermissions(options?)",{"type":52,"value":3358},{"type":47,"tag":61,"props":3375,"children":3377},{"className":3376},[],[3378],{"type":52,"value":3364},{"type":52,"value":3380},") to ",{"type":47,"tag":61,"props":3382,"children":3384},{"className":3383},[],[3385],{"type":52,"value":3386},"api.methods",{"type":52,"value":3388},", and a ",{"type":47,"tag":61,"props":3390,"children":3392},{"className":3391},[],[3393],{"type":52,"value":3394},"PermissionStatus",{"type":52,"value":3396}," interface to ",{"type":47,"tag":61,"props":3398,"children":3400},{"className":3399},[],[3401],{"type":52,"value":472},{"type":52,"value":3403},". Without these the migrated plugin will violate Capacitor convention and consumers will expect them.",{"type":47,"tag":207,"props":3405,"children":3406},{},[3407,3425],{"type":47,"tag":229,"props":3408,"children":3409},{},[3410,3412,3417,3418,3423],{"type":52,"value":3411},"Cordova native source has a helper class for metadata extraction (",{"type":47,"tag":61,"props":3413,"children":3415},{"className":3414},[],[3416],{"type":52,"value":567},{"type":52,"value":495},{"type":47,"tag":61,"props":3419,"children":3421},{"className":3420},[],[3422],{"type":52,"value":574},{"type":52,"value":3424},", etc.) but the Cordova JS docs don't list the resulting fields",{"type":47,"tag":229,"props":3426,"children":3427},{},[3428,3430,3436,3437,3443,3444,3450],{"type":52,"value":3429},"Read the native response-construction site. Add the metadata fields (typically ",{"type":47,"tag":61,"props":3431,"children":3433},{"className":3432},[],[3434],{"type":52,"value":3435},"exif?: any",{"type":52,"value":495},{"type":47,"tag":61,"props":3438,"children":3440},{"className":3439},[],[3441],{"type":52,"value":3442},"mimeType?",{"type":52,"value":495},{"type":47,"tag":61,"props":3445,"children":3447},{"className":3446},[],[3448],{"type":52,"value":3449},"size?",{"type":52,"value":3451},") to the result type. The Cordova JS docs frequently understate what the native side actually returns.",{"type":47,"tag":207,"props":3453,"children":3454},{},[3455,3460],{"type":47,"tag":229,"props":3456,"children":3457},{},[3458],{"type":52,"value":3459},"Official Capacitor equivalent's native source is more than 3× the LOC of the Cordova source",{"type":47,"tag":229,"props":3461,"children":3462},{},[3463,3465,3470,3472,3477,3479,3485],{"type":52,"value":3464},"Add a ",{"type":47,"tag":61,"props":3466,"children":3468},{"className":3467},[],[3469],{"type":52,"value":601},{"type":52,"value":3471}," entry warning the reviewer that a literal port will leave platform-specific behavior unimplemented (e.g., iOS ",{"type":47,"tag":61,"props":3473,"children":3475},{"className":3474},[],[3476],{"type":52,"value":609},{"type":52,"value":3478}," over ",{"type":47,"tag":61,"props":3480,"children":3482},{"className":3481},[],[3483],{"type":52,"value":3484},"AudioServicesPlaySystemSound",{"type":52,"value":3486},", Android pattern-based haptics over single-shot vibration). Recommend reviewing whether to retarget consumers to the official package.",{"type":47,"tag":207,"props":3488,"children":3489},{},[3490,3507],{"type":47,"tag":229,"props":3491,"children":3492},{},[3493,3495,3500,3502],{"type":52,"value":3494},"Cordova plugin.xml has ",{"type":47,"tag":61,"props":3496,"children":3498},{"className":3497},[],[3499],{"type":52,"value":912},{"type":52,"value":3501}," or any ",{"type":47,"tag":61,"props":3503,"children":3505},{"className":3504},[],[3506],{"type":52,"value":920},{"type":47,"tag":229,"props":3508,"children":3509},{},[3510,3512,3517,3519,3524,3526,3531,3533,3538,3540,3545,3546,3551],{"type":52,"value":3511},"Plugin already ships SPM support alongside CocoaPods. Lift its ",{"type":47,"tag":61,"props":3513,"children":3515},{"className":3514},[],[3516],{"type":52,"value":928},{"type":52,"value":3518}," dependencies into ",{"type":47,"tag":61,"props":3520,"children":3522},{"className":3521},[],[3523],{"type":52,"value":943},{"type":52,"value":3525},"; lift only pods without ",{"type":47,"tag":61,"props":3527,"children":3529},{"className":3528},[],[3530],{"type":52,"value":958},{"type":52,"value":3532}," into ",{"type":47,"tag":61,"props":3534,"children":3536},{"className":3535},[],[3537],{"type":52,"value":966},{"type":52,"value":3539},". Capacitor port must ship both ",{"type":47,"tag":61,"props":3541,"children":3543},{"className":3542},[],[3544],{"type":52,"value":928},{"type":52,"value":541},{"type":47,"tag":61,"props":3547,"children":3549},{"className":3548},[],[3550],{"type":52,"value":712},{"type":52,"value":129},{"type":47,"tag":207,"props":3553,"children":3554},{},[3555,3566],{"type":47,"tag":229,"props":3556,"children":3557},{},[3558,3559,3564],{"type":52,"value":2370},{"type":47,"tag":61,"props":3560,"children":3562},{"className":3561},[],[3563],{"type":52,"value":1438},{"type":52,"value":3565}," on another Cordova plugin",{"type":47,"tag":229,"props":3567,"children":3568},{},[3569],{"type":52,"value":3570},"Resolve the dependency target separately. If it lacks a Capacitor equivalent or migration plan, treat as blocker for the current plugin.",{"type":47,"tag":207,"props":3572,"children":3573},{},[3574,3579],{"type":47,"tag":229,"props":3575,"children":3576},{},[3577],{"type":52,"value":3578},"Plugin's iOS source is Objective-C only",{"type":47,"tag":229,"props":3580,"children":3581},{},[3582,3584,3590],{"type":52,"value":3583},"Record ",{"type":47,"tag":61,"props":3585,"children":3587},{"className":3586},[],[3588],{"type":52,"value":3589},"migration.language_modernization.ios: { from: objective_c, to: swift }",{"type":52,"value":3591},". Note bridging headers consumers may still need.",{"type":47,"tag":207,"props":3593,"children":3594},{},[3595,3600],{"type":47,"tag":229,"props":3596,"children":3597},{},[3598],{"type":52,"value":3599},"Plugin's Android source is Java only",{"type":47,"tag":229,"props":3601,"children":3602},{},[3603,3604,3610],{"type":52,"value":3583},{"type":47,"tag":61,"props":3605,"children":3607},{"className":3606},[],[3608],{"type":52,"value":3609},"migration.language_modernization.android: { from: java, to: kotlin }",{"type":52,"value":3611},". The generator will still produce Java if the user asks, but Kotlin is the default recommendation.",{"type":47,"tag":207,"props":3613,"children":3614},{},[3615,3620],{"type":47,"tag":229,"props":3616,"children":3617},{},[3618],{"type":52,"value":3619},"YAML rejected by the generator",{"type":47,"tag":229,"props":3621,"children":3622},{},[3623,3625,3630],{"type":52,"value":3624},"Re-read ",{"type":47,"tag":61,"props":3626,"children":3628},{"className":3627},[],[3629],{"type":52,"value":74},{"type":52,"value":3631},". Fix the YAML in this skill, not in the generator. Do not work around the contract.",{"type":47,"tag":207,"props":3633,"children":3634},{},[3635,3640],{"type":47,"tag":229,"props":3636,"children":3637},{},[3638],{"type":52,"value":3639},"Generator flags missing wire-format strings",{"type":47,"tag":229,"props":3641,"children":3642},{},[3643,3645,3650,3652,3657],{"type":52,"value":3644},"Re-read the official Capacitor equivalent's ",{"type":47,"tag":61,"props":3646,"children":3648},{"className":3647},[],[3649],{"type":52,"value":415},{"type":52,"value":3651},". Update ",{"type":47,"tag":61,"props":3653,"children":3655},{"className":3654},[],[3656],{"type":52,"value":472},{"type":52,"value":3658}," values verbatim. Do not \"translate\" from the human-friendly names.",{"type":47,"tag":207,"props":3660,"children":3661},{},[3662,3667],{"type":47,"tag":229,"props":3663,"children":3664},{},[3665],{"type":52,"value":3666},"User requests Mode A but the working copy is not under version control or is read-only",{"type":47,"tag":229,"props":3668,"children":3669},{},[3670],{"type":52,"value":3671},"Refuse Mode A. Recommend Mode B. Recovery from a botched in-place move without VCS is manual.",{"type":47,"tag":207,"props":3673,"children":3674},{},[3675,3680],{"type":47,"tag":229,"props":3676,"children":3677},{},[3678],{"type":52,"value":3679},"Plugin advertises features the source does not implement",{"type":47,"tag":229,"props":3681,"children":3682},{},[3683,3685,3690],{"type":52,"value":3684},"Trust the source. Record the advertised-but-unimplemented features under ",{"type":47,"tag":61,"props":3686,"children":3688},{"className":3687},[],[3689],{"type":52,"value":868},{"type":52,"value":3691},". Do not fabricate API methods to match documentation.",{"type":47,"tag":207,"props":3693,"children":3694},{},[3695,3700],{"type":47,"tag":229,"props":3696,"children":3697},{},[3698],{"type":52,"value":3699},"Hook classified as Tier 1 by filename but actually interactive",{"type":47,"tag":229,"props":3701,"children":3702},{},[3703,3705,3710,3711,3717,3719,3725,3726,3732],{"type":52,"value":3704},"Read the script source, not just the ",{"type":47,"tag":61,"props":3706,"children":3708},{"className":3707},[],[3709],{"type":52,"value":386},{"type":52,"value":952},{"type":47,"tag":61,"props":3712,"children":3714},{"className":3713},[],[3715],{"type":52,"value":3716},"name",{"type":52,"value":3718}," attribute. Anything that prompts via stdin, opens a TTY, or shells to ",{"type":47,"tag":61,"props":3720,"children":3722},{"className":3721},[],[3723],{"type":52,"value":3724},"read",{"type":52,"value":451},{"type":47,"tag":61,"props":3727,"children":3729},{"className":3728},[],[3730],{"type":52,"value":3731},"prompt",{"type":52,"value":3733}," is Tier 3.",{"type":47,"tag":207,"props":3735,"children":3736},{},[3737,3742],{"type":47,"tag":229,"props":3738,"children":3739},{},[3740],{"type":52,"value":3741},"Dep marked \"direct migration\" but the pod \u002F Gradle artifact is abandoned",{"type":47,"tag":229,"props":3743,"children":3744},{},[3745],{"type":52,"value":3746},"Cross-check the latest release date and Swift \u002F AndroidX compatibility before marking as direct. Anything not updated in 3+ years moves to \"replace\" or \"blocker\".",{"type":47,"tag":207,"props":3748,"children":3749},{},[3750,3755],{"type":47,"tag":229,"props":3751,"children":3752},{},[3753],{"type":52,"value":3754},"Complexity assessed \"Simple\" but plugin has 15+ public API methods",{"type":47,"tag":229,"props":3756,"children":3757},{},[3758],{"type":52,"value":3759},"Always count public API methods. Any plugin with more than 10 public methods is at least Moderate, regardless of other signals.",{"type":47,"tag":207,"props":3761,"children":3762},{},[3763,3768],{"type":47,"tag":229,"props":3764,"children":3765},{},[3766],{"type":52,"value":3767},"Blocker missed during analysis",{"type":47,"tag":229,"props":3769,"children":3770},{},[3771,3773,3778,3780,3785,3786,3791,3792,3797,3798,3803,3805,3810],{"type":52,"value":3772},"Always scan ",{"type":47,"tag":61,"props":3774,"children":3776},{"className":3775},[],[3777],{"type":52,"value":244},{"type":52,"value":3779}," for ",{"type":47,"tag":61,"props":3781,"children":3783},{"className":3782},[],[3784],{"type":52,"value":145},{"type":52,"value":495},{"type":47,"tag":61,"props":3787,"children":3789},{"className":3788},[],[3790],{"type":52,"value":1423},{"type":52,"value":495},{"type":47,"tag":61,"props":3793,"children":3795},{"className":3794},[],[3796],{"type":52,"value":2948},{"type":52,"value":495},{"type":47,"tag":61,"props":3799,"children":3801},{"className":3800},[],[3802],{"type":52,"value":386},{"type":52,"value":3804},", and ",{"type":47,"tag":61,"props":3806,"children":3808},{"className":3807},[],[3809],{"type":52,"value":1438},{"type":52,"value":3811},", these are the non-negotiable blocker candidates. Re-scan before Phase 9 if anything in the YAML looks too tidy.",{"type":47,"tag":207,"props":3813,"children":3814},{},[3815,3820],{"type":47,"tag":229,"props":3816,"children":3817},{},[3818],{"type":52,"value":3819},"Generator re-reads Cordova source during Phase 11",{"type":47,"tag":229,"props":3821,"children":3822},{},[3823,3825,3830],{"type":52,"value":3824},"The YAML plan is incomplete. Re-validate against ",{"type":47,"tag":61,"props":3826,"children":3828},{"className":3827},[],[3829],{"type":52,"value":74},{"type":52,"value":3831},"; include JS API signatures, native method mappings, permissions, dependencies, and blockers inline so the generator never has to look at the Cordova tree.",{"type":47,"tag":207,"props":3833,"children":3834},{},[3835,3840],{"type":47,"tag":229,"props":3836,"children":3837},{},[3838],{"type":52,"value":3839},"User halts at checkpoint due to a blocker they will not accept",{"type":47,"tag":229,"props":3841,"children":3842},{},[3843,3845,3850],{"type":52,"value":3844},"Document the blocker in ",{"type":47,"tag":61,"props":3846,"children":3848},{"className":3847},[],[3849],{"type":52,"value":66},{"type":52,"value":3851}," and stop. Do not invoke the generator. Capture the rejection reason so the next attempt can address it.",{"type":47,"tag":207,"props":3853,"children":3854},{},[3855,3860],{"type":47,"tag":229,"props":3856,"children":3857},{},[3858],{"type":52,"value":3859},"Complex plugin overwhelms generator context on a single invocation",{"type":47,"tag":229,"props":3861,"children":3862},{},[3863,3865,3869,3871,3876],{"type":52,"value":3864},"Use ",{"type":47,"tag":98,"props":3866,"children":3867},{},[3868],{"type":52,"value":1995},{"type":52,"value":3870},": invoke the generator once per platform (web → iOS → Android → final) with user checkpoints between each, not once for the whole plugin. See ",{"type":47,"tag":61,"props":3872,"children":3874},{"className":3873},[],[3875],{"type":52,"value":1215},{"type":52,"value":129},{"type":47,"tag":207,"props":3878,"children":3879},{},[3880,3885],{"type":47,"tag":229,"props":3881,"children":3882},{},[3883],{"type":52,"value":3884},"Mode A relocation conflicts with files in the Cordova repo (top-level name collision)",{"type":47,"tag":229,"props":3886,"children":3887},{},[3888],{"type":52,"value":3889},"Halt the chain. Either resolve manually with the user (rename, delete, or move conflicting files), or fall back to Mode B by re-running Phase 11 against a sibling directory.",{"type":47,"tag":86,"props":3891,"children":3893},{"id":3892},"related-skills",[3894],{"type":52,"value":3895},"Related Skills",{"type":47,"tag":104,"props":3897,"children":3898},{},[3899,3922],{"type":47,"tag":108,"props":3900,"children":3901},{},[3902,3907,3908,3913,3915,3920],{"type":47,"tag":61,"props":3903,"children":3905},{"className":3904},[],[3906],{"type":52,"value":82},{"type":52,"value":952},{"type":47,"tag":1316,"props":3909,"children":3910},{},[3911],{"type":52,"value":3912},"(required downstream dependency)",{"type":52,"value":3914},":\nPhase 11 invokes this skill via the Skill tool in structured mode\nwith the YAML plan produced in Phase 9. The generator's\n",{"type":47,"tag":61,"props":3916,"children":3918},{"className":3917},[],[3919],{"type":52,"value":1827},{"type":52,"value":3921}," is the authoritative shape for handoff.\nThis skill conforms and cites it but does not duplicate any\ngenerator-side rules.",{"type":47,"tag":108,"props":3923,"children":3924},{},[3925,3930,3931,3936,3938,3943,3945,3951,3953,3958],{"type":47,"tag":61,"props":3926,"children":3928},{"className":3927},[],[3929],{"type":52,"value":1200},{"type":52,"value":952},{"type":47,"tag":1316,"props":3932,"children":3933},{},[3934],{"type":52,"value":3935},"(optional downstream dependency, ODC path only)",{"type":52,"value":3937},":\nPhase 11a invokes this skill when ",{"type":47,"tag":61,"props":3939,"children":3941},{"className":3940},[],[3942],{"type":52,"value":1192},{"type":52,"value":3944},". It generates\n",{"type":47,"tag":61,"props":3946,"children":3948},{"className":3947},[],[3949],{"type":52,"value":3950},"buildAction.json",{"type":52,"value":3952}," for the Capacitor plugin's ",{"type":47,"tag":61,"props":3954,"children":3956},{"className":3955},[],[3957],{"type":52,"value":2040},{"type":52,"value":3959}," directory,\ncovering config-level native setup (manifest, plist, Gradle deps,\nentitlements) so the generator does not need to emit Capacitor hook\nequivalents for those items.",{"type":47,"tag":86,"props":3961,"children":3963},{"id":3962},"references",[3964],{"type":52,"value":3965},"References",{"type":47,"tag":104,"props":3967,"children":3968},{},[3969,3994,4030,4040,4050,4089,4100,4135,4159,4176],{"type":47,"tag":108,"props":3970,"children":3971},{},[3972,3977,3979,3984,3986,3992],{"type":47,"tag":61,"props":3973,"children":3975},{"className":3974},[],[3976],{"type":52,"value":1295},{"type":52,"value":3978},": Mode A (in-place with ",{"type":47,"tag":61,"props":3980,"children":3982},{"className":3981},[],[3983],{"type":52,"value":1006},{"type":52,"value":3985},") vs Mode B (side-by-side) directory layouts and ",{"type":47,"tag":61,"props":3987,"children":3989},{"className":3988},[],[3990],{"type":52,"value":3991},"git mv",{"type":52,"value":3993}," patterns.",{"type":47,"tag":108,"props":3995,"children":3996},{},[3997,4003,4004,4009,4010,4015,4016,4021,4022,4028],{"type":47,"tag":61,"props":3998,"children":4000},{"className":3999},[],[4001],{"type":52,"value":4002},"references\u002Funsupported-patterns.md",{"type":52,"value":906},{"type":47,"tag":61,"props":4005,"children":4007},{"className":4006},[],[4008],{"type":52,"value":145},{"type":52,"value":495},{"type":47,"tag":61,"props":4011,"children":4013},{"className":4012},[],[4014],{"type":52,"value":1423},{"type":52,"value":495},{"type":47,"tag":61,"props":4017,"children":4019},{"className":4018},[],[4020],{"type":52,"value":386},{"type":52,"value":495},{"type":47,"tag":61,"props":4023,"children":4025},{"className":4024},[],[4026],{"type":52,"value":4027},"\u003Cjs-module runs>",{"type":52,"value":4029},", preferences, permissions, and per-pattern blocker thresholds.",{"type":47,"tag":108,"props":4031,"children":4032},{},[4033,4038],{"type":47,"tag":61,"props":4034,"children":4036},{"className":4035},[],[4037],{"type":52,"value":832},{"type":52,"value":4039},": CocoaPods, SPM, system frameworks, Gradle coordinates, AAR\u002FJAR, custom Maven repos, and per-dependency blocker thresholds.",{"type":47,"tag":108,"props":4041,"children":4042},{},[4043,4048],{"type":47,"tag":61,"props":4044,"children":4046},{"className":4045},[],[4047],{"type":52,"value":394},{"type":52,"value":4049},": Three-tier hook classification (Tier 1 Capacitor hooks, Tier 2 npm scripts, Tier 3 blocker) with script analysis workflow.",{"type":47,"tag":108,"props":4051,"children":4052},{},[4053,4058,4060,4065,4067,4073,4075,4080,4081,4087],{"type":47,"tag":61,"props":4054,"children":4056},{"className":4055},[],[4057],{"type":52,"value":1612},{"type":52,"value":4059},": JavaScript bridge, iOS (",{"type":47,"tag":61,"props":4061,"children":4063},{"className":4062},[],[4064],{"type":52,"value":1676},{"type":52,"value":4066}," → ",{"type":47,"tag":61,"props":4068,"children":4070},{"className":4069},[],[4071],{"type":52,"value":4072},"CAPPlugin",{"type":52,"value":4074},"), Android (",{"type":47,"tag":61,"props":4076,"children":4078},{"className":4077},[],[4079],{"type":52,"value":1724},{"type":52,"value":4066},{"type":47,"tag":61,"props":4082,"children":4084},{"className":4083},[],[4085],{"type":52,"value":4086},"Plugin",{"type":52,"value":4088},"), and plugin.xml → package.json conversion.",{"type":47,"tag":108,"props":4090,"children":4091},{},[4092,4098],{"type":47,"tag":61,"props":4093,"children":4095},{"className":4094},[],[4096],{"type":52,"value":4097},"references\u002Fmigration-patterns.md",{"type":52,"value":4099},": Callback → Promise, permission handling, multi-platform configuration, and consistent error handling across platforms.",{"type":47,"tag":108,"props":4101,"children":4102},{},[4103,4108,4110,4115,4116,4121,4122,4127,4128,4133],{"type":47,"tag":61,"props":4104,"children":4106},{"className":4105},[],[4107],{"type":52,"value":1766},{"type":52,"value":4109},": Scoring rubric for ",{"type":47,"tag":61,"props":4111,"children":4113},{"className":4112},[],[4114],{"type":52,"value":1774},{"type":52,"value":451},{"type":47,"tag":61,"props":4117,"children":4119},{"className":4118},[],[4120],{"type":52,"value":1781},{"type":52,"value":451},{"type":47,"tag":61,"props":4123,"children":4125},{"className":4124},[],[4126],{"type":52,"value":1788},{"type":52,"value":451},{"type":47,"tag":61,"props":4129,"children":4131},{"className":4130},[],[4132],{"type":52,"value":1795},{"type":52,"value":4134}," and the inputs that move a plugin between buckets.",{"type":47,"tag":108,"props":4136,"children":4137},{},[4138,4143,4145,4150,4152,4157],{"type":47,"tag":61,"props":4139,"children":4141},{"className":4140},[],[4142],{"type":52,"value":1215},{"type":52,"value":4144},": Building the YAML against ",{"type":47,"tag":61,"props":4146,"children":4148},{"className":4147},[],[4149],{"type":52,"value":74},{"type":52,"value":4151},", the ",{"type":47,"tag":61,"props":4153,"children":4155},{"className":4154},[],[4156],{"type":52,"value":1871},{"type":52,"value":4158}," optional block, and the Phase 11 invocation pattern (standard vs incremental mode).",{"type":47,"tag":108,"props":4160,"children":4161},{},[4162,4167,4169,4174],{"type":47,"tag":61,"props":4163,"children":4165},{"className":4164},[],[4166],{"type":52,"value":2098},{"type":52,"value":4168},": Consolidating intermediate notes into ",{"type":47,"tag":61,"props":4170,"children":4172},{"className":4171},[],[4173],{"type":52,"value":66},{"type":52,"value":4175},", the Mode A relocation flow, archiving Cordova source, updating README, and the consumer-facing breaking-change checklist.",{"type":47,"tag":108,"props":4177,"children":4178},{},[4179,4185],{"type":47,"tag":61,"props":4180,"children":4182},{"className":4181},[],[4183],{"type":52,"value":4184},"references\u002Fexample-analysis.md",{"type":52,"value":4186},": Full worked example end-to-end, plugin.xml read, dependency analysis, hooks classification, YAML output, and generator handoff.",{"items":4188,"total":4224},[4189,4203,4215],{"slug":1200,"name":1200,"fn":4190,"description":4191,"org":4192,"tags":4193,"stars":30,"repoUrl":31,"updatedAt":4202},"configure OutSystems ODC Capacitor builds","Generates OutSystems Developer Cloud (ODC) build action JSON files that configure Capacitor mobile plugin builds for Android and iOS. Produces correct JSON with platform-specific actions, input variables, and conditional logic. Use when a developer says \"create a build action for my ODC plugin\", \"generate a buildAction.json file\", \"set up Gradle or plist build actions for a Capacitor or Cordova plugin\", \"configure AndroidManifest for ODC build\", or \"scaffold ODC native build configuration\". If the target platform is ambiguous, still generate and note that build actions only apply to ODC — they have no effect in standalone Capacitor apps. Do not use when the developer explicitly mentions Cordova apps, O11, Cordova extensibility configurations, MABS versions prior to 12, or uploading and registering the JSON in ODC Studio.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4194,4195,4196,4199,4200,4201],{"name":14,"slug":15,"type":16},{"name":24,"slug":25,"type":16},{"name":4197,"slug":4198,"type":16},"Deployment","deployment",{"name":9,"slug":8,"type":16},{"name":18,"slug":19,"type":16},{"name":21,"slug":22,"type":16},"2026-07-12T07:37:41.801053",{"slug":82,"name":82,"fn":4204,"description":4205,"org":4206,"tags":4207,"stars":30,"repoUrl":31,"updatedAt":4214},"generate Capacitor plugin scaffolds","Generates new Capacitor plugin scaffolds and first-pass implementations from conversational requirements or a structured YAML input contract. Use when a user says \"generate a Capacitor plugin\", \"create a Capacitor plugin scaffold\", \"build a native plugin for iOS and Android\", \"turn this plugin plan into Capacitor code\", or \"use this YAML contract to generate a plugin\". Do not use for analyzing Cordova source, migrating whole apps, installing existing plugins, upgrading Capacitor versions, or publishing production-ready code without human review.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4208,4209,4212,4213],{"name":24,"slug":25,"type":16},{"name":4210,"slug":4211,"type":16},"Engineering","engineering",{"name":9,"slug":8,"type":16},{"name":21,"slug":22,"type":16},"2026-07-12T07:37:44.39093",{"slug":4,"name":4,"fn":5,"description":6,"org":4216,"tags":4217,"stars":30,"repoUrl":31,"updatedAt":32},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4218,4219,4220,4221,4222,4223],{"name":14,"slug":15,"type":16},{"name":24,"slug":25,"type":16},{"name":9,"slug":8,"type":16},{"name":18,"slug":19,"type":16},{"name":27,"slug":28,"type":16},{"name":21,"slug":22,"type":16},3,{"items":4226,"total":4224},[4227,4236,4243],{"slug":1200,"name":1200,"fn":4190,"description":4191,"org":4228,"tags":4229,"stars":30,"repoUrl":31,"updatedAt":4202},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4230,4231,4232,4233,4234,4235],{"name":14,"slug":15,"type":16},{"name":24,"slug":25,"type":16},{"name":4197,"slug":4198,"type":16},{"name":9,"slug":8,"type":16},{"name":18,"slug":19,"type":16},{"name":21,"slug":22,"type":16},{"slug":82,"name":82,"fn":4204,"description":4205,"org":4237,"tags":4238,"stars":30,"repoUrl":31,"updatedAt":4214},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4239,4240,4241,4242],{"name":24,"slug":25,"type":16},{"name":4210,"slug":4211,"type":16},{"name":9,"slug":8,"type":16},{"name":21,"slug":22,"type":16},{"slug":4,"name":4,"fn":5,"description":6,"org":4244,"tags":4245,"stars":30,"repoUrl":31,"updatedAt":32},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4246,4247,4248,4249,4250,4251],{"name":14,"slug":15,"type":16},{"name":24,"slug":25,"type":16},{"name":9,"slug":8,"type":16},{"name":18,"slug":19,"type":16},{"name":27,"slug":28,"type":16},{"name":21,"slug":22,"type":16}]