ADFA-4857 | Add project-to-template plugin - #56
Conversation
… .cgt template) Incorporates the standalone templatize-project plugin into the monorepo as project-to-template, conforming to repo conventions and wired into the build and website-deploy pipelines. - Full rename to org.appdevforall.projecttotemplate / "Project to Template". - Uses shared repo-root ../libs/*.jar and ../gradlew (no bundled copies). - Fixes tooltip category to the full plugin.id (plugin_org.appdevforall.projecttotemplate) so the in-IDE tooltip renders real text instead of "n/a". - Sanitizes the user-typed template name before using it as a filesystem path. - Adds Tier 3 offline docs (assets/docs/index.html) + website documentation page. - New icon: solid project card -> arrow -> dashed template card (day/night PNGs + monochrome ic_plugin vector), replacing the 4-square grid glyph. Source SVGs + generator under icon-src/. - Normalizes user-facing text to "Code On The Go". - Adds README Examples row and update-libs.yml website MAP entry. Device-verified on emulator: installs, activates, sidebar + 3-tier tooltip render, and a real conversion of an open project produces a .cgt that installs via IdeTemplateService.
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
jatezzz
left a comment
There was a problem hiding this comment.
Review
Reviewed against freshly-fetched origin/main. I did not build or device-test — taking the PR's "builds clean + emulator-verified end-to-end" at face value.
What's right
The repo conventions are all here, including the ones that usually get missed: tooltip category is the full "plugin_org.appdevforall.projecttotemplate" form (not a slug), TOOLTIP_TAG is a shared const wired to the NavigationItem, Tier 3 getTier3DocsAssetPath() + a real assets/docs/index.html (white bg / black text), repo-root ../libs/*.jar + ../gradlew with no bundled copies, Theme.Material3.DayNight + values-night/, AAR metadata checks disabled, permission strings are exact enum values, sanitizeTemplateName genuinely kills traversal, views nulled in onDestroyView, dry run against a disposable temp copy, and both README + update-libs.yml MAP wiring are present.
Summary of findings
Should fix before merge:
- Dark-mode status colors are hardcoded — the
values-nightvariants are dead resources. - Re-running with a different template name zips the previous run into the new
.cgt. skipCleanupsuppresses the personal-info warning too, including keystores.local.propertiesships in the.cgtby default.
Worth fixing (device-level cost):
- The entire
build/tree is copied, then deleted. - Log rendering is O(n^2) on the main thread.
Minor: install button can't be retried after a failed install; the "unit-testable" KDoc claim is contradicted by android.util.Base64 + unitTests.isReturnDefaultValues = true; UI strings hardcoded rather than in strings.xml; duplicate log lines; isIgnoredUnderRoot is redundant with the onEnter prune; compileSdk/targetSdk = 34 will collide with #54.
Details are in the inline comments.
Verdict
Approve once #1 and #2 are fixed — those two produce visibly wrong output. #3/#4 are judgment calls, but both cut against the plugin's purpose (shipping a template someone else installs), so worth folding in here. Everything else is follow-up material.
Fixes from jatezzz's review: Should-fix (produce visibly wrong output): - Dark-mode status colors: use ContextCompat.getColor(status_*_text) instead of hardcoded light hex, so values-night/ is no longer dead. - Re-run isolation: wipe the whole output dir (not just dest/) before a real run, so a previous template name's tree isn't zipped into the new .cgt. - skipCleanup no longer suppresses the personal-info warning: keystores are flagged (not silently shipped) when cleanup is skipped, and flagPersonalInfoFiles always runs. - local.properties is now in COPY_IGNORE (always machine-specific), so it is never bundled. Worth-fixing: - build/ is skipped at copy time when cleaning up, instead of copied then deleted (hundreds of MB of I/O on device). - Log rendering uses TextView.append() (O(1)/line) instead of rebuilding the whole string per line. Minor: - Install button re-enables after a failed install so it can be retried. - Switch android.util.Base64 -> java.util.Base64 (minSdk 26) and add JVM unit tests for sanitizeTemplateName + a dry-run substitution path. - Move user-facing UI strings into strings.xml. - Remove duplicate per-file [OK] log lines (writePeb already logs). - Drop redundant isIgnoredUnderRoot (onEnter prune + name filter cover it). Verified: testDebugUnitTest + assemblePlugin green; a JVM harness runs the real createTemplateBundle twice (Foo then Bar) and confirms no stale-tree / local.properties / build/ / keystore leakage into the .cgt.
|
Thanks for the thorough review, @jatezzz — addressed everything in 2957e4e. Should-fix
Worth-fixing Minor
Note (12) — left Verification — |
Device verification (emulator, Code On The Go)Installed the debug
|
…-plugin # Conflicts: # .github/workflows/update-libs.yml # README.md
Two plugins landed on main after this branch was cut, so they were never standardized: - project-to-template (#56): compileSdk/targetSdk 34 -> 36 - get-ai-models (#55): Kotlin 2.1.0 -> 2.3.0 Both get-ai-models and template-manager pin Kotlin twice: the kotlin-gradle-plugin classpath in settings.gradle.kts, and `kotlin` in gradle/libs.versions.toml, which drives libs.kotlin.stdlib. The catalog comment states the two must match, so both were bumped. That surfaced a defect in this branch: it had already bumped template-manager's classpath to 2.3.0 but left its catalog at 2.1.0, so the compiler and stdlib disagreed. Fixed here. Verified: all 27 plugins now report compileSdk/targetSdk 36, AGP 8.11.0, Kotlin 2.3.0, with no catalog left at an older pin. All four affected plugins build assemblePlugin successfully; kotlin-stdlib resolves to 2.3.0 in get-ai-models and template-manager, and the packaged manifests of project-to-template and get-ai-models report targetSdkVersion=36.
…P 8.11.0, Kotlin 2.3.0, Gradle 8.14.3 (#54) * ADFA-4907 | Standardize plugin toolchain: compileSdk/targetSdk 36, AGP 8.11.0, Kotlin 2.3.0, Gradle 8.14.3 Aligns all 25 example plugins with Code On The Go's on-device build toolchain (verified on device: CoGo ships only android-36, AGP 8.11.0, Gradle 8.14.3; does not pin Kotlin). Relevant because plugins are being built with CoGo itself (ADFA-4693). - compileSdk & targetSdk -> 36 (22 plugins; 3 template installers already 36) - AGP -> 8.11.0 (ai-assistant, ai-core from 8.13.2; client-time-tracker, compose-preview, layout-editor from 8.8.2 -- downgrades intentional, match CoGo) - Kotlin -> 2.3.0 (flutter-template, pebble, template-manager from 2.1.0) - Gradle wrapper -> 8.14.3 (ai-assistant, ai-core from 8.14.4; client-time-tracker, compose-preview, layout-editor from 8.10.2) - template-manager: migrate deprecated kotlinOptions.jvmTarget string DSL to compilerOptions { jvmTarget.set(JvmTarget.JVM_17) } (required by Kotlin 2.3.0) Java/jvmTarget already uniform at 17. 20/25 plugins build clean. 5 (ai-assistant, ai-core, code-suggestions-plugin, speech-to-text-plugin, vector-search-plugin) fail with pre-existing unresolved-reference errors (stale libs/plugin-api.jar, missing newer API symbols) -- verified failing at baseline before this change, out of scope here. * ADFA-4907 | Extend toolchain standardization to 3 missed plugins Two plugins landed on main after this branch was cut, so they were never standardized: - project-to-template (#56): compileSdk/targetSdk 34 -> 36 - get-ai-models (#55): Kotlin 2.1.0 -> 2.3.0 Both get-ai-models and template-manager pin Kotlin twice: the kotlin-gradle-plugin classpath in settings.gradle.kts, and `kotlin` in gradle/libs.versions.toml, which drives libs.kotlin.stdlib. The catalog comment states the two must match, so both were bumped. That surfaced a defect in this branch: it had already bumped template-manager's classpath to 2.3.0 but left its catalog at 2.1.0, so the compiler and stdlib disagreed. Fixed here. Verified: all 27 plugins now report compileSdk/targetSdk 36, AGP 8.11.0, Kotlin 2.3.0, with no catalog left at an older pin. All four affected plugins build assemblePlugin successfully; kotlin-stdlib resolves to 2.3.0 in get-ai-models and template-manager, and the packaged manifests of project-to-template and get-ai-models report targetSdkVersion=36. * ADFA-4907 | Enforce the standard toolchain in CI Adds scripts/check-toolchain.sh and a pull_request-triggered workflow that fails the build when any Gradle module drifts off the ADFA-4907 standard (compileSdk/targetSdk 36, AGP 8.11.0, Kotlin 2.3.0, Gradle 8.14.3-bin, Java 17). Until now nothing enforced this. Both existing workflows are workflow_dispatch-only, so a PR could move any of these values with zero CI signal — which is how origin/main still carries compileSdk 33/34/35, AGP 8.8.2/8.13.2 and Gradle 8.10.2. The check is pure text inspection (no JDK, no Gradle, no network), so it runs in seconds and is cheap to require. It walks every build.gradle.kts, including subprojects. The earlier sweep enumerated only top-level plugin folders, which is why ai-core/llama-impl kept compileSdk = 34 through a dedicated standardization pass. Files under src/main/assets/ are excluded: those are project templates that Code On The Go stamps out for the user's own app, not our builds. minSdk is deliberately not checked — it legitimately varies (21 template installers, 26 most, 28 Beepy/sketch-to-ui, 33 the AI plugins). Also fixes the nine violations the check found, so it lands green: * kotlin-stdlib pinned behind the Kotlin plugin -> 2.3.0 (flutter-template, bookshelf, ndk-installer-plugin, cotg-ndk, pebble) * ai-core/llama-impl compileSdk 34 -> 36 * ai-assistant + ai-core wrapper -all.zip -> -bin.zip * ai-core catalog agp "8.13.2" -> "8.11.0" (contradicted settings.gradle.kts) * ADFA-4907 | Simplify check-toolchain.sh Collapses the nine copy-pasted "extract, compare, report" blocks into two helpers (check_value for first-match keys, check_every for all-match keys), plus small file_matches/reject/module_of helpers. That duplication had already caused a real defect: four of the nine copies omitted the --list echo, so --list silently under-reported the compose-compiler pin, the wrapper bin/all flavor, and both catalog entries. Recording the value is now part of the helper, so it cannot be forgotten. --list goes from 5 fact types / 134 lines to 9 / 164, sorted by module instead of grouped by internal scan order. Also: * One matching idiom. The header claimed grep|sed was avoided for BSD sed portability, then the kotlin-stdlib check used exactly that. Everything is bash =~ now, so the claim is true and no subprocesses are spawned. * One find traversal with a case dispatch instead of four full walks of the 12.8k-entry tree. Runtime 1.02s -> 0.38s. * Documents why discovery is deliberately broader than plugin_dirs() in .githooks/pre-push, so a future "DRY win" does not silently drop ai-core/llama-api and llama-impl from coverage. * Narrows the --list usage text, which overstated what it prints. * Workflow header no longer restates the version numbers (third copy). Deliberately NOT changed: no declarative rules table (four of the checks have genuinely different shapes and a table would gut the failure-message hints), and the standard stays a set of literal constants rather than being derived from the root wrapper -- deriving it would make a wrong root wrapper undetectable. * ADFA-4907 | Align dependency versions across the AI plugins The toolchain check enforces compileSdk/AGP/Kotlin/Gradle/Java, but every other library version is unchecked, and the AI plugins had drifted as a group -- all four kotlinx-coroutines 1.7.3 pins in the repo were AI plugins, against a repo majority of 1.8.1. Library alignments (all upgrades to the repo majority): * kotlinx-coroutines 1.7.3 -> 1.8.1 in ai-core, code-suggestions-plugin, speech-to-text-plugin, vector-search-plugin; -test 1.7.3 -> 1.8.1 in ai-assistant; get-ai-models catalog 1.6.4 -> 1.8.1 (was the oldest pin in the repo) * androidx.lifecycle 2.6.2 -> 2.8.7 in code-suggestions-plugin, speech-to-text-plugin and the get-ai-models catalog, matching client-time-tracker / compose-preview / sketch-to-ui * ai-assistant fragment-ktx 1.6.2 -> 1.8.8. This was the only 1.6.2 in the repo against 17 modules on 1.8.8, and the comment directly above it claimed the block matched random-xkcd, sketch-to-ui-plugin and Beepy -- all three of which are on 1.8.8. The comment is now true. * ai-assistant org.json 20231013 -> 20240303 Deliberately NOT changed: coordinates where the AI plugins are merely AHEAD of the majority (get-ai-models material 1.12.0, ai-literacy webkit 1.11.0, llama-impl slf4j 2.0.12). Being ahead is not a defect, and downgrading carries real risk for no gain. ai-core/gradle/libs.versions.toml: pruned 334 lines -> 40. It was copied wholesale from the CodeOnTheGo app repo and declared 281 entries of which exactly 4 were ever referenced (98.6% dead). The dead bulk had drifted into self-contradiction -- androidx.core:core-ktx declared at three different versions, appcompat at two, gson at two, plus a malformed ksp = "2.3.6" and typo'd keys ("anroidx"). That is not inert: it is the number the next person greps for. While pruning, the two surviving aliases that encoded their version in the NAME (androidx-core-ktx-v1120, androidx-appcompat-v171) were renamed to version-neutral names, since such a name lies the moment the version moves. Call sites in llama-impl updated to match. The catalog also resolved two real conflicts inside a single Gradle build: appcompat was 1.7.1 there while ai-core/build.gradle.kts pinned 1.6.1, and llama-api pulled coroutines-core 1.10.2 while ai-core pulled coroutines-android 1.8.1 -- the coroutines artifacts are released as a set and must not be split. Verified: all six changed AI plugins build assemblePluginDebug clean and emit a .cgp. Resolved classpaths confirm coroutines is now uniformly 1.8.1 in ai-core (previously split), lifecycle 2.8.7, fragment-ktx 1.8.8. The renamed catalog aliases were verified by forcing llama-api/llama-impl into the build, with a negative control proving an unknown alias fails loudly.
Summary
Incorporates the standalone
templatize-projectplugin into the monorepo asproject-to-template/, conforming to repo conventions and wired into the build + website-deploy pipelines.The plugin adds a Project to Template sidebar item that converts the currently-open Android project into a Code On The Go
.cgttemplate bundle (original untouched — it copies then tokenizes with Pebble${{TOKEN}}s) and can install it straight into the New Project template picker viaIdeTemplateService.What changed on the way in
org.appdevforall.projecttotemplate/ "Project to Template".../libs/*.jarand../gradlew— no bundled jars or wrapper.getTooltipCategory()now returns the fullplugin_org.appdevforall.projecttotemplateid, so the in-IDE tooltip renders real text instead of the literaln/a.assets/docs/index.html) + top-level websiteproject-to-template-documentation.html.ic_pluginvector), replacing the 4-square grid glyph. Source SVGs + generator undericon-src/.update-libs.ymlwebsite MAP entry.Verification
../gradlew assemblePluginandassemblePluginDebugboth build clean.plugin-reviewrubric (green-light; 6.1 min-only IDE version is the repo norm).n/a), and a real conversion of an open project (15 modified) produces a.cgtthat installs viaIdeTemplateService([OK] Installed template).🤖 Generated with Claude Code