Skip to content

Commit a61431e

Browse files
Template Manager plugin: build fix, manifest completeness, in-app help & icons (#51)
* First attempt on the template manager * template-manager: fix build, complete manifest, add in-app help & icons - build: reference shared ../libs jars instead of a missing local libs/ - manifest: add plugin.editor_tabs, max_ide_version (26.29–26.30), and filesystem.read; rewrite permissions comment for least privilege - in-app help: add top-level HTML doc + Tier 3 offline docs/index.html, wire tooltipTags and the Tier 3 button, and fix the tooltip category so the 3-arg showTooltip resolves the entry (was rendering "n/a") - cards: title with the .cgt file name; hide first-template description on multi-template files - icons: new 192px day/night CGT file glyphs - naming: display name "Template Manager"; full "Code On The Go" in user-facing text Verified end-to-end on emulator-5554 (Code On The Go ~26.29). * template-manager: rename doc to template-manager.html (folder-name convention) * docs: retro for template-manager — codify tooltip wiring & doc-filename convention - CLAUDE.md: add "In-app help wiring (DocumentationExtension)" recipe — the deterministic tooltip contract (category = plugin_<pluginId>, 3-arg showTooltip, Tier 3 setup, documentation.db debug query) so every plugin gets it right without a device round-trip - plugin-review skill: RUBRIC 6.7 now fails a wrong category / bare 2-arg showTooltip (the "n/a" trap); SKILL 6.6 disambiguates the doc filename to the kebab folder-name form (template-manager.html) - learnings: tooltip n/a root-cause + Glide icon-cache invalidation - retrospective: 2026-07-24 session log
1 parent 2158c65 commit a61431e

46 files changed

Lines changed: 2523 additions & 2 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/plugin-review/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ Search the source tree:
9797
- May have other sections. If other sections are present, ensure they are relevant and correct
9898
- Must have a white background and body text must be black.
9999
- Must be written in English
100-
- Must be at the top-level of the plugin. Must have the same name as the plugin with the .html extension
100+
- Must be at the top-level of the plugin folder, named after the **plugin folder** (kebab-case) with a `.html` extension: `template-manager/``template-manager.html`. The short folder-name form is preferred; a `-documentation` suffix (`random-xkcd-documentation.html`) is also acceptable. Do **not** name it after the lowercase `pluginBuilder { pluginName }` when that differs from the folder (i.e. not `templatemanagerplugin.html`).
101101

102102
#### 6.7 Tooltips and in-app help
103103
Code On The Go has a three-tier in-IDE help model: Tier 1 (brief) and Tier 2 (more detail) are tooltips; Tier 3 is a full offline web page reached from a button on the tooltip. Plugins participate through `DocumentationExtension` (all symbols verifiable in `plugin-api.jar`). This is separate from the 6.6 install-decision page — grade them independently.

.claude/skills/plugin-review/references/RUBRIC.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ Help must be available *inside* the running IDE, not only in the standalone 6.6
3838

3939
Requirements:
4040

41-
- The plugin implements `DocumentationExtension` and returns its `plugin_<pluginId>` category from `getTooltipCategory()`.
41+
- The plugin implements `DocumentationExtension` and returns **exactly** `"plugin_<pluginId>"` (the full `plugin.id`) from `getTooltipCategory()`. Any other value (short slug, dotless/underscore form) registers entries under a category the lookup never queries, so tooltips render the literal `n/a` at runtime — **Fail**.
42+
- **Manual `showTooltip` calls must pass the category.** If the plugin shows a tooltip on a custom view via `IdeTooltipService`, it must use the 3-arg `showTooltip(anchorView, category, tag)` with `category = "plugin_<pluginId>"`. A bare 2-arg `showTooltip(view, tag)` resolves under the wrong default category and renders `n/a` even though the entry is registered correctly — **Fail** (the entry exists but never displays; only device long-press reveals it). See the CLAUDE.md "In-app help wiring" recipe.
4243
- **Every UI element the plugin contributes has a tooltip.** Each `NavigationItem`, `MenuItem`, `TabItem`, FAB/toolbar action, and `EditorTabItem` carries a `tooltipTag` (or `tooltip` for `EditorTabItem`); any custom `View` the plugin shows is wired to the tooltip system. No contributed element may be left without help.
4344
- Every `tooltipTag` resolves to a `PluginTooltipEntry` returned from `getTooltipEntries()` — no dangling tags. Each entry provides a Tier 1 `summary` and a Tier 2 `detail`.
4445
- **Complete help is available within the app.** The plugin ships a Tier 3 bundle via `getTier3DocsAssetPath()` that comprehensively covers its functionality, and tooltips link to it through `PluginTooltipButton`s. Tier 3 must work offline (served locally); it is not a link out to the public internet.

CLAUDE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ A plugin is an Android *application* module (despite installing as a library) wi
5757

5858
Available permission strings (declared comma-separated in `plugin.permissions`): `filesystem.read`, `filesystem.write`, `network.access`, `system.commands`, `ide.settings`, `project.structure`.
5959

60+
### In-app help wiring (tooltips + Tier 3, `DocumentationExtension`)
61+
62+
Every plugin with UI implements `com.itsaky.androidide.plugins.extensions.DocumentationExtension`. This wiring is fixed and foundational — get **all** of it right or the tooltip renders the literal string **`n/a`** at runtime. The build stays green and the manifest looks fine, so **only device long-press testing catches a mistake** (this bit us once). All symbols are in `plugin-api.jar`.
63+
64+
1. **Category is `"plugin_<pluginId>"` — exactly.** `getTooltipCategory()` MUST return `"plugin_"` + the full `plugin.id` (e.g. `"plugin_org.appdevforall.templatemanagerplugin"`). The host registers your entries under this string **and** derives the same string when resolving a lookup. Any other value — a short slug, a dotless/underscore form — silently mismatches → `n/a`.
65+
2. **Entries.** `getTooltipEntries()` returns `PluginTooltipEntry(tag, summary, detail, buttons)`: `summary` = Tier 1 (one line shown on long-press), `detail` = Tier 2 (HTML behind "See more"). Keep the `tag` in one shared `const val` used by steps 3–4.
66+
3. **Look tooltips up with the 3-arg overload.** Call `IdeTooltipService.showTooltip(anchorView, category, tag)` and pass `category = "plugin_<pluginId>"` explicitly. **Never use the 2-arg `showTooltip(view, tag)`** — it resolves under a different default category and renders `n/a` even when the entry is registered correctly. Param order is `(anchorView, category, tag)`.
67+
4. **Attach tags to UI.** Set `tooltipTag = <that same tag>` on every contributed `NavigationItem` / `TabItem` / menu item / FAB; `EditorTabItem` instead takes a literal `tooltip = "..."` string. A contributed element with no tooltip fails review clause 6.7.
68+
5. **Tier 3 (offline page).** Override `getTier3DocsAssetPath()` to return an assets subdir name (convention: `"docs"`), ship real HTML at `src/main/assets/<dir>/index.html` (white background, black text, English), and link it from an entry via `PluginTooltipButton(description, uri = "index.html", order = 0)` — leave `directPath` false (`true` targets the host's shared docs tree, not your bundle).
69+
70+
Debug a mismatch against the on-device store (`adb root` first):
71+
`sqlite3 /data/data/com.itsaky.androidide/databases/documentation.db "SELECT c.category, t.tag, substr(t.summary,1,40) FROM Tooltips t JOIN TooltipCategories c ON c.id=t.categoryId WHERE c.category LIKE 'plugin_%'"`. If the row is present but the tooltip still shows `n/a`, the bug is the **lookup** (step 1 or 3), not registration. (The unused `ide_tooltip_table` is a red herring — plugin entries live in `Tooltips` + `TooltipCategories`.)
72+
6073
### Convention: AAR metadata checks are disabled
6174

6275
Most plugins end with:

docs/process/learnings.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Cross-session gotchas, discoveries, and patterns worth not re-deriving.
1818

1919
- **On-device install markers hide code changes.** `ai-literacy-course`'s `CourseInstaller` extracts its bundle once and gates it behind `.installed-v<INSTALL_VERSION>`; if the marker exists, extraction *and* `CourseShell.generate()` are skipped. A logic fix (e.g. lesson-item ordering) has zero on-device effect until `INSTALL_VERSION` is bumped — it looks like "the fix didn't work" and costs a device round-trip. Bump the version constant as part of any extraction/generation change.
2020
- **`assemblePlugin` silently ships broken `.cgp`s when downloaded assets are missing.** Plugins with a `downloadAssets` task (`ai-literacy-course` → course ZIP + `pdfjs.zip`; `ndk-installer-plugin`) don't fetch those assets during a plain `assemblePlugin`, and there's no build-time warning — the missing asset only surfaces as a runtime failure on device (`Bundled asset not found: pdfjs.zip` → "Could not prepare the course"). Run `./gradlew downloadAssets assemblePlugin` (or `scripts/update-libs.sh`) and `unzip -l` the `.cgp` to confirm assets are present before handing it over.
21+
- **Plugin tooltips render `n/a` when the category/lookup is wrong — build stays green.** `DocumentationExtension` help is registered into `documentation.db` (`Tooltips` + `TooltipCategories`), but a static build/manifest check can't see a category or overload mismatch. Two traps: (1) `getTooltipCategory()` must be exactly `"plugin_<pluginId>"` (full `plugin.id`); (2) manual lookups must use the 3-arg `IdeTooltipService.showTooltip(anchorView, category, tag)` — the 2-arg `showTooltip(view, tag)` resolves under a different default category and shows `n/a` even though the entry is registered. Only a device long-press reveals it. To debug, `adb root` then query `documentation.db`: if the row is present under `plugin_<id>` but the tooltip shows `n/a`, the bug is the lookup, not registration. Full recipe now in `CLAUDE.md` → "In-app help wiring".
22+
- **Plugin Manager icons need `plugin.icon_day`/`_night` → real PNGs, and the Glide cache defeats icon re-verification.** The card icon comes from those two manifest paths (not `android:icon`); ship `src/main/assets/icon_{day,night}.png` (~192px). When re-verifying an icon change under the same plugin id, the Plugin Manager caches via Glide keyed by path with no mtime invalidation — the old icon persists until you `adb shell rm -rf /data/data/com.itsaky.androidide/cache/image_manager_disk_cache` (needs `adb root`) or install on a clean device.
2123

2224
## CoGo project templates (Pebble `.cgt`)
2325

docs/process/retrospective.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,43 @@
119119
| Agent waited to be asked before running plugin-review | CLAUDE.md | Added "Proactively offer `/plugin-review`" paragraph to the "Plugin review skill" section, listing the triggering changes (new plugin import, dep change, API touch, new asset, libs/ update) |
120120
| Agent marked builds "verified" without device-level proof | CLAUDE.md | Added new "Verification" section before "Adding a new plugin", stating build success is necessary but never sufficient and device install is the terminal verification step |
121121
| Same as above, reinforcement | Memory | `feedback_plugin_verify_on_device.md` created mid-session — per-project memory layer reinforcing the CLAUDE.md rule |
122+
123+
## 2026-07-24 - Template Manager plugin: review → fix blockers → device verify → icons/naming → PR
124+
125+
### Time Breakdown
126+
| Started | Phase | 👤 Hands-On | 🤖 Agent | Problems |
127+
|---------|-------|-------------|----------|----------|
128+
| 3:28pm | Initial review (research subagent, build via symlink, security audit, rubric scorecard) | ██ 8m | ██ 11m | |
129+
| 3:39pm | Fix blockers + first device install (`../libs`, manifest, Tier 3, HTML docs; build; emulator install; sidebar + list verified) | ██ 10m | ████ 39m | ⚠ tooltip showed `n/a` |
130+
| 4:18pm | Root-cause tooltip + icons + card + permissions (`documentation.db` → 3-arg `showTooltip`; icons v1→v2 CGT; card title; reinstall; Tier 1/2/3 verified) | ██ 8m | ██ 22m | ⚠ 1 wrong hypothesis; icons redone once |
131+
| 4:40pm | Naming normalization + "Template Manager" rename (reinstall + verify) | █ 3m | █ 12m | |
132+
| 4:52pm | Commit + push + PR #51 | █ 1m | █ 5m | |
133+
134+
### Metrics
135+
| Metric | Duration |
136+
|--------|----------|
137+
| Total wall-clock | ~1h 32m |
138+
| Hands-on | ~30m (33%) |
139+
| Automated agent time | ~62m (67%) |
140+
| Idle/testing/away | minimal |
141+
| Retro analysis time | ~2 min |
142+
143+
_Note: the transcript script reported 108 min "hands-on" but over-counted — it billed two skill injections (plugin-review SKILL text; commit-push-pr context) as user typing (~54 min phantom). Real hands-on ≈ 30 min, mostly reading review reports._
144+
145+
### Key Observations
146+
- **Device verification, not the build, found the defect.** Build green + manifest correct, yet the tooltip rendered `n/a` — a bug the original code also had. Only a device long-press exposed it. Strongest evidence yet for "build success ≠ verification."
147+
- **First tooltip fix hypothesis was wrong.** Changing `getTooltipCategory` alone didn't work; the fix came from inspecting `documentation.db` (entry was registered; the 2-arg `showTooltip` lookup was at fault). Lesson: go to ground truth sooner instead of reasoning from sibling-plugin comparison.
148+
- **Icons rendered twice** (stacked-cards → "meh" → CGT-file). Partly driven by the later CGT requirement; a quick direction sketch before a full render could have saved a pass.
149+
- **~20 turns of autonomous device driving** (install/uninstall/reinstall/DB queries/tooltip tests) with no input needed. High productive-to-rework ratio.
150+
- **Platform reinstall cost is inherent** (release signature mismatch forces uninstall→restart→clear-cache→reinstall→restart); batching changes to minimize cycles was correct.
151+
152+
### Feedback
153+
**What worked:** (from user) The tooltip issue should never recur — asked to codify the foundational wiring so it's right the first time.
154+
**What didn't:** Getting the tooltip wiring right required a device round-trip and one wrong hypothesis; it's deterministic tech that shouldn't have been ambiguous.
155+
156+
### Actions Taken
157+
| Issue | Action Type | Change |
158+
|---|---|---|
159+
| Tooltip wiring got `n/a` and cost a device round-trip; it's foundational and deterministic | CLAUDE.md | Added "### In-app help wiring (tooltips + Tier 3, `DocumentationExtension`)" under Architecture — the exact recipe: category = `plugin_<pluginId>`, always 3-arg `showTooltip(anchorView, category, tag)`, tooltipTag rules, Tier 3 setup, and the `documentation.db` debug query |
160+
| `/plugin-review` couldn't statically catch the 2-arg `showTooltip` / wrong-category trap | Skill (RUBRIC.md 6.7) | Added two Fail-level checks: category must be exactly `plugin_<pluginId>`, and manual `showTooltip` must use the 3-arg category overload (bare 2-arg → `n/a`) |
161+
| Tooltip + icon-cache gotchas would otherwise be re-learned | Docs (learnings.md) | Added the tooltip `n/a` root-cause + debug query and the Glide icon-cache invalidation note to "Plugin build & install gotchas" |

template-manager/.gitignore

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Built application files
2+
*.apk
3+
*.aar
4+
*.ap_
5+
*.aab
6+
7+
# Files for the ART/Dalvik VM
8+
*.dex
9+
10+
# Java class files
11+
*.class
12+
13+
# Generated files
14+
/bin/
15+
/gen/
16+
/out/
17+
# Uncomment the following line in case you need and you don't have the release build type files in your app
18+
# Gradle files
19+
.gradle/
20+
/build/
21+
22+
# Local configuration file (sdk path, etc)
23+
local.properties
24+
25+
# Proguard folder generated by Eclipse
26+
proguard/
27+
28+
# Log Files
29+
*.log
30+
31+
# Android Studio Navigation editor temp files
32+
.navigation/
33+
34+
# Android Studio captures folder
35+
captures/
36+
37+
# IntelliJ
38+
*.iml
39+
.idea
40+
# Android Studio 3 in .gitignore file.
41+
.idea/caches
42+
.idea/modules.xml
43+
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
44+
.idea/navEditor.xml
45+
46+
# Keystore files
47+
# Uncomment the following lines if you do not want to check your keystore files in.
48+
#*.jks
49+
#*.keystore
50+
51+
# External native build folder generated in Android Studio 2.2 and later
52+
.externalNativeBuild
53+
.cxx/
54+
55+
# Google Services (e.g. APIs or Firebase)
56+
# google-services.json
57+
58+
# Freeline
59+
freeline.py
60+
freeline/
61+
freeline_project_description.json
62+
63+
# fastlane
64+
fastlane/report.xml
65+
fastlane/Preview.html
66+
fastlane/screenshots
67+
fastlane/test_output
68+
fastlane/readme.md
69+
70+
# Version control
71+
vcs.xml
72+
73+
# lint
74+
lint/intermediates/
75+
lint/generated/
76+
lint/outputs/
77+
lint/tmp/
78+
# lint/reports/

0 commit comments

Comments
 (0)