Skip to content

Latest commit

 

History

History
224 lines (193 loc) · 15.1 KB

File metadata and controls

224 lines (193 loc) · 15.1 KB

Titanium for JetBrains — Project Handoff Brief

A complete context dump so a fresh conversation can continue seamlessly.

1. What this project is

A JetBrains IDE plugin that ports the vscode-titanium extension to the IntelliJ Platform. It develops Titanium SDK apps/modules by wrapping the titanium (ti) and alloy CLIs.

  • Language/build: Kotlin + Gradle, IntelliJ Platform Gradle Plugin 2.6.0.
  • Compiles against: IntelliJ IDEA Ultimate 2024.3 (platformType=IU, build 243) because it bundles the closed-source JavaScript plugin.
  • Runs on: EVERY IntelliJ-Platform IDE incl. Community editions + Android Studio (NOT Fleet).
  • Location on disk: /Users/AbdullahFaqeir/dev/TiDev/JetBrains Plugin/titanium-jetbrains
  • Git: repo exists, branch main, remote https://github.com/devloopsnet/titanium-jetbrains.git. Commits must be made by the user from their Mac terminal (the sandbox can't manage git locks on the synced mount). ~72 main Kotlin files + 2 test files.

2. The core architectural decision (must preserve)

Universal-core + optional-JS split. Titanium is JS/Alloy, so JS-aware features need the bundled JavaScript plugin — which only ships in paid IDEs. To still run on Community:

  • Core (META-INF/plugin.xml) hard-depends only on com.intellij.modules.platform (+ com.intellij.modules.xml). This is ~everything.
  • Optional JS layer (META-INF/titanium-javascript.xml) loads only when the JavaScript plugin is present, via <depends optional="true" config-file="titanium-javascript.xml">JavaScript</depends>. It holds ONLY language="JavaScript" contributors.
  • Hard rule: NO core code may import com.intellij.lang.javascript.*. Only the alloy/js/ package may, and it's wired solely from the optional descriptor. Verified clean.
  • Compiling against Ultimate is compile-time only; the optional <depends> keeps runtime loadable on Community. The JS plugin is bundled-only, so use bundledPlugin("JavaScript"), never plugin("JavaScript", …).

3. Feature inventory (all implemented, code-complete)

  • Build / Run / Clean via a run configuration (run/TiRunConfiguration*), platform/target/device/ SDK/deploy-type/build-only/LiveView options; producer from tiapp.xml context.
  • Debug (debug/*): from-scratch Chrome DevTools Protocol client over JDK WebSocket, own breakpoint type, variable inspection AND expression evaluation/watches.
  • Package (dist builds) iOS App Store/Ad Hoc + Android Play Store (actions/pkg/*, run/TiPackage*), cert/profile from ti info, keystore fields; runs in a console.
  • Create Keystore via keytool (actions/pkg/TiCreateKeystore*).
  • Wizards: Create App / Create Module (ti create); Alloy generators (controller/view/style/model/migration/widget via alloy generate).
  • SDK mgmt: install/select/uninstall/check-updates (sdk/TiSdkManager, actions/sdk/*); Update CLI/Alloy (npm i -g).
  • Tool windows: build explorer (tree of project → recent builds → platforms/targets/devices → SDKs → env issues, double-click to run) + Help window.
  • Toolbar (New UI MainToolbarRight): Platform picker + Device picker (ComboBoxAction, values from ti info), Build, Debug, Package, Clean, Refresh, + Titanium dropdown.
  • Settings (settings/*): CLI/alloy/node paths, log level, LiveView default, dist dir, i18n lang, keystore path/alias, default creation dir, JS function template. PersistentStateComponent.
  • Editor intelligence: completion for Alloy views (XML), tiapp.xml, TSS, JS controllers (optional); hover docs from api.jsca; go-to-definition (handler→controller, i18n→strings.xml, id/class→TSS rule); intentions (insert handler, insert i18n, extract style); related-file gutter markers + Open-Related actions (Ctrl+Alt+X/V/S/A); Live Templates (ti*, al*).
  • TSS language: file type, hand-written lexer, syntax highlighting, flat parser (PSI), brace matcher, commenter, completion.
  • SDK-backed completion: environment/TiApiMetadata parses installed SDK's api.jsca.
  • Recent builds persisted per-workspace; clickable file paths in build/package consoles (run/TiFilePathFilter).
  • Packaging/CI: LICENSE (Apache-2.0), CHANGELOG, .github/workflows/build.yml (test+build) and release.yml (sign+publish on tag).

4. Current status — READ THIS FIRST

  • Compile: PROVEN GREEN. :compileKotlin succeeded on the user's machine. The only earlier test failure was missing JUnit — fixed by adding testImplementation("junit:junit:4.13.2") to build.gradle.kts.
  • The big fix just made (v8 CLI): The user's CLI is Titanium CLI v8 (8.1.5). TiCli used to append --no-prompt --no-banner --no-colors --no-progress-bars to every command and --types to info. v8 rejects these, so ti -v and ti info returned nothing → the tool window showed nothing on Refresh. FIXED: TiCli now uses bare ti -v and ti info --output json, and builds run in the project dir (cwd) with no --project-dir/--no-* flags.
  • TiInfoParser rewritten to the REAL v8 JSON shape (validated against the user's actual ti info output — extracts 14 SDKs, 30 devices, 5 certs, 27 profiles, 3 issues). Real structure:
    • titanium: map "<id>": {version, path, platforms} (no selected); selected SDK = ios.tisdk or android.tisdk.
    • iOS sims: ios.simulators.ios.<runtime>[] {udid,name,version}.
    • iOS devices: ios.devices[].
    • Android emulators: android.emulators[] (NOT avds); devices: android.devices[].
    • Certs: ios.certs.keychains.<keychain>.{developer,distribution}[].
    • Profiles: ios.provisioning.{development,distribution,adhoc,enterprise}[].
    • Issues: ios.issues[] + android.issues[] (objects with message); no top-level issues.

4b. Hardening pass (July 2026) — done in-code, needs one green build

A robustness sweep across all layers (compile not yet verified — run ./gradlew test buildPlugin):

  • CLI layer: TiCli.extractJson now strips trailing garbage too (npm warnings after JSON broke Gson); ti -v parsing tolerates banners/notices (extractVersion, regex-based); PATH injection deduped into cli/CliEnv.kt (reads cmd.parentEnvironment, not System.getenv); missing project dir no longer set as cwd. SDK versions sort numerically (TiInfoParser.VERSION_ORDER) — 13.x above 9.x.
  • Services: TiEnvironmentService catches unexpected refresh failures (PCE rethrown), guards project.isDisposed in onFinished. TiApiMetadata coalesces concurrent loads, type-safe JSON access. TiProjectService auto-invalidates its cache via a VFS listener on tiapp.xml/timodule.xml changes (now Disposable), skips hidden dirs. TiSdkManager reports timeouts and hints when a subcommand is unsupported (v8 sdk select concern).
  • Run/debug: TiRunLauncher reuses same-name run configs instead of duplicating them. extraArgs tokenized quote-aware (ParametersListUtil). CdpClient: HTTP/WS timeouts, /json/list fallback, serialized sends (JDK WS forbids overlap), callback cleanup on close, error responses logged. TiDebugProcess: retry window 5 min, bails on stop/dead build process.
  • UI/actions: dialogs validate names/app IDs/keystore paths/validity; background tasks snapshot Swing values on EDT; timeouts reported; TiVfs.refresh is async (sync refresh off-EDT can deadlock); intentions wrap VFS writes in try/IOException + XML-escape i18n keys.
  • TSS lexer bug fixed: trailing backslash in an unterminated string pushed tokenEnd past the buffer (highlighting exception). Regression-tested.
  • Tests added: TiCliParsingTest, TiInfoParserEdgeTest, expanded TssLexerTest (bounds/termination invariants checked for every token).

4c. vscode-titanium parity sweep (July 2026) — closes every known gap

  • Create TSS rule intention (intentions/AlloyCreateTssRuleIntention.kt) + tssIdTemplate/ tssClassTemplate/tssTagTemplate settings (vscode codeTemplates.tss*). Registered in plugin.xml + Settings UI.
  • Build command echo (displayBuildCommandInConsole, default on): run console echoes the ti build line; packaging console echoes with passwords masked (TiPackager.maskedCommandLine, unit-tested in TiPackagerMaskingTest).
  • Snippet parity: liveTemplates/Titanium.xml now 18 templates (added tiinfo, tidebug, titrace, tiopt, tiremevent, tifireevent, tianim, tifile, tisound, tiaudio, tivideo, ticamera); Alloy.xml now 14 (added alglo, alcfg, alargs, alcon, alcol, almod, alwid, ifios, ifand, ifwin).
  • Image path completion (alloy/TiImageAssets.kt): TSS image-like properties and view attributes complete runtime-style paths (/images/foo.png) from app/assets, app/images, Resources; platform subdirs stripped; capped at 500.
  • Fix Environment Issues (actions/sdk/TiFixEnvironmentAction.kt): CLI missing → offer npm i -g titanium alloy; no SDK → offer install latest; else list ti info issues.
  • Select Updates / Install All Updates (sdk/TiUpdateChecker.kt, actions/sdk/TiUpdatesActions.kt): unified SDK + titanium + alloy check (npm view/ls -g --json via new cli/NpmCli.kt), checkbox dialog, install-all.
  • Periodic update check (updateCheckFrequencyHours, default 24, 0 = off) in TiStartupActivity; lastUpdateCheckMs persisted app-wide.
  • TiToolingUpdateActions now reuses NpmCli/CliEnv (PATH handling deduped).

With this, all vscode-titanium commands/settings/snippets have JetBrains equivalents. Remaining qualitative gap: debugger maturity (source maps) — see §5/§6.

4d. New Project wizard (July 2026)

Titanium now appears in the IDE's New Project dialog (wizard/ package), dual-registered:

  • IDEA / Android Studio: TiNewProjectWizard (GeneratorNewProjectWizard) exposed via TiModuleBuilderAdapter (GeneratorNewProjectWizardBuilderAdapter, registered at the moduleBuilder EP). The options form is a chained NewProjectWizardStep after the standard name/location step; setupProject calls TiProjectScaffolder. History: a first attempt used legacy ModuleType/ModuleBuilder.getCustomOptionsStep — the NEW (2022.1+) wizard dialog does not render that, producing an empty page. Don't go back to it.
  • WebStorm-family (PyCharm, PhpStorm, GoLand…): TiProjectGenerator (WebProjectTemplate)
    • TiProjectGeneratorPeer implementing ProjectGeneratorPeer directly, registered as directoryProjectGenerator. Gotcha (hit live in WebStorm): the dialog renders the page via peer.buildUI(settingsStep); extending GeneratorPeerImpl with its no-arg constructor makes buildUI add an internal empty JPanel (overriding getComponent() is not enough) — the page shows only the Location field. Always override buildUI and add the component via settingsStep.addSettingsComponent(...).
  • Both share TiNewProjectPanel/TiNewProjectSettings and TiProjectScaffolder, which runs ti create -t app|module -n <dirname> --id <id> -p <platforms> -d <parent> [-u <url>] [--ios-code-base objc|swift] [--android-code-base java|kotlin] --force in the background, then refreshes VFS + project cache + environment.
  • Full option set (parity with ti create interactive prompts): project type (app/module); for apps a framework choice — Alloy (default) or Classic (Alloy is applied by running alloy new <dir> after the scaffold, with graceful fallback to Classic if alloy is missing); for modules per-platform code bases (iOS: Objective-C/Swift, Android: Java/Kotlin); app id (validated reverse-domain, auto-derived from name); platforms; optional author URL (-u). The panel shows/hides app vs module options as the type changes.
  • The Tools-menu Create App/Module dialogs (actions/create/*) now embed the same panel (TiNewProjectPanel(fixedType=…)) and delegate to the same scaffolder (showOpenHint=true shows the "open via File | Open" dialog afterwards).
  • Flag-validation risk (same class as §5): --ios-code-base/--android-code-base and the alloy new invocation need one live run to confirm exact v8/SDK flag names.
  • Compile-risk watchpoints (verify on first build): WebProjectTemplate.createPeer() signature, GeneratorPeerImpl no-arg constructor, and the new-wizard chain API (RootNewProjectWizardStep / NewProjectWizardBaseStep / NewProjectWizardChainStep.Companion.nextStep / GeneratorNewProjectWizardBuilderAdapter). All standard platform APIs, but they drift between majors.

5. What still needs live validation (the ONLY remaining work)

Not "unknowns" anymore — each is "run it once, paste the error, trim a flag":

  1. Confirm Refresh populates in the running IDE after rebuild+reinstall (logic validated vs real data, but not seen live).
  2. Other v8 CLI commands may reject flags (same class of fix as info):
    • build: --liveview, --log-level, --deploy-type, --debug-host (in run/TiBuildCommandBuilder).
    • sdk select: v8 may have dropped select (lists install/uninstall only) — sdk/TiSdkManager.
    • create: -t, --force (actions/create/*).
    • package: dist flags (run/TiPackageCommandBuilder).
  3. Debugger never run against a real simulator/device (source-map fidelity, iOS needs ios-webkit-debug-proxy).

6. Deliberately deferred (larger, optional polish)

  • Structured TSS grammar/PSI for rename/find-usages of rules (go-to-definition already works).
  • More test coverage (only TiInfoParser + TssLexer are unit-tested).

7. How to build / run / install

cd "/Users/AbdullahFaqeir/dev/TiDev/JetBrains Plugin/titanium-jetbrains"
./gradlew test buildPlugin      # -> build/distributions/Titanium-0.1.0.zip
./gradlew runIde                # sandbox IDE with plugin loaded

Install: Settings → Plugins → ⚙ → Install Plugin from Disk → the ZIP → Restart. Commit (from Mac terminal — sandbox can't): rm -f .git/index.lock && git add -A && git commit && git push.

8. Key working constraints for the assistant

  • The assistant's shell is an isolated Linux sandbox, NOT the user's Mac. It cannot run the user's ti, and the sandbox npm registry blocks the titanium package (403). To inspect real CLI output, the user runs the command and saves output into the project folder (mounted) for the assistant to read.
  • The assistant cannot compile (no IntelliJ SDK/gradle in sandbox); it grep-verifies wiring and reasons through APIs. The user runs ./gradlew and pastes results.
  • Editing files in the connected folder requires reading them first in-session.
  • Highest-risk APIs to watch on builds: ComboBoxAction.createPopupActionGroup (deprecation, suppressed), RunContentExecutor, AbstractDocumentationProvider, XDebugger XValue/evaluator, VFS writes in intentions.

9. Suggested next message to open the new conversation

"Continuing the Titanium JetBrains plugin (see HANDOFF.md in the repo). I've rebuilt and reinstalled. Refresh [does/doesn't] show devices now. When I run a Build it [works / prints: ]. Let's fix the remaining v8 CLI flag issues."