diff --git a/plugins/MinikuraEnvironmentConfigPatcher/.gitignore b/plugins/MinikuraEnvironmentConfigPatcher/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/plugins/MinikuraEnvironmentConfigPatcher/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/plugins/MinikuraEnvironmentConfigPatcher/.run/minikura-environment-config-patcher.run.xml b/plugins/MinikuraEnvironmentConfigPatcher/.run/minikura-environment-config-patcher.run.xml
new file mode 100644
index 0000000..a23a18c
--- /dev/null
+++ b/plugins/MinikuraEnvironmentConfigPatcher/.run/minikura-environment-config-patcher.run.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/MinikuraEnvironmentConfigPatcher/dependency-reduced-pom.xml b/plugins/MinikuraEnvironmentConfigPatcher/dependency-reduced-pom.xml
new file mode 100644
index 0000000..f97a89d
--- /dev/null
+++ b/plugins/MinikuraEnvironmentConfigPatcher/dependency-reduced-pom.xml
@@ -0,0 +1,138 @@
+
+
+ 4.0.0
+ cafe.kirameki
+ minikura-environment-config-patcher
+ 1.0-SNAPSHOT
+
+ src/main/kotlin
+ src/test/kotlin
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ 2.0.20
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+
+ maven-surefire-plugin
+ 2.22.2
+
+
+ maven-failsafe-plugin
+ 2.22.2
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+ MainKt
+
+
+
+ maven-jar-plugin
+ 3.2.2
+
+
+
+ MainKt
+
+
+
+
+
+ maven-shade-plugin
+ 3.4.1
+
+
+ package
+
+ shade
+
+
+ true
+
+
+ MainKt
+
+
+
+
+
+
+
+
+
+
+ mavenCentral
+ https://repo1.maven.org/maven2/
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-test-junit5
+ 2.0.20
+ test
+
+
+ kotlin-test
+ org.jetbrains.kotlin
+
+
+ junit-jupiter-api
+ org.junit.jupiter
+
+
+ junit-jupiter-engine
+ org.junit.jupiter
+
+
+ junit-platform-launcher
+ org.junit.platform
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.0
+ test
+
+
+ junit-jupiter-params
+ org.junit.jupiter
+
+
+ junit-jupiter-api
+ org.junit.jupiter
+
+
+ junit-jupiter-engine
+ org.junit.jupiter
+
+
+
+
+
+ official
+ UTF-8
+ 1.8
+
+
diff --git a/plugins/MinikuraEnvironmentConfigPatcher/pom.xml b/plugins/MinikuraEnvironmentConfigPatcher/pom.xml
new file mode 100644
index 0000000..821437b
--- /dev/null
+++ b/plugins/MinikuraEnvironmentConfigPatcher/pom.xml
@@ -0,0 +1,126 @@
+
+
+ 4.0.0
+
+ cafe.kirameki
+ minikura-environment-config-patcher
+ 1.0-SNAPSHOT
+
+
+ UTF-8
+ official
+ 1.8
+
+
+
+
+ mavenCentral
+ https://repo1.maven.org/maven2/
+
+
+
+
+ src/main/kotlin
+ src/test/kotlin
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ 2.0.20
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+
+ maven-surefire-plugin
+ 2.22.2
+
+
+ maven-failsafe-plugin
+ 2.22.2
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+ MainKt
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.2
+
+
+
+ MainKt
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.4.1
+
+
+ package
+
+ shade
+
+
+ true
+
+
+ MainKt
+
+
+
+
+
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-test-junit5
+ 2.0.20
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.0
+ test
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ 2.0.20
+
+
+ org.yaml
+ snakeyaml
+ 2.0
+
+
+
+
\ No newline at end of file
diff --git a/plugins/MinikuraEnvironmentConfigPatcher/src/main/kotlin/Main.kt b/plugins/MinikuraEnvironmentConfigPatcher/src/main/kotlin/Main.kt
new file mode 100644
index 0000000..2cce665
--- /dev/null
+++ b/plugins/MinikuraEnvironmentConfigPatcher/src/main/kotlin/Main.kt
@@ -0,0 +1,147 @@
+import org.yaml.snakeyaml.DumperOptions
+import org.yaml.snakeyaml.LoaderOptions
+import org.yaml.snakeyaml.Yaml
+import org.yaml.snakeyaml.constructor.Constructor
+import java.io.File
+
+const val PREFIX = "minikura-environment-config-patcher"
+
+fun main() {
+ val envVars = System.getenv()
+
+ val patchConfigVars = envVars.filter { it.key.startsWith("PATCH_YAML_CONFIG_") }
+
+ for ((key, value) in patchConfigVars) {
+ println("[${getCurrentTime()} INFO] [$PREFIX]: Processing $key")
+
+ val lines = splitWithEscapedPipe(value)
+ if (lines.size < 2) {
+ println("[${getCurrentTime()} INFO] [$PREFIX]: Skipping. Insufficient data.")
+ continue
+ }
+
+ val yamlFilePath = lines[0].trim()
+ val yamlFile = File(yamlFilePath)
+ if (!yamlFile.exists()) {
+ println("[${getCurrentTime()} INFO] [$PREFIX]: Skipping. File does not exist.")
+ continue
+ }
+
+ val replacements = mutableMapOf()
+
+ lines.drop(1).forEach { line ->
+ val keyValue = line.split("=", limit = 2)
+ if (keyValue.size == 2) {
+ val key = keyValue[0].trim()
+ val value = parseValue(keyValue[1].trim())
+
+ val (baseKey, index, subKey) = parseKeyWithIndex(key)
+
+ if (index != null) {
+ val arrayData = replacements.computeIfAbsent(baseKey) { mutableListOf>() } as MutableList>
+
+ while (arrayData.size <= index) {
+ arrayData.add(mutableMapOf())
+ }
+
+ val arrayItem = arrayData[index]
+ arrayItem[subKey] = value
+ println("[${getCurrentTime()} INFO] [$PREFIX]: Editing key: $baseKey[$index].$subKey")
+ } else {
+ replacements[baseKey] = value
+ println("[${getCurrentTime()} INFO] [$PREFIX]: Editing key: $baseKey")
+ }
+ } else {
+ println("[${getCurrentTime()} WARN] [$PREFIX]: Skipping malformed line.")
+ }
+ }
+
+ try {
+ val updatedYaml = updateYaml(yamlFile, replacements)
+ yamlFile.writeText(updatedYaml)
+ println("[${getCurrentTime()} INFO] [$PREFIX]: Successfully updated $yamlFilePath")
+ } catch (e: Exception) {
+ println("[${getCurrentTime()} ERROR] [$PREFIX]: Error processing $yamlFilePath. ${e.message}")
+ }
+ }
+
+ println("[${getCurrentTime()} INFO] [$PREFIX]: Patch completed")
+}
+
+fun getCurrentTime(): String {
+ val currentDate = java.time.LocalTime.now()
+ return currentDate.toString().substring(0, 8)
+}
+
+fun splitWithEscapedPipe(value: String): List {
+ val regex = "(? true
+ value.equals("false", ignoreCase = true) -> false
+ value.startsWith("\"") && value.endsWith("\"") -> value.substring(1, value.length - 1)
+ value.startsWith("'") && value.endsWith("'") -> value.substring(1, value.length - 1)
+ value.toIntOrNull() != null -> value.toInt()
+ value.startsWith("[") && value.endsWith("]") -> parseArray(value)
+ else -> value
+ }
+}
+
+fun parseArray(value: String): List