Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
Commit0377886unknown_key

Add JetBrains plugin skeleton — IntelliJ/WebStorm/GoLand support

Add JetBrains plugin skeleton — IntelliJ/WebStorm/GoLand support

https://claude.ai/code/session_01DzJMTFASjMHt2f5ze4cNLR
Claude committed on June 6, 2026Parent: f5f3fba
15 files changed+888003778860006e7cc6e50d93b408caf7c2d8bae45a
15 changed files+888−0
Modified.gitignore+7−0View fileUnifiedSplit
2222
2323# standalone box local DB backups
2424backups/
25
26# JetBrains plugin build artifacts
27jetbrains-plugin/build/
28jetbrains-plugin/.gradle/
29jetbrains-plugin/.idea/
30jetbrains-plugin/*.iml
31jetbrains-plugin/*.class
Addedjetbrains-plugin/.gitignore+23−0View fileUnifiedSplit
1# Gradle build artifacts
2build/
3.gradle/
4
5# Compiled JVM bytecode
6*.class
7*.jar
8
9# IntelliJ IDEA project files (generated by Gradle plugin during development)
10.idea/
11*.iml
12*.iws
13*.ipr
14
15# Kotlin incremental compilation cache
16.kotlin/
17
18# macOS
19.DS_Store
20
21# Local Gradle properties (may contain credentials)
22local.properties
23gradle-local.properties
Addedjetbrains-plugin/README.md+115−0View fileUnifiedSplit
1# Gluecron JetBrains Plugin
2
3IntelliJ Platform plugin for [Gluecron](https://gluecron.com) — AI-native code intelligence.
4
5Works in **IntelliJ IDEA**, **WebStorm**, **GoLand**, **PyCharm**, and any other JetBrains IDE
6based on the IntelliJ Platform 2023.1+.
7
8## Features
9
10| Action | Location | What it does |
11|--------|----------|--------------|
12| **Open PR List** | Gluecron menu / VCS Operations | Opens `{host}/{owner}/{repo}/pulls` in your browser |
13| **Create Issue** | Gluecron menu / VCS Operations | Opens `{host}/{owner}/{repo}/issues/new` in your browser |
14| **Merge PR for Current Branch** | Gluecron menu / VCS Operations | POSTs to the Gluecron API to merge the open PR for the checked-out branch |
15| **View Repo Health** | Gluecron menu / VCS Operations | Opens `{host}/{owner}/{repo}/health` in your browser |
16
17The plugin detects `owner/repo` automatically from your project's git remote URL.
18
19## Requirements
20
21- JDK 17+
22- Gradle 8.x (the Gradle wrapper `gradlew` is the recommended way to build)
23- A Gluecron server (self-hosted or [gluecron.com](https://gluecron.com))
24- A personal access token with `repo` scope (generate one at `{host}/settings/tokens`)
25
26## Building
27
28```bash
29# Clone the repository
30git clone https://gluecron.com/ccantynz/Gluecron.com.git
31cd Gluecron.com/jetbrains-plugin
32
33# Build the plugin zip (output: build/distributions/gluecron-jetbrains-0.1.0.zip)
34./gradlew buildPlugin
35
36# Run the plugin in a sandboxed IDE for development
37./gradlew runIde
38```
39
40The `buildPlugin` task produces a zip archive at:
41
42```
43build/distributions/gluecron-jetbrains-<version>.zip
44```
45
46## Installing the Plugin
47
48### From local zip (manual install)
49
501. Open your JetBrains IDE.
512. Go to **Settings → Plugins → ⚙ → Install Plugin from Disk…**
523. Select `build/distributions/gluecron-jetbrains-0.1.0.zip`.
534. Restart the IDE when prompted.
54
55### From JetBrains Marketplace (once published)
56
57Search for **"Gluecron"** in **Settings → Plugins → Marketplace**.
58
59## Configuration
60
61After installation, configure the plugin:
62
631. Open **Settings → Tools → Gluecron**.
642. Set **Server URL** to your Gluecron instance (e.g. `https://gluecron.com`).
653. Set **Access Token** to a personal access token generated at `{host}/settings/tokens`.
66
67Alternatively, set environment variables before launching your IDE:
68
69```bash
70export GLUECRON_HOST=https://gluecron.com
71export GLUECRON_TOKEN=glc_your_token_here
72```
73
74The plugin reads these on startup and pre-fills the settings if they are not yet configured.
75
76## Project Structure
77
78```
79jetbrains-plugin/
80 build.gradle.kts Gradle build — IntelliJ Platform Plugin 1.x
81 settings.gradle.kts Root project name
82 gradle.properties plugin.id, plugin.version, platform.version
83 src/main/
84 resources/META-INF/plugin.xml Plugin manifest (actions, extensions)
85 kotlin/com/gluecron/
86 GluecronPlugin.kt Startup activity (env var seeding, welcome notification)
87 GluecronUtil.kt Shared helpers (git remote detection, browser, API)
88 actions/
89 OpenPrAction.kt Opens PR list in browser
90 CreateIssueAction.kt Opens new issue form in browser
91 MergePrAction.kt Calls Gluecron API to merge current branch's PR
92 ViewHealthAction.kt Opens repo health dashboard in browser
93 settings/
94 GluecronSettingsState.kt PersistentStateComponent (host + token)
95 GluecronSettingsConfigurable.kt Settings UI (two text fields)
96```
97
98## Merge PR — API details
99
100`MergePrAction` sends:
101
102```
103POST {host}/api/repos/{owner}/{repo}/pulls/merge
104Authorization: Bearer {token}
105Content-Type: application/json
106
107{"head": "<current-branch>", "merge_method": "merge"}
108```
109
110A confirmation dialog is shown before the request is sent. The action
111requires a valid access token to be configured.
112
113## License
114
115MIT — see the root `LICENSE` file.
Addedjetbrains-plugin/build.gradle.kts+52−0View fileUnifiedSplit
1plugins {
2 id("java")
3 id("org.jetbrains.kotlin.jvm") version "1.9.21"
4 id("org.jetbrains.intellij") version "1.16.1"
5}
6
7group = "com.gluecron"
8version = "0.1.0"
9
10repositories {
11 mavenCentral()
12}
13
14// Configure IntelliJ Platform Plugin Gradle Plugin 1.x
15intellij {
16 pluginName.set("Gluecron")
17 version.set(project.property("platform.version").toString())
18 type.set("IC") // IntelliJ IDEA Community Edition
19 plugins.set(listOf("git4idea"))
20}
21
22kotlin {
23 jvmToolchain(17)
24}
25
26tasks {
27 buildSearchableOptions {
28 enabled = false
29 }
30
31 patchPluginXml {
32 sinceBuild.set("231") // 2023.1
33 untilBuild.set("251.*") // 2025.1.*
34 changeNotes.set(
35 """
36 <ul>
37 <li>0.1.0: Initial release — Open PR, Create Issue, Merge PR, View Health</li>
38 </ul>
39 """.trimIndent()
40 )
41 }
42
43 signPlugin {
44 certificateChain.set(System.getenv("CERTIFICATE_CHAIN") ?: "")
45 privateKey.set(System.getenv("PRIVATE_KEY") ?: "")
46 password.set(System.getenv("PRIVATE_KEY_PASSWORD") ?: "")
47 }
48
49 publishPlugin {
50 token.set(System.getenv("PUBLISH_TOKEN") ?: "")
51 }
52}
Addedjetbrains-plugin/gradle.properties+11−0View fileUnifiedSplit
1# Plugin metadata
2plugin.id=com.gluecron.jetbrains
3plugin.version=0.1.0
4
5# IntelliJ Platform version to build against (2023.1)
6platform.version=2023.1
7
8# Gradle settings
9org.gradle.caching=true
10org.gradle.parallel=true
11kotlin.incremental=true
Addedjetbrains-plugin/settings.gradle.kts+1−0View fileUnifiedSplit
1rootProject.name = "gluecron-jetbrains"
Addedjetbrains-plugin/src/main/kotlin/com/gluecron/GluecronPlugin.kt+48−0View fileUnifiedSplit
1package com.gluecron
2
3import com.gluecron.settings.GluecronSettingsState
4import com.intellij.notification.NotificationGroupManager
5import com.intellij.notification.NotificationType
6import com.intellij.openapi.project.Project
7import com.intellij.openapi.startup.StartupActivity
8
9/**
10 * Post-startup activity for the Gluecron plugin.
11 *
12 * Runs once per project open, after the IDE has fully initialized.
13 * Responsibilities:
14 * 1. Seed settings from environment variables if not already configured
15 * (GLUECRON_HOST → host, GLUECRON_TOKEN → token).
16 * 2. Emit a notification if the host is still at the default localhost
17 * value so new users know to configure the plugin.
18 */
19class GluecronPlugin : StartupActivity {
20
21 override fun runActivity(project: Project) {
22 val settings = GluecronSettingsState.getInstance()
23
24 // Seed from environment variables on first run
25 val envHost = System.getenv("GLUECRON_HOST")
26 if (!envHost.isNullOrBlank() && settings.host == "http://localhost:3000") {
27 settings.host = envHost
28 }
29
30 val envToken = System.getenv("GLUECRON_TOKEN")
31 if (!envToken.isNullOrBlank() && settings.token.isBlank()) {
32 settings.token = envToken
33 }
34
35 // Warn if still using the default localhost address
36 if (settings.host == "http://localhost:3000" && settings.token.isBlank()) {
37 NotificationGroupManager.getInstance()
38 .getNotificationGroup("Gluecron Notifications")
39 .createNotification(
40 "Gluecron",
41 "Configure your Gluecron server URL and access token in " +
42 "<b>Settings → Tools → Gluecron</b>.",
43 NotificationType.INFORMATION
44 )
45 .notify(project)
46 }
47 }
48}
Addedjetbrains-plugin/src/main/kotlin/com/gluecron/GluecronUtil.kt+142−0View fileUnifiedSplit
1package com.gluecron
2
3import com.gluecron.settings.GluecronSettingsState
4import com.intellij.notification.NotificationGroupManager
5import com.intellij.notification.NotificationType
6import com.intellij.openapi.ide.CopyPasteManager
7import com.intellij.openapi.project.Project
8import git4idea.repo.GitRepositoryManager
9import java.awt.Desktop
10import java.net.URI
11import java.net.http.HttpClient
12import java.net.http.HttpRequest
13import java.net.http.HttpResponse
14import java.time.Duration
15
16/**
17 * Shared utilities for Gluecron actions.
18 *
19 * - [detectOwnerRepo] — infers `owner/repo` from the project's git remote URL
20 * - [openBrowser] — opens a URL in the system's default browser
21 * - [apiPost] — synchronous POST helper used by MergePrAction
22 * - [notify] — show a balloon notification
23 */
24object GluecronUtil {
25
26 /**
27 * Detects the owner and repository name from the first git remote URL
28 * in the project that contains the configured Gluecron host, or falls
29 * back to any remote named "origin".
30 *
31 * Handles both HTTPS and SSH remote formats:
32 * https://gluecron.com/owner/repo.git
33 * git@gluecron.com:owner/repo.git
34 *
35 * Returns null if no usable git remote is found.
36 */
37 fun detectOwnerRepo(project: Project): Pair<String, String>? {
38 val settings = GluecronSettingsState.getInstance()
39 val manager = GitRepositoryManager.getInstance(project)
40 val repos = manager.repositories
41 if (repos.isEmpty()) return null
42
43 // Prefer remotes whose URL contains the configured host
44 val hostDomain = settings.host
45 .removePrefix("https://")
46 .removePrefix("http://")
47 .trimEnd('/')
48
49 fun parseRemoteUrl(url: String): Pair<String, String>? {
50 // Normalise: strip protocol + host prefix or git@ prefix
51 val cleaned = url
52 .replace(Regex("^https?://[^/]+/"), "")
53 .replace(Regex("^git@[^:]+:"), "")
54 .removeSuffix(".git")
55 val parts = cleaned.split("/").filter { it.isNotBlank() }
56 if (parts.size < 2) return null
57 return Pair(parts[0], parts[1])
58 }
59
60 for (repo in repos) {
61 val remotes = repo.remotes
62 // Try host-matching remote first
63 for (remote in remotes) {
64 val url = remote.firstUrl ?: continue
65 if (url.contains(hostDomain)) {
66 return parseRemoteUrl(url)
67 }
68 }
69 // Fall back to any remote named "origin"
70 val origin = remotes.firstOrNull { it.name == "origin" }
71 if (origin != null) {
72 val url = origin.firstUrl ?: continue
73 return parseRemoteUrl(url)
74 }
75 }
76 return null
77 }
78
79 /**
80 * Returns the name of the currently checked-out branch in the first
81 * git repository found in the project, or null if none.
82 */
83 fun currentBranch(project: Project): String? {
84 val manager = GitRepositoryManager.getInstance(project)
85 return manager.repositories.firstOrNull()
86 ?.currentBranchName
87 }
88
89 /**
90 * Opens [url] in the system's default browser.
91 * Falls back gracefully if Desktop is not supported.
92 */
93 fun openBrowser(url: String) {
94 if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
95 Desktop.getDesktop().browse(URI(url))
96 }
97 }
98
99 /**
100 * Performs a synchronous HTTP POST to [path] (relative to the configured host)
101 * with a JSON [body]. Returns the response body as a string, or throws on error.
102 *
103 * This is intentionally minimal — used only by MergePrAction which needs a
104 * blocking call so we can surface the result in the same action invocation.
105 */
106 fun apiPost(path: String, body: String): String {
107 val settings = GluecronSettingsState.getInstance()
108 val url = "${settings.host}$path"
109 val token = settings.token
110
111 val client = HttpClient.newBuilder()
112 .connectTimeout(Duration.ofSeconds(10))
113 .build()
114
115 val requestBuilder = HttpRequest.newBuilder()
116 .uri(URI(url))
117 .timeout(Duration.ofSeconds(30))
118 .header("Content-Type", "application/json")
119 .header("Accept", "application/json")
120 .POST(HttpRequest.BodyPublishers.ofString(body))
121
122 if (token.isNotBlank()) {
123 requestBuilder.header("Authorization", "Bearer $token")
124 }
125
126 val response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString())
127 if (response.statusCode() !in 200..299) {
128 throw RuntimeException("HTTP ${response.statusCode()}: ${response.body().take(200)}")
129 }
130 return response.body()
131 }
132
133 /**
134 * Shows a balloon notification attached to [project].
135 */
136 fun notify(project: Project, message: String, type: NotificationType = NotificationType.INFORMATION) {
137 NotificationGroupManager.getInstance()
138 .getNotificationGroup("Gluecron Notifications")
139 .createNotification("Gluecron", message, type)
140 .notify(project)
141 }
142}
Addedjetbrains-plugin/src/main/kotlin/com/gluecron/actions/CreateIssueAction.kt+44−0View fileUnifiedSplit
1package com.gluecron.actions
2
3import com.gluecron.GluecronUtil
4import com.gluecron.settings.GluecronSettingsState
5import com.intellij.notification.NotificationType
6import com.intellij.openapi.actionSystem.AnAction
7import com.intellij.openapi.actionSystem.AnActionEvent
8import com.intellij.openapi.project.DumbAware
9
10/**
11 * Opens a browser tab showing the new-issue form for the current repository.
12 *
13 * URL pattern: {host}/{owner}/{repo}/issues/new
14 *
15 * This is the JetBrains equivalent of the VS Code "gluecron.createIssue" flow.
16 * Rather than embedding a form in the IDE (which would require additional UI
17 * scaffolding), we open the Gluecron web UI so users can fill in labels,
18 * assignees, and description with full markdown preview.
19 */
20class CreateIssueAction : AnAction(), DumbAware {
21
22 override fun actionPerformed(e: AnActionEvent) {
23 val project = e.project ?: return
24 val settings = GluecronSettingsState.getInstance()
25
26 val (owner, repo) = GluecronUtil.detectOwnerRepo(project)
27 ?: run {
28 GluecronUtil.notify(
29 project,
30 "No Gluecron remote detected. Ensure the project has a git remote " +
31 "pointing to ${settings.host}.",
32 NotificationType.WARNING
33 )
34 return
35 }
36
37 val url = "${settings.host}/$owner/$repo/issues/new"
38 GluecronUtil.openBrowser(url)
39 }
40
41 override fun update(e: AnActionEvent) {
42 e.presentation.isEnabledAndVisible = e.project != null
43 }
44}
Addedjetbrains-plugin/src/main/kotlin/com/gluecron/actions/MergePrAction.kt+116−0View fileUnifiedSplit
1package com.gluecron.actions
2
3import com.gluecron.GluecronUtil
4import com.gluecron.settings.GluecronSettingsState
5import com.intellij.notification.NotificationType
6import com.intellij.openapi.actionSystem.AnAction
7import com.intellij.openapi.actionSystem.AnActionEvent
8import com.intellij.openapi.application.ApplicationManager
9import com.intellij.openapi.progress.ProgressIndicator
10import com.intellij.openapi.progress.ProgressManager
11import com.intellij.openapi.progress.Task
12import com.intellij.openapi.project.DumbAware
13import com.intellij.openapi.ui.Messages
14
15/**
16 * Merges the open pull request for the currently checked-out branch.
17 *
18 * Flow:
19 * 1. Detect owner/repo from the git remote URL.
20 * 2. Detect the current branch name.
21 * 3. Ask the user to confirm (the merge is irreversible).
22 * 4. POST to {host}/api/repos/{owner}/{repo}/pulls/merge
23 * with body: { "head": "<branch>", "merge_method": "merge" }
24 * 5. Show a success or error balloon notification.
25 *
26 * The API call runs on a background thread via ProgressManager so it
27 * doesn't block the EDT.
28 *
29 * This is the JetBrains equivalent of the VS Code "gluecron.mergePr" command.
30 */
31class MergePrAction : AnAction(), DumbAware {
32
33 override fun actionPerformed(e: AnActionEvent) {
34 val project = e.project ?: return
35 val settings = GluecronSettingsState.getInstance()
36
37 if (settings.token.isBlank()) {
38 GluecronUtil.notify(
39 project,
40 "Gluecron access token is not configured. " +
41 "Go to Settings → Tools → Gluecron to add your token.",
42 NotificationType.ERROR
43 )
44 return
45 }
46
47 val (owner, repo) = GluecronUtil.detectOwnerRepo(project)
48 ?: run {
49 GluecronUtil.notify(
50 project,
51 "No Gluecron remote detected. Ensure the project has a git remote " +
52 "pointing to ${settings.host}.",
53 NotificationType.WARNING
54 )
55 return
56 }
57
58 val branch = GluecronUtil.currentBranch(project)
59 ?: run {
60 GluecronUtil.notify(
61 project,
62 "Could not determine the current branch.",
63 NotificationType.WARNING
64 )
65 return
66 }
67
68 // Confirm before merging — this is a destructive action
69 val confirmed = Messages.showYesNoDialog(
70 project,
71 "Merge the open pull request for branch \"$branch\" into $owner/$repo?\n\n" +
72 "This action cannot be undone.",
73 "Merge PR — Gluecron",
74 "Merge",
75 "Cancel",
76 Messages.getQuestionIcon()
77 )
78 if (confirmed != Messages.YES) return
79
80 // Run the API call on a background thread
81 ProgressManager.getInstance().run(object : Task.Backgroundable(
82 project,
83 "Gluecron: Merging PR for branch \"$branch\"…",
84 false
85 ) {
86 override fun run(indicator: ProgressIndicator) {
87 indicator.isIndeterminate = true
88 try {
89 val path = "/api/repos/$owner/$repo/pulls/merge"
90 val body = """{"head":"$branch","merge_method":"merge"}"""
91 GluecronUtil.apiPost(path, body)
92
93 ApplicationManager.getApplication().invokeLater {
94 GluecronUtil.notify(
95 project,
96 "PR for branch \"$branch\" merged successfully into $owner/$repo.",
97 NotificationType.INFORMATION
98 )
99 }
100 } catch (ex: Exception) {
101 ApplicationManager.getApplication().invokeLater {
102 GluecronUtil.notify(
103 project,
104 "Failed to merge PR: ${ex.message}",
105 NotificationType.ERROR
106 )
107 }
108 }
109 }
110 })
111 }
112
113 override fun update(e: AnActionEvent) {
114 e.presentation.isEnabledAndVisible = e.project != null
115 }
116}
Addedjetbrains-plugin/src/main/kotlin/com/gluecron/actions/OpenPrAction.kt+44−0View fileUnifiedSplit
1package com.gluecron.actions
2
3import com.gluecron.GluecronUtil
4import com.gluecron.settings.GluecronSettingsState
5import com.intellij.notification.NotificationType
6import com.intellij.openapi.actionSystem.AnAction
7import com.intellij.openapi.actionSystem.AnActionEvent
8import com.intellij.openapi.project.DumbAware
9
10/**
11 * Opens a browser tab showing the pull request list for the current repository.
12 *
13 * URL pattern: {host}/{owner}/{repo}/pulls
14 *
15 * This is the JetBrains equivalent of the VS Code "gluecron.openOnWeb" command
16 * adapted for PR-centric workflow — surfacing the PR list rather than an
17 * individual file, since JetBrains users primarily navigate via the IDE tree.
18 */
19class OpenPrAction : AnAction(), DumbAware {
20
21 override fun actionPerformed(e: AnActionEvent) {
22 val project = e.project ?: return
23 val settings = GluecronSettingsState.getInstance()
24
25 val (owner, repo) = GluecronUtil.detectOwnerRepo(project)
26 ?: run {
27 GluecronUtil.notify(
28 project,
29 "No Gluecron remote detected. Ensure the project has a git remote " +
30 "pointing to ${settings.host}.",
31 NotificationType.WARNING
32 )
33 return
34 }
35
36 val url = "${settings.host}/$owner/$repo/pulls"
37 GluecronUtil.openBrowser(url)
38 }
39
40 override fun update(e: AnActionEvent) {
41 // Only enable when a project is open
42 e.presentation.isEnabledAndVisible = e.project != null
43 }
44}
Addedjetbrains-plugin/src/main/kotlin/com/gluecron/actions/ViewHealthAction.kt+48−0View fileUnifiedSplit
1package com.gluecron.actions
2
3import com.gluecron.GluecronUtil
4import com.gluecron.settings.GluecronSettingsState
5import com.intellij.notification.NotificationType
6import com.intellij.openapi.actionSystem.AnAction
7import com.intellij.openapi.actionSystem.AnActionEvent
8import com.intellij.openapi.project.DumbAware
9
10/**
11 * Opens a browser tab showing the repository health / CI dashboard.
12 *
13 * URL pattern: {host}/{owner}/{repo}/health
14 *
15 * The health page aggregates:
16 * - GateTest scan results from the most recent push
17 * - CI/CD pipeline status
18 * - Branch protection rule compliance
19 * - Open PR count and review coverage
20 *
21 * This is the JetBrains equivalent of the VS Code "gluecron.viewHealth" command,
22 * and mirrors the /admin/deploys live step stream mentioned in the project docs.
23 */
24class ViewHealthAction : AnAction(), DumbAware {
25
26 override fun actionPerformed(e: AnActionEvent) {
27 val project = e.project ?: return
28 val settings = GluecronSettingsState.getInstance()
29
30 val (owner, repo) = GluecronUtil.detectOwnerRepo(project)
31 ?: run {
32 GluecronUtil.notify(
33 project,
34 "No Gluecron remote detected. Ensure the project has a git remote " +
35 "pointing to ${settings.host}.",
36 NotificationType.WARNING
37 )
38 return
39 }
40
41 val url = "${settings.host}/$owner/$repo/health"
42 GluecronUtil.openBrowser(url)
43 }
44
45 override fun update(e: AnActionEvent) {
46 e.presentation.isEnabledAndVisible = e.project != null
47 }
48}
Addedjetbrains-plugin/src/main/kotlin/com/gluecron/settings/GluecronSettingsConfigurable.kt+71−0View fileUnifiedSplit
1package com.gluecron.settings
2
3import com.intellij.openapi.options.Configurable
4import com.intellij.ui.components.JBLabel
5import com.intellij.ui.components.JBTextField
6import com.intellij.util.ui.FormBuilder
7import javax.swing.JComponent
8import javax.swing.JPanel
9
10/**
11 * Settings UI for the Gluecron plugin.
12 *
13 * Accessible via: Settings → Tools → Gluecron
14 *
15 * Provides two fields:
16 * - Server URL — the Gluecron host (e.g. "https://gluecron.com")
17 * - Access Token — personal access token (glc_...)
18 */
19class GluecronSettingsConfigurable : Configurable {
20
21 private var hostField: JBTextField? = null
22 private var tokenField: JBTextField? = null
23
24 override fun getDisplayName(): String = "Gluecron"
25
26 override fun createComponent(): JComponent {
27 val settings = GluecronSettingsState.getInstance()
28
29 hostField = JBTextField(settings.host, 40)
30 tokenField = JBTextField(settings.token, 40)
31
32 return FormBuilder.createFormBuilder()
33 .addLabeledComponent(
34 JBLabel("Server URL:"),
35 hostField!!,
36 1,
37 false
38 )
39 .addLabeledComponent(
40 JBLabel("Access Token:"),
41 tokenField!!,
42 1,
43 false
44 )
45 .addComponentFillVertically(JPanel(), 0)
46 .panel
47 }
48
49 override fun isModified(): Boolean {
50 val settings = GluecronSettingsState.getInstance()
51 return hostField?.text?.trimEnd('/') != settings.host ||
52 tokenField?.text != settings.token
53 }
54
55 override fun apply() {
56 val settings = GluecronSettingsState.getInstance()
57 hostField?.text?.let { settings.host = it }
58 tokenField?.text?.let { settings.token = it }
59 }
60
61 override fun reset() {
62 val settings = GluecronSettingsState.getInstance()
63 hostField?.text = settings.host
64 tokenField?.text = settings.token
65 }
66
67 override fun disposeUIResources() {
68 hostField = null
69 tokenField = null
70 }
71}
Addedjetbrains-plugin/src/main/kotlin/com/gluecron/settings/GluecronSettingsState.kt+56−0View fileUnifiedSplit
1package com.gluecron.settings
2
3import com.intellij.openapi.application.ApplicationManager
4import com.intellij.openapi.components.PersistentStateComponent
5import com.intellij.openapi.components.State
6import com.intellij.openapi.components.Storage
7
8/**
9 * Persistent state for Gluecron plugin settings.
10 *
11 * Stored in: <config>/options/GluecronSettings.xml
12 *
13 * Fields:
14 * host — the Gluecron server base URL (e.g. "https://gluecron.com")
15 * token — a personal access token (glc_...) with read+write repo scope
16 *
17 * Both fields can also be seeded from environment variables at first
18 * launch (see [GluecronPlugin]):
19 * GLUECRON_HOST → host
20 * GLUECRON_TOKEN → token
21 */
22@State(
23 name = "GluecronSettingsState",
24 storages = [Storage("GluecronSettings.xml")]
25)
26class GluecronSettingsState : PersistentStateComponent<GluecronSettingsState.State> {
27
28 data class State(
29 var host: String = "http://localhost:3000",
30 var token: String = ""
31 )
32
33 private var myState = State()
34
35 override fun getState(): State = myState
36
37 override fun loadState(state: State) {
38 myState = state
39 }
40
41 /** Gluecron server base URL, e.g. "https://gluecron.com" (no trailing slash). */
42 var host: String
43 get() = myState.host.trimEnd('/')
44 set(value) { myState.host = value.trimEnd('/') }
45
46 /** Personal access token (glc_...). May be empty if the server is public. */
47 var token: String
48 get() = myState.token
49 set(value) { myState.token = value }
50
51 companion object {
52 fun getInstance(): GluecronSettingsState =
53 ApplicationManager.getApplication()
54 .getService(GluecronSettingsState::class.java)
55 }
56}
Addedjetbrains-plugin/src/main/resources/META-INF/plugin.xml+110−0View fileUnifiedSplit
1<idea-plugin>
2 <id>com.gluecron.jetbrains</id>
3 <name>Gluecron</name>
4 <version>0.1.0</version>
5
6 <vendor email="support@gluecron.com" url="https://gluecron.com">Gluecron</vendor>
7
8 <description><![CDATA[
9 <p>Gluecron integration for JetBrains IDEs (IntelliJ IDEA, WebStorm, GoLand, PyCharm, and more).</p>
10 <p>AI-native code intelligence platform — git hosting, automated CI, and push-time gate enforcement.</p>
11 <br/>
12 <p><b>Features:</b></p>
13 <ul>
14 <li><b>Open PR List</b> — browse open pull requests for the current repository in your browser</li>
15 <li><b>Create Issue</b> — open the new issue form for the current repository in your browser</li>
16 <li><b>Merge PR</b> — merge the open pull request for the current branch via the Gluecron API</li>
17 <li><b>View Health</b> — open the repository health/CI dashboard in your browser</li>
18 </ul>
19 <br/>
20 <p>Configure your Gluecron host URL and personal access token via
21 <b>Settings → Tools → Gluecron</b>.</p>
22 ]]></description>
23
24 <change-notes><![CDATA[
25 <ul>
26 <li>0.1.0: Initial release — Open PR, Create Issue, Merge PR, View Health</li>
27 </ul>
28 ]]></change-notes>
29
30 <!-- Minimum/maximum IDE versions (2023.1+) -->
31 <idea-version since-build="231" until-build="251.*"/>
32
33 <!-- Depends on the bundled Git4Idea plugin for VCS root detection -->
34 <depends>com.intellij.modules.platform</depends>
35 <depends>Git4Idea</depends>
36
37 <extensions defaultExtensionNs="com.intellij">
38 <!-- Startup activity: loads settings and validates connectivity -->
39 <postStartupActivity
40 implementation="com.gluecron.GluecronPlugin"/>
41
42 <!-- Persistent settings storage -->
43 <applicationService
44 serviceImplementation="com.gluecron.settings.GluecronSettingsState"/>
45
46 <!-- Settings UI page under Tools -->
47 <applicationConfigurable
48 parentId="tools"
49 instance="com.gluecron.settings.GluecronSettingsConfigurable"
50 id="com.gluecron.settings"
51 displayName="Gluecron"/>
52 </extensions>
53
54 <actions>
55 <!-- Top-level Gluecron menu in the main menu bar -->
56 <group id="GluecronMenuGroup" text="Gluecron" description="Gluecron actions" popup="true">
57 <add-to-group group-id="MainMenu" anchor="last"/>
58
59 <action
60 id="com.gluecron.actions.OpenPrAction"
61 class="com.gluecron.actions.OpenPrAction"
62 text="Open PR List"
63 description="Open the pull request list for this repository in a browser tab"
64 icon="AllIcons.Vcs.Branch">
65 </action>
66
67 <action
68 id="com.gluecron.actions.CreateIssueAction"
69 class="com.gluecron.actions.CreateIssueAction"
70 text="Create Issue"
71 description="Open the new issue form for this repository in a browser tab"
72 icon="AllIcons.General.Add">
73 </action>
74
75 <action
76 id="com.gluecron.actions.MergePrAction"
77 class="com.gluecron.actions.MergePrAction"
78 text="Merge PR for Current Branch"
79 description="Merge the open pull request for the current branch via the Gluecron API"
80 icon="AllIcons.Vcs.Merge">
81 </action>
82
83 <action
84 id="com.gluecron.actions.ViewHealthAction"
85 class="com.gluecron.actions.ViewHealthAction"
86 text="View Repo Health"
87 description="Open the repository health and CI dashboard in a browser tab"
88 icon="AllIcons.Debugger.ThreadStates.Idle">
89 </action>
90
91 <separator/>
92
93 <action
94 id="com.gluecron.actions.OpenSettingsAction"
95 class="com.intellij.openapi.options.ShowSettingsUtil"
96 text="Gluecron Settings..."
97 description="Open Gluecron plugin settings">
98 </action>
99 </group>
100
101 <!-- Also surface actions in the VCS Operations popup -->
102 <group id="GluecronVcsGroup" text="Gluecron" description="Gluecron actions" popup="true">
103 <add-to-group group-id="VcsGroups" anchor="last"/>
104 <reference ref="com.gluecron.actions.OpenPrAction"/>
105 <reference ref="com.gluecron.actions.CreateIssueAction"/>
106 <reference ref="com.gluecron.actions.MergePrAction"/>
107 <reference ref="com.gluecron.actions.ViewHealthAction"/>
108 </group>
109 </actions>
110</idea-plugin>
0111