{"owner":"ankidroid","repo":"Anki-Android","hasSkills":true,"totalSkillsCount":9,"totalTokensCount":6410,"categories":["anthropic-skill","claude-rule","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":["tools/release-description.md","tools/localization/package.json","tools/chromeos/release.crx.json","CLAUDE.md",".agents/skills/README.md",".agents/skills/pr-full-review/SKILL.md","tools/localization/tsconfig.json",".agents/skills/pr-full-review/reviewer-guide.md","tools/localization/README.md"],"skills":{"tools/release-description.md":"> [!IMPORTANT]\n> GitHub does not auto-update apps\n\n\n## For regular users\n\nInstall `arm64-v8a` from the **Assets** section below. If it fails to install, use `Parallel.A`.\n\n`Parallel` builds install side-by-side with the main APK, allowing you to use different settings and profiles (via the `AnkiDroid directory` advanced setting and a different AnkiWeb login).\n\n\n## For testers\n\nThe builds with `full`, `play` and `amazon` are useful for testing our builds for different app stores:\n\n- **`full`**: F-Droid & GitHub `Parallel` apks\n- **`play`**: Google Play - does not have `MANAGE_EXTERNAL_STORAGE` permission as it is forbidden by Google, on uninstall the user is invited to delete data.\n- **`amazon`**: Amazon - currently same as full, historically removed `CAMERA` permission\n\n\n## ABI variants\n\nWe perform ABI splits to reduce APK size. In rare cases, a phone may not be using the `arm64-v8a` ABI. You can find your phone's ABI using [kamgurgul/cpu-info](https://github.com/kamgurgul/cpu-info). If disk space isn't an issue, use the `full` apk.","tools/localization/package.json":"{\n    \"name\": \"ankidroid-localization\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Extract localization for AnkiDroid using Crowdin JS client api\",\n    \"main\": \"index.ts\",\n    \"private\": true,\n    \"scripts\": {\n        \"build\": \"tsc\",\n        \"start\": \"node ./dist/index.js\",\n        \"dev\": \"tsc --watch\",\n        \"checkformat\": \"npx prettier --check *js src/\",\n        \"format\": \"npx prettier --write *js src/\",\n        \"lint\": \"eslint src/ --max-warnings=0\",\n        \"test\": \"jest --passWithNoTests\"\n    },\n    \"repository\": \"https://github.com/ankidroid/Anki-Android\",\n    \"author\": \"AnkiDroid Open Source Team\",\n    \"license\": \"GPL-3.0\",\n    \"dependencies\": {\n        \"@crowdin/crowdin-api-client\": \"^1.58.0\",\n        \"axios\": \"^1.20.0\",\n        \"dotenv\": \"^18.0.4\",\n        \"extract-zip\": \"^2.0.1\",\n        \"typescript\": \"^6.0.3\"\n    },\n    \"devDependencies\": {\n        \"@eslint/eslintrc\": \"^3.3.7\",\n        \"@eslint/js\": \"^10.0.1\",\n        \"@types/jest\": \"^30.0.0\",\n        \"@types/node\": \"^26.6.3\",\n        \"@typescript-eslint/eslint-plugin\": \"^8.71.0\",\n        \"@typescript-eslint/parser\": \"^8.71.0\",\n        \"eslint\": \"^10.11.0\",\n        \"eslint-config-prettier\": \"^10.1.8\",\n        \"eslint-config-standard\": \"^17.1.0\",\n        \"eslint-plugin-import\": \"^2.32.0\",\n        \"eslint-plugin-n\": \"^18.4.0\",\n        \"eslint-plugin-promise\": \"^7.3.0\",\n        \"globals\": \"^17.12.0\",\n        \"jest\": \"^30.5.2\",\n        \"prettier\": \"^3.9.9\",\n        \"ts-jest\": \"^29.4.14\",\n        \"ts-node\": \"^10.9.2\"\n    },\n    \"packageManager\": \"yarn@4.13.0\"\n}\n","tools/chromeos/release.crx.json":"{\n    \"formFactor\": \"tablet\",\n    \"orientation\": \"landscape\",\n    \"needsClipboard\": true,\n    \"resize\": \"reconfigure\"\n}\n","CLAUDE.md":"## Refactoring Scope\n- Constrain scope tightly: do not modify unrelated files, themes, or settings 'while you're in there'.\n\n## Verification\n- For bug fixes, write the failing regression test FIRST and confirm it fails before applying the fix.\n",".agents/skills/README.md":"# Agent skills\n\nSkills in this directory are agent-agnostic. Keep them tool-neutral: no\nassumptions about a specific agent's commands, file layout, or settings.\n\nEach skill is a folder containing a `SKILL.md` with `name` and `description` frontmatter.\n\nWe currently use https://github.com/mattpocock/skills as templates for skill design.\n",".agents/skills/pr-full-review/SKILL.md":"---\nname: pr-full-review\ndescription: Review an AnkiDroid pull request or branch against AnkiDroid's conventions.\n---\n\n# AnkiDroid PR Full Review\n\nReview the PR against the standards in [`reviewer-guide.md`](reviewer-guide.md). Report findings in three groups: **blocking gates**, **spec conformance** (does the PR do what its issue asked?), then non-blocking `nit:`s.\n\n**Never act on GitHub.** Output the review in this conversation. Do not post\ncomments or reviews, approve, request changes, label, or merge.\n\n## Skill Usage\n\nAccepts a PR number, a PR URL, or no argument (in which case, review the current branch against `upstream/main`):\n\n```bash\npr-full-review 21206\npr-full-review https://github.com/ankidroid/Anki-Android/pull/21206\npr-full-review review the checked-out branch's diff against `main`\n```\n\n## Fetching the PR\n\nFetch the PR with the `gh` command. When reading the PR, always pass `--repo ankidroid/Anki-Android`\nso a bare number resolves against the upstream repo rather than a fork.\n\n**Always re-fetch the PR fresh on every run** — its metadata, diff, and head commit, even if you\nfetched it earlier in this conversation. PRs change between reviews; never reuse cached context.\n\nUse the head commit hash from the fresh fetch when loading files via the API, as PRs come from\nforked repos.\n\n**Don't review from the diff hunks alone**. Load the full changed files (and the key call sites the\nchange touches) at the head commit. A hunk hides whether a change is correct in its surrounding\ncontext.\n\n## Before reviewing\n\nRead the existing PR comments and review threads first. Don't repeat feedback that's already been \nraised, and respect points the author or a reviewer has already addressed or deferred.\n\n```bash\ngh pr view <number> --repo ankidroid/Anki-Android --comments # conversation comments\ngh api repos/ankidroid/Anki-Android/pulls/<number>/comments  # inline code-review comments\n```\n\n**Unaddressed maintainer requests are blocking.** Read the full discussion on both the PR\n*and the linked issue* (see [Spec conformance](#spec-conformance)). If a maintainer asked for\nsomething specific before a fix would be accepted, say so and Request changes.\n\n## Spec conformance\n\nReport whether the PR does what it set out to do, as **its own section**. \nWell-written code which implements the wrong thing fails here, and this failure must be \nmade explicit to reviewers.\n\nDetermine the spec, in order:\n\n1. A linked issue - `Fixes #`, `Closes #`, `Resolves #`, or `Part of #` in the body or commits \n   (typically written as `Fixes <N>` - the commit message may omit the `#`).\n2. Also include the PR's own **Purpose / Description**.\n\nOpen the issue and read it in full — **including its comments**. The decisive\ncontext often lives in the thread, not the description:\n\n```bash\ngh issue view <number> --repo ankidroid/Anki-Android --comments\n```\n\n### Bug fixes: establish the root cause before endorsing the fix\n\nFor a bug fix, spec conformance means the PR fixes **the actual cause**, not that it plausibly\nmight. Verify the author's fix:\n\n- **Trace the real code path** that triggers the bug (load the call sites and any resource/theme\n  values they read), and confirm the claimed trigger can actually occur. If your trace shows it\n*can't occur the way the PR describes, then the root cause is not understood. Say so explicitly.\n- **A fix applied without an understood, demonstrated trigger is tech debt:**. Treat \"unknown \n  root cause\" as a blocking finding and ask for the diagnostics / reproduction needed to establish \n  it first unless it is explicitly acknowledged as not being understood. \n    - State that it risks masking the real bug and the fallback behavior can't be validated against\n    a scenario nobody has captured.\n- Confirm the bug-fix commit actually evidences a reproduction.\n\n## Output\n\nOpen the review with a one-line verdict, mirroring GitHub's three review actions — the reader\nwill pick one of these on the PR:\n\n> **Verdict:** \\[Request changes / Comment / Approve\\]: <most important reason>\n\n- **Request changes:** a blocking gate fails (red/pending CI, unfilled template, merge commits,\n  missing license header, or a closing keyword on a partially-resolved issue), an explicit\n  maintainer request was skipped, a bug fix lands without an established/verified root cause, or\n  a correctness, spec, or test finding must be fixed before merge.\n- **Comment:** no blockers; nits, questions, or judgment calls raised without signing off.\n- **Approve:** gates pass and the change is sound - only `nit:`s remain, if anything.\n\nOne unaddressed blocker means Request changes, however polished the rest is.\n\nAfter the verdict, list the findings, grouped as above (blocking gates, spec conformance, nits).\n\n**Closing**: if this was a self-review, a `gh` command to checkout the PR (without `--repo`).\nClose with a final line linking the PR which was reviewed.\n","tools/localization/tsconfig.json":"{\n    \"compilerOptions\": {\n        /* Visit https://aka.ms/tsconfig to read more about this file */\n\n        /* Projects */\n        // \"incremental\": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */\n        // \"composite\": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */\n        // \"tsBuildInfoFile\": \"./.tsbuildinfo\",              /* Specify the path to .tsbuildinfo incremental compilation file. */\n        // \"disableSourceOfProjectReferenceRedirect\": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */\n        // \"disableSolutionSearching\": true,                 /* Opt a project out of multi-project reference checking when editing. */\n        // \"disableReferencedProjectLoad\": true,             /* Reduce the number of projects loaded automatically by TypeScript. */\n\n        /* Language and Environment */\n        \"target\": \"es2016\" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,\n        \"lib\": [\n            \"es2019\"\n        ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,\n        // \"jsx\": \"preserve\",                                /* Specify what JSX code is generated. */\n        // \"experimentalDecorators\": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */\n        // \"emitDecoratorMetadata\": true,                    /* Emit design-type metadata for decorated declarations in source files. */\n        // \"jsxFactory\": \"\",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */\n        // \"jsxFragmentFactory\": \"\",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */\n        // \"jsxImportSource\": \"\",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */\n        // \"reactNamespace\": \"\",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */\n        // \"noLib\": true,                                    /* Disable including any library files, including the default lib.d.ts. */\n        // \"useDefineForClassFields\": true,                  /* Emit ECMAScript-standard-compliant class fields. */\n        // \"moduleDetection\": \"auto\",                        /* Control what method is used to detect module-format JS files. */\n\n        /* Modules */\n        \"module\": \"commonjs\" /* Specify what module code is generated. */,\n        \"rootDir\": \"src\" /* Specify the root folder within your source files. */,\n        // \"moduleResolution\": \"node\",                       /* Specify how TypeScript looks up a file from a given module specifier. */\n        // \"baseUrl\": \"./\",                                  /* Specify the base directory to resolve non-relative module names. */\n        // \"paths\": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */\n        // \"rootDirs\": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */\n        // \"typeRoots\": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */\n        // \"types\": [],                                      /* Specify type package names to be included without being referenced in a source file. */\n        // \"allowUmdGlobalAccess\": true,                     /* Allow accessing UMD globals from modules. */\n        // \"moduleSuffixes\": [],                             /* List of file name suffixes to search when resolving a module. */\n        // \"resolveJsonModule\": true,                        /* Enable importing .json files. */\n        // \"noResolve\": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */\n\n        /* JavaScript Support */\n        // \"allowJs\": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */\n        // \"checkJs\": true,                                  /* Enable error reporting in type-checked JavaScript files. */\n        // \"maxNodeModuleJsDepth\": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */\n\n        /* Emit */\n        // \"declaration\": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */\n        // \"declarationMap\": true,                           /* Create sourcemaps for d.ts files. */\n        // \"emitDeclarationOnly\": true,                      /* Only output d.ts files and not JavaScript files. */\n        // \"sourceMap\": true,                                /* Create source map files for emitted JavaScript files. */\n        // \"outFile\": \"./\",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */\n        \"outDir\": \"./dist\" /* Specify an output folder for all emitted files. */,\n        // \"removeComments\": true,                           /* Disable emitting comments. */\n        // \"noEmit\": true,                                   /* Disable emitting files from a compilation. */\n        // \"importHelpers\": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */\n        // \"importsNotUsedAsValues\": \"remove\",               /* Specify emit/checking behavior for imports that are only used for types. */\n        // \"downlevelIteration\": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */\n        // \"sourceRoot\": \"\",                                 /* Specify the root path for debuggers to find the reference source code. */\n        // \"mapRoot\": \"\",                                    /* Specify the location where debugger should locate map files instead of generated locations. */\n        // \"inlineSourceMap\": true,                          /* Include sourcemap files inside the emitted JavaScript. */\n        // \"inlineSources\": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */\n        // \"emitBOM\": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */\n        // \"newLine\": \"crlf\",                                /* Set the newline character for emitting files. */\n        // \"stripInternal\": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */\n        // \"noEmitHelpers\": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */\n        // \"noEmitOnError\": true,                            /* Disable emitting files if any type checking errors are reported. */\n        // \"preserveConstEnums\": true,                       /* Disable erasing 'const enum' declarations in generated code. */\n        // \"declarationDir\": \"./\",                           /* Specify the output directory for generated declaration files. */\n        // \"preserveValueImports\": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */\n\n        /* Interop Constraints */\n        // \"isolatedModules\": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */\n        // \"allowSyntheticDefaultImports\": true,             /* Allow 'import x from y' when a module doesn't have a default export. */\n        \"esModuleInterop\": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,\n        // \"preserveSymlinks\": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */\n        \"forceConsistentCasingInFileNames\": true /* Ensure that casing is correct in imports. */,\n\n        /* Type Checking */\n        \"strict\": true /* Enable all strict type-checking options. */,\n        \"noImplicitAny\": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */,\n        // \"strictNullChecks\": true,                         /* When type checking, take into account 'null' and 'undefined'. */\n        // \"strictFunctionTypes\": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */\n        // \"strictBindCallApply\": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */\n        // \"strictPropertyInitialization\": true,             /* Check for class properties that are declared but not set in the constructor. */\n        // \"noImplicitThis\": true,                           /* Enable error reporting when 'this' is given the type 'any'. */\n        // \"useUnknownInCatchVariables\": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */\n        // \"alwaysStrict\": true,                             /* Ensure 'use strict' is always emitted. */\n        // \"noUnusedLocals\": true,                           /* Enable error reporting when local variables aren't read. */\n        // \"noUnusedParameters\": true,                       /* Raise an error when a function parameter isn't read. */\n        // \"exactOptionalPropertyTypes\": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */\n        // \"noImplicitReturns\": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */\n        // \"noFallthroughCasesInSwitch\": true,               /* Enable error reporting for fallthrough cases in switch statements. */\n        // \"noUncheckedIndexedAccess\": true,                 /* Add 'undefined' to a type when accessed using an index. */\n        // \"noImplicitOverride\": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */\n        // \"noPropertyAccessFromIndexSignature\": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */\n        // \"allowUnusedLabels\": true,                        /* Disable error reporting for unused labels. */\n        // \"allowUnreachableCode\": true,                     /* Disable error reporting for unreachable code. */\n\n        /* Completeness */\n        // \"skipDefaultLibCheck\": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */\n        \"skipLibCheck\": true /* Skip type checking all .d.ts files. */\n    }\n}\n",".agents/skills/pr-full-review/reviewer-guide.md":"# AnkiDroid PR Reviewer Guide\n\n## How to use this guide\n\nThis is the **standards corpus** for reviewing AnkiDroid changes - *what* to check, not\n*how* to run a review. It distills the project's documented standards into an actionable\nchecklist so a reviewer (human or agent) can work without opening ten other files.\n\nTwo rules of engagement:\n\n1. **The linked canonical sources are authoritative.** Where this guide and a source\n   disagree, the source wins. Load all the [Canonical sources](#canonical-sources) into context.\n2. **Reviewing is subjective.** As the wiki puts it: \"these guidelines are ONLY guidelines,\n   use your best judgment.\" Prefer the implementer's choice when a decision is a genuine\n   toss-up.\n\n## Tone\n\nFrom the [Code-review guide](https://github.com/ankidroid/Anki-Android/wiki/Code-review-guide):\n\n- **Establish contributor status first.** Check for the `New Contributor` label and count the\n  author's PRs, merged and unmerged (`gh pr list --author <login> --state all`), to gauge how\n  established and experienced they are - it sets the tone bar below and the AI-use policy applied.\n- **Be kind.** Note the good things in the PR and say thank you. Terse critique reads as\n  hostile in text.\n- **Relax for first-timers.** On PRs labelled `New Contributor`, lower the bar to make a\n  good first impression — get them landed, mentor later.\n- **Prefix non-blocking feedback with `nit:`** so the author knows it's optional.\n- **Defer to the implementer** when you're uncertain a change is actually an improvement.\n- Avoid demanding large changes unless they're a meaningful long-term improvement; suggest\n  splitting big PRs into smaller ones.\n\n## Blocking gates\n\nRequest changes if any of these fail — they're table stakes before deeper review:\n\n- **CI is green.** Lint, unit, emulator and CodeQL must pass. Don't just glance at the rollup\n  status (`gh pr checks <number> --repo ankidroid/Anki-Android`): if a check is **pending**, say\n  the gate is unverified; if a check is **failing**, read its log (`gh run view <run-id>\n  --repo ankidroid/Anki-Android --log-failed`) and report the actual cause, not just \"red\".\n  For new contributors, explain how to find and read the failure themselves — and consider pasting\n  the relevant CI output into the review so they don't have to dig for it. Refer the submitter to\n  [`.github/workflows/README.md`](../../../.github/workflows/README.md).\n- **PR template is filled in** (Purpose / Approach / How tested) and the PR is **linked to\n  an issue** (`Fixes #`) where one applies.\n- **Commit hygiene:** no merge commits in the history (rebase and force push, don't merge); \n  each commit compiles and does one thing. Commit titles should not be longer than 80 chars. \n  There is a suggestion for a <= 50 char title. Only flag this if you provide a reworded title.\n- **New source files carry an licensing header:** see [Licensing](#licensing).\n\n## What to check\n\n### Correctness & clarity\n- The codebase is better after the change than before.\n- Edge cases and exceptions are handled.\n- Names are understandable; hard-to-follow code is commented.\n\n### Bug fixes \n- Bug fix commits must contain a confirmation that the author reproduced the bug, unless the bug \n  is obvious, or the submitter has specifically stated why they were unable to reproduce it.\n- Trace the code path and the values it reads to confirm the claimed trigger occurs.\n\n### Tests\n- Significant new logic ships with tests, **or** is annotated\n  [`@NeedsTest(\"reason\")`](../../../common/src/main/java/com/ichi2/anki/common/annotations/NeedsTest.kt)\n  explaining why the test is deferred. The annotation exists so we signal that we care about\n  testing without blocking a contributor's first commits.\n- **Bug fixes need a regression test.** The expectation (see [`CLAUDE.md`](../../../CLAUDE.md))\n  is write-the-failing-test-first, confirm it fails, then fix.\n- **A test must exercise the changed production code and fail without the fix.** A contributor\n  should not copy production code into tests to ensure correctness.\n\n### Scope\n- Each commit must be focused. Refactors should be split from functional changes. \n- Flag unnecessary whitespace churn. Flag if a PR unnecessarily affects more than one concern.\n\n### Commit messages\n- Flag if a 'refactor:' commit title is used for a functional change.\n\n### GitHub\n- For new contributors, flag commits whose `user.email` isn't linked to a GitHub account, as\n  they won't receive attribution on their GitHub heatmap.\n\n### Licensing\n- **Never remove an existing copyright header** unless it is your own. See\n  [`docs/contributing/copyright-headers.md`](../../../docs/contributing/copyright-headers.md).\n- New external dependencies/resources: ensure the PR fills the **Licenses** table in the\n  template, and apply the `Licenses` label / update the licenses wiki on merge.\n\n### AI-use policy\nPer [`AI_POLICY.md`](../../../AI_POLICY.md):\n- Use the current documentation and determine if the user is a new contributor. Ensure that AI-use\n  restrictions are appropriately applied.\n\n### UI changes\n- A Roborazzi test of large UI changes is optional, but greatly appreciated. \n- Screenshots of **all** affected screens (especially new/changed strings).\n- Large changed are tested with the Google Accessibility Scanner.\n\n### Compose\nFor code under `com.ichi2.anki.ui.compose.*` (see\n[`docs/development/compose.md`](../../../docs/development/compose.md)):\n- Pure \"migrate this XML screen to Compose\" PRs aren't accepted — there must be another\n  reason to touch the screen.\n- No `Anki` prefix on component names; let the package path namespace them.\n- Wrap top-level composables in the project `Theme { }`; don't define parallel color tokens\n  in Kotlin (XML themes stay the source of truth).\n- Host Compose via a `ComposeView` returned from a Fragment's `onCreateView`.\n- Use existing drawables via `painterResource(R.drawable.…)`; don't add the\n  material-icons artifacts.\n- A rewrite adds a **Roborazzi screenshot test of the existing screen first** (ideally a\n  separate PR), then the rewrite. One concern per migration — no simultaneous state/nav\n  rework.\n\n## Canonical sources\n\nDefer to these authoritative references over the distillation above:\n\n- [Code-review guide (wiki)](https://github.com/ankidroid/Anki-Android/wiki/Code-review-guide) — tone, process, when to skip second approval.\n- [`CONTRIBUTING.md`](../../../CONTRIBUTING.md) — contribution workflow, commits, PR labels.\n- [`.github/pull_request_template.md`](../../../.github/pull_request_template.md) — required PR sections and checklist.\n- [`.github/workflows/README.md`](../../../.github/workflows/README.md) — the exact CI jobs and local commands.\n- [`lint-rules/.../IssueRegistry.kt`](../../../lint-rules/src/main/java/com/ichi2/anki/lint/IssueRegistry.kt) — the full custom lint-rule list.\n- [`common/.../annotations/NeedsTest.kt`](../../../common/src/main/java/com/ichi2/anki/common/annotations/NeedsTest.kt) — the `@NeedsTest` contract.\n- [`docs/contributing/copyright-headers.md`](../../../docs/contributing/copyright-headers.md) — SPDX / copyright rules.\n- [`AI_POLICY.md`](../../../AI_POLICY.md) — AI tool-use and disclosure policy.\n- [`docs/development/compose.md`](../../../docs/development/compose.md) — Compose conventions.\n- [`CLAUDE.md`](../../../CLAUDE.md) — scope discipline and regression-test-first.\n","tools/localization/README.md":"# Localization Tool\n\nThis project provides a localization tool built with Yarn, built specifically to interact with the crowdin API via their javascript API client\n\nIts purpose is to provide a way to upload our English-language localization files to crowdin so that translators may do their work, and then to download that translation work and faithfully copy it into the non-English Android resource locations.\n\n## Getting Started\n\nFollow these steps to set up and run the localization tool.\n\n```bash\n# Move to the proper directory\ncd ./tools/localization\n# Install the javascript dependencies\nyarn\n# Build the project so it is ready to run\nyarn build\n```\n\n## Commands\n\nThe following commands are available. Run them from the `./tools/localization` directory:\n\n### Upload\n\nUploads the English `res/values` files (from `common/android/src/main/res`) to Crowdin.\n\n> yarn start upload\n\n### Download\n\nBuilds and downloads all translations from Crowdin.\n\n> yarn start download\n\n### Extract\n\nExtracts files from `ankidroid.zip` into an internal staging area\n\n> yarn start extract\n\n### Update\n\nUpdates the files from the extracted `ankidroid.zip` file by processing them lightly (adding copyright information, fixing some common errors, etc), then copying them into `common/android/src/main/res/values-*` for the translated languages.\n\n> yarn start update\n\n## Build / Execution Notes\n\nThe project is implemented in typescript, which must be transpiled into javascript before it may be executed by the node interpreter.\n\nTo transpile the project run:\n\n> yarn build\n\n...or alternatively if you are actively developing the project, you may wish to have the code transpiled for testing on any change, this is possible with\n\n> yarn dev\n\n...which starts the `tsc` typescript compiler in `--watch` mode\n\nAfter building the project, you may use the `package.json` run scripts, or the following commands can also be used if you want to execute the transpiled scripts directly:\n\n```bash\nnode .\\dist\\index.js upload\nnode .\\dist\\index.js download\nnode .\\dist\\index.js extract\nnode .\\dist\\index.js update\n```\n"},"files":{"tools/release-description.md":"> [!IMPORTANT]\n> GitHub does not auto-update apps\n\n\n## For regular users\n\nInstall `arm64-v8a` from the **Assets** section below. If it fails to install, use `Parallel.A`.\n\n`Parallel` builds install side-by-side with the main APK, allowing you to use different settings and profiles (via the `AnkiDroid directory` advanced setting and a different AnkiWeb login).\n\n\n## For testers\n\nThe builds with `full`, `play` and `amazon` are useful for testing our builds for different app stores:\n\n- **`full`**: F-Droid & GitHub `Parallel` apks\n- **`play`**: Google Play - does not have `MANAGE_EXTERNAL_STORAGE` permission as it is forbidden by Google, on uninstall the user is invited to delete data.\n- **`amazon`**: Amazon - currently same as full, historically removed `CAMERA` permission\n\n\n## ABI variants\n\nWe perform ABI splits to reduce APK size. In rare cases, a phone may not be using the `arm64-v8a` ABI. You can find your phone's ABI using [kamgurgul/cpu-info](https://github.com/kamgurgul/cpu-info). If disk space isn't an issue, use the `full` apk.","tools/localization/package.json":"{\n    \"name\": \"ankidroid-localization\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Extract localization for AnkiDroid using Crowdin JS client api\",\n    \"main\": \"index.ts\",\n    \"private\": true,\n    \"scripts\": {\n        \"build\": \"tsc\",\n        \"start\": \"node ./dist/index.js\",\n        \"dev\": \"tsc --watch\",\n        \"checkformat\": \"npx prettier --check *js src/\",\n        \"format\": \"npx prettier --write *js src/\",\n        \"lint\": \"eslint src/ --max-warnings=0\",\n        \"test\": \"jest --passWithNoTests\"\n    },\n    \"repository\": \"https://github.com/ankidroid/Anki-Android\",\n    \"author\": \"AnkiDroid Open Source Team\",\n    \"license\": \"GPL-3.0\",\n    \"dependencies\": {\n        \"@crowdin/crowdin-api-client\": \"^1.58.0\",\n        \"axios\": \"^1.20.0\",\n        \"dotenv\": \"^18.0.4\",\n        \"extract-zip\": \"^2.0.1\",\n        \"typescript\": \"^6.0.3\"\n    },\n    \"devDependencies\": {\n        \"@eslint/eslintrc\": \"^3.3.7\",\n        \"@eslint/js\": \"^10.0.1\",\n        \"@types/jest\": \"^30.0.0\",\n        \"@types/node\": \"^26.6.3\",\n        \"@typescript-eslint/eslint-plugin\": \"^8.71.0\",\n        \"@typescript-eslint/parser\": \"^8.71.0\",\n        \"eslint\": \"^10.11.0\",\n        \"eslint-config-prettier\": \"^10.1.8\",\n        \"eslint-config-standard\": \"^17.1.0\",\n        \"eslint-plugin-import\": \"^2.32.0\",\n        \"eslint-plugin-n\": \"^18.4.0\",\n        \"eslint-plugin-promise\": \"^7.3.0\",\n        \"globals\": \"^17.12.0\",\n        \"jest\": \"^30.5.2\",\n        \"prettier\": \"^3.9.9\",\n        \"ts-jest\": \"^29.4.14\",\n        \"ts-node\": \"^10.9.2\"\n    },\n    \"packageManager\": \"yarn@4.13.0\"\n}\n","tools/chromeos/release.crx.json":"{\n    \"formFactor\": \"tablet\",\n    \"orientation\": \"landscape\",\n    \"needsClipboard\": true,\n    \"resize\": \"reconfigure\"\n}\n","CLAUDE.md":"## Refactoring Scope\n- Constrain scope tightly: do not modify unrelated files, themes, or settings 'while you're in there'.\n\n## Verification\n- For bug fixes, write the failing regression test FIRST and confirm it fails before applying the fix.\n",".agents/skills/README.md":"# Agent skills\n\nSkills in this directory are agent-agnostic. Keep them tool-neutral: no\nassumptions about a specific agent's commands, file layout, or settings.\n\nEach skill is a folder containing a `SKILL.md` with `name` and `description` frontmatter.\n\nWe currently use https://github.com/mattpocock/skills as templates for skill design.\n",".agents/skills/pr-full-review/SKILL.md":"---\nname: pr-full-review\ndescription: Review an AnkiDroid pull request or branch against AnkiDroid's conventions.\n---\n\n# AnkiDroid PR Full Review\n\nReview the PR against the standards in [`reviewer-guide.md`](reviewer-guide.md). Report findings in three groups: **blocking gates**, **spec conformance** (does the PR do what its issue asked?), then non-blocking `nit:`s.\n\n**Never act on GitHub.** Output the review in this conversation. Do not post\ncomments or reviews, approve, request changes, label, or merge.\n\n## Skill Usage\n\nAccepts a PR number, a PR URL, or no argument (in which case, review the current branch against `upstream/main`):\n\n```bash\npr-full-review 21206\npr-full-review https://github.com/ankidroid/Anki-Android/pull/21206\npr-full-review review the checked-out branch's diff against `main`\n```\n\n## Fetching the PR\n\nFetch the PR with the `gh` command. When reading the PR, always pass `--repo ankidroid/Anki-Android`\nso a bare number resolves against the upstream repo rather than a fork.\n\n**Always re-fetch the PR fresh on every run** — its metadata, diff, and head commit, even if you\nfetched it earlier in this conversation. PRs change between reviews; never reuse cached context.\n\nUse the head commit hash from the fresh fetch when loading files via the API, as PRs come from\nforked repos.\n\n**Don't review from the diff hunks alone**. Load the full changed files (and the key call sites the\nchange touches) at the head commit. A hunk hides whether a change is correct in its surrounding\ncontext.\n\n## Before reviewing\n\nRead the existing PR comments and review threads first. Don't repeat feedback that's already been \nraised, and respect points the author or a reviewer has already addressed or deferred.\n\n```bash\ngh pr view <number> --repo ankidroid/Anki-Android --comments # conversation comments\ngh api repos/ankidroid/Anki-Android/pulls/<number>/comments  # inline code-review comments\n```\n\n**Unaddressed maintainer requests are blocking.** Read the full discussion on both the PR\n*and the linked issue* (see [Spec conformance](#spec-conformance)). If a maintainer asked for\nsomething specific before a fix would be accepted, say so and Request changes.\n\n## Spec conformance\n\nReport whether the PR does what it set out to do, as **its own section**. \nWell-written code which implements the wrong thing fails here, and this failure must be \nmade explicit to reviewers.\n\nDetermine the spec, in order:\n\n1. A linked issue - `Fixes #`, `Closes #`, `Resolves #`, or `Part of #` in the body or commits \n   (typically written as `Fixes <N>` - the commit message may omit the `#`).\n2. Also include the PR's own **Purpose / Description**.\n\nOpen the issue and read it in full — **including its comments**. The decisive\ncontext often lives in the thread, not the description:\n\n```bash\ngh issue view <number> --repo ankidroid/Anki-Android --comments\n```\n\n### Bug fixes: establish the root cause before endorsing the fix\n\nFor a bug fix, spec conformance means the PR fixes **the actual cause**, not that it plausibly\nmight. Verify the author's fix:\n\n- **Trace the real code path** that triggers the bug (load the call sites and any resource/theme\n  values they read), and confirm the claimed trigger can actually occur. If your trace shows it\n*can't occur the way the PR describes, then the root cause is not understood. Say so explicitly.\n- **A fix applied without an understood, demonstrated trigger is tech debt:**. Treat \"unknown \n  root cause\" as a blocking finding and ask for the diagnostics / reproduction needed to establish \n  it first unless it is explicitly acknowledged as not being understood. \n    - State that it risks masking the real bug and the fallback behavior can't be validated against\n    a scenario nobody has captured.\n- Confirm the bug-fix commit actually evidences a reproduction.\n\n## Output\n\nOpen the review with a one-line verdict, mirroring GitHub's three review actions — the reader\nwill pick one of these on the PR:\n\n> **Verdict:** \\[Request changes / Comment / Approve\\]: <most important reason>\n\n- **Request changes:** a blocking gate fails (red/pending CI, unfilled template, merge commits,\n  missing license header, or a closing keyword on a partially-resolved issue), an explicit\n  maintainer request was skipped, a bug fix lands without an established/verified root cause, or\n  a correctness, spec, or test finding must be fixed before merge.\n- **Comment:** no blockers; nits, questions, or judgment calls raised without signing off.\n- **Approve:** gates pass and the change is sound - only `nit:`s remain, if anything.\n\nOne unaddressed blocker means Request changes, however polished the rest is.\n\nAfter the verdict, list the findings, grouped as above (blocking gates, spec conformance, nits).\n\n**Closing**: if this was a self-review, a `gh` command to checkout the PR (without `--repo`).\nClose with a final line linking the PR which was reviewed.\n","tools/localization/tsconfig.json":"{\n    \"compilerOptions\": {\n        /* Visit https://aka.ms/tsconfig to read more about this file */\n\n        /* Projects */\n        // \"incremental\": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */\n        // \"composite\": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */\n        // \"tsBuildInfoFile\": \"./.tsbuildinfo\",              /* Specify the path to .tsbuildinfo incremental compilation file. */\n        // \"disableSourceOfProjectReferenceRedirect\": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */\n        // \"disableSolutionSearching\": true,                 /* Opt a project out of multi-project reference checking when editing. */\n        // \"disableReferencedProjectLoad\": true,             /* Reduce the number of projects loaded automatically by TypeScript. */\n\n        /* Language and Environment */\n        \"target\": \"es2016\" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,\n        \"lib\": [\n            \"es2019\"\n        ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,\n        // \"jsx\": \"preserve\",                                /* Specify what JSX code is generated. */\n        // \"experimentalDecorators\": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */\n        // \"emitDecoratorMetadata\": true,                    /* Emit design-type metadata for decorated declarations in source files. */\n        // \"jsxFactory\": \"\",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */\n        // \"jsxFragmentFactory\": \"\",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */\n        // \"jsxImportSource\": \"\",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */\n        // \"reactNamespace\": \"\",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */\n        // \"noLib\": true,                                    /* Disable including any library files, including the default lib.d.ts. */\n        // \"useDefineForClassFields\": true,                  /* Emit ECMAScript-standard-compliant class fields. */\n        // \"moduleDetection\": \"auto\",                        /* Control what method is used to detect module-format JS files. */\n\n        /* Modules */\n        \"module\": \"commonjs\" /* Specify what module code is generated. */,\n        \"rootDir\": \"src\" /* Specify the root folder within your source files. */,\n        // \"moduleResolution\": \"node\",                       /* Specify how TypeScript looks up a file from a given module specifier. */\n        // \"baseUrl\": \"./\",                                  /* Specify the base directory to resolve non-relative module names. */\n        // \"paths\": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */\n        // \"rootDirs\": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */\n        // \"typeRoots\": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */\n        // \"types\": [],                                      /* Specify type package names to be included without being referenced in a source file. */\n        // \"allowUmdGlobalAccess\": true,                     /* Allow accessing UMD globals from modules. */\n        // \"moduleSuffixes\": [],                             /* List of file name suffixes to search when resolving a module. */\n        // \"resolveJsonModule\": true,                        /* Enable importing .json files. */\n        // \"noResolve\": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */\n\n        /* JavaScript Support */\n        // \"allowJs\": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */\n        // \"checkJs\": true,                                  /* Enable error reporting in type-checked JavaScript files. */\n        // \"maxNodeModuleJsDepth\": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */\n\n        /* Emit */\n        // \"declaration\": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */\n        // \"declarationMap\": true,                           /* Create sourcemaps for d.ts files. */\n        // \"emitDeclarationOnly\": true,                      /* Only output d.ts files and not JavaScript files. */\n        // \"sourceMap\": true,                                /* Create source map files for emitted JavaScript files. */\n        // \"outFile\": \"./\",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */\n        \"outDir\": \"./dist\" /* Specify an output folder for all emitted files. */,\n        // \"removeComments\": true,                           /* Disable emitting comments. */\n        // \"noEmit\": true,                                   /* Disable emitting files from a compilation. */\n        // \"importHelpers\": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */\n        // \"importsNotUsedAsValues\": \"remove\",               /* Specify emit/checking behavior for imports that are only used for types. */\n        // \"downlevelIteration\": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */\n        // \"sourceRoot\": \"\",                                 /* Specify the root path for debuggers to find the reference source code. */\n        // \"mapRoot\": \"\",                                    /* Specify the location where debugger should locate map files instead of generated locations. */\n        // \"inlineSourceMap\": true,                          /* Include sourcemap files inside the emitted JavaScript. */\n        // \"inlineSources\": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */\n        // \"emitBOM\": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */\n        // \"newLine\": \"crlf\",                                /* Set the newline character for emitting files. */\n        // \"stripInternal\": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */\n        // \"noEmitHelpers\": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */\n        // \"noEmitOnError\": true,                            /* Disable emitting files if any type checking errors are reported. */\n        // \"preserveConstEnums\": true,                       /* Disable erasing 'const enum' declarations in generated code. */\n        // \"declarationDir\": \"./\",                           /* Specify the output directory for generated declaration files. */\n        // \"preserveValueImports\": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */\n\n        /* Interop Constraints */\n        // \"isolatedModules\": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */\n        // \"allowSyntheticDefaultImports\": true,             /* Allow 'import x from y' when a module doesn't have a default export. */\n        \"esModuleInterop\": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,\n        // \"preserveSymlinks\": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */\n        \"forceConsistentCasingInFileNames\": true /* Ensure that casing is correct in imports. */,\n\n        /* Type Checking */\n        \"strict\": true /* Enable all strict type-checking options. */,\n        \"noImplicitAny\": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */,\n        // \"strictNullChecks\": true,                         /* When type checking, take into account 'null' and 'undefined'. */\n        // \"strictFunctionTypes\": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */\n        // \"strictBindCallApply\": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */\n        // \"strictPropertyInitialization\": true,             /* Check for class properties that are declared but not set in the constructor. */\n        // \"noImplicitThis\": true,                           /* Enable error reporting when 'this' is given the type 'any'. */\n        // \"useUnknownInCatchVariables\": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */\n        // \"alwaysStrict\": true,                             /* Ensure 'use strict' is always emitted. */\n        // \"noUnusedLocals\": true,                           /* Enable error reporting when local variables aren't read. */\n        // \"noUnusedParameters\": true,                       /* Raise an error when a function parameter isn't read. */\n        // \"exactOptionalPropertyTypes\": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */\n        // \"noImplicitReturns\": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */\n        // \"noFallthroughCasesInSwitch\": true,               /* Enable error reporting for fallthrough cases in switch statements. */\n        // \"noUncheckedIndexedAccess\": true,                 /* Add 'undefined' to a type when accessed using an index. */\n        // \"noImplicitOverride\": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */\n        // \"noPropertyAccessFromIndexSignature\": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */\n        // \"allowUnusedLabels\": true,                        /* Disable error reporting for unused labels. */\n        // \"allowUnreachableCode\": true,                     /* Disable error reporting for unreachable code. */\n\n        /* Completeness */\n        // \"skipDefaultLibCheck\": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */\n        \"skipLibCheck\": true /* Skip type checking all .d.ts files. */\n    }\n}\n",".agents/skills/pr-full-review/reviewer-guide.md":"# AnkiDroid PR Reviewer Guide\n\n## How to use this guide\n\nThis is the **standards corpus** for reviewing AnkiDroid changes - *what* to check, not\n*how* to run a review. It distills the project's documented standards into an actionable\nchecklist so a reviewer (human or agent) can work without opening ten other files.\n\nTwo rules of engagement:\n\n1. **The linked canonical sources are authoritative.** Where this guide and a source\n   disagree, the source wins. Load all the [Canonical sources](#canonical-sources) into context.\n2. **Reviewing is subjective.** As the wiki puts it: \"these guidelines are ONLY guidelines,\n   use your best judgment.\" Prefer the implementer's choice when a decision is a genuine\n   toss-up.\n\n## Tone\n\nFrom the [Code-review guide](https://github.com/ankidroid/Anki-Android/wiki/Code-review-guide):\n\n- **Establish contributor status first.** Check for the `New Contributor` label and count the\n  author's PRs, merged and unmerged (`gh pr list --author <login> --state all`), to gauge how\n  established and experienced they are - it sets the tone bar below and the AI-use policy applied.\n- **Be kind.** Note the good things in the PR and say thank you. Terse critique reads as\n  hostile in text.\n- **Relax for first-timers.** On PRs labelled `New Contributor`, lower the bar to make a\n  good first impression — get them landed, mentor later.\n- **Prefix non-blocking feedback with `nit:`** so the author knows it's optional.\n- **Defer to the implementer** when you're uncertain a change is actually an improvement.\n- Avoid demanding large changes unless they're a meaningful long-term improvement; suggest\n  splitting big PRs into smaller ones.\n\n## Blocking gates\n\nRequest changes if any of these fail — they're table stakes before deeper review:\n\n- **CI is green.** Lint, unit, emulator and CodeQL must pass. Don't just glance at the rollup\n  status (`gh pr checks <number> --repo ankidroid/Anki-Android`): if a check is **pending**, say\n  the gate is unverified; if a check is **failing**, read its log (`gh run view <run-id>\n  --repo ankidroid/Anki-Android --log-failed`) and report the actual cause, not just \"red\".\n  For new contributors, explain how to find and read the failure themselves — and consider pasting\n  the relevant CI output into the review so they don't have to dig for it. Refer the submitter to\n  [`.github/workflows/README.md`](../../../.github/workflows/README.md).\n- **PR template is filled in** (Purpose / Approach / How tested) and the PR is **linked to\n  an issue** (`Fixes #`) where one applies.\n- **Commit hygiene:** no merge commits in the history (rebase and force push, don't merge); \n  each commit compiles and does one thing. Commit titles should not be longer than 80 chars. \n  There is a suggestion for a <= 50 char title. Only flag this if you provide a reworded title.\n- **New source files carry an licensing header:** see [Licensing](#licensing).\n\n## What to check\n\n### Correctness & clarity\n- The codebase is better after the change than before.\n- Edge cases and exceptions are handled.\n- Names are understandable; hard-to-follow code is commented.\n\n### Bug fixes \n- Bug fix commits must contain a confirmation that the author reproduced the bug, unless the bug \n  is obvious, or the submitter has specifically stated why they were unable to reproduce it.\n- Trace the code path and the values it reads to confirm the claimed trigger occurs.\n\n### Tests\n- Significant new logic ships with tests, **or** is annotated\n  [`@NeedsTest(\"reason\")`](../../../common/src/main/java/com/ichi2/anki/common/annotations/NeedsTest.kt)\n  explaining why the test is deferred. The annotation exists so we signal that we care about\n  testing without blocking a contributor's first commits.\n- **Bug fixes need a regression test.** The expectation (see [`CLAUDE.md`](../../../CLAUDE.md))\n  is write-the-failing-test-first, confirm it fails, then fix.\n- **A test must exercise the changed production code and fail without the fix.** A contributor\n  should not copy production code into tests to ensure correctness.\n\n### Scope\n- Each commit must be focused. Refactors should be split from functional changes. \n- Flag unnecessary whitespace churn. Flag if a PR unnecessarily affects more than one concern.\n\n### Commit messages\n- Flag if a 'refactor:' commit title is used for a functional change.\n\n### GitHub\n- For new contributors, flag commits whose `user.email` isn't linked to a GitHub account, as\n  they won't receive attribution on their GitHub heatmap.\n\n### Licensing\n- **Never remove an existing copyright header** unless it is your own. See\n  [`docs/contributing/copyright-headers.md`](../../../docs/contributing/copyright-headers.md).\n- New external dependencies/resources: ensure the PR fills the **Licenses** table in the\n  template, and apply the `Licenses` label / update the licenses wiki on merge.\n\n### AI-use policy\nPer [`AI_POLICY.md`](../../../AI_POLICY.md):\n- Use the current documentation and determine if the user is a new contributor. Ensure that AI-use\n  restrictions are appropriately applied.\n\n### UI changes\n- A Roborazzi test of large UI changes is optional, but greatly appreciated. \n- Screenshots of **all** affected screens (especially new/changed strings).\n- Large changed are tested with the Google Accessibility Scanner.\n\n### Compose\nFor code under `com.ichi2.anki.ui.compose.*` (see\n[`docs/development/compose.md`](../../../docs/development/compose.md)):\n- Pure \"migrate this XML screen to Compose\" PRs aren't accepted — there must be another\n  reason to touch the screen.\n- No `Anki` prefix on component names; let the package path namespace them.\n- Wrap top-level composables in the project `Theme { }`; don't define parallel color tokens\n  in Kotlin (XML themes stay the source of truth).\n- Host Compose via a `ComposeView` returned from a Fragment's `onCreateView`.\n- Use existing drawables via `painterResource(R.drawable.…)`; don't add the\n  material-icons artifacts.\n- A rewrite adds a **Roborazzi screenshot test of the existing screen first** (ideally a\n  separate PR), then the rewrite. One concern per migration — no simultaneous state/nav\n  rework.\n\n## Canonical sources\n\nDefer to these authoritative references over the distillation above:\n\n- [Code-review guide (wiki)](https://github.com/ankidroid/Anki-Android/wiki/Code-review-guide) — tone, process, when to skip second approval.\n- [`CONTRIBUTING.md`](../../../CONTRIBUTING.md) — contribution workflow, commits, PR labels.\n- [`.github/pull_request_template.md`](../../../.github/pull_request_template.md) — required PR sections and checklist.\n- [`.github/workflows/README.md`](../../../.github/workflows/README.md) — the exact CI jobs and local commands.\n- [`lint-rules/.../IssueRegistry.kt`](../../../lint-rules/src/main/java/com/ichi2/anki/lint/IssueRegistry.kt) — the full custom lint-rule list.\n- [`common/.../annotations/NeedsTest.kt`](../../../common/src/main/java/com/ichi2/anki/common/annotations/NeedsTest.kt) — the `@NeedsTest` contract.\n- [`docs/contributing/copyright-headers.md`](../../../docs/contributing/copyright-headers.md) — SPDX / copyright rules.\n- [`AI_POLICY.md`](../../../AI_POLICY.md) — AI tool-use and disclosure policy.\n- [`docs/development/compose.md`](../../../docs/development/compose.md) — Compose conventions.\n- [`CLAUDE.md`](../../../CLAUDE.md) — scope discipline and regression-test-first.\n","tools/localization/README.md":"# Localization Tool\n\nThis project provides a localization tool built with Yarn, built specifically to interact with the crowdin API via their javascript API client\n\nIts purpose is to provide a way to upload our English-language localization files to crowdin so that translators may do their work, and then to download that translation work and faithfully copy it into the non-English Android resource locations.\n\n## Getting Started\n\nFollow these steps to set up and run the localization tool.\n\n```bash\n# Move to the proper directory\ncd ./tools/localization\n# Install the javascript dependencies\nyarn\n# Build the project so it is ready to run\nyarn build\n```\n\n## Commands\n\nThe following commands are available. Run them from the `./tools/localization` directory:\n\n### Upload\n\nUploads the English `res/values` files (from `common/android/src/main/res`) to Crowdin.\n\n> yarn start upload\n\n### Download\n\nBuilds and downloads all translations from Crowdin.\n\n> yarn start download\n\n### Extract\n\nExtracts files from `ankidroid.zip` into an internal staging area\n\n> yarn start extract\n\n### Update\n\nUpdates the files from the extracted `ankidroid.zip` file by processing them lightly (adding copyright information, fixing some common errors, etc), then copying them into `common/android/src/main/res/values-*` for the translated languages.\n\n> yarn start update\n\n## Build / Execution Notes\n\nThe project is implemented in typescript, which must be transpiled into javascript before it may be executed by the node interpreter.\n\nTo transpile the project run:\n\n> yarn build\n\n...or alternatively if you are actively developing the project, you may wish to have the code transpiled for testing on any change, this is possible with\n\n> yarn dev\n\n...which starts the `tsc` typescript compiler in `--watch` mode\n\nAfter building the project, you may use the `package.json` run scripts, or the following commands can also be used if you want to execute the transpiled scripts directly:\n\n```bash\nnode .\\dist\\index.js upload\nnode .\\dist\\index.js download\nnode .\\dist\\index.js extract\nnode .\\dist\\index.js update\n```\n"},"items":[{"name":"reviewer-guide.md","path":".agents/skills/pr-full-review/reviewer-guide.md","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/.agents/skills/pr-full-review/reviewer-guide.md","title":"Pr-full-review Skill","category":"anthropic-skill","format":"markdown","content":"# AnkiDroid PR Reviewer Guide\n\n## How to use this guide\n\nThis is the **standards corpus** for reviewing AnkiDroid changes - *what* to check, not\n*how* to run a review. It distills the project's documented standards into an actionable\nchecklist so a reviewer (human or agent) can work without opening ten other files.\n\nTwo rules of engagement:\n\n1. **The linked canonical sources are authoritative.** Where this guide and a source\n   disagree, the source wins. Load all the [Canonical sources](#canonical-sources) into context.\n2. **Reviewing is subjective.** As the wiki puts it: \"these guidelines are ONLY guidelines,\n   use your best judgment.\" Prefer the implementer's choice when a decision is a genuine\n   toss-up.\n\n## Tone\n\nFrom the [Code-review guide](https://github.com/ankidroid/Anki-Android/wiki/Code-review-guide):\n\n- **Establish contributor status first.** Check for the `New Contributor` label and count the\n  author's PRs, merged and unmerged (`gh pr list --author <login> --state all`), to gauge how\n  established and experienced they are - it sets the tone bar below and the AI-use policy applied.\n- **Be kind.** Note the good things in the PR and say thank you. Terse critique reads as\n  hostile in text.\n- **Relax for first-timers.** On PRs labelled `New Contributor`, lower the bar to make a\n  good first impression — get them landed, mentor later.\n- **Prefix non-blocking feedback with `nit:`** so the author knows it's optional.\n- **Defer to the implementer** when you're uncertain a change is actually an improvement.\n- Avoid demanding large changes unless they're a meaningful long-term improvement; suggest\n  splitting big PRs into smaller ones.\n\n## Blocking gates\n\nRequest changes if any of these fail — they're table stakes before deeper review:\n\n- **CI is green.** Lint, unit, emulator and CodeQL must pass. Don't just glance at the rollup\n  status (`gh pr checks <number> --repo ankidroid/Anki-Android`): if a check is **pending**, say\n  the gate is unverified; if a check is **failing**, read its log (`gh run view <run-id>\n  --repo ankidroid/Anki-Android --log-failed`) and report the actual cause, not just \"red\".\n  For new contributors, explain how to find and read the failure themselves — and consider pasting\n  the relevant CI output into the review so they don't have to dig for it. Refer the submitter to\n  [`.github/workflows/README.md`](../../../.github/workflows/README.md).\n- **PR template is filled in** (Purpose / Approach / How tested) and the PR is **linked to\n  an issue** (`Fixes #`) where one applies.\n- **Commit hygiene:** no merge commits in the history (rebase and force push, don't merge); \n  each commit compiles and does one thing. Commit titles should not be longer than 80 chars. \n  There is a suggestion for a <= 50 char title. Only flag this if you provide a reworded title.\n- **New source files carry an licensing header:** see [Licensing](#licensing).\n\n## What to check\n\n### Correctness & clarity\n- The codebase is better after the change than before.\n- Edge cases and exceptions are handled.\n- Names are understandable; hard-to-follow code is commented.\n\n### Bug fixes \n- Bug fix commits must contain a confirmation that the author reproduced the bug, unless the bug \n  is obvious, or the submitter has specifically stated why they were unable to reproduce it.\n- Trace the code path and the values it reads to confirm the claimed trigger occurs.\n\n### Tests\n- Significant new logic ships with tests, **or** is annotated\n  [`@NeedsTest(\"reason\")`](../../../common/src/main/java/com/ichi2/anki/common/annotations/NeedsTest.kt)\n  explaining why the test is deferred. The annotation exists so we signal that we care about\n  testing without blocking a contributor's first commits.\n- **Bug fixes need a regression test.** The expectation (see [`CLAUDE.md`](../../../CLAUDE.md))\n  is write-the-failing-test-first, confirm it fails, then fix.\n- **A test must exercise the changed production code and fail without the fix.** A contributor\n  should not copy production code into tests to ensure correctness.\n\n### Scope\n- Each commit must be focused. Refactors should be split from functional changes. \n- Flag unnecessary whitespace churn. Flag if a PR unnecessarily affects more than one concern.\n\n### Commit messages\n- Flag if a 'refactor:' commit title is used for a functional change.\n\n### GitHub\n- For new contributors, flag commits whose `user.email` isn't linked to a GitHub account, as\n  they won't receive attribution on their GitHub heatmap.\n\n### Licensing\n- **Never remove an existing copyright header** unless it is your own. See\n  [`docs/contributing/copyright-headers.md`](../../../docs/contributing/copyright-headers.md).\n- New external dependencies/resources: ensure the PR fills the **Licenses** table in the\n  template, and apply the `Licenses` label / update the licenses wiki on merge.\n\n### AI-use policy\nPer [`AI_POLICY.md`](../../../AI_POLICY.md):\n- Use the current documentation and determine if the user is a new contributor. Ensure that AI-use\n  restrictions are appropriately applied.\n\n### UI changes\n- A Roborazzi test of large UI changes is optional, but greatly appreciated. \n- Screenshots of **all** affected screens (especially new/changed strings).\n- Large changed are tested with the Google Accessibility Scanner.\n\n### Compose\nFor code under `com.ichi2.anki.ui.compose.*` (see\n[`docs/development/compose.md`](../../../docs/development/compose.md)):\n- Pure \"migrate this XML screen to Compose\" PRs aren't accepted — there must be another\n  reason to touch the screen.\n- No `Anki` prefix on component names; let the package path namespace them.\n- Wrap top-level composables in the project `Theme { }`; don't define parallel color tokens\n  in Kotlin (XML themes stay the source of truth).\n- Host Compose via a `ComposeView` returned from a Fragment's `onCreateView`.\n- Use existing drawables via `painterResource(R.drawable.…)`; don't add the\n  material-icons artifacts.\n- A rewrite adds a **Roborazzi screenshot test of the existing screen first** (ideally a\n  separate PR), then the rewrite. One concern per migration — no simultaneous state/nav\n  rework.\n\n## Canonical sources\n\nDefer to these authoritative references over the distillation above:\n\n- [Code-review guide (wiki)](https://github.com/ankidroid/Anki-Android/wiki/Code-review-guide) — tone, process, when to skip second approval.\n- [`CONTRIBUTING.md`](../../../CONTRIBUTING.md) — contribution workflow, commits, PR labels.\n- [`.github/pull_request_template.md`](../../../.github/pull_request_template.md) — required PR sections and checklist.\n- [`.github/workflows/README.md`](../../../.github/workflows/README.md) — the exact CI jobs and local commands.\n- [`lint-rules/.../IssueRegistry.kt`](../../../lint-rules/src/main/java/com/ichi2/anki/lint/IssueRegistry.kt) — the full custom lint-rule list.\n- [`common/.../annotations/NeedsTest.kt`](../../../common/src/main/java/com/ichi2/anki/common/annotations/NeedsTest.kt) — the `@NeedsTest` contract.\n- [`docs/contributing/copyright-headers.md`](../../../docs/contributing/copyright-headers.md) — SPDX / copyright rules.\n- [`AI_POLICY.md`](../../../AI_POLICY.md) — AI tool-use and disclosure policy.\n- [`docs/development/compose.md`](../../../docs/development/compose.md) — Compose conventions.\n- [`CLAUDE.md`](../../../CLAUDE.md) — scope discipline and regression-test-first.\n","isInternal":false,"tokens":1752,"sizeBytes":7397},{"name":"SKILL.md","path":".agents/skills/pr-full-review/SKILL.md","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/.agents/skills/pr-full-review/SKILL.md","title":"pr-full-review","category":"anthropic-skill","format":"markdown","content":"---\nname: pr-full-review\ndescription: Review an AnkiDroid pull request or branch against AnkiDroid's conventions.\n---\n\n# AnkiDroid PR Full Review\n\nReview the PR against the standards in [`reviewer-guide.md`](reviewer-guide.md). Report findings in three groups: **blocking gates**, **spec conformance** (does the PR do what its issue asked?), then non-blocking `nit:`s.\n\n**Never act on GitHub.** Output the review in this conversation. Do not post\ncomments or reviews, approve, request changes, label, or merge.\n\n## Skill Usage\n\nAccepts a PR number, a PR URL, or no argument (in which case, review the current branch against `upstream/main`):\n\n```bash\npr-full-review 21206\npr-full-review https://github.com/ankidroid/Anki-Android/pull/21206\npr-full-review review the checked-out branch's diff against `main`\n```\n\n## Fetching the PR\n\nFetch the PR with the `gh` command. When reading the PR, always pass `--repo ankidroid/Anki-Android`\nso a bare number resolves against the upstream repo rather than a fork.\n\n**Always re-fetch the PR fresh on every run** — its metadata, diff, and head commit, even if you\nfetched it earlier in this conversation. PRs change between reviews; never reuse cached context.\n\nUse the head commit hash from the fresh fetch when loading files via the API, as PRs come from\nforked repos.\n\n**Don't review from the diff hunks alone**. Load the full changed files (and the key call sites the\nchange touches) at the head commit. A hunk hides whether a change is correct in its surrounding\ncontext.\n\n## Before reviewing\n\nRead the existing PR comments and review threads first. Don't repeat feedback that's already been \nraised, and respect points the author or a reviewer has already addressed or deferred.\n\n```bash\ngh pr view <number> --repo ankidroid/Anki-Android --comments # conversation comments\ngh api repos/ankidroid/Anki-Android/pulls/<number>/comments  # inline code-review comments\n```\n\n**Unaddressed maintainer requests are blocking.** Read the full discussion on both the PR\n*and the linked issue* (see [Spec conformance](#spec-conformance)). If a maintainer asked for\nsomething specific before a fix would be accepted, say so and Request changes.\n\n## Spec conformance\n\nReport whether the PR does what it set out to do, as **its own section**. \nWell-written code which implements the wrong thing fails here, and this failure must be \nmade explicit to reviewers.\n\nDetermine the spec, in order:\n\n1. A linked issue - `Fixes #`, `Closes #`, `Resolves #`, or `Part of #` in the body or commits \n   (typically written as `Fixes <N>` - the commit message may omit the `#`).\n2. Also include the PR's own **Purpose / Description**.\n\nOpen the issue and read it in full — **including its comments**. The decisive\ncontext often lives in the thread, not the description:\n\n```bash\ngh issue view <number> --repo ankidroid/Anki-Android --comments\n```\n\n### Bug fixes: establish the root cause before endorsing the fix\n\nFor a bug fix, spec conformance means the PR fixes **the actual cause**, not that it plausibly\nmight. Verify the author's fix:\n\n- **Trace the real code path** that triggers the bug (load the call sites and any resource/theme\n  values they read), and confirm the claimed trigger can actually occur. If your trace shows it\n*can't occur the way the PR describes, then the root cause is not understood. Say so explicitly.\n- **A fix applied without an understood, demonstrated trigger is tech debt:**. Treat \"unknown \n  root cause\" as a blocking finding and ask for the diagnostics / reproduction needed to establish \n  it first unless it is explicitly acknowledged as not being understood. \n    - State that it risks masking the real bug and the fallback behavior can't be validated against\n    a scenario nobody has captured.\n- Confirm the bug-fix commit actually evidences a reproduction.\n\n## Output\n\nOpen the review with a one-line verdict, mirroring GitHub's three review actions — the reader\nwill pick one of these on the PR:\n\n> **Verdict:** \\[Request changes / Comment / Approve\\]: <most important reason>\n\n- **Request changes:** a blocking gate fails (red/pending CI, unfilled template, merge commits,\n  missing license header, or a closing keyword on a partially-resolved issue), an explicit\n  maintainer request was skipped, a bug fix lands without an established/verified root cause, or\n  a correctness, spec, or test finding must be fixed before merge.\n- **Comment:** no blockers; nits, questions, or judgment calls raised without signing off.\n- **Approve:** gates pass and the change is sound - only `nit:`s remain, if anything.\n\nOne unaddressed blocker means Request changes, however polished the rest is.\n\nAfter the verdict, list the findings, grouped as above (blocking gates, spec conformance, nits).\n\n**Closing**: if this was a self-review, a `gh` command to checkout the PR (without `--repo`).\nClose with a final line linking the PR which was reviewed.\n","frontmatter":{"name":"pr-full-review","description":"Review an AnkiDroid pull request or branch against AnkiDroid's conventions."},"isInternal":false,"tokens":1145,"sizeBytes":4904},{"name":"README.md","path":".agents/skills/README.md","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/.agents/skills/README.md","title":"Skills Skill","category":"anthropic-skill","format":"markdown","content":"# Agent skills\n\nSkills in this directory are agent-agnostic. Keep them tool-neutral: no\nassumptions about a specific agent's commands, file layout, or settings.\n\nEach skill is a folder containing a `SKILL.md` with `name` and `description` frontmatter.\n\nWe currently use https://github.com/mattpocock/skills as templates for skill design.\n","isInternal":false,"tokens":78,"sizeBytes":338},{"name":"release.crx.json","path":"tools/chromeos/release.crx.json","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/tools/chromeos/release.crx.json","title":"Chromeos Skill","category":"anthropic-skill","format":"json","content":"{\n    \"formFactor\": \"tablet\",\n    \"orientation\": \"landscape\",\n    \"needsClipboard\": true,\n    \"resize\": \"reconfigure\"\n}\n","frontmatter":{"formFactor":"tablet","orientation":"landscape","needsClipboard":true,"resize":"reconfigure"},"isInternal":false,"tokens":32,"sizeBytes":120},{"name":"package.json","path":"tools/localization/package.json","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/tools/localization/package.json","title":"ankidroid-localization","category":"anthropic-skill","format":"json","content":"{\n    \"name\": \"ankidroid-localization\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Extract localization for AnkiDroid using Crowdin JS client api\",\n    \"main\": \"index.ts\",\n    \"private\": true,\n    \"scripts\": {\n        \"build\": \"tsc\",\n        \"start\": \"node ./dist/index.js\",\n        \"dev\": \"tsc --watch\",\n        \"checkformat\": \"npx prettier --check *js src/\",\n        \"format\": \"npx prettier --write *js src/\",\n        \"lint\": \"eslint src/ --max-warnings=0\",\n        \"test\": \"jest --passWithNoTests\"\n    },\n    \"repository\": \"https://github.com/ankidroid/Anki-Android\",\n    \"author\": \"AnkiDroid Open Source Team\",\n    \"license\": \"GPL-3.0\",\n    \"dependencies\": {\n        \"@crowdin/crowdin-api-client\": \"^1.58.0\",\n        \"axios\": \"^1.20.0\",\n        \"dotenv\": \"^18.0.4\",\n        \"extract-zip\": \"^2.0.1\",\n        \"typescript\": \"^6.0.3\"\n    },\n    \"devDependencies\": {\n        \"@eslint/eslintrc\": \"^3.3.7\",\n        \"@eslint/js\": \"^10.0.1\",\n        \"@types/jest\": \"^30.0.0\",\n        \"@types/node\": \"^26.6.3\",\n        \"@typescript-eslint/eslint-plugin\": \"^8.71.0\",\n        \"@typescript-eslint/parser\": \"^8.71.0\",\n        \"eslint\": \"^10.11.0\",\n        \"eslint-config-prettier\": \"^10.1.8\",\n        \"eslint-config-standard\": \"^17.1.0\",\n        \"eslint-plugin-import\": \"^2.32.0\",\n        \"eslint-plugin-n\": \"^18.4.0\",\n        \"eslint-plugin-promise\": \"^7.3.0\",\n        \"globals\": \"^17.12.0\",\n        \"jest\": \"^30.5.2\",\n        \"prettier\": \"^3.9.9\",\n        \"ts-jest\": \"^29.4.14\",\n        \"ts-node\": \"^10.9.2\"\n    },\n    \"packageManager\": \"yarn@4.13.0\"\n}\n","frontmatter":{"name":"ankidroid-localization","version":"1.0.0","description":"Extract localization for AnkiDroid using Crowdin JS client api","main":"index.ts","private":true,"scripts":{"build":"tsc","start":"node ./dist/index.js","dev":"tsc --watch","checkformat":"npx prettier --check *js src/","format":"npx prettier --write *js src/","lint":"eslint src/ --max-warnings=0","test":"jest --passWithNoTests"},"repository":"https://github.com/ankidroid/Anki-Android","author":"AnkiDroid Open Source Team","license":"GPL-3.0","dependencies":{"@crowdin/crowdin-api-client":"^1.58.0","axios":"^1.20.0","dotenv":"^18.0.4","extract-zip":"^2.0.1","typescript":"^6.0.3"},"devDependencies":{"@eslint/eslintrc":"^3.3.7","@eslint/js":"^10.0.1","@types/jest":"^30.0.0","@types/node":"^26.6.3","@typescript-eslint/eslint-plugin":"^8.71.0","@typescript-eslint/parser":"^8.71.0","eslint":"^10.11.0","eslint-config-prettier":"^10.1.8","eslint-config-standard":"^17.1.0","eslint-plugin-import":"^2.32.0","eslint-plugin-n":"^18.4.0","eslint-plugin-promise":"^7.3.0","globals":"^17.12.0","jest":"^30.5.2","prettier":"^3.9.9","ts-jest":"^29.4.14","ts-node":"^10.9.2"},"packageManager":"yarn@4.13.0"},"isInternal":false,"tokens":506,"sizeBytes":1546},{"name":"tsconfig.json","path":"tools/localization/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/tools/localization/tsconfig.json","title":"Localization Skill","category":"anthropic-skill","format":"json","content":"{\n    \"compilerOptions\": {\n        /* Visit https://aka.ms/tsconfig to read more about this file */\n\n        /* Projects */\n        // \"incremental\": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */\n        // \"composite\": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */\n        // \"tsBuildInfoFile\": \"./.tsbuildinfo\",              /* Specify the path to .tsbuildinfo incremental compilation file. */\n        // \"disableSourceOfProjectReferenceRedirect\": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */\n        // \"disableSolutionSearching\": true,                 /* Opt a project out of multi-project reference checking when editing. */\n        // \"disableReferencedProjectLoad\": true,             /* Reduce the number of projects loaded automatically by TypeScript. */\n\n        /* Language and Environment */\n        \"target\": \"es2016\" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,\n        \"lib\": [\n            \"es2019\"\n        ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,\n        // \"jsx\": \"preserve\",                                /* Specify what JSX code is generated. */\n        // \"experimentalDecorators\": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */\n        // \"emitDecoratorMetadata\": true,                    /* Emit design-type metadata for decorated declarations in source files. */\n        // \"jsxFactory\": \"\",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */\n        // \"jsxFragmentFactory\": \"\",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */\n        // \"jsxImportSource\": \"\",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */\n        // \"reactNamespace\": \"\",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */\n        // \"noLib\": true,                                    /* Disable including any library files, including the default lib.d.ts. */\n        // \"useDefineForClassFields\": true,                  /* Emit ECMAScript-standard-compliant class fields. */\n        // \"moduleDetection\": \"auto\",                        /* Control what method is used to detect module-format JS files. */\n\n        /* Modules */\n        \"module\": \"commonjs\" /* Specify what module code is generated. */,\n        \"rootDir\": \"src\" /* Specify the root folder within your source files. */,\n        // \"moduleResolution\": \"node\",                       /* Specify how TypeScript looks up a file from a given module specifier. */\n        // \"baseUrl\": \"./\",                                  /* Specify the base directory to resolve non-relative module names. */\n        // \"paths\": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */\n        // \"rootDirs\": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */\n        // \"typeRoots\": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */\n        // \"types\": [],                                      /* Specify type package names to be included without being referenced in a source file. */\n        // \"allowUmdGlobalAccess\": true,                     /* Allow accessing UMD globals from modules. */\n        // \"moduleSuffixes\": [],                             /* List of file name suffixes to search when resolving a module. */\n        // \"resolveJsonModule\": true,                        /* Enable importing .json files. */\n        // \"noResolve\": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */\n\n        /* JavaScript Support */\n        // \"allowJs\": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */\n        // \"checkJs\": true,                                  /* Enable error reporting in type-checked JavaScript files. */\n        // \"maxNodeModuleJsDepth\": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */\n\n        /* Emit */\n        // \"declaration\": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */\n        // \"declarationMap\": true,                           /* Create sourcemaps for d.ts files. */\n        // \"emitDeclarationOnly\": true,                      /* Only output d.ts files and not JavaScript files. */\n        // \"sourceMap\": true,                                /* Create source map files for emitted JavaScript files. */\n        // \"outFile\": \"./\",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */\n        \"outDir\": \"./dist\" /* Specify an output folder for all emitted files. */,\n        // \"removeComments\": true,                           /* Disable emitting comments. */\n        // \"noEmit\": true,                                   /* Disable emitting files from a compilation. */\n        // \"importHelpers\": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */\n        // \"importsNotUsedAsValues\": \"remove\",               /* Specify emit/checking behavior for imports that are only used for types. */\n        // \"downlevelIteration\": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */\n        // \"sourceRoot\": \"\",                                 /* Specify the root path for debuggers to find the reference source code. */\n        // \"mapRoot\": \"\",                                    /* Specify the location where debugger should locate map files instead of generated locations. */\n        // \"inlineSourceMap\": true,                          /* Include sourcemap files inside the emitted JavaScript. */\n        // \"inlineSources\": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */\n        // \"emitBOM\": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */\n        // \"newLine\": \"crlf\",                                /* Set the newline character for emitting files. */\n        // \"stripInternal\": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */\n        // \"noEmitHelpers\": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */\n        // \"noEmitOnError\": true,                            /* Disable emitting files if any type checking errors are reported. */\n        // \"preserveConstEnums\": true,                       /* Disable erasing 'const enum' declarations in generated code. */\n        // \"declarationDir\": \"./\",                           /* Specify the output directory for generated declaration files. */\n        // \"preserveValueImports\": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */\n\n        /* Interop Constraints */\n        // \"isolatedModules\": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */\n        // \"allowSyntheticDefaultImports\": true,             /* Allow 'import x from y' when a module doesn't have a default export. */\n        \"esModuleInterop\": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,\n        // \"preserveSymlinks\": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */\n        \"forceConsistentCasingInFileNames\": true /* Ensure that casing is correct in imports. */,\n\n        /* Type Checking */\n        \"strict\": true /* Enable all strict type-checking options. */,\n        \"noImplicitAny\": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */,\n        // \"strictNullChecks\": true,                         /* When type checking, take into account 'null' and 'undefined'. */\n        // \"strictFunctionTypes\": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */\n        // \"strictBindCallApply\": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */\n        // \"strictPropertyInitialization\": true,             /* Check for class properties that are declared but not set in the constructor. */\n        // \"noImplicitThis\": true,                           /* Enable error reporting when 'this' is given the type 'any'. */\n        // \"useUnknownInCatchVariables\": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */\n        // \"alwaysStrict\": true,                             /* Ensure 'use strict' is always emitted. */\n        // \"noUnusedLocals\": true,                           /* Enable error reporting when local variables aren't read. */\n        // \"noUnusedParameters\": true,                       /* Raise an error when a function parameter isn't read. */\n        // \"exactOptionalPropertyTypes\": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */\n        // \"noImplicitReturns\": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */\n        // \"noFallthroughCasesInSwitch\": true,               /* Enable error reporting for fallthrough cases in switch statements. */\n        // \"noUncheckedIndexedAccess\": true,                 /* Add 'undefined' to a type when accessed using an index. */\n        // \"noImplicitOverride\": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */\n        // \"noPropertyAccessFromIndexSignature\": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */\n        // \"allowUnusedLabels\": true,                        /* Disable error reporting for unused labels. */\n        // \"allowUnreachableCode\": true,                     /* Disable error reporting for unreachable code. */\n\n        /* Completeness */\n        // \"skipDefaultLibCheck\": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */\n        \"skipLibCheck\": true /* Skip type checking all .d.ts files. */\n    }\n}\n","isInternal":false,"tokens":2126,"sizeBytes":11384},{"name":"release-description.md","path":"tools/release-description.md","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/tools/release-description.md","title":"Tools Skill","category":"anthropic-skill","format":"markdown","content":"> [!IMPORTANT]\n> GitHub does not auto-update apps\n\n\n## For regular users\n\nInstall `arm64-v8a` from the **Assets** section below. If it fails to install, use `Parallel.A`.\n\n`Parallel` builds install side-by-side with the main APK, allowing you to use different settings and profiles (via the `AnkiDroid directory` advanced setting and a different AnkiWeb login).\n\n\n## For testers\n\nThe builds with `full`, `play` and `amazon` are useful for testing our builds for different app stores:\n\n- **`full`**: F-Droid & GitHub `Parallel` apks\n- **`play`**: Google Play - does not have `MANAGE_EXTERNAL_STORAGE` permission as it is forbidden by Google, on uninstall the user is invited to delete data.\n- **`amazon`**: Amazon - currently same as full, historically removed `CAMERA` permission\n\n\n## ABI variants\n\nWe perform ABI splits to reduce APK size. In rare cases, a phone may not be using the `arm64-v8a` ABI. You can find your phone's ABI using [kamgurgul/cpu-info](https://github.com/kamgurgul/cpu-info). If disk space isn't an issue, use the `full` apk.","isInternal":false,"tokens":265,"sizeBytes":1048},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"## Refactoring Scope\n- Constrain scope tightly: do not modify unrelated files, themes, or settings 'while you're in there'.\n\n## Verification\n- For bug fixes, write the failing regression test FIRST and confirm it fails before applying the fix.\n","isInternal":false,"tokens":51,"sizeBytes":244},{"name":"README.md","path":"tools/localization/README.md","rawUrl":"https://raw.githubusercontent.com/ankidroid/Anki-Android/HEAD/tools/localization/README.md","title":"localization Documentation","category":"plugin-manifest","format":"markdown","content":"# Localization Tool\n\nThis project provides a localization tool built with Yarn, built specifically to interact with the crowdin API via their javascript API client\n\nIts purpose is to provide a way to upload our English-language localization files to crowdin so that translators may do their work, and then to download that translation work and faithfully copy it into the non-English Android resource locations.\n\n## Getting Started\n\nFollow these steps to set up and run the localization tool.\n\n```bash\n# Move to the proper directory\ncd ./tools/localization\n# Install the javascript dependencies\nyarn\n# Build the project so it is ready to run\nyarn build\n```\n\n## Commands\n\nThe following commands are available. Run them from the `./tools/localization` directory:\n\n### Upload\n\nUploads the English `res/values` files (from `common/android/src/main/res`) to Crowdin.\n\n> yarn start upload\n\n### Download\n\nBuilds and downloads all translations from Crowdin.\n\n> yarn start download\n\n### Extract\n\nExtracts files from `ankidroid.zip` into an internal staging area\n\n> yarn start extract\n\n### Update\n\nUpdates the files from the extracted `ankidroid.zip` file by processing them lightly (adding copyright information, fixing some common errors, etc), then copying them into `common/android/src/main/res/values-*` for the translated languages.\n\n> yarn start update\n\n## Build / Execution Notes\n\nThe project is implemented in typescript, which must be transpiled into javascript before it may be executed by the node interpreter.\n\nTo transpile the project run:\n\n> yarn build\n\n...or alternatively if you are actively developing the project, you may wish to have the code transpiled for testing on any change, this is possible with\n\n> yarn dev\n\n...which starts the `tsc` typescript compiler in `--watch` mode\n\nAfter building the project, you may use the `package.json` run scripts, or the following commands can also be used if you want to execute the transpiled scripts directly:\n\n```bash\nnode .\\dist\\index.js upload\nnode .\\dist\\index.js download\nnode .\\dist\\index.js extract\nnode .\\dist\\index.js update\n```\n","isInternal":false,"tokens":455,"sizeBytes":2090}],"systemPromptSnippet":"<yakaai_skills repo=\"ankidroid/Anki-Android\">\n<!-- File: .agents/skills/pr-full-review/reviewer-guide.md (Tokens: ~1752 | Category: anthropic-skill) -->\n# AnkiDroid PR Reviewer Guide\n\n## How to use this guide\n\nThis is the **standards corpus** for reviewing AnkiDroid changes - *what* to check, not\n*how* to run a review. It distills the project's documented standards into an actionable\nchecklist so a reviewer (human or agent) can work without opening ten other files.\n\nTwo rules of engagement:\n\n1. **The linked canonical sources are authoritative.** Where this guide and a source\n   disagree, the source wins. Load all the [Canonical sources](#canonical-sources) into context.\n2. **Reviewing is subjective.** As the wiki puts it: \"these guidelines are ONLY guidelines,\n   use your best judgment.\" Prefer the implementer's choice when a decision is a genuine\n   toss-up.\n\n## Tone\n\nFrom the [Code-review guide](https://github.com/ankidroid/Anki-Android/wiki/Code-review-guide):\n\n- **Establish contributor status first.** Check for the `New Contributor` label and count the\n  author's PRs, merged and unmerged (`gh pr list --author <login> --state all`), to gauge how\n  established and experienced they are - it sets the tone bar below and the AI-use policy applied.\n- **Be kind.** Note the good things in the PR and say thank you. Terse critique reads as\n  hostile in text.\n- **Relax for first-timers.** On PRs labelled `New Contributor`, lower the bar to make a\n  good first impression — get them landed, mentor later.\n- **Prefix non-blocking feedback with `nit:`** so the author knows it's optional.\n- **Defer to the implementer** when you're uncertain a change is actually an improvement.\n- Avoid demanding large changes unless they're a meaningful long-term improvement; suggest\n  splitting big PRs into smaller ones.\n\n## Blocking gates\n\nRequest changes if any of these fail — they're table stakes before deeper review:\n\n- **CI is green.** Lint, unit, emulator and CodeQL must pass. Don't just glance at the rollup\n  status (`gh pr checks <number> --repo ankidroid/Anki-Android`): if a check is **pending**, say\n  the gate is unverified; if a check is **failing**, read its log (`gh run view <run-id>\n  --repo ankidroid/Anki-Android --log-failed`) and report the actual cause, not just \"red\".\n  For new contributors, explain how to find and read the failure themselves — and consider pasting\n  the relevant CI output into the review so they don't have to dig for it. Refer the submitter to\n  [`.github/workflows/README.md`](../../../.github/workflows/README.md).\n- **PR template is filled in** (Purpose / Approach / How tested) and the PR is **linked to\n  an issue** (`Fixes #`) where one applies.\n- **Commit hygiene:** no merge commits in the history (rebase and force push, don't merge); \n  each commit compiles and does one thing. Commit titles should not be longer than 80 chars. \n  There is a suggestion for a <= 50 char title. Only flag this if you provide a reworded title.\n- **New source files carry an licensing header:** see [Licensing](#licensing).\n\n## What to check\n\n### Correctness & clarity\n- The codebase is better after the change than before.\n- Edge cases and exceptions are handled.\n- Names are understandable; hard-to-follow code is commented.\n\n### Bug fixes \n- Bug fix commits must contain a confirmation that the author reproduced the bug, unless the bug \n  is obvious, or the submitter has specifically stated why they were unable to reproduce it.\n- Trace the code path and the values it reads to confirm the claimed trigger occurs.\n\n### Tests\n- Significant new logic ships with tests, **or** is annotated\n  [`@NeedsTest(\"reason\")`](../../../common/src/main/java/com/ichi2/anki/common/annotations/NeedsTest.kt)\n  explaining why the test is deferred. The annotation exists so we signal that we care about\n  testing without blocking a contributor's first commits.\n- **Bug fixes need a regression test.** The expectation (see [`CLAUDE.md`](../../../CLAUDE.md))\n  is write-the-failing-test-first, confirm it fails, then fix.\n- **A test must exercise the changed production code and fail without the fix.** A contributor\n  should not copy production code into tests to ensure correctness.\n\n### Scope\n- Each commit must be focused. Refactors should be split from functional changes. \n- Flag unnecessary whitespace churn. Flag if a PR unnecessarily affects more than one concern.\n\n### Commit messages\n- Flag if a 'refactor:' commit title is used for a functional change.\n\n### GitHub\n- For new contributors, flag commits whose `user.email` isn't linked to a GitHub account, as\n  they won't receive attribution on their GitHub heatmap.\n\n### Licensing\n- **Never remove an existing copyright header** unless it is your own. See\n  [`docs/contributing/copyright-headers.md`](../../../docs/contributing/copyright-headers.md).\n- New external dependencies/resources: ensure the PR fills the **Licenses** table in the\n  template, and apply the `Licenses` label / update the licenses wiki on merge.\n\n### AI-use policy\nPer [`AI_POLICY.md`](../../../AI_POLICY.md):\n- Use the current documentation and determine if the user is a new contributor. Ensure that AI-use\n  restrictions are appropriately applied.\n\n### UI changes\n- A Roborazzi test of large UI changes is optional, but greatly appreciated. \n- Screenshots of **all** affected screens (especially new/changed strings).\n- Large changed are tested with the Google Accessibility Scanner.\n\n### Compose\nFor code under `com.ichi2.anki.ui.compose.*` (see\n[`docs/development/compose.md`](../../../docs/development/compose.md)):\n- Pure \"migrate this XML screen to Compose\" PRs aren't accepted — there must be another\n  reason to touch the screen.\n- No `Anki` prefix on component names; let the package path namespace them.\n- Wrap top-level composables in the project `Theme { }`; don't define parallel color tokens\n  in Kotlin (XML themes stay the source of truth).\n- Host Compose via a `ComposeView` returned from a Fragment's `onCreateView`.\n- Use existing drawables via `painterResource(R.drawable.…)`; don't add the\n  material-icons artifacts.\n- A rewrite adds a **Roborazzi screenshot test of the existing screen first** (ideally a\n  separate PR), then the rewrite. One concern per migration — no simultaneous state/nav\n  rework.\n\n## Canonical sources\n\nDefer to these authoritative references over the distillation above:\n\n- [Code-review guide (wiki)](https://github.com/ankidroid/Anki-Android/wiki/Code-review-guide) — tone, process, when to skip second approval.\n- [`CONTRIBUTING.md`](../../../CONTRIBUTING.md) — contribution workflow, commits, PR labels.\n- [`.github/pull_request_template.md`](../../../.github/pull_request_template.md) — required PR sections and checklist.\n- [`.github/workflows/README.md`](../../../.github/workflows/README.md) — the exact CI jobs and local commands.\n- [`lint-rules/.../IssueRegistry.kt`](../../../lint-rules/src/main/java/com/ichi2/anki/lint/IssueRegistry.kt) — the full custom lint-rule list.\n- [`common/.../annotations/NeedsTest.kt`](../../../common/src/main/java/com/ichi2/anki/common/annotations/NeedsTest.kt) — the `@NeedsTest` contract.\n- [`docs/contributing/copyright-headers.md`](../../../docs/contributing/copyright-headers.md) — SPDX / copyright rules.\n- [`AI_POLICY.md`](../../../AI_POLICY.md) — AI tool-use and disclosure policy.\n- [`docs/development/compose.md`](../../../docs/development/compose.md) — Compose conventions.\n- [`CLAUDE.md`](../../../CLAUDE.md) — scope discipline and regression-test-first.\n\n<!-- File: .agents/skills/pr-full-review/SKILL.md (Tokens: ~1145 | Category: anthropic-skill) -->\n---\nname: pr-full-review\ndescription: Review an AnkiDroid pull request or branch against AnkiDroid's conventions.\n---\n\n# AnkiDroid PR Full Review\n\nReview the PR against the standards in [`reviewer-guide.md`](reviewer-guide.md). Report findings in three groups: **blocking gates**, **spec conformance** (does the PR do what its issue asked?), then non-blocking `nit:`s.\n\n**Never act on GitHub.** Output the review in this conversation. Do not post\ncomments or reviews, approve, request changes, label, or merge.\n\n## Skill Usage\n\nAccepts a PR number, a PR URL, or no argument (in which case, review the current branch against `upstream/main`):\n\n```bash\npr-full-review 21206\npr-full-review https://github.com/ankidroid/Anki-Android/pull/21206\npr-full-review review the checked-out branch's diff against `main`\n```\n\n## Fetching the PR\n\nFetch the PR with the `gh` command. When reading the PR, always pass `--repo ankidroid/Anki-Android`\nso a bare number resolves against the upstream repo rather than a fork.\n\n**Always re-fetch the PR fresh on every run** — its metadata, diff, and head commit, even if you\nfetched it earlier in this conversation. PRs change between reviews; never reuse cached context.\n\nUse the head commit hash from the fresh fetch when loading files via the API, as PRs come from\nforked repos.\n\n**Don't review from the diff hunks alone**. Load the full changed files (and the key call sites the\nchange touches) at the head commit. A hunk hides whether a change is correct in its surrounding\ncontext.\n\n## Before reviewing\n\nRead the existing PR comments and review threads first. Don't repeat feedback that's already been \nraised, and respect points the author or a reviewer has already addressed or deferred.\n\n```bash\ngh pr view <number> --repo ankidroid/Anki-Android --comments # conversation comments\ngh api repos/ankidroid/Anki-Android/pulls/<number>/comments  # inline code-review comments\n```\n\n**Unaddressed maintainer requests are blocking.** Read the full discussion on both the PR\n*and the linked issue* (see [Spec conformance](#spec-conformance)). If a maintainer asked for\nsomething specific before a fix would be accepted, say so and Request changes.\n\n## Spec conformance\n\nReport whether the PR does what it set out to do, as **its own section**. \nWell-written code which implements the wrong thing fails here, and this failure must be \nmade explicit to reviewers.\n\nDetermine the spec, in order:\n\n1. A linked issue - `Fixes #`, `Closes #`, `Resolves #`, or `Part of #` in the body or commits \n   (typically written as `Fixes <N>` - the commit message may omit the `#`).\n2. Also include the PR's own **Purpose / Description**.\n\nOpen the issue and read it in full — **including its comments**. The decisive\ncontext often lives in the thread, not the description:\n\n```bash\ngh issue view <number> --repo ankidroid/Anki-Android --comments\n```\n\n### Bug fixes: establish the root cause before endorsing the fix\n\nFor a bug fix, spec conformance means the PR fixes **the actual cause**, not that it plausibly\nmight. Verify the author's fix:\n\n- **Trace the real code path** that triggers the bug (load the call sites and any resource/theme\n  values they read), and confirm the claimed trigger can actually occur. If your trace shows it\n*can't occur the way the PR describes, then the root cause is not understood. Say so explicitly.\n- **A fix applied without an understood, demonstrated trigger is tech debt:**. Treat \"unknown \n  root cause\" as a blocking finding and ask for the diagnostics / reproduction needed to establish \n  it first unless it is explicitly acknowledged as not being understood. \n    - State that it risks masking the real bug and the fallback behavior can't be validated against\n    a scenario nobody has captured.\n- Confirm the bug-fix commit actually evidences a reproduction.\n\n## Output\n\nOpen the review with a one-line verdict, mirroring GitHub's three review actions — the reader\nwill pick one of these on the PR:\n\n> **Verdict:** \\[Request changes / Comment / Approve\\]: <most important reason>\n\n- **Request changes:** a blocking gate fails (red/pending CI, unfilled template, merge commits,\n  missing license header, or a closing keyword on a partially-resolved issue), an explicit\n  maintainer request was skipped, a bug fix lands without an established/verified root cause, or\n  a correctness, spec, or test finding must be fixed before merge.\n- **Comment:** no blockers; nits, questions, or judgment calls raised without signing off.\n- **Approve:** gates pass and the change is sound - only `nit:`s remain, if anything.\n\nOne unaddressed blocker means Request changes, however polished the rest is.\n\nAfter the verdict, list the findings, grouped as above (blocking gates, spec conformance, nits).\n\n**Closing**: if this was a self-review, a `gh` command to checkout the PR (without `--repo`).\nClose with a final line linking the PR which was reviewed.\n\n<!-- File: .agents/skills/README.md (Tokens: ~78 | Category: anthropic-skill) -->\n# Agent skills\n\nSkills in this directory are agent-agnostic. Keep them tool-neutral: no\nassumptions about a specific agent's commands, file layout, or settings.\n\nEach skill is a folder containing a `SKILL.md` with `name` and `description` frontmatter.\n\nWe currently use https://github.com/mattpocock/skills as templates for skill design.\n\n<!-- File: tools/chromeos/release.crx.json (Tokens: ~32 | Category: anthropic-skill) -->\n{\n    \"formFactor\": \"tablet\",\n    \"orientation\": \"landscape\",\n    \"needsClipboard\": true,\n    \"resize\": \"reconfigure\"\n}\n\n<!-- File: tools/localization/package.json (Tokens: ~506 | Category: anthropic-skill) -->\n{\n    \"name\": \"ankidroid-localization\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Extract localization for AnkiDroid using Crowdin JS client api\",\n    \"main\": \"index.ts\",\n    \"private\": true,\n    \"scripts\": {\n        \"build\": \"tsc\",\n        \"start\": \"node ./dist/index.js\",\n        \"dev\": \"tsc --watch\",\n        \"checkformat\": \"npx prettier --check *js src/\",\n        \"format\": \"npx prettier --write *js src/\",\n        \"lint\": \"eslint src/ --max-warnings=0\",\n        \"test\": \"jest --passWithNoTests\"\n    },\n    \"repository\": \"https://github.com/ankidroid/Anki-Android\",\n    \"author\": \"AnkiDroid Open Source Team\",\n    \"license\": \"GPL-3.0\",\n    \"dependencies\": {\n        \"@crowdin/crowdin-api-client\": \"^1.58.0\",\n        \"axios\": \"^1.20.0\",\n        \"dotenv\": \"^18.0.4\",\n        \"extract-zip\": \"^2.0.1\",\n        \"typescript\": \"^6.0.3\"\n    },\n    \"devDependencies\": {\n        \"@eslint/eslintrc\": \"^3.3.7\",\n        \"@eslint/js\": \"^10.0.1\",\n        \"@types/jest\": \"^30.0.0\",\n        \"@types/node\": \"^26.6.3\",\n        \"@typescript-eslint/eslint-plugin\": \"^8.71.0\",\n        \"@typescript-eslint/parser\": \"^8.71.0\",\n        \"eslint\": \"^10.11.0\",\n        \"eslint-config-prettier\": \"^10.1.8\",\n        \"eslint-config-standard\": \"^17.1.0\",\n        \"eslint-plugin-import\": \"^2.32.0\",\n        \"eslint-plugin-n\": \"^18.4.0\",\n        \"eslint-plugin-promise\": \"^7.3.0\",\n        \"globals\": \"^17.12.0\",\n        \"jest\": \"^30.5.2\",\n        \"prettier\": \"^3.9.9\",\n        \"ts-jest\": \"^29.4.14\",\n        \"ts-node\": \"^10.9.2\"\n    },\n    \"packageManager\": \"yarn@4.13.0\"\n}\n\n<!-- File: tools/localization/tsconfig.json (Tokens: ~2126 | Category: anthropic-skill) -->\n{\n    \"compilerOptions\": {\n        /* Visit https://aka.ms/tsconfig to read more about this file */\n\n        /* Projects */\n        // \"incremental\": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */\n        // \"composite\": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */\n        // \"tsBuildInfoFile\": \"./.tsbuildinfo\",              /* Specify the path to .tsbuildinfo incremental compilation file. */\n        // \"disableSourceOfProjectReferenceRedirect\": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */\n        // \"disableSolutionSearching\": true,                 /* Opt a project out of multi-project reference checking when editing. */\n        // \"disableReferencedProjectLoad\": true,             /* Reduce the number of projects loaded automatically by TypeScript. */\n\n        /* Language and Environment */\n        \"target\": \"es2016\" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,\n        \"lib\": [\n            \"es2019\"\n        ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,\n        // \"jsx\": \"preserve\",                                /* Specify what JSX code is generated. */\n        // \"experimentalDecorators\": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */\n        // \"emitDecoratorMetadata\": true,                    /* Emit design-type metadata for decorated declarations in source files. */\n        // \"jsxFactory\": \"\",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */\n        // \"jsxFragmentFactory\": \"\",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */\n        // \"jsxImportSource\": \"\",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */\n        // \"reactNamespace\": \"\",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */\n        // \"noLib\": true,                                    /* Disable including any library files, including the default lib.d.ts. */\n        // \"useDefineForClassFields\": true,                  /* Emit ECMAScript-standard-compliant class fields. */\n        // \"moduleDetection\": \"auto\",                        /* Control what method is used to detect module-format JS files. */\n\n        /* Modules */\n        \"module\": \"commonjs\" /* Specify what module code is generated. */,\n        \"rootDir\": \"src\" /* Specify the root folder within your source files. */,\n        // \"moduleResolution\": \"node\",                       /* Specify how TypeScript looks up a file from a given module specifier. */\n        // \"baseUrl\": \"./\",                                  /* Specify the base directory to resolve non-relative module names. */\n        // \"paths\": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */\n        // \"rootDirs\": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */\n        // \"typeRoots\": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */\n        // \"types\": [],                                      /* Specify type package names to be included without being referenced in a source file. */\n        // \"allowUmdGlobalAccess\": true,                     /* Allow accessing UMD globals from modules. */\n        // \"moduleSuffixes\": [],                             /* List of file name suffixes to search when resolving a module. */\n        // \"resolveJsonModule\": true,                        /* Enable importing .json files. */\n        // \"noResolve\": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */\n\n        /* JavaScript Support */\n        // \"allowJs\": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */\n        // \"checkJs\": true,                                  /* Enable error reporting in type-checked JavaScript files. */\n        // \"maxNodeModuleJsDepth\": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */\n\n        /* Emit */\n        // \"declaration\": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */\n        // \"declarationMap\": true,                           /* Create sourcemaps for d.ts files. */\n        // \"emitDeclarationOnly\": true,                      /* Only output d.ts files and not JavaScript files. */\n        // \"sourceMap\": true,                                /* Create source map files for emitted JavaScript files. */\n        // \"outFile\": \"./\",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */\n        \"outDir\": \"./dist\" /* Specify an output folder for all emitted files. */,\n        // \"removeComments\": true,                           /* Disable emitting comments. */\n        // \"noEmit\": true,                                   /* Disable emitting files from a compilation. */\n        // \"importHelpers\": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */\n        // \"importsNotUsedAsValues\": \"remove\",               /* Specify emit/checking behavior for imports that are only used for types. */\n        // \"downlevelIteration\": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */\n        // \"sourceRoot\": \"\",                                 /* Specify the root path for debuggers to find the reference source code. */\n        // \"mapRoot\": \"\",                                    /* Specify the location where debugger should locate map files instead of generated locations. */\n        // \"inlineSourceMap\": true,                          /* Include sourcemap files inside the emitted JavaScript. */\n        // \"inlineSources\": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */\n        // \"emitBOM\": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */\n        // \"newLine\": \"crlf\",                                /* Set the newline character for emitting files. */\n        // \"stripInternal\": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */\n        // \"noEmitHelpers\": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */\n        // \"noEmitOnError\": true,                            /* Disable emitting files if any type checking errors are reported. */\n        // \"preserveConstEnums\": true,                       /* Disable erasing 'const enum' declarations in generated code. */\n        // \"declarationDir\": \"./\",                           /* Specify the output directory for generated declaration files. */\n        // \"preserveValueImports\": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */\n\n        /* Interop Constraints */\n        // \"isolatedModules\": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */\n        // \"allowSyntheticDefaultImports\": true,             /* Allow 'import x from y' when a module doesn't have a default export. */\n        \"esModuleInterop\": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,\n        // \"preserveSymlinks\": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */\n        \"forceConsistentCasingInFileNames\": true /* Ensure that casing is correct in imports. */,\n\n        /* Type Checking */\n        \"strict\": true /* Enable all strict type-checking options. */,\n        \"noImplicitAny\": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */,\n        // \"strictNullChecks\": true,                         /* When type checking, take into account 'null' and 'undefined'. */\n        // \"strictFunctionTypes\": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */\n        // \"strictBindCallApply\": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */\n        // \"strictPropertyInitialization\": true,             /* Check for class properties that are declared but not set in the constructor. */\n        // \"noImplicitThis\": true,                           /* Enable error reporting when 'this' is given the type 'any'. */\n        // \"useUnknownInCatchVariables\": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */\n        // \"alwaysStrict\": true,                             /* Ensure 'use strict' is always emitted. */\n        // \"noUnusedLocals\": true,                           /* Enable error reporting when local variables aren't read. */\n        // \"noUnusedParameters\": true,                       /* Raise an error when a function parameter isn't read. */\n        // \"exactOptionalPropertyTypes\": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */\n        // \"noImplicitReturns\": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */\n        // \"noFallthroughCasesInSwitch\": true,               /* Enable error reporting for fallthrough cases in switch statements. */\n        // \"noUncheckedIndexedAccess\": true,                 /* Add 'undefined' to a type when accessed using an index. */\n        // \"noImplicitOverride\": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */\n        // \"noPropertyAccessFromIndexSignature\": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */\n        // \"allowUnusedLabels\": true,                        /* Disable error reporting for unused labels. */\n        // \"allowUnreachableCode\": true,                     /* Disable error reporting for unreachable code. */\n\n        /* Completeness */\n        // \"skipDefaultLibCheck\": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */\n        \"skipLibCheck\": true /* Skip type checking all .d.ts files. */\n    }\n}\n\n<!-- File: tools/release-description.md (Tokens: ~265 | Category: anthropic-skill) -->\n> [!IMPORTANT]\n> GitHub does not auto-update apps\n\n\n## For regular users\n\nInstall `arm64-v8a` from the **Assets** section below. If it fails to install, use `Parallel.A`.\n\n`Parallel` builds install side-by-side with the main APK, allowing you to use different settings and profiles (via the `AnkiDroid directory` advanced setting and a different AnkiWeb login).\n\n\n## For testers\n\nThe builds with `full`, `play` and `amazon` are useful for testing our builds for different app stores:\n\n- **`full`**: F-Droid & GitHub `Parallel` apks\n- **`play`**: Google Play - does not have `MANAGE_EXTERNAL_STORAGE` permission as it is forbidden by Google, on uninstall the user is invited to delete data.\n- **`amazon`**: Amazon - currently same as full, historically removed `CAMERA` permission\n\n\n## ABI variants\n\nWe perform ABI splits to reduce APK size. In rare cases, a phone may not be using the `arm64-v8a` ABI. You can find your phone's ABI using [kamgurgul/cpu-info](https://github.com/kamgurgul/cpu-info). If disk space isn't an issue, use the `full` apk.\n\n<!-- File: CLAUDE.md (Tokens: ~51 | Category: claude-rule) -->\n## Refactoring Scope\n- Constrain scope tightly: do not modify unrelated files, themes, or settings 'while you're in there'.\n\n## Verification\n- For bug fixes, write the failing regression test FIRST and confirm it fails before applying the fix.\n\n<!-- File: tools/localization/README.md (Tokens: ~455 | Category: plugin-manifest) -->\n# Localization Tool\n\nThis project provides a localization tool built with Yarn, built specifically to interact with the crowdin API via their javascript API client\n\nIts purpose is to provide a way to upload our English-language localization files to crowdin so that translators may do their work, and then to download that translation work and faithfully copy it into the non-English Android resource locations.\n\n## Getting Started\n\nFollow these steps to set up and run the localization tool.\n\n```bash\n# Move to the proper directory\ncd ./tools/localization\n# Install the javascript dependencies\nyarn\n# Build the project so it is ready to run\nyarn build\n```\n\n## Commands\n\nThe following commands are available. Run them from the `./tools/localization` directory:\n\n### Upload\n\nUploads the English `res/values` files (from `common/android/src/main/res`) to Crowdin.\n\n> yarn start upload\n\n### Download\n\nBuilds and downloads all translations from Crowdin.\n\n> yarn start download\n\n### Extract\n\nExtracts files from `ankidroid.zip` into an internal staging area\n\n> yarn start extract\n\n### Update\n\nUpdates the files from the extracted `ankidroid.zip` file by processing them lightly (adding copyright information, fixing some common errors, etc), then copying them into `common/android/src/main/res/values-*` for the translated languages.\n\n> yarn start update\n\n## Build / Execution Notes\n\nThe project is implemented in typescript, which must be transpiled into javascript before it may be executed by the node interpreter.\n\nTo transpile the project run:\n\n> yarn build\n\n...or alternatively if you are actively developing the project, you may wish to have the code transpiled for testing on any change, this is possible with\n\n> yarn dev\n\n...which starts the `tsc` typescript compiler in `--watch` mode\n\nAfter building the project, you may use the `package.json` run scripts, or the following commands can also be used if you want to execute the transpiled scripts directly:\n\n```bash\nnode .\\dist\\index.js upload\nnode .\\dist\\index.js download\nnode .\\dist\\index.js extract\nnode .\\dist\\index.js update\n```\n</yakaai_skills>"}