[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-ionic-capacitor-plugin-generator":3,"mdc-x6nfk6-key":34,"related-org-ionic-capacitor-plugin-generator":1783,"related-repo-ionic-capacitor-plugin-generator":1827},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":24,"repoUrl":25,"updatedAt":26,"license":27,"forks":28,"topics":29,"repo":30,"sourceUrl":32,"mdContent":33},"capacitor-plugin-generator","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},"ionic","Ionic","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fionic.png","ionic-team",[13,17,20,23],{"name":14,"slug":15,"type":16},"Mobile","mobile","tag",{"name":18,"slug":19,"type":16},"Capacitor","capacitor",{"name":21,"slug":22,"type":16},"Engineering","engineering",{"name":9,"slug":8,"type":16},14,"https:\u002F\u002Fgithub.com\u002Fionic-team\u002Fcapacitor-skills","2026-07-12T07:37:44.39093",null,1,[],{"repoUrl":25,"stars":24,"forks":28,"topics":31,"description":27},[],"https:\u002F\u002Fgithub.com\u002Fionic-team\u002Fcapacitor-skills\u002Ftree\u002FHEAD\u002Fskills\u002Fcapacitor-plugin-generator","---\nname: capacitor-plugin-generator\ndescription: >-\n  Generates new Capacitor plugin scaffolds and first-pass implementations from\n  conversational requirements or a structured YAML input contract. Use when a\n  user says \"generate a Capacitor plugin\", \"create a Capacitor plugin scaffold\",\n  \"build a native plugin for iOS and Android\", \"turn this plugin plan into\n  Capacitor code\", or \"use this YAML contract to generate a plugin\". Do not use\n  for analyzing Cordova source, migrating whole apps, installing existing\n  plugins, upgrading Capacitor versions, or publishing production-ready code\n  without human review.\nmetadata:\n  author: ionic\n  source: https:\u002F\u002Fgithub.com\u002Fionic-team\u002Fcapacitor-skills\n---\n\n# Capacitor Plugin Generator\n\nGenerate a reviewable Capacitor plugin candidate from either human intent or a\nstructured YAML contract. The output should follow the official Capacitor plugin\narchitecture, but it is a first pass that requires human review before release.\n\n## When to Use This Skill\n\n✅ **Use this skill when:**\n\n- Creating a new Capacitor plugin from scratch.\n- Adding native functionality (camera, sensors, storage, etc.) to a Capacitor app.\n- Designing plugin architecture and API contracts.\n- Implementing native code for iOS (Swift) or Android (Kotlin\u002FJava).\n- Bridging native APIs to JavaScript\u002FTypeScript.\n- Setting up plugin configuration and build systems.\n- Generating a plugin from a structured YAML contract handed off by the\n  `cordova-capacitor-plugin-migration` skill.\n\n❌ **Do NOT use this skill for:**\n\n- Building standard Capacitor apps (use Capacitor documentation instead).\n- Web-only features that don't require native bridges.\n- Modifying existing Capacitor core plugins.\n- *Analyzing* Cordova plugin structure (use `cordova-capacitor-plugin-migration`\n  first; that skill produces the input contract this skill consumes).\n- Upgrading existing plugins to newer Capacitor versions.\n- Publishing production-ready code without human review.\n\n## Prerequisites\n\n| Requirement | Use |\n| --- | --- |\n| Node.js LTS and npm | Run the Capacitor plugin generator and package scripts. |\n| Xcode | Build and verify iOS output when iOS is targeted. |\n| Android Studio and Android SDK | Build and verify Android output when Android is targeted. |\n| CocoaPods and Gradle | Resolve native dependencies when required by generated code. |\n| Capacitor plugin knowledge | Review generated native bridge code before publishing. |\n\n## Agent Behavior\n\n- Detect whether the user provided conversational intent or structured YAML.\n- In conversational mode, ask only for missing plugin identity, methods,\n  platforms, events, permissions, configuration, and native dependencies.\n- In structured mode, parse `references\u002Finput-contract.md`, skip elicitation,\n  and halt if the optional migration block contains blockers or tier 3 hooks.\n- Treat migration metadata as implementation context only. Do not inspect or\n  analyze Cordova source; that belongs to the migration skill.\n- Prefer the official Capacitor plugin generator, then edit the generated\n  scaffold to implement the requested API.\n- Keep generated code contract-first: TypeScript definitions drive web, iOS,\n  Android, docs, and sample app behavior.\n- Use only Capacitor classes that exist in the installed `@capacitor\u002Fcore`,\n  `@capacitor\u002Fandroid`, and `@capacitor\u002Fios` packages. Do not invent helper\n  classes, utilities, or import paths. When uncertain whether an API exists,\n  read the package source rather than infer from its name.\n- When the generated TypeScript contract mirrors an existing public API\n  (Capacitor core\u002Fcommunity, Capawesome, internal libraries, or a documented\n  JavaScript API the user is replacing), look up the actual string literal\n  values used on the wire. Do not derive them from human-friendly names.\n  Structured-mode YAML pins these values explicitly; conversational-mode\n  generation must consult the source.\n- Keep bridge files thin. Split native logic into implementation, manager,\n  permission, config, and mapper helpers when a method would otherwise become\n  a large mixed-responsibility block.\n- Choose native APIs by intended product behavior, not by demo convenience. If\n  the requested behavior requires permissions, special app settings, or manual\n  app configuration, generate the proper `checkPermissions()` \u002F\n  `requestPermissions()` flow and document the manual setup.\n- Clearly report which verification commands were run and which need local\n  human\u002Fdevice validation.\n- Never publish for real from this skill. Run publish checks and `npm publish\n  --access public --dry-run` only.\n\n## Procedures\n\n### Phase 1: Determine the Task and Entry Mode\n\nRead `references\u002Finput-contract.md`. If the input is YAML with `plugin`,\n`platforms`, and `api`, parse it as structured mode and skip questions. If the\ninput is conversational, elicit the minimum missing fields needed to create the\nsame contract shape internally.\n\n### Phase 2: Scaffold\n\nRead `references\u002Fscaffolding.md`. Run the official Capacitor plugin generator\nwith non-interactive flags when possible. Enforce name parity:\n`registerPlugin()` JavaScript name equals iOS `jsName` equals Android\n`@CapacitorPlugin(name)`.\n\n### Phase 3: Design the TypeScript API\n\nRead `references\u002Fapi-design.md`. Define `src\u002Fdefinitions.ts` before native\nimplementation. Use options\u002Fresult interfaces per method, string unions instead\nof enums, listener signatures for events, and JSDoc with `@since` everywhere.\n\n### Phase 4: Implement the Web Layer\n\nRead `references\u002Fweb-guide.md`. Extend `WebPlugin`, feature-detect browser APIs\nbefore use, throw `unavailable()` when an API exists but is unavailable in the\ncurrent browser, and throw `unimplemented()` when no web equivalent exists.\nRegister the web layer through a dynamic import.\n\n### Phase 5: Define Method Signatures\n\nRead `references\u002Fapi-design.md`. For every method, choose one bridge return\ntype: value, void, or callback. Use callback return types only for streams or\nlong-lived watchers. Keep event names identical across TypeScript, web, iOS, and\nAndroid.\n\n### Phase 6: Implement iOS\n\nRead `references\u002Farchitecture-patterns.md` and `references\u002Fios-implementation.md`. Use the\nBridge pattern by default: a thin Capacitor plugin class delegates to an\nimplementation class. Use a Facade only for complex plugins with multiple native\nsubsystems, permission flows, or lifecycle concerns.\n\n### Phase 7: Implement Android\n\nRead `references\u002Farchitecture-patterns.md` and `references\u002Fandroid-implementation.md`. Use the\nBridge pattern by default: a thin `Plugin` class delegates to an implementation\nclass. Use a Facade only for complex plugins with multiple managers, permission\nflows, services, activities, or lifecycle hooks.\n\n### Phase 8: Generate a Sample App\n\nRead `references\u002Fsample-app.md`. Create or update a sample app that exercises\nthe entire public plugin API, including success paths, expected errors,\npermissions, configuration, and listeners.\n\n### Phase 9: Docgen and Verify\n\nRead `references\u002Ftesting-strategies.md` and `references\u002Fpublishing.md`.\nGenerate API docs from JSDoc with `npm run docgen`; do not hand-write API docs.\nRun the relevant verify commands for targeted platforms and record any\nenvironment-limited checks.\n\n### Phase 10: Publish Checks\n\nRead `references\u002Fpublishing.md`. Run the pre-publish checklist and dry run:\n`npm publish --access public --dry-run`. Do not publish the generated plugin\nwithout explicit human review outside this skill.\n\n## Best Practices\n\n### DO\n\n- ✅ Use command-line flags with `npm init @capacitor\u002Fplugin` so the\n  scaffolder runs non-interactively.\n- ✅ Detect entry mode (conversational vs structured YAML) before asking\n  questions. Skip elicitation entirely in structured mode.\n- ✅ Design the TypeScript API first (contract-first), then implement\n  web, iOS, and Android against that contract.\n- ✅ Implement the web layer for testing without devices, even when\n  most methods throw `unimplemented()`.\n- ✅ Inspect the official plugin's native dependencies when mirroring an\n  existing API; declare the same SDKs and write a thin adapter rather\n  than reimplementing.\n- ✅ Document every public symbol with JSDoc and `@since`.\n- ✅ Run `npm run fmt` before committing and `npm run verify` before\n  reporting completion.\n- ✅ Use the two-class pattern (bridge + implementation) on iOS and\n  Android for testability.\n- ✅ Match wire-format string and numeric values exactly when mirroring\n  an existing API. Look up the official `definitions.ts` rather than\n  guessing from human-friendly names.\n- ✅ Keep event names identical across TypeScript \u002F web \u002F iOS \u002F Android.\n\n### DON'T\n\n- ❌ Mix concerns — keep the plugin focused on one capability.\n- ❌ Skip error handling. Reject with codes from the canonical 4-code\n  taxonomy (`UNAVAILABLE`, `PERMISSION_DENIED`, `INVALID_PARAMETER`,\n  `OPERATION_FAILED`).\n- ❌ Use callbacks instead of promises in the TypeScript surface.\n- ❌ Forget the web implementation, even for iOS\u002FAndroid-only features.\n- ❌ Hard-code values that should be configurable. Use\n  `references\u002Fconfiguration.md` runtime plugin configuration.\n- ❌ Invent Capacitor classes, helpers, or import paths. Verify against\n  the installed `@capacitor\u002Fcore`, `@capacitor\u002Fandroid`, and\n  `@capacitor\u002Fios` packages.\n- ❌ Call `notifyListeners(...)` from outside the `Plugin` subclass —\n  see `references\u002Farchitecture-patterns.md` \"Event Dispatch Locality\".\n- ❌ Publish from this skill. Run dry-run only with\n  `npm publish --access public --dry-run`.\n- ❌ Inspect or analyze Cordova source — that belongs to the sibling\n  migration skill.\n\n## Error Handling\n\n| Symptom | Fix |\n| --- | --- |\n| `npm init @capacitor\u002Fplugin` fails with `Refusing to prompt in non-TTY environment` | Pass all required flags non-interactively: `npm init @capacitor\u002Fplugin \u003Cfolder> -- --name \"\u003Cnpm-name>\" --package-id \"\u003Creverse-dns>\" --class-name \"\u003CPascalCase>\" --description \"\u003Cone-line>\" --author \"\u003Cname \u003Cemail>>\" --license \"\u003CSPDX>\" --repo \"\u003Curl>\" --android-lang \"\u003Ckotlin\\|java>\"`. See `references\u002Fscaffolding.md`. |\n| `npm init @capacitor\u002Fplugin` fails with `invalid option: --android-lang undefined: Must be either 'kotlin' or 'java'` | The `--android-lang` flag is required when running non-interactively. Add `--android-lang \"kotlin\"` (recommended for new plugins) or `--android-lang \"java\"` to the command. |\n| Plugin silently fails to load | Make `registerPlugin()` name match iOS `jsName` and Android `@CapacitorPlugin(name)`. |\n| Event not received in JS | Make the event name string identical across TypeScript, web, iOS, and Android. |\n| iOS method not callable from JS | Ensure the method is marked `@objc` and listed in `pluginMethods`. |\n| Android method not callable from JS | Ensure the method is public and annotated with `@PluginMethod()`. |\n| `npm run verify:ios` fails | Run `pod install --repo-update`; then rerun the iOS verify command. |\n| `npm run verify:android` fails | Sync Gradle and check Android SDK, compile SDK, and dependency versions. |\n| Android compile error: `class X is public, should be declared in a file named X.java` | Java requires a public class to live in a file matching its name. When generating multiple Java classes per plugin, place each public class in its own file. Kotlin does not impose this rule. |\n| Android compile error: `notifyListeners(...) has protected access in Plugin` | `notifyListeners()` is `protected` on `Plugin`. Call it only from inside a class that extends `Plugin`. If another class needs to emit events, return the data to the plugin and dispatch there, or expose a public wrapper on the plugin that calls `notifyListeners()` internally. |\n| Android compile error: `cannot find symbol: class …` for a `com.getcapacitor.*` import | The import does not exist on the installed `@capacitor\u002Fandroid` surface. Verify imports against the package source before generating; do not infer Capacitor classes from their names. |\n| Android compile error: `\u003Cmethod> in \u003CSubclass> cannot override \u003Cmethod> in Plugin; attempting to assign weaker access privileges; was public` | A helper on the `Plugin` subclass collides with a `public` method that `com.getcapacitor.Plugin` already defines (e.g., `hasPermission`, `getPermissionState`, `notifyListeners`). Either rename the helper or match the parent's `public` visibility. |\n| TypeScript build error: `Cannot find type definition file for '\u003Cname>'` or `Invalid module name in augmentation, module '\u003Cname>' cannot be found` | The augmented module is not installed. Add it to `devDependencies` (and to `tsconfig.json` `compilerOptions.types` if a triple-slash reference is used). Applies to any module augmentation, not just `@capacitor\u002Fcli`. |\n| TypeScript build error: `Interface 'X' incorrectly extends interface 'Y'. Property 'Z' is optional in type 'X' but required in type 'Y'` (or the symmetric error) | Do not redeclare members the built-in lib type already provides. Use the lib type directly, or augment via `declare global { interface Y { newMember?: ... } }` for genuinely new members only. Use `'name' in target` runtime guards for capability checks. |\n| `npm run docgen` produces empty output | Add JSDoc to `src\u002Fdefinitions.ts`; docgen reads the TypeScript contract. |\n| Web API absent in target browser | Use `unavailable()` when the API exists but is missing here; use `unimplemented()` when no web equivalent exists. |\n| Structured YAML is rejected | Validate against `references\u002Finput-contract.md`; ensure required base fields are present and blockers are empty. |\n| Generated output looks too broad | Split unrelated capabilities into separate plugins and regenerate with a smaller API surface. |\n| Generated native code reimplements logic the official plugin delegates to a native SDK | Inspect the official plugin's `.podspec` \u002F `Package.swift` \u002F `android\u002Fbuild.gradle` for native SDK dependencies. If present, declare the same SDK and write a thin adapter — see `references\u002Fapi-design.md` \"Native Dependency Detection\". |\n\n## Related Skills\n\n- `cordova-capacitor-plugin-migration`: Analyze Cordova plugins and produce a\n  structured migration plan for this generator.\n\n## References\n\n- `references\u002Finput-contract.md`: Structured YAML contract for generator input.\n- `references\u002Fscaffolding.md`: Generator invocation, name parity, and scaffold verification.\n- `references\u002Fapi-design.md`: TypeScript API design, JSDoc, event signatures, and method return types.\n- `references\u002Fweb-guide.md`: WebPlugin patterns, dynamic import, feature detection, and errors.\n- `references\u002Farchitecture-patterns.md`: Bridge and Facade patterns plus event parity.\n- `references\u002Fios-implementation.md`: iOS bridge, implementation class, permissions, dependencies, and Podspec.\n- `references\u002Fandroid-implementation.md`: Android bridge, implementation class, permissions, dependencies, and Gradle.\n- `references\u002Fconfiguration.md`: Capacitor config keys under `plugins.\u003CPluginJSName>`.\n- `references\u002Ftesting-strategies.md`: Local linking, verify commands, hooks, and review workflow.\n- `references\u002Fpublishing.md`: Package fields, docgen, checklist, and dry-run publishing.\n- `references\u002Fsample-app.md`: Sample app requirements that exercise the full API.\n- `references\u002Fpermission-patterns.md`: Deep-dive on permission flows — multi-permission DispatchGroup on iOS, location delegate, check-before-use \u002F just-in-time \u002F deferred consumer patterns, opening system settings.\n- `references\u002Ftypescript-implementation.md`: Deep-dive on TypeScript layer — singleton plugin pattern, typed error classes, full event listener handle bookkeeping, helper utilities, Jest scaffolding.\n",{"data":35,"body":37},{"name":4,"description":6,"metadata":36},{"author":8,"source":25},{"type":38,"children":39},"root",[40,48,54,61,72,121,131,177,183,276,282,401,407,414,448,454,490,496,524,530,566,572,583,589,609,615,641,647,659,665,692,698,716,722,728,825,831,965,971,1616,1622,1635,1641],{"type":41,"tag":42,"props":43,"children":44},"element","h1",{"id":4},[45],{"type":46,"value":47},"text","Capacitor Plugin Generator",{"type":41,"tag":49,"props":50,"children":51},"p",{},[52],{"type":46,"value":53},"Generate a reviewable Capacitor plugin candidate from either human intent or a\nstructured YAML contract. The output should follow the official Capacitor plugin\narchitecture, but it is a first pass that requires human review before release.",{"type":41,"tag":55,"props":56,"children":58},"h2",{"id":57},"when-to-use-this-skill",[59],{"type":46,"value":60},"When to Use This Skill",{"type":41,"tag":49,"props":62,"children":63},{},[64,66],{"type":46,"value":65},"✅ ",{"type":41,"tag":67,"props":68,"children":69},"strong",{},[70],{"type":46,"value":71},"Use this skill when:",{"type":41,"tag":73,"props":74,"children":75},"ul",{},[76,82,87,92,97,102,107],{"type":41,"tag":77,"props":78,"children":79},"li",{},[80],{"type":46,"value":81},"Creating a new Capacitor plugin from scratch.",{"type":41,"tag":77,"props":83,"children":84},{},[85],{"type":46,"value":86},"Adding native functionality (camera, sensors, storage, etc.) to a Capacitor app.",{"type":41,"tag":77,"props":88,"children":89},{},[90],{"type":46,"value":91},"Designing plugin architecture and API contracts.",{"type":41,"tag":77,"props":93,"children":94},{},[95],{"type":46,"value":96},"Implementing native code for iOS (Swift) or Android (Kotlin\u002FJava).",{"type":41,"tag":77,"props":98,"children":99},{},[100],{"type":46,"value":101},"Bridging native APIs to JavaScript\u002FTypeScript.",{"type":41,"tag":77,"props":103,"children":104},{},[105],{"type":46,"value":106},"Setting up plugin configuration and build systems.",{"type":41,"tag":77,"props":108,"children":109},{},[110,112,119],{"type":46,"value":111},"Generating a plugin from a structured YAML contract handed off by the\n",{"type":41,"tag":113,"props":114,"children":116},"code",{"className":115},[],[117],{"type":46,"value":118},"cordova-capacitor-plugin-migration",{"type":46,"value":120}," skill.",{"type":41,"tag":49,"props":122,"children":123},{},[124,126],{"type":46,"value":125},"❌ ",{"type":41,"tag":67,"props":127,"children":128},{},[129],{"type":46,"value":130},"Do NOT use this skill for:",{"type":41,"tag":73,"props":132,"children":133},{},[134,139,144,149,167,172],{"type":41,"tag":77,"props":135,"children":136},{},[137],{"type":46,"value":138},"Building standard Capacitor apps (use Capacitor documentation instead).",{"type":41,"tag":77,"props":140,"children":141},{},[142],{"type":46,"value":143},"Web-only features that don't require native bridges.",{"type":41,"tag":77,"props":145,"children":146},{},[147],{"type":46,"value":148},"Modifying existing Capacitor core plugins.",{"type":41,"tag":77,"props":150,"children":151},{},[152,158,160,165],{"type":41,"tag":153,"props":154,"children":155},"em",{},[156],{"type":46,"value":157},"Analyzing",{"type":46,"value":159}," Cordova plugin structure (use ",{"type":41,"tag":113,"props":161,"children":163},{"className":162},[],[164],{"type":46,"value":118},{"type":46,"value":166},"\nfirst; that skill produces the input contract this skill consumes).",{"type":41,"tag":77,"props":168,"children":169},{},[170],{"type":46,"value":171},"Upgrading existing plugins to newer Capacitor versions.",{"type":41,"tag":77,"props":173,"children":174},{},[175],{"type":46,"value":176},"Publishing production-ready code without human review.",{"type":41,"tag":55,"props":178,"children":180},{"id":179},"prerequisites",[181],{"type":46,"value":182},"Prerequisites",{"type":41,"tag":184,"props":185,"children":186},"table",{},[187,206],{"type":41,"tag":188,"props":189,"children":190},"thead",{},[191],{"type":41,"tag":192,"props":193,"children":194},"tr",{},[195,201],{"type":41,"tag":196,"props":197,"children":198},"th",{},[199],{"type":46,"value":200},"Requirement",{"type":41,"tag":196,"props":202,"children":203},{},[204],{"type":46,"value":205},"Use",{"type":41,"tag":207,"props":208,"children":209},"tbody",{},[210,224,237,250,263],{"type":41,"tag":192,"props":211,"children":212},{},[213,219],{"type":41,"tag":214,"props":215,"children":216},"td",{},[217],{"type":46,"value":218},"Node.js LTS and npm",{"type":41,"tag":214,"props":220,"children":221},{},[222],{"type":46,"value":223},"Run the Capacitor plugin generator and package scripts.",{"type":41,"tag":192,"props":225,"children":226},{},[227,232],{"type":41,"tag":214,"props":228,"children":229},{},[230],{"type":46,"value":231},"Xcode",{"type":41,"tag":214,"props":233,"children":234},{},[235],{"type":46,"value":236},"Build and verify iOS output when iOS is targeted.",{"type":41,"tag":192,"props":238,"children":239},{},[240,245],{"type":41,"tag":214,"props":241,"children":242},{},[243],{"type":46,"value":244},"Android Studio and Android SDK",{"type":41,"tag":214,"props":246,"children":247},{},[248],{"type":46,"value":249},"Build and verify Android output when Android is targeted.",{"type":41,"tag":192,"props":251,"children":252},{},[253,258],{"type":41,"tag":214,"props":254,"children":255},{},[256],{"type":46,"value":257},"CocoaPods and Gradle",{"type":41,"tag":214,"props":259,"children":260},{},[261],{"type":46,"value":262},"Resolve native dependencies when required by generated code.",{"type":41,"tag":192,"props":264,"children":265},{},[266,271],{"type":41,"tag":214,"props":267,"children":268},{},[269],{"type":46,"value":270},"Capacitor plugin knowledge",{"type":41,"tag":214,"props":272,"children":273},{},[274],{"type":46,"value":275},"Review generated native bridge code before publishing.",{"type":41,"tag":55,"props":277,"children":279},{"id":278},"agent-behavior",[280],{"type":46,"value":281},"Agent Behavior",{"type":41,"tag":73,"props":283,"children":284},{},[285,290,295,308,313,318,323,352,357,362,383,388],{"type":41,"tag":77,"props":286,"children":287},{},[288],{"type":46,"value":289},"Detect whether the user provided conversational intent or structured YAML.",{"type":41,"tag":77,"props":291,"children":292},{},[293],{"type":46,"value":294},"In conversational mode, ask only for missing plugin identity, methods,\nplatforms, events, permissions, configuration, and native dependencies.",{"type":41,"tag":77,"props":296,"children":297},{},[298,300,306],{"type":46,"value":299},"In structured mode, parse ",{"type":41,"tag":113,"props":301,"children":303},{"className":302},[],[304],{"type":46,"value":305},"references\u002Finput-contract.md",{"type":46,"value":307},", skip elicitation,\nand halt if the optional migration block contains blockers or tier 3 hooks.",{"type":41,"tag":77,"props":309,"children":310},{},[311],{"type":46,"value":312},"Treat migration metadata as implementation context only. Do not inspect or\nanalyze Cordova source; that belongs to the migration skill.",{"type":41,"tag":77,"props":314,"children":315},{},[316],{"type":46,"value":317},"Prefer the official Capacitor plugin generator, then edit the generated\nscaffold to implement the requested API.",{"type":41,"tag":77,"props":319,"children":320},{},[321],{"type":46,"value":322},"Keep generated code contract-first: TypeScript definitions drive web, iOS,\nAndroid, docs, and sample app behavior.",{"type":41,"tag":77,"props":324,"children":325},{},[326,328,334,336,342,344,350],{"type":46,"value":327},"Use only Capacitor classes that exist in the installed ",{"type":41,"tag":113,"props":329,"children":331},{"className":330},[],[332],{"type":46,"value":333},"@capacitor\u002Fcore",{"type":46,"value":335},",\n",{"type":41,"tag":113,"props":337,"children":339},{"className":338},[],[340],{"type":46,"value":341},"@capacitor\u002Fandroid",{"type":46,"value":343},", and ",{"type":41,"tag":113,"props":345,"children":347},{"className":346},[],[348],{"type":46,"value":349},"@capacitor\u002Fios",{"type":46,"value":351}," packages. Do not invent helper\nclasses, utilities, or import paths. When uncertain whether an API exists,\nread the package source rather than infer from its name.",{"type":41,"tag":77,"props":353,"children":354},{},[355],{"type":46,"value":356},"When the generated TypeScript contract mirrors an existing public API\n(Capacitor core\u002Fcommunity, Capawesome, internal libraries, or a documented\nJavaScript API the user is replacing), look up the actual string literal\nvalues used on the wire. Do not derive them from human-friendly names.\nStructured-mode YAML pins these values explicitly; conversational-mode\ngeneration must consult the source.",{"type":41,"tag":77,"props":358,"children":359},{},[360],{"type":46,"value":361},"Keep bridge files thin. Split native logic into implementation, manager,\npermission, config, and mapper helpers when a method would otherwise become\na large mixed-responsibility block.",{"type":41,"tag":77,"props":363,"children":364},{},[365,367,373,375,381],{"type":46,"value":366},"Choose native APIs by intended product behavior, not by demo convenience. If\nthe requested behavior requires permissions, special app settings, or manual\napp configuration, generate the proper ",{"type":41,"tag":113,"props":368,"children":370},{"className":369},[],[371],{"type":46,"value":372},"checkPermissions()",{"type":46,"value":374}," \u002F\n",{"type":41,"tag":113,"props":376,"children":378},{"className":377},[],[379],{"type":46,"value":380},"requestPermissions()",{"type":46,"value":382}," flow and document the manual setup.",{"type":41,"tag":77,"props":384,"children":385},{},[386],{"type":46,"value":387},"Clearly report which verification commands were run and which need local\nhuman\u002Fdevice validation.",{"type":41,"tag":77,"props":389,"children":390},{},[391,393,399],{"type":46,"value":392},"Never publish for real from this skill. Run publish checks and ",{"type":41,"tag":113,"props":394,"children":396},{"className":395},[],[397],{"type":46,"value":398},"npm publish --access public --dry-run",{"type":46,"value":400}," only.",{"type":41,"tag":55,"props":402,"children":404},{"id":403},"procedures",[405],{"type":46,"value":406},"Procedures",{"type":41,"tag":408,"props":409,"children":411},"h3",{"id":410},"phase-1-determine-the-task-and-entry-mode",[412],{"type":46,"value":413},"Phase 1: Determine the Task and Entry Mode",{"type":41,"tag":49,"props":415,"children":416},{},[417,419,424,426,432,433,439,440,446],{"type":46,"value":418},"Read ",{"type":41,"tag":113,"props":420,"children":422},{"className":421},[],[423],{"type":46,"value":305},{"type":46,"value":425},". If the input is YAML with ",{"type":41,"tag":113,"props":427,"children":429},{"className":428},[],[430],{"type":46,"value":431},"plugin",{"type":46,"value":335},{"type":41,"tag":113,"props":434,"children":436},{"className":435},[],[437],{"type":46,"value":438},"platforms",{"type":46,"value":343},{"type":41,"tag":113,"props":441,"children":443},{"className":442},[],[444],{"type":46,"value":445},"api",{"type":46,"value":447},", parse it as structured mode and skip questions. If the\ninput is conversational, elicit the minimum missing fields needed to create the\nsame contract shape internally.",{"type":41,"tag":408,"props":449,"children":451},{"id":450},"phase-2-scaffold",[452],{"type":46,"value":453},"Phase 2: Scaffold",{"type":41,"tag":49,"props":455,"children":456},{},[457,458,464,466,472,474,480,482,488],{"type":46,"value":418},{"type":41,"tag":113,"props":459,"children":461},{"className":460},[],[462],{"type":46,"value":463},"references\u002Fscaffolding.md",{"type":46,"value":465},". Run the official Capacitor plugin generator\nwith non-interactive flags when possible. Enforce name parity:\n",{"type":41,"tag":113,"props":467,"children":469},{"className":468},[],[470],{"type":46,"value":471},"registerPlugin()",{"type":46,"value":473}," JavaScript name equals iOS ",{"type":41,"tag":113,"props":475,"children":477},{"className":476},[],[478],{"type":46,"value":479},"jsName",{"type":46,"value":481}," equals Android\n",{"type":41,"tag":113,"props":483,"children":485},{"className":484},[],[486],{"type":46,"value":487},"@CapacitorPlugin(name)",{"type":46,"value":489},".",{"type":41,"tag":408,"props":491,"children":493},{"id":492},"phase-3-design-the-typescript-api",[494],{"type":46,"value":495},"Phase 3: Design the TypeScript API",{"type":41,"tag":49,"props":497,"children":498},{},[499,500,506,508,514,516,522],{"type":46,"value":418},{"type":41,"tag":113,"props":501,"children":503},{"className":502},[],[504],{"type":46,"value":505},"references\u002Fapi-design.md",{"type":46,"value":507},". Define ",{"type":41,"tag":113,"props":509,"children":511},{"className":510},[],[512],{"type":46,"value":513},"src\u002Fdefinitions.ts",{"type":46,"value":515}," before native\nimplementation. Use options\u002Fresult interfaces per method, string unions instead\nof enums, listener signatures for events, and JSDoc with ",{"type":41,"tag":113,"props":517,"children":519},{"className":518},[],[520],{"type":46,"value":521},"@since",{"type":46,"value":523}," everywhere.",{"type":41,"tag":408,"props":525,"children":527},{"id":526},"phase-4-implement-the-web-layer",[528],{"type":46,"value":529},"Phase 4: Implement the Web Layer",{"type":41,"tag":49,"props":531,"children":532},{},[533,534,540,542,548,550,556,558,564],{"type":46,"value":418},{"type":41,"tag":113,"props":535,"children":537},{"className":536},[],[538],{"type":46,"value":539},"references\u002Fweb-guide.md",{"type":46,"value":541},". Extend ",{"type":41,"tag":113,"props":543,"children":545},{"className":544},[],[546],{"type":46,"value":547},"WebPlugin",{"type":46,"value":549},", feature-detect browser APIs\nbefore use, throw ",{"type":41,"tag":113,"props":551,"children":553},{"className":552},[],[554],{"type":46,"value":555},"unavailable()",{"type":46,"value":557}," when an API exists but is unavailable in the\ncurrent browser, and throw ",{"type":41,"tag":113,"props":559,"children":561},{"className":560},[],[562],{"type":46,"value":563},"unimplemented()",{"type":46,"value":565}," when no web equivalent exists.\nRegister the web layer through a dynamic import.",{"type":41,"tag":408,"props":567,"children":569},{"id":568},"phase-5-define-method-signatures",[570],{"type":46,"value":571},"Phase 5: Define Method Signatures",{"type":41,"tag":49,"props":573,"children":574},{},[575,576,581],{"type":46,"value":418},{"type":41,"tag":113,"props":577,"children":579},{"className":578},[],[580],{"type":46,"value":505},{"type":46,"value":582},". For every method, choose one bridge return\ntype: value, void, or callback. Use callback return types only for streams or\nlong-lived watchers. Keep event names identical across TypeScript, web, iOS, and\nAndroid.",{"type":41,"tag":408,"props":584,"children":586},{"id":585},"phase-6-implement-ios",[587],{"type":46,"value":588},"Phase 6: Implement iOS",{"type":41,"tag":49,"props":590,"children":591},{},[592,593,599,601,607],{"type":46,"value":418},{"type":41,"tag":113,"props":594,"children":596},{"className":595},[],[597],{"type":46,"value":598},"references\u002Farchitecture-patterns.md",{"type":46,"value":600}," and ",{"type":41,"tag":113,"props":602,"children":604},{"className":603},[],[605],{"type":46,"value":606},"references\u002Fios-implementation.md",{"type":46,"value":608},". Use the\nBridge pattern by default: a thin Capacitor plugin class delegates to an\nimplementation class. Use a Facade only for complex plugins with multiple native\nsubsystems, permission flows, or lifecycle concerns.",{"type":41,"tag":408,"props":610,"children":612},{"id":611},"phase-7-implement-android",[613],{"type":46,"value":614},"Phase 7: Implement Android",{"type":41,"tag":49,"props":616,"children":617},{},[618,619,624,625,631,633,639],{"type":46,"value":418},{"type":41,"tag":113,"props":620,"children":622},{"className":621},[],[623],{"type":46,"value":598},{"type":46,"value":600},{"type":41,"tag":113,"props":626,"children":628},{"className":627},[],[629],{"type":46,"value":630},"references\u002Fandroid-implementation.md",{"type":46,"value":632},". Use the\nBridge pattern by default: a thin ",{"type":41,"tag":113,"props":634,"children":636},{"className":635},[],[637],{"type":46,"value":638},"Plugin",{"type":46,"value":640}," class delegates to an implementation\nclass. Use a Facade only for complex plugins with multiple managers, permission\nflows, services, activities, or lifecycle hooks.",{"type":41,"tag":408,"props":642,"children":644},{"id":643},"phase-8-generate-a-sample-app",[645],{"type":46,"value":646},"Phase 8: Generate a Sample App",{"type":41,"tag":49,"props":648,"children":649},{},[650,651,657],{"type":46,"value":418},{"type":41,"tag":113,"props":652,"children":654},{"className":653},[],[655],{"type":46,"value":656},"references\u002Fsample-app.md",{"type":46,"value":658},". Create or update a sample app that exercises\nthe entire public plugin API, including success paths, expected errors,\npermissions, configuration, and listeners.",{"type":41,"tag":408,"props":660,"children":662},{"id":661},"phase-9-docgen-and-verify",[663],{"type":46,"value":664},"Phase 9: Docgen and Verify",{"type":41,"tag":49,"props":666,"children":667},{},[668,669,675,676,682,684,690],{"type":46,"value":418},{"type":41,"tag":113,"props":670,"children":672},{"className":671},[],[673],{"type":46,"value":674},"references\u002Ftesting-strategies.md",{"type":46,"value":600},{"type":41,"tag":113,"props":677,"children":679},{"className":678},[],[680],{"type":46,"value":681},"references\u002Fpublishing.md",{"type":46,"value":683},".\nGenerate API docs from JSDoc with ",{"type":41,"tag":113,"props":685,"children":687},{"className":686},[],[688],{"type":46,"value":689},"npm run docgen",{"type":46,"value":691},"; do not hand-write API docs.\nRun the relevant verify commands for targeted platforms and record any\nenvironment-limited checks.",{"type":41,"tag":408,"props":693,"children":695},{"id":694},"phase-10-publish-checks",[696],{"type":46,"value":697},"Phase 10: Publish Checks",{"type":41,"tag":49,"props":699,"children":700},{},[701,702,707,709,714],{"type":46,"value":418},{"type":41,"tag":113,"props":703,"children":705},{"className":704},[],[706],{"type":46,"value":681},{"type":46,"value":708},". Run the pre-publish checklist and dry run:\n",{"type":41,"tag":113,"props":710,"children":712},{"className":711},[],[713],{"type":46,"value":398},{"type":46,"value":715},". Do not publish the generated plugin\nwithout explicit human review outside this skill.",{"type":41,"tag":55,"props":717,"children":719},{"id":718},"best-practices",[720],{"type":46,"value":721},"Best Practices",{"type":41,"tag":408,"props":723,"children":725},{"id":724},"do",[726],{"type":46,"value":727},"DO",{"type":41,"tag":73,"props":729,"children":730},{},[731,744,749,754,765,770,781,802,807,820],{"type":41,"tag":77,"props":732,"children":733},{},[734,736,742],{"type":46,"value":735},"✅ Use command-line flags with ",{"type":41,"tag":113,"props":737,"children":739},{"className":738},[],[740],{"type":46,"value":741},"npm init @capacitor\u002Fplugin",{"type":46,"value":743}," so the\nscaffolder runs non-interactively.",{"type":41,"tag":77,"props":745,"children":746},{},[747],{"type":46,"value":748},"✅ Detect entry mode (conversational vs structured YAML) before asking\nquestions. Skip elicitation entirely in structured mode.",{"type":41,"tag":77,"props":750,"children":751},{},[752],{"type":46,"value":753},"✅ Design the TypeScript API first (contract-first), then implement\nweb, iOS, and Android against that contract.",{"type":41,"tag":77,"props":755,"children":756},{},[757,759,764],{"type":46,"value":758},"✅ Implement the web layer for testing without devices, even when\nmost methods throw ",{"type":41,"tag":113,"props":760,"children":762},{"className":761},[],[763],{"type":46,"value":563},{"type":46,"value":489},{"type":41,"tag":77,"props":766,"children":767},{},[768],{"type":46,"value":769},"✅ Inspect the official plugin's native dependencies when mirroring an\nexisting API; declare the same SDKs and write a thin adapter rather\nthan reimplementing.",{"type":41,"tag":77,"props":771,"children":772},{},[773,775,780],{"type":46,"value":774},"✅ Document every public symbol with JSDoc and ",{"type":41,"tag":113,"props":776,"children":778},{"className":777},[],[779],{"type":46,"value":521},{"type":46,"value":489},{"type":41,"tag":77,"props":782,"children":783},{},[784,786,792,794,800],{"type":46,"value":785},"✅ Run ",{"type":41,"tag":113,"props":787,"children":789},{"className":788},[],[790],{"type":46,"value":791},"npm run fmt",{"type":46,"value":793}," before committing and ",{"type":41,"tag":113,"props":795,"children":797},{"className":796},[],[798],{"type":46,"value":799},"npm run verify",{"type":46,"value":801}," before\nreporting completion.",{"type":41,"tag":77,"props":803,"children":804},{},[805],{"type":46,"value":806},"✅ Use the two-class pattern (bridge + implementation) on iOS and\nAndroid for testability.",{"type":41,"tag":77,"props":808,"children":809},{},[810,812,818],{"type":46,"value":811},"✅ Match wire-format string and numeric values exactly when mirroring\nan existing API. Look up the official ",{"type":41,"tag":113,"props":813,"children":815},{"className":814},[],[816],{"type":46,"value":817},"definitions.ts",{"type":46,"value":819}," rather than\nguessing from human-friendly names.",{"type":41,"tag":77,"props":821,"children":822},{},[823],{"type":46,"value":824},"✅ Keep event names identical across TypeScript \u002F web \u002F iOS \u002F Android.",{"type":41,"tag":408,"props":826,"children":828},{"id":827},"dont",[829],{"type":46,"value":830},"DON'T",{"type":41,"tag":73,"props":832,"children":833},{},[834,839,874,879,884,897,922,949,960],{"type":41,"tag":77,"props":835,"children":836},{},[837],{"type":46,"value":838},"❌ Mix concerns — keep the plugin focused on one capability.",{"type":41,"tag":77,"props":840,"children":841},{},[842,844,850,852,858,859,865,866,872],{"type":46,"value":843},"❌ Skip error handling. Reject with codes from the canonical 4-code\ntaxonomy (",{"type":41,"tag":113,"props":845,"children":847},{"className":846},[],[848],{"type":46,"value":849},"UNAVAILABLE",{"type":46,"value":851},", ",{"type":41,"tag":113,"props":853,"children":855},{"className":854},[],[856],{"type":46,"value":857},"PERMISSION_DENIED",{"type":46,"value":851},{"type":41,"tag":113,"props":860,"children":862},{"className":861},[],[863],{"type":46,"value":864},"INVALID_PARAMETER",{"type":46,"value":335},{"type":41,"tag":113,"props":867,"children":869},{"className":868},[],[870],{"type":46,"value":871},"OPERATION_FAILED",{"type":46,"value":873},").",{"type":41,"tag":77,"props":875,"children":876},{},[877],{"type":46,"value":878},"❌ Use callbacks instead of promises in the TypeScript surface.",{"type":41,"tag":77,"props":880,"children":881},{},[882],{"type":46,"value":883},"❌ Forget the web implementation, even for iOS\u002FAndroid-only features.",{"type":41,"tag":77,"props":885,"children":886},{},[887,889,895],{"type":46,"value":888},"❌ Hard-code values that should be configurable. Use\n",{"type":41,"tag":113,"props":890,"children":892},{"className":891},[],[893],{"type":46,"value":894},"references\u002Fconfiguration.md",{"type":46,"value":896}," runtime plugin configuration.",{"type":41,"tag":77,"props":898,"children":899},{},[900,902,907,908,913,915,920],{"type":46,"value":901},"❌ Invent Capacitor classes, helpers, or import paths. Verify against\nthe installed ",{"type":41,"tag":113,"props":903,"children":905},{"className":904},[],[906],{"type":46,"value":333},{"type":46,"value":851},{"type":41,"tag":113,"props":909,"children":911},{"className":910},[],[912],{"type":46,"value":341},{"type":46,"value":914},", and\n",{"type":41,"tag":113,"props":916,"children":918},{"className":917},[],[919],{"type":46,"value":349},{"type":46,"value":921}," packages.",{"type":41,"tag":77,"props":923,"children":924},{},[925,927,933,935,940,942,947],{"type":46,"value":926},"❌ Call ",{"type":41,"tag":113,"props":928,"children":930},{"className":929},[],[931],{"type":46,"value":932},"notifyListeners(...)",{"type":46,"value":934}," from outside the ",{"type":41,"tag":113,"props":936,"children":938},{"className":937},[],[939],{"type":46,"value":638},{"type":46,"value":941}," subclass —\nsee ",{"type":41,"tag":113,"props":943,"children":945},{"className":944},[],[946],{"type":46,"value":598},{"type":46,"value":948}," \"Event Dispatch Locality\".",{"type":41,"tag":77,"props":950,"children":951},{},[952,954,959],{"type":46,"value":953},"❌ Publish from this skill. Run dry-run only with\n",{"type":41,"tag":113,"props":955,"children":957},{"className":956},[],[958],{"type":46,"value":398},{"type":46,"value":489},{"type":41,"tag":77,"props":961,"children":962},{},[963],{"type":46,"value":964},"❌ Inspect or analyze Cordova source — that belongs to the sibling\nmigration skill.",{"type":41,"tag":55,"props":966,"children":968},{"id":967},"error-handling",[969],{"type":46,"value":970},"Error Handling",{"type":41,"tag":184,"props":972,"children":973},{},[974,990],{"type":41,"tag":188,"props":975,"children":976},{},[977],{"type":41,"tag":192,"props":978,"children":979},{},[980,985],{"type":41,"tag":196,"props":981,"children":982},{},[983],{"type":46,"value":984},"Symptom",{"type":41,"tag":196,"props":986,"children":987},{},[988],{"type":46,"value":989},"Fix",{"type":41,"tag":207,"props":991,"children":992},{},[993,1031,1078,1111,1124,1152,1172,1199,1217,1236,1289,1324,1394,1452,1488,1513,1540,1560,1573],{"type":41,"tag":192,"props":994,"children":995},{},[996,1012],{"type":41,"tag":214,"props":997,"children":998},{},[999,1004,1006],{"type":41,"tag":113,"props":1000,"children":1002},{"className":1001},[],[1003],{"type":46,"value":741},{"type":46,"value":1005}," fails with ",{"type":41,"tag":113,"props":1007,"children":1009},{"className":1008},[],[1010],{"type":46,"value":1011},"Refusing to prompt in non-TTY environment",{"type":41,"tag":214,"props":1013,"children":1014},{},[1015,1017,1023,1025,1030],{"type":46,"value":1016},"Pass all required flags non-interactively: ",{"type":41,"tag":113,"props":1018,"children":1020},{"className":1019},[],[1021],{"type":46,"value":1022},"npm init @capacitor\u002Fplugin \u003Cfolder> -- --name \"\u003Cnpm-name>\" --package-id \"\u003Creverse-dns>\" --class-name \"\u003CPascalCase>\" --description \"\u003Cone-line>\" --author \"\u003Cname \u003Cemail>>\" --license \"\u003CSPDX>\" --repo \"\u003Curl>\" --android-lang \"\u003Ckotlin|java>\"",{"type":46,"value":1024},". See ",{"type":41,"tag":113,"props":1026,"children":1028},{"className":1027},[],[1029],{"type":46,"value":463},{"type":46,"value":489},{"type":41,"tag":192,"props":1032,"children":1033},{},[1034,1049],{"type":41,"tag":214,"props":1035,"children":1036},{},[1037,1042,1043],{"type":41,"tag":113,"props":1038,"children":1040},{"className":1039},[],[1041],{"type":46,"value":741},{"type":46,"value":1005},{"type":41,"tag":113,"props":1044,"children":1046},{"className":1045},[],[1047],{"type":46,"value":1048},"invalid option: --android-lang undefined: Must be either 'kotlin' or 'java'",{"type":41,"tag":214,"props":1050,"children":1051},{},[1052,1054,1060,1062,1068,1070,1076],{"type":46,"value":1053},"The ",{"type":41,"tag":113,"props":1055,"children":1057},{"className":1056},[],[1058],{"type":46,"value":1059},"--android-lang",{"type":46,"value":1061}," flag is required when running non-interactively. Add ",{"type":41,"tag":113,"props":1063,"children":1065},{"className":1064},[],[1066],{"type":46,"value":1067},"--android-lang \"kotlin\"",{"type":46,"value":1069}," (recommended for new plugins) or ",{"type":41,"tag":113,"props":1071,"children":1073},{"className":1072},[],[1074],{"type":46,"value":1075},"--android-lang \"java\"",{"type":46,"value":1077}," to the command.",{"type":41,"tag":192,"props":1079,"children":1080},{},[1081,1086],{"type":41,"tag":214,"props":1082,"children":1083},{},[1084],{"type":46,"value":1085},"Plugin silently fails to load",{"type":41,"tag":214,"props":1087,"children":1088},{},[1089,1091,1096,1098,1103,1105,1110],{"type":46,"value":1090},"Make ",{"type":41,"tag":113,"props":1092,"children":1094},{"className":1093},[],[1095],{"type":46,"value":471},{"type":46,"value":1097}," name match iOS ",{"type":41,"tag":113,"props":1099,"children":1101},{"className":1100},[],[1102],{"type":46,"value":479},{"type":46,"value":1104}," and Android ",{"type":41,"tag":113,"props":1106,"children":1108},{"className":1107},[],[1109],{"type":46,"value":487},{"type":46,"value":489},{"type":41,"tag":192,"props":1112,"children":1113},{},[1114,1119],{"type":41,"tag":214,"props":1115,"children":1116},{},[1117],{"type":46,"value":1118},"Event not received in JS",{"type":41,"tag":214,"props":1120,"children":1121},{},[1122],{"type":46,"value":1123},"Make the event name string identical across TypeScript, web, iOS, and Android.",{"type":41,"tag":192,"props":1125,"children":1126},{},[1127,1132],{"type":41,"tag":214,"props":1128,"children":1129},{},[1130],{"type":46,"value":1131},"iOS method not callable from JS",{"type":41,"tag":214,"props":1133,"children":1134},{},[1135,1137,1143,1145,1151],{"type":46,"value":1136},"Ensure the method is marked ",{"type":41,"tag":113,"props":1138,"children":1140},{"className":1139},[],[1141],{"type":46,"value":1142},"@objc",{"type":46,"value":1144}," and listed in ",{"type":41,"tag":113,"props":1146,"children":1148},{"className":1147},[],[1149],{"type":46,"value":1150},"pluginMethods",{"type":46,"value":489},{"type":41,"tag":192,"props":1153,"children":1154},{},[1155,1160],{"type":41,"tag":214,"props":1156,"children":1157},{},[1158],{"type":46,"value":1159},"Android method not callable from JS",{"type":41,"tag":214,"props":1161,"children":1162},{},[1163,1165,1171],{"type":46,"value":1164},"Ensure the method is public and annotated with ",{"type":41,"tag":113,"props":1166,"children":1168},{"className":1167},[],[1169],{"type":46,"value":1170},"@PluginMethod()",{"type":46,"value":489},{"type":41,"tag":192,"props":1173,"children":1174},{},[1175,1186],{"type":41,"tag":214,"props":1176,"children":1177},{},[1178,1184],{"type":41,"tag":113,"props":1179,"children":1181},{"className":1180},[],[1182],{"type":46,"value":1183},"npm run verify:ios",{"type":46,"value":1185}," fails",{"type":41,"tag":214,"props":1187,"children":1188},{},[1189,1191,1197],{"type":46,"value":1190},"Run ",{"type":41,"tag":113,"props":1192,"children":1194},{"className":1193},[],[1195],{"type":46,"value":1196},"pod install --repo-update",{"type":46,"value":1198},"; then rerun the iOS verify command.",{"type":41,"tag":192,"props":1200,"children":1201},{},[1202,1212],{"type":41,"tag":214,"props":1203,"children":1204},{},[1205,1211],{"type":41,"tag":113,"props":1206,"children":1208},{"className":1207},[],[1209],{"type":46,"value":1210},"npm run verify:android",{"type":46,"value":1185},{"type":41,"tag":214,"props":1213,"children":1214},{},[1215],{"type":46,"value":1216},"Sync Gradle and check Android SDK, compile SDK, and dependency versions.",{"type":41,"tag":192,"props":1218,"children":1219},{},[1220,1231],{"type":41,"tag":214,"props":1221,"children":1222},{},[1223,1225],{"type":46,"value":1224},"Android compile error: ",{"type":41,"tag":113,"props":1226,"children":1228},{"className":1227},[],[1229],{"type":46,"value":1230},"class X is public, should be declared in a file named X.java",{"type":41,"tag":214,"props":1232,"children":1233},{},[1234],{"type":46,"value":1235},"Java requires a public class to live in a file matching its name. When generating multiple Java classes per plugin, place each public class in its own file. Kotlin does not impose this rule.",{"type":41,"tag":192,"props":1237,"children":1238},{},[1239,1249],{"type":41,"tag":214,"props":1240,"children":1241},{},[1242,1243],{"type":46,"value":1224},{"type":41,"tag":113,"props":1244,"children":1246},{"className":1245},[],[1247],{"type":46,"value":1248},"notifyListeners(...) has protected access in Plugin",{"type":41,"tag":214,"props":1250,"children":1251},{},[1252,1258,1260,1266,1268,1273,1275,1280,1282,1287],{"type":41,"tag":113,"props":1253,"children":1255},{"className":1254},[],[1256],{"type":46,"value":1257},"notifyListeners()",{"type":46,"value":1259}," is ",{"type":41,"tag":113,"props":1261,"children":1263},{"className":1262},[],[1264],{"type":46,"value":1265},"protected",{"type":46,"value":1267}," on ",{"type":41,"tag":113,"props":1269,"children":1271},{"className":1270},[],[1272],{"type":46,"value":638},{"type":46,"value":1274},". Call it only from inside a class that extends ",{"type":41,"tag":113,"props":1276,"children":1278},{"className":1277},[],[1279],{"type":46,"value":638},{"type":46,"value":1281},". If another class needs to emit events, return the data to the plugin and dispatch there, or expose a public wrapper on the plugin that calls ",{"type":41,"tag":113,"props":1283,"children":1285},{"className":1284},[],[1286],{"type":46,"value":1257},{"type":46,"value":1288}," internally.",{"type":41,"tag":192,"props":1290,"children":1291},{},[1292,1312],{"type":41,"tag":214,"props":1293,"children":1294},{},[1295,1296,1302,1304,1310],{"type":46,"value":1224},{"type":41,"tag":113,"props":1297,"children":1299},{"className":1298},[],[1300],{"type":46,"value":1301},"cannot find symbol: class …",{"type":46,"value":1303}," for a ",{"type":41,"tag":113,"props":1305,"children":1307},{"className":1306},[],[1308],{"type":46,"value":1309},"com.getcapacitor.*",{"type":46,"value":1311}," import",{"type":41,"tag":214,"props":1313,"children":1314},{},[1315,1317,1322],{"type":46,"value":1316},"The import does not exist on the installed ",{"type":41,"tag":113,"props":1318,"children":1320},{"className":1319},[],[1321],{"type":46,"value":341},{"type":46,"value":1323}," surface. Verify imports against the package source before generating; do not infer Capacitor classes from their names.",{"type":41,"tag":192,"props":1325,"children":1326},{},[1327,1337],{"type":41,"tag":214,"props":1328,"children":1329},{},[1330,1331],{"type":46,"value":1224},{"type":41,"tag":113,"props":1332,"children":1334},{"className":1333},[],[1335],{"type":46,"value":1336},"\u003Cmethod> in \u003CSubclass> cannot override \u003Cmethod> in Plugin; attempting to assign weaker access privileges; was public",{"type":41,"tag":214,"props":1338,"children":1339},{},[1340,1342,1347,1349,1355,1357,1363,1365,1371,1372,1378,1379,1385,1387,1392],{"type":46,"value":1341},"A helper on the ",{"type":41,"tag":113,"props":1343,"children":1345},{"className":1344},[],[1346],{"type":46,"value":638},{"type":46,"value":1348}," subclass collides with a ",{"type":41,"tag":113,"props":1350,"children":1352},{"className":1351},[],[1353],{"type":46,"value":1354},"public",{"type":46,"value":1356}," method that ",{"type":41,"tag":113,"props":1358,"children":1360},{"className":1359},[],[1361],{"type":46,"value":1362},"com.getcapacitor.Plugin",{"type":46,"value":1364}," already defines (e.g., ",{"type":41,"tag":113,"props":1366,"children":1368},{"className":1367},[],[1369],{"type":46,"value":1370},"hasPermission",{"type":46,"value":851},{"type":41,"tag":113,"props":1373,"children":1375},{"className":1374},[],[1376],{"type":46,"value":1377},"getPermissionState",{"type":46,"value":851},{"type":41,"tag":113,"props":1380,"children":1382},{"className":1381},[],[1383],{"type":46,"value":1384},"notifyListeners",{"type":46,"value":1386},"). Either rename the helper or match the parent's ",{"type":41,"tag":113,"props":1388,"children":1390},{"className":1389},[],[1391],{"type":46,"value":1354},{"type":46,"value":1393}," visibility.",{"type":41,"tag":192,"props":1395,"children":1396},{},[1397,1416],{"type":41,"tag":214,"props":1398,"children":1399},{},[1400,1402,1408,1410],{"type":46,"value":1401},"TypeScript build error: ",{"type":41,"tag":113,"props":1403,"children":1405},{"className":1404},[],[1406],{"type":46,"value":1407},"Cannot find type definition file for '\u003Cname>'",{"type":46,"value":1409}," or ",{"type":41,"tag":113,"props":1411,"children":1413},{"className":1412},[],[1414],{"type":46,"value":1415},"Invalid module name in augmentation, module '\u003Cname>' cannot be found",{"type":41,"tag":214,"props":1417,"children":1418},{},[1419,1421,1427,1429,1435,1437,1443,1445,1451],{"type":46,"value":1420},"The augmented module is not installed. Add it to ",{"type":41,"tag":113,"props":1422,"children":1424},{"className":1423},[],[1425],{"type":46,"value":1426},"devDependencies",{"type":46,"value":1428}," (and to ",{"type":41,"tag":113,"props":1430,"children":1432},{"className":1431},[],[1433],{"type":46,"value":1434},"tsconfig.json",{"type":46,"value":1436}," ",{"type":41,"tag":113,"props":1438,"children":1440},{"className":1439},[],[1441],{"type":46,"value":1442},"compilerOptions.types",{"type":46,"value":1444}," if a triple-slash reference is used). Applies to any module augmentation, not just ",{"type":41,"tag":113,"props":1446,"children":1448},{"className":1447},[],[1449],{"type":46,"value":1450},"@capacitor\u002Fcli",{"type":46,"value":489},{"type":41,"tag":192,"props":1453,"children":1454},{},[1455,1467],{"type":41,"tag":214,"props":1456,"children":1457},{},[1458,1459,1465],{"type":46,"value":1401},{"type":41,"tag":113,"props":1460,"children":1462},{"className":1461},[],[1463],{"type":46,"value":1464},"Interface 'X' incorrectly extends interface 'Y'. Property 'Z' is optional in type 'X' but required in type 'Y'",{"type":46,"value":1466}," (or the symmetric error)",{"type":41,"tag":214,"props":1468,"children":1469},{},[1470,1472,1478,1480,1486],{"type":46,"value":1471},"Do not redeclare members the built-in lib type already provides. Use the lib type directly, or augment via ",{"type":41,"tag":113,"props":1473,"children":1475},{"className":1474},[],[1476],{"type":46,"value":1477},"declare global { interface Y { newMember?: ... } }",{"type":46,"value":1479}," for genuinely new members only. Use ",{"type":41,"tag":113,"props":1481,"children":1483},{"className":1482},[],[1484],{"type":46,"value":1485},"'name' in target",{"type":46,"value":1487}," runtime guards for capability checks.",{"type":41,"tag":192,"props":1489,"children":1490},{},[1491,1501],{"type":41,"tag":214,"props":1492,"children":1493},{},[1494,1499],{"type":41,"tag":113,"props":1495,"children":1497},{"className":1496},[],[1498],{"type":46,"value":689},{"type":46,"value":1500}," produces empty output",{"type":41,"tag":214,"props":1502,"children":1503},{},[1504,1506,1511],{"type":46,"value":1505},"Add JSDoc to ",{"type":41,"tag":113,"props":1507,"children":1509},{"className":1508},[],[1510],{"type":46,"value":513},{"type":46,"value":1512},"; docgen reads the TypeScript contract.",{"type":41,"tag":192,"props":1514,"children":1515},{},[1516,1521],{"type":41,"tag":214,"props":1517,"children":1518},{},[1519],{"type":46,"value":1520},"Web API absent in target browser",{"type":41,"tag":214,"props":1522,"children":1523},{},[1524,1526,1531,1533,1538],{"type":46,"value":1525},"Use ",{"type":41,"tag":113,"props":1527,"children":1529},{"className":1528},[],[1530],{"type":46,"value":555},{"type":46,"value":1532}," when the API exists but is missing here; use ",{"type":41,"tag":113,"props":1534,"children":1536},{"className":1535},[],[1537],{"type":46,"value":563},{"type":46,"value":1539}," when no web equivalent exists.",{"type":41,"tag":192,"props":1541,"children":1542},{},[1543,1548],{"type":41,"tag":214,"props":1544,"children":1545},{},[1546],{"type":46,"value":1547},"Structured YAML is rejected",{"type":41,"tag":214,"props":1549,"children":1550},{},[1551,1553,1558],{"type":46,"value":1552},"Validate against ",{"type":41,"tag":113,"props":1554,"children":1556},{"className":1555},[],[1557],{"type":46,"value":305},{"type":46,"value":1559},"; ensure required base fields are present and blockers are empty.",{"type":41,"tag":192,"props":1561,"children":1562},{},[1563,1568],{"type":41,"tag":214,"props":1564,"children":1565},{},[1566],{"type":46,"value":1567},"Generated output looks too broad",{"type":41,"tag":214,"props":1569,"children":1570},{},[1571],{"type":46,"value":1572},"Split unrelated capabilities into separate plugins and regenerate with a smaller API surface.",{"type":41,"tag":192,"props":1574,"children":1575},{},[1576,1581],{"type":41,"tag":214,"props":1577,"children":1578},{},[1579],{"type":46,"value":1580},"Generated native code reimplements logic the official plugin delegates to a native SDK",{"type":41,"tag":214,"props":1582,"children":1583},{},[1584,1586,1592,1594,1600,1601,1607,1609,1614],{"type":46,"value":1585},"Inspect the official plugin's ",{"type":41,"tag":113,"props":1587,"children":1589},{"className":1588},[],[1590],{"type":46,"value":1591},".podspec",{"type":46,"value":1593}," \u002F ",{"type":41,"tag":113,"props":1595,"children":1597},{"className":1596},[],[1598],{"type":46,"value":1599},"Package.swift",{"type":46,"value":1593},{"type":41,"tag":113,"props":1602,"children":1604},{"className":1603},[],[1605],{"type":46,"value":1606},"android\u002Fbuild.gradle",{"type":46,"value":1608}," for native SDK dependencies. If present, declare the same SDK and write a thin adapter — see ",{"type":41,"tag":113,"props":1610,"children":1612},{"className":1611},[],[1613],{"type":46,"value":505},{"type":46,"value":1615}," \"Native Dependency Detection\".",{"type":41,"tag":55,"props":1617,"children":1619},{"id":1618},"related-skills",[1620],{"type":46,"value":1621},"Related Skills",{"type":41,"tag":73,"props":1623,"children":1624},{},[1625],{"type":41,"tag":77,"props":1626,"children":1627},{},[1628,1633],{"type":41,"tag":113,"props":1629,"children":1631},{"className":1630},[],[1632],{"type":46,"value":118},{"type":46,"value":1634},": Analyze Cordova plugins and produce a\nstructured migration plan for this generator.",{"type":41,"tag":55,"props":1636,"children":1638},{"id":1637},"references",[1639],{"type":46,"value":1640},"References",{"type":41,"tag":73,"props":1642,"children":1643},{},[1644,1654,1664,1674,1684,1694,1704,1714,1731,1741,1751,1761,1772],{"type":41,"tag":77,"props":1645,"children":1646},{},[1647,1652],{"type":41,"tag":113,"props":1648,"children":1650},{"className":1649},[],[1651],{"type":46,"value":305},{"type":46,"value":1653},": Structured YAML contract for generator input.",{"type":41,"tag":77,"props":1655,"children":1656},{},[1657,1662],{"type":41,"tag":113,"props":1658,"children":1660},{"className":1659},[],[1661],{"type":46,"value":463},{"type":46,"value":1663},": Generator invocation, name parity, and scaffold verification.",{"type":41,"tag":77,"props":1665,"children":1666},{},[1667,1672],{"type":41,"tag":113,"props":1668,"children":1670},{"className":1669},[],[1671],{"type":46,"value":505},{"type":46,"value":1673},": TypeScript API design, JSDoc, event signatures, and method return types.",{"type":41,"tag":77,"props":1675,"children":1676},{},[1677,1682],{"type":41,"tag":113,"props":1678,"children":1680},{"className":1679},[],[1681],{"type":46,"value":539},{"type":46,"value":1683},": WebPlugin patterns, dynamic import, feature detection, and errors.",{"type":41,"tag":77,"props":1685,"children":1686},{},[1687,1692],{"type":41,"tag":113,"props":1688,"children":1690},{"className":1689},[],[1691],{"type":46,"value":598},{"type":46,"value":1693},": Bridge and Facade patterns plus event parity.",{"type":41,"tag":77,"props":1695,"children":1696},{},[1697,1702],{"type":41,"tag":113,"props":1698,"children":1700},{"className":1699},[],[1701],{"type":46,"value":606},{"type":46,"value":1703},": iOS bridge, implementation class, permissions, dependencies, and Podspec.",{"type":41,"tag":77,"props":1705,"children":1706},{},[1707,1712],{"type":41,"tag":113,"props":1708,"children":1710},{"className":1709},[],[1711],{"type":46,"value":630},{"type":46,"value":1713},": Android bridge, implementation class, permissions, dependencies, and Gradle.",{"type":41,"tag":77,"props":1715,"children":1716},{},[1717,1722,1724,1730],{"type":41,"tag":113,"props":1718,"children":1720},{"className":1719},[],[1721],{"type":46,"value":894},{"type":46,"value":1723},": Capacitor config keys under ",{"type":41,"tag":113,"props":1725,"children":1727},{"className":1726},[],[1728],{"type":46,"value":1729},"plugins.\u003CPluginJSName>",{"type":46,"value":489},{"type":41,"tag":77,"props":1732,"children":1733},{},[1734,1739],{"type":41,"tag":113,"props":1735,"children":1737},{"className":1736},[],[1738],{"type":46,"value":674},{"type":46,"value":1740},": Local linking, verify commands, hooks, and review workflow.",{"type":41,"tag":77,"props":1742,"children":1743},{},[1744,1749],{"type":41,"tag":113,"props":1745,"children":1747},{"className":1746},[],[1748],{"type":46,"value":681},{"type":46,"value":1750},": Package fields, docgen, checklist, and dry-run publishing.",{"type":41,"tag":77,"props":1752,"children":1753},{},[1754,1759],{"type":41,"tag":113,"props":1755,"children":1757},{"className":1756},[],[1758],{"type":46,"value":656},{"type":46,"value":1760},": Sample app requirements that exercise the full API.",{"type":41,"tag":77,"props":1762,"children":1763},{},[1764,1770],{"type":41,"tag":113,"props":1765,"children":1767},{"className":1766},[],[1768],{"type":46,"value":1769},"references\u002Fpermission-patterns.md",{"type":46,"value":1771},": Deep-dive on permission flows — multi-permission DispatchGroup on iOS, location delegate, check-before-use \u002F just-in-time \u002F deferred consumer patterns, opening system settings.",{"type":41,"tag":77,"props":1773,"children":1774},{},[1775,1781],{"type":41,"tag":113,"props":1776,"children":1778},{"className":1777},[],[1779],{"type":46,"value":1780},"references\u002Ftypescript-implementation.md",{"type":46,"value":1782},": Deep-dive on TypeScript layer — singleton plugin pattern, typed error classes, full event listener handle bookkeeping, helper utilities, Jest scaffolding.",{"items":1784,"total":1826},[1785,1804,1811],{"slug":1786,"name":1786,"fn":1787,"description":1788,"org":1789,"tags":1790,"stars":24,"repoUrl":25,"updatedAt":1803},"build-actions-generator","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},[1791,1794,1795,1798,1799,1802],{"name":1792,"slug":1793,"type":16},"Android","android",{"name":18,"slug":19,"type":16},{"name":1796,"slug":1797,"type":16},"Deployment","deployment",{"name":9,"slug":8,"type":16},{"name":1800,"slug":1801,"type":16},"iOS","ios",{"name":14,"slug":15,"type":16},"2026-07-12T07:37:41.801053",{"slug":4,"name":4,"fn":5,"description":6,"org":1805,"tags":1806,"stars":24,"repoUrl":25,"updatedAt":26},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1807,1808,1809,1810],{"name":18,"slug":19,"type":16},{"name":21,"slug":22,"type":16},{"name":9,"slug":8,"type":16},{"name":14,"slug":15,"type":16},{"slug":1812,"name":1812,"fn":1813,"description":1814,"org":1815,"tags":1816,"stars":24,"repoUrl":25,"updatedAt":1825},"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},[1817,1818,1819,1820,1821,1824],{"name":1792,"slug":1793,"type":16},{"name":18,"slug":19,"type":16},{"name":9,"slug":8,"type":16},{"name":1800,"slug":1801,"type":16},{"name":1822,"slug":1823,"type":16},"Migration","migration",{"name":14,"slug":15,"type":16},"2026-07-12T07:37:43.055071",3,{"items":1828,"total":1826},[1829,1838,1845],{"slug":1786,"name":1786,"fn":1787,"description":1788,"org":1830,"tags":1831,"stars":24,"repoUrl":25,"updatedAt":1803},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1832,1833,1834,1835,1836,1837],{"name":1792,"slug":1793,"type":16},{"name":18,"slug":19,"type":16},{"name":1796,"slug":1797,"type":16},{"name":9,"slug":8,"type":16},{"name":1800,"slug":1801,"type":16},{"name":14,"slug":15,"type":16},{"slug":4,"name":4,"fn":5,"description":6,"org":1839,"tags":1840,"stars":24,"repoUrl":25,"updatedAt":26},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1841,1842,1843,1844],{"name":18,"slug":19,"type":16},{"name":21,"slug":22,"type":16},{"name":9,"slug":8,"type":16},{"name":14,"slug":15,"type":16},{"slug":1812,"name":1812,"fn":1813,"description":1814,"org":1846,"tags":1847,"stars":24,"repoUrl":25,"updatedAt":1825},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1848,1849,1850,1851,1852,1853],{"name":1792,"slug":1793,"type":16},{"name":18,"slug":19,"type":16},{"name":9,"slug":8,"type":16},{"name":1800,"slug":1801,"type":16},{"name":1822,"slug":1823,"type":16},{"name":14,"slug":15,"type":16}]